From 4e13164a4aab044ce5ba76c6a6dad8b566d41794 Mon Sep 17 00:00:00 2001 From: Antonio Carlos Ribeiro Date: Sun, 22 Sep 2024 21:35:46 +0200 Subject: [PATCH] Fix up all config variables --- config/classes.php | 22 +- config/domains.php | 18 +- config/{frontend-checker.php => frontend.php} | 2 +- config/invalidations.php | 294 +++++++++--------- config/responses.php | 2 +- config/{routes.php => routing.php} | 0 config/services.php | 72 ++--- config/strategies.php | 4 +- config/warmer.php | 118 ++++--- src/Behaviours/CastObject.php | 2 +- src/Behaviours/MakeTag.php | 27 +- src/ServiceProvider.php | 6 +- src/Services/BaseService.php | 4 +- src/Services/CacheControl.php | 62 ++-- src/Services/Entity.php | 18 +- src/Services/Tags.php | 13 +- src/Support/Helpers.php | 21 +- 17 files changed, 345 insertions(+), 340 deletions(-) rename config/{frontend-checker.php => frontend.php} (81%) rename config/{routes.php => routing.php} (100%) diff --git a/config/classes.php b/config/classes.php index 5e5935f..e5bbcfd 100644 --- a/config/classes.php +++ b/config/classes.php @@ -1,19 +1,17 @@ [ - 'cdn' => A17\EdgeFlush\Services\CloudFront\Service::class, +/** + * Service classes + * + * Supported CDN services: Akamai, CloudFront + * + */ + 'cdn' => A17\EdgeFlush\Services\CloudFront\Service::class, - 'cache-control' => A17\EdgeFlush\Services\CacheControl::class, + 'cache-control' => A17\EdgeFlush\Services\CacheControl::class, - 'tags' => A17\EdgeFlush\Services\Tags::class, + 'tags' => A17\EdgeFlush\Services\Tags::class, - 'warmer' => A17\EdgeFlush\Services\Warmer::class, - ], + 'warmer' => A17\EdgeFlush\Services\Warmer::class, ]; diff --git a/config/domains.php b/config/domains.php index a082aa9..f22aa29 100644 --- a/config/domains.php +++ b/config/domains.php @@ -3,15 +3,13 @@ use A17\EdgeFlush\Support\Helpers; return [ - /** - * Only allowed domains will have tags stored. - * An empty array will allow all domains. - */ - 'domains' => [ - 'allowed' => [ - Helpers::parseUrl(env('APP_URL'))['host'] - ], - - 'blocked' => [] +/** + * Only allowed domains will have tags stored. + * An empty array will allow all domains. + */ + 'allowed' => [ + Helpers::parseUrl(env('APP_URL'))['host'] ], + + 'blocked' => [] ]; diff --git a/config/frontend-checker.php b/config/frontend.php similarity index 81% rename from config/frontend-checker.php rename to config/frontend.php index 3b56605..9131fa1 100644 --- a/config/frontend-checker.php +++ b/config/frontend.php @@ -11,5 +11,5 @@ * 'frontend-checker' => true, * */ - 'frontend-checker' => A17\EdgeFlush\Services\FrontendChecker::class, + 'checker' => A17\EdgeFlush\Services\FrontendChecker::class, ]; diff --git a/config/invalidations.php b/config/invalidations.php index a3ba70f..8220d40 100644 --- a/config/invalidations.php +++ b/config/invalidations.php @@ -1,178 +1,176 @@ 'invalidate', // invalidate, delete + + 'type' => 'batch', // single, batch + + 'batch' => [ + 'size' => 2999, /// urls + + 'flush_roots_if_exceeds' => 15000, + + 'roots' => ['/*'], + ], + /** - * Invalidations. - * - * Invalidations can be sent one by one or in batch. In this section you can configure - * this and also set the limits. - * - * method: - * invalidate: tell CDN to invalidate the page - * delete: tell CDN to delete the page - * - * type: - * single: invalidations are executed immediately after a model is updated. - * batch: invalidations are executed every x minutes. - * - * batch: - * size: How many invalidations should be sent every time we invalidate? - * flush_roots_if_exceeds: If there are more than this, we should just invalidate the whole site - * roots: What are the paths to invalidate "the whole site"? + * Ignore certain attributes when invalidating or creating tags */ - 'invalidations' => [ - 'method' => 'invalidate', // invalidate, delete - - 'type' => 'batch', // single, batch - - 'batch' => [ - 'size' => 2999, /// urls + 'attributes' => [ + 'ignore' => [ + '*' => ['id', 'locale', 'localMacros', 'without'], - 'flush_roots_if_exceeds' => 15000, - - 'roots' => ['/*'], + 'App\Models\Translations\EventTranslation' => ['event_id'] + ], + 'always-add' => [ + '*' => ['published'] ], + ], - /** - * Ignore certain attributes when invalidating or creating tags - */ - 'attributes' => [ - 'ignore' => [ - '*' => ['id', 'locale', 'localMacros', 'without'], + 'crud-strategy' => [ + 'updated' => [ + /** + * Default behaviour if model not specified + * + * invalidate-dependents: invalidate paths that depends of this model and attribute + * invalidate-all: invalidate all paths + * invalidate-none: don't do anything + */ + 'default' => 'invalidate-dependents', // invalidate-dependents, invalidate-all, invalidate-none + + /** + * We can setup specific behaviour for each model, depending on how their attributes changes + * + * Let's say you have a listing on your site that shows all the posts on a page when you publish them. + * If you create a new post unpublished, your pages should not be invalidated because this new post + * would not appear on a page. But if you publish it, your pages should be invalidated. + */ + 'when-models' => [ + [ + /** + * List of models + */ + 'models' => [ + 'App\Models\Artwork', + 'App\Models\Event', + ], - 'App\Models\Translations\EventTranslation' => ['event_id'] - ], - 'always-add' => [ - '*' => ['published'] - ], - ], + /** + * When a particular attribute changes + */ + 'on-change' => [ + 'published' => true, // attribute changed to "true" + ], - 'crud-strategy' => [ - 'updated' => [ - /** - * Default behaviour if model not specified - * - * invalidate-dependents: invalidate paths that depends of this model and attribute - * invalidate-all: invalidate all paths - * invalidate-none: don't do anything - */ - 'default' => 'invalidate-dependents', // invalidate-dependents, invalidate-all, invalidate-none - - /** - * We can setup specific behaviour for each model, depending on how their attributes changes - * - * Let's say you have a listing on your site that shows all the posts on a page when you publish them. - * If you create a new post unpublished, your pages should not be invalidated because this new post - * would not appear on a page. But if you publish it, your pages should be invalidated. - */ - 'when-models' => [ - [ - /** - * List of models - */ - 'models' => [ - 'App\Models\Artwork', - 'App\Models\Event', - ], - - /** - * When a particular attribute changes - */ - 'on-change' => [ - 'published' => true, // attribute changed to "true" - ], - - /** - * Invalidate the whole site - * - * TODO: should we tell which pages to invalidate here? - */ - 'strategy' => 'invalidate-all', + /** + * Invalidate the whole site + * + * TODO: should we tell which pages to invalidate here? + */ + 'strategy' => 'invalidate-all', + ], + [ + 'models' => [ + A17\EdgeFlush\Models\Url::class, + A17\EdgeFlush\Models\Tag::class, ], - [ - 'models' => [ - A17\EdgeFlush\Models\Url::class, - A17\EdgeFlush\Models\Tag::class, - ], - 'strategy' => 'invalidate-none', - ] + 'strategy' => 'invalidate-none', ] - ], + ] + ], - 'created' => [ - /** - * If when-model condition is not met, we don't do anything - */ - 'default' => 'invalidate-none', - - 'when-models' => [ - [ - 'models' => [ - 'App\Models\Person', - ], - - /** - * If we are creating a new person, already published, we should invalidate the whole site - */ - 'on-change' => [ - 'published' => true, // attribute changed to "true" - ], - - 'strategy' => 'invalidate-all', + 'created' => [ + /** + * If when-model condition is not met, we don't do anything + */ + 'default' => 'invalidate-none', + + 'when-models' => [ + [ + 'models' => [ + 'App\Models\Person', ], - [ - 'models' => [ - A17\EdgeFlush\Models\Url::class, - A17\EdgeFlush\Models\Tag::class, - ], - 'strategy' => 'invalidate-none', - ] - ], - ], + /** + * If we are creating a new person, already published, we should invalidate the whole site + */ + 'on-change' => [ + 'published' => true, // attribute changed to "true" + ], - 'deleted' => [ - /** - * Anything deleted on the website invalidates the whole site - */ - 'default' => 'invalidate-all', + 'strategy' => 'invalidate-all', + ], + [ + 'models' => [ + A17\EdgeFlush\Models\Url::class, + A17\EdgeFlush\Models\Tag::class, + ], - 'when-models' => [ - [ - 'models' => [ - A17\EdgeFlush\Models\Url::class, - A17\EdgeFlush\Models\Tag::class, - ], + 'strategy' => 'invalidate-none', + ] + ], + ], - 'strategy' => 'invalidate-none', + 'deleted' => [ + /** + * Anything deleted on the website invalidates the whole site + */ + 'default' => 'invalidate-all', + + 'when-models' => [ + [ + 'models' => [ + A17\EdgeFlush\Models\Url::class, + A17\EdgeFlush\Models\Tag::class, ], + + 'strategy' => 'invalidate-none', ], ], + ], - 'pivot-synced' => [ - /** - * Anything deleted on the website invalidates the whole site - */ - 'default' => 'invalidate-dependents', - ], + 'pivot-synced' => [ + /** + * Anything deleted on the website invalidates the whole site + */ + 'default' => 'invalidate-dependents', + ], - 'on-all-events' => [ - /** - * On all events, also invalidate those - */ - 'default' => 'invalidate-none', + 'on-all-events' => [ + /** + * On all events, also invalidate those + */ + 'default' => 'invalidate-none', - 'when-models' => [ - [ - 'models' => ['*'], + 'when-models' => [ + [ + 'models' => ['*'], - 'strategy' => 'invalidate-urls', + 'strategy' => 'invalidate-urls', - 'urls' => [ - '%sitemap.xml%', - ] - ], + 'urls' => [ + '%sitemap.xml%', + ] ], ], ], diff --git a/config/responses.php b/config/responses.php index 41f1881..1ad8617 100644 --- a/config/responses.php +++ b/config/responses.php @@ -18,7 +18,7 @@ /** * Allowed responses */ - 'responses' => [ + 'types' => [ 'cachable' => [ Illuminate\Http\Response::class, Illuminate\Http\JsonResponse::class, diff --git a/config/routes.php b/config/routing.php similarity index 100% rename from config/routes.php rename to config/routing.php diff --git a/config/services.php b/config/services.php index 68cb7d8..20af69c 100644 --- a/config/services.php +++ b/config/services.php @@ -1,54 +1,54 @@ [ - 'akamai' => [ - 'host' => env('EDGE_FLUSH_AKAMAI_HOST', env('AKAMAI_HOST')), +/** + * Services configuration + */ + 'akamai' => [ + 'enabled' => env('EDGE_FLUSH_AKAMAI_ENABLED', false), - 'access_token' => env('EDGE_FLUSH_AKAMAI_ACCESS_TOKEN', env('AKAMAI_ACCESS_TOKEN')), + 'host' => env('EDGE_FLUSH_AKAMAI_HOST', env('AKAMAI_HOST')), - 'client_token' => env('EDGE_FLUSH_AKAMAI_CLIENT_TOKEN', env('AKAMAI_CLIENT_TOKEN')), + 'access_token' => env('EDGE_FLUSH_AKAMAI_ACCESS_TOKEN', env('AKAMAI_ACCESS_TOKEN')), - 'client_secret' => env('EDGE_FLUSH_AKAMAI_CLIENT_SECRET', env('AKAMAI_CLIENT_SECRET')), + 'client_token' => env('EDGE_FLUSH_AKAMAI_CLIENT_TOKEN', env('AKAMAI_CLIENT_TOKEN')), - 'invalidate_all_paths' => null, // there's no invalidate all on Akamai + 'client_secret' => env('EDGE_FLUSH_AKAMAI_CLIENT_SECRET', env('AKAMAI_CLIENT_SECRET')), - 'max_urls' => 499, // Akamai is limited to 500 cache tags per minute - ], + 'invalidate_all_paths' => null, // there's no invalidate all on Akamai - 'cloud_front' => [ - 'enabled' => env('EDGE_FLUSH_CLOUD_FRONT_ENABLED', true), + 'max_urls' => 499, // Akamai is limited to 500 cache tags per minute + ], + + 'cloud_front' => [ + 'enabled' => env('EDGE_FLUSH_CLOUD_FRONT_ENABLED', true), - 'sdk_version' => env( - 'EDGE_FLUSH_CLOUD_FRONT_SDK_VERSION', - '2016-01-13', - ), + 'sdk_version' => env( + 'EDGE_FLUSH_CLOUD_FRONT_SDK_VERSION', + '2016-01-13', + ), - 'region' => env( - 'EDGE_FLUSH_AWS_DEFAULT_REGION', - env('AWS_DEFAULT_REGION', 'us-east-1'), - ), + 'region' => env( + 'EDGE_FLUSH_AWS_DEFAULT_REGION', + env('AWS_DEFAULT_REGION', 'us-east-1'), + ), - 'distribution_id' => env( - 'EDGE_FLUSH_AWS_CLOUDFRONT_DISTRIBUTION_ID', - ), + 'distribution_id' => env( + 'EDGE_FLUSH_AWS_CLOUDFRONT_DISTRIBUTION_ID', + ), - 'key' => env( - 'EDGE_FLUSH_AWS_CLOUDFRONT_KEY', - env('AWS_ACCESS_KEY_ID'), - ), + 'key' => env( + 'EDGE_FLUSH_AWS_CLOUDFRONT_KEY', + env('AWS_ACCESS_KEY_ID'), + ), - 'secret' => env( - 'EDGE_FLUSH_AWS_CLOUDFRONT_SECRET', - env('AWS_SECRET_ACCESS_KEY'), - ), + 'secret' => env( + 'EDGE_FLUSH_AWS_CLOUDFRONT_SECRET', + env('AWS_SECRET_ACCESS_KEY'), + ), - 'invalidate_all_paths' => ['/*'], + 'invalidate_all_paths' => ['/*'], - 'max_urls' => 3000, // CloudFront has this limit - ], + 'max_urls' => 3000, // CloudFront has this limit ], ]; diff --git a/config/strategies.php b/config/strategies.php index 09d97dc..c0a3df4 100644 --- a/config/strategies.php +++ b/config/strategies.php @@ -33,7 +33,7 @@ ], /** - * Caching strategies. + * Caching strategy types. * * Refer to https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control * @@ -64,7 +64,7 @@ * only-if-cached * */ - 'strategies' => [ + 'types' => [ 'dynamic' => ['s-maxage', 'max-age', 'public'], // built-in 'zero' => ['s-maxage=0', 'max-age=0', 'no-store'], // built-in diff --git a/config/warmer.php b/config/warmer.php index 0a9d7fa..3e46f6d 100644 --- a/config/warmer.php +++ b/config/warmer.php @@ -3,65 +3,63 @@ use A17\EdgeFlush\Support\Constants; return [ - /** - * Purged cache can be rewarmed. Enable and configure it here. - * - * max_urls: how many urls max should the warmer try to warm per session? - * - * max_time: how much time the whole job warming session can take? - * - * connection_timeout: to warm up a page we don't actually need to get the page contents - * that's why the warmer will kill the connection (possibly) before - * the server is able to respond with contents. The idea here is - * to speed up the warming process and save bandwidth. - * - * concurrent_requests: how many concurrent requests the warmer should dispatch per session? - * - * warm_all_on_purge: if the whole CDN cache is purged, do you wish to warm back all pages? - * - * basic_authentication: to be used by Guzzle to authenticate - * - * headers: as the headers are not built by a webserver, we need to pass the actual - * expected headers after webserver or PHP processed them. It's the case for the - * Authorization, which, after unpacking, is translated to PHP_AUTH_USER and PHP_AUTH_PW - */ - 'warmer' => [ - 'enabled' => env('EDGE_FLUSH_WARMER_ENABLED', true), - - 'types' => ['internal', 'external'], - - 'max_urls' => 100, - - 'max_time' => Constants::MILLISECOND * 1000, - - 'connection_timeout' => Constants::MILLISECOND * 500, - - 'concurrent_requests' => 50, - - 'warm_all_on_purge' => true, - - 'basic_authentication' => [ - 'username' => ($username = env('HTTP_AUTH_USER')), - 'password' => ($password = env('HTTP_AUTH_PASSWORD')) - ], - - 'headers' => [ - 'PHP_AUTH_USER' => $username, - 'PHP_AUTH_PW' => $password, - ], - - 'check_ssl_certificate' => false, // It's too slow to check SSL certificates - - 'curl' => [ - 'connect_only' => false, // only connect to the server? - - 'get_body' => true, // get the page data? Use HEAD instead of GET - - 'compress' => true, // force cURL requests to behave like browser ones by accepting compressed content - - 'extra_options' => [] // cURL extra options - ], - - 'extra_options' => [], // Guzzle extra options +/** + * Purged cache can be rewarmed. Enable and configure it here. + * + * max_urls: how many urls max should the warmer try to warm per session? + * + * max_time: how much time the whole job warming session can take? + * + * connection_timeout: to warm up a page we don't actually need to get the page contents + * that's why the warmer will kill the connection (possibly) before + * the server is able to respond with contents. The idea here is + * to speed up the warming process and save bandwidth. + * + * concurrent_requests: how many concurrent requests the warmer should dispatch per session? + * + * warm_all_on_purge: if the whole CDN cache is purged, do you wish to warm back all pages? + * + * basic_authentication: to be used by Guzzle to authenticate + * + * headers: as the headers are not built by a webserver, we need to pass the actual + * expected headers after webserver or PHP processed them. It's the case for the + * Authorization, which, after unpacking, is translated to PHP_AUTH_USER and PHP_AUTH_PW + */ + 'enabled' => env('EDGE_FLUSH_WARMER_ENABLED', true), + + 'types' => ['internal', 'external'], + + 'max_urls' => 100, + + 'max_time' => Constants::MILLISECOND * 1000, + + 'connection_timeout' => Constants::MILLISECOND * 500, + + 'concurrent_requests' => 50, + + 'warm_all_on_purge' => true, + + 'basic_authentication' => [ + 'username' => ($username = env('HTTP_AUTH_USER')), + 'password' => ($password = env('HTTP_AUTH_PASSWORD')) ], + + 'headers' => [ + 'PHP_AUTH_USER' => $username, + 'PHP_AUTH_PW' => $password, + ], + + 'check_ssl_certificate' => false, // It's too slow to check SSL certificates + + 'curl' => [ + 'connect_only' => false, // only connect to the server? + + 'get_body' => true, // get the page data? Use HEAD instead of GET + + 'compress' => true, // force cURL requests to behave like browser ones by accepting compressed content + + 'extra_options' => [] // cURL extra options + ], + + 'extra_options' => [], // Guzzle extra options ]; diff --git a/src/Behaviours/CastObject.php b/src/Behaviours/CastObject.php index d793a2c..6bc327f 100644 --- a/src/Behaviours/CastObject.php +++ b/src/Behaviours/CastObject.php @@ -9,7 +9,7 @@ trait CastObject { public function getInternalModel(Model $model): Model { - $internal = Helpers::configString('edge-flush.tags.external-models.'.get_class($model)); + $internal = Helpers::configString('edge-flush.strategies.tags.external-models.'.get_class($model)); if (blank($internal)) { return $model; diff --git a/src/Behaviours/MakeTag.php b/src/Behaviours/MakeTag.php index 9ecedc7..23bda54 100644 --- a/src/Behaviours/MakeTag.php +++ b/src/Behaviours/MakeTag.php @@ -61,7 +61,7 @@ public function getCDNCacheTagFromModel(mixed $model, string $key = null, string public function tagIsExcluded(string $tag): bool { - $this->excludedModels ??= Helpers::collect(config('edge-flush.tags.excluded-model-classes')); + $this->excludedModels ??= Helpers::collect(config('edge-flush.strategies.tags.excluded-model-classes')); /** * @param callable(string $pattern): boolean $pattern @@ -87,7 +87,11 @@ public function encodeValueForComparison(mixed $value, string|null $type = null) } if ($type === 'boolean' || is_bool($value)) { - return (bool) $value ? 'true' : 'false'; + return (bool) $value ? '1' : '0'; + } + + if ($value instanceof \Carbon\Carbon) { + $value = (string) $value; } if ($type === 'string' || $type === 'array' || $type === 'object') { @@ -108,13 +112,9 @@ public function encodeValueForComparison(mixed $value, string|null $type = null) return '--- cannot cast to string --- ' . Str::random(16); } - public function granularPropertyIsAllowed(string $name, Model|string $model): bool + public function granularAttributeIsAllowed(string $name, Model|string $model): bool { - $ignored = Helpers::collect(Helpers::configArray('edge-flush.invalidations.properties.ignored')); - - $model = $model instanceof Model ? get_class($model) : $model; - - return !$ignored->contains($name) && !$ignored->contains("$model@$name"); + return !$this->attributeMustBeIgnored($model, $name); } public function attributeExists(Model $model, string $attribute): bool @@ -142,4 +142,15 @@ public function isRelation(Model $model, string $attribute): bool return $relation instanceof Relation; } + + protected function attributeMustBeIgnored(Model|string $model, string $attribute): bool + { + $model = $model instanceof Model ? get_class($model) : $model; + + $attributes = Helpers::configArray("edge-flush.invalidations.attributes.ignore", []); + + $ignore = array_merge($attributes[$model] ?? [], ($attributes['*'] ?? [])); + + return in_array($attribute, $ignore); + } } diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 5c88063..5b43693 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -28,12 +28,12 @@ class ServiceProvider extends IlluminateServiceProvider 'domains', 'strategies', 'classes', - 'routes', + 'routing', 'invalidations', 'services', 'warmer', 'responses', - 'frontend-checker', + 'frontend', ]; public function boot(): void @@ -137,7 +137,7 @@ public function registerMainConfig(): void public function registerConfigSections(): void { foreach ($this->configSections as $section) { - $this->mergeConfigFrom(__DIR__ . "/../config/{$section}.php", "{$this->packageName}"); + $this->mergeConfigFrom(__DIR__ . "/../config/{$section}.php", "{$this->packageName}.{$section}"); } config(["{$this->packageName}.package.name" => $this->packageName]); diff --git a/src/Services/BaseService.php b/src/Services/BaseService.php index 383898a..e51c720 100644 --- a/src/Services/BaseService.php +++ b/src/Services/BaseService.php @@ -99,7 +99,7 @@ public function getInvalidationPathsForTags(Invalidation $invalidation): Collect public function addHeadersFromRequest(Response $response): void { - (new Collection(Helpers::configArray('edge-flush.headers.from-request')))->each(function (string $header) use ( + (new Collection(Helpers::configArray('edge-flush.strategies.headers.from-request')))->each(function (string $header) use ( $response ) { if (filled($value = request()->header($header))) { @@ -110,7 +110,7 @@ public function addHeadersFromRequest(Response $response): void protected function addTagToHeaders(string $service, Response $response, string $value): void { - (new Collection(Helpers::configArray("edge-flush.headers.$service")))->each( + (new Collection(Helpers::configArray("edge-flush.strategies.headers.$service")))->each( fn(string $header) => $response->headers->set($header, (new Collection([$value]))->join(', ')), ); } diff --git a/src/Services/CacheControl.php b/src/Services/CacheControl.php index f21c54c..da2fdff 100644 --- a/src/Services/CacheControl.php +++ b/src/Services/CacheControl.php @@ -80,17 +80,17 @@ public function getCacheStrategy(Response $response): string if (!$this->methodIsCachable()) { return $this->buildStrategy( - Helpers::configString('edge-flush.default-strategies.non-cachable-http-methods'), + Helpers::configString('edge-flush.strategies.default-strategies.non-cachable-http-methods'), ); } if ($this->containsValidForm($response)) { - return $this->buildStrategy(Helpers::configString('edge-flush.default-strategies.pages-with-valid-forms')); + return $this->buildStrategy(Helpers::configString('edge-flush.strategies.default-strategies.pages-with-valid-forms')); } return $this->isCachable($response) - ? $this->buildStrategy(Helpers::configString('edge-flush.default-strategies.cachable-requests')) - : $this->buildStrategy(Helpers::configString('edge-flush.default-strategies.non-cachable-requests')); + ? $this->buildStrategy(Helpers::configString('edge-flush.strategies.default-strategies.cachable-requests')) + : $this->buildStrategy(Helpers::configString('edge-flush.strategies.default-strategies.non-cachable-requests')); } protected function getContent(Response $response): string @@ -145,8 +145,8 @@ protected function containsValidForm(Response $response): bool { $hasForm = false; - if (Helpers::configBool('edge-flush.valid_forms.enabled', false)) { - $hasForm = Helpers::collect(Helpers::configArray('edge-flush.valid_forms.strings'))->reduce(function ( + if (Helpers::configBool('edge-flush.responses.valid_forms.enabled', false)) { + $hasForm = Helpers::collect(Helpers::configArray('edge-flush.responses.valid_forms.strings'))->reduce(function ( bool $hasForm, mixed $string ) use ($response) { @@ -166,7 +166,7 @@ protected function containsValidForm(Response $response): bool protected function isFrontend(): bool { - $checker = Helpers::configMixed('edge-flush.frontend-checker'); + $checker = Helpers::configMixed('edge-flush.frontend.checker'); if (is_callable($checker)) { return $checker(); @@ -242,7 +242,7 @@ protected function __setMaxAge(int|string $age, string $field): self return $this; } - $strategy = Helpers::configString("edge-flush.$field.strategy"); + $strategy = Helpers::configString("edge-flush.strategies.$field.strategy"); $property = $field === 's-maxage' ? 'sMaxAge' : 'maxAge'; @@ -265,12 +265,12 @@ protected function __setMaxAge(int|string $age, string $field): self public function getDefaultSMaxAge(): int { - return Helpers::configInt('edge-flush.s-maxage.default') ?? Constants::MS_WEEK; + return Helpers::configInt('edge-flush.strategies.s-maxage.default') ?? Constants::MS_WEEK; } public function getDefaultMaxAge(): int { - return Helpers::configInt('edge-flush.max-age.default') ?? 0; + return Helpers::configInt('edge-flush.strategies.max-age.default') ?? 0; } public function buildStrategy(string|null $strategy): string @@ -337,9 +337,9 @@ public function responseIsCachable(Response $response): bool return false; } - return (Helpers::collect(Helpers::configArray('edge-flush.responses.cachable'))->isEmpty() || - Helpers::collect(Helpers::configArray('edge-flush.responses.cachable'))->contains(get_class($response))) && - !Helpers::collect(Helpers::configArray('edge-flush.responses.not-cachable'))->contains(get_class($response)); + return (Helpers::collect(Helpers::configArray('edge-flush.responses.types.cachable'))->isEmpty() || + Helpers::collect(Helpers::configArray('edge-flush.responses.types.cachable'))->contains(get_class($response))) && + !Helpers::collect(Helpers::configArray('edge-flush.responses.types.not-cachable'))->contains(get_class($response)); } public function methodIsCachable(): bool @@ -348,9 +348,9 @@ public function methodIsCachable(): bool return false; } - return (Helpers::collect(Helpers::configArray('edge-flush.methods.cachable'))->isEmpty() || - Helpers::collect(Helpers::configArray('edge-flush.methods.cachable'))->contains(EdgeFlush::getRequest()->getMethod())) && - !Helpers::collect(Helpers::configArray('edge-flush.methods.not-cachable'))->contains( + return (Helpers::collect(Helpers::configArray('edge-flush.strategies.methods.cachable'))->isEmpty() || + Helpers::collect(Helpers::configArray('edge-flush.strategies.methods.cachable'))->contains(EdgeFlush::getRequest()->getMethod())) && + !Helpers::collect(Helpers::configArray('edge-flush.strategies.methods.not-cachable'))->contains( EdgeFlush::getRequest()->getMethod(), ); } @@ -361,9 +361,9 @@ public function statusCodeIsCachable(Response $response): bool return false; } - return (Helpers::collect(Helpers::configArray('edge-flush.statuses.cachable'))->isEmpty() || - Helpers::collect(Helpers::configArray('edge-flush.statuses.cachable'))->contains($response->getStatusCode())) && - !Helpers::collect(Helpers::configArray('edge-flush.statuses.not-cachable'))->contains($response->getStatusCode()); + return (Helpers::collect(Helpers::configArray('edge-flush.strategies.statuses.cachable'))->isEmpty() || + Helpers::collect(Helpers::configArray('edge-flush.strategies.statuses.cachable'))->contains($response->getStatusCode())) && + !Helpers::collect(Helpers::configArray('edge-flush.strategies.statuses.not-cachable'))->contains($response->getStatusCode()); } public function routeIsCachable(): bool @@ -377,7 +377,7 @@ public function routeIsCachable(): bool $route = (string) ($route instanceof Route ? $route->getName() : null); if (blank($route)) { - return Helpers::configBool('edge-flush.routes.cache_nameless_routes', false); + return Helpers::configBool('edge-flush.routing.routes.cache_nameless_routes', false); } /** @@ -385,9 +385,9 @@ public function routeIsCachable(): bool */ $filter = fn(string $pattern) => EdgeFlush::match($pattern, $route); - return (Helpers::collect(Helpers::configArray('edge-flush.routes.cachable'))->isEmpty() || - Helpers::collect(Helpers::configArray('edge-flush.routes.cachable'))->contains($filter)) && - !Helpers::collect(Helpers::configArray('edge-flush.routes.not-cachable'))->contains($filter); + return (Helpers::collect(Helpers::configArray('edge-flush.routing.routes.cachable'))->isEmpty() || + Helpers::collect(Helpers::configArray('edge-flush.routing.routes.cachable'))->contains($filter)) && + !Helpers::collect(Helpers::configArray('edge-flush.routing.routes.not-cachable'))->contains($filter); } public function urlIsCachable(): bool @@ -403,14 +403,14 @@ public function urlIsCachable(): bool */ $filter = fn(string $pattern) => EdgeFlush::match($pattern, $url); - return (Helpers::collect(Helpers::configArray('edge-flush.urls.cachable'))->isEmpty() || - Helpers::collect(Helpers::configArray('edge-flush.urls.cachable'))->contains($filter)) && - !Helpers::collect(Helpers::configArray('edge-flush.urls.not-cachable'))->contains($filter); + return (Helpers::collect(Helpers::configArray('edge-flush.routing.urls.cachable'))->isEmpty() || + Helpers::collect(Helpers::configArray('edge-flush.routing.urls.cachable'))->contains($filter)) && + !Helpers::collect(Helpers::configArray('edge-flush.routing.urls.not-cachable'))->contains($filter); } public function stripCookies(Response $response, string $strategy): Response { - $strip = Helpers::configArray('edge-flush.strip_cookies') ?? []; + $strip = Helpers::configArray('edge-flush.responses.strip_cookies') ?? []; /** * We only strip cookies from cachable responses because those cookies (potentially logged in users), if cached by the CDN @@ -432,16 +432,18 @@ public function stripCookies(Response $response, string $strategy): Response public function getStrategyArray(string|null $strategyName): array { if (!$this->enabled() || $strategyName === null) { - return Helpers::configArray('edge-flush.strategies.zero') ?? []; + return Helpers::configArray('edge-flush.strategies.types.zero') ?? []; } - $strategyName = Helpers::configString("edge-flush.built-in-strategies.$strategyName") ?? $strategyName; + Helpers::debug("1: $strategyName"); + $strategyName = Helpers::configString("edge-flush.strategies.built-in-strategies.$strategyName") ?? $strategyName; + Helpers::debug("2: $strategyName"); if (trim($strategyName) === '') { return []; } - return Helpers::configArray("edge-flush.strategies.$strategyName") ?? []; + return Helpers::configArray("edge-flush.strategies.types.$strategyName") ?? []; } public function willBeCached(Response $response, string|null $strategy = null): bool diff --git a/src/Services/Entity.php b/src/Services/Entity.php index 8d73011..441f4eb 100644 --- a/src/Services/Entity.php +++ b/src/Services/Entity.php @@ -74,7 +74,7 @@ public function attributesAreDirty(string|null $targetKey = null): bool $original = $this->encodeValueForComparison($this->original[$key], gettype($value)); - if ($updated !== $original && $this->granularPropertyIsAllowed($key, $this->modelClass)) { + if ($updated !== $original && $this->granularAttributeIsAllowed($key, $this->modelClass)) { $keyIsDirty = true; } @@ -131,13 +131,13 @@ public function getDirtyModelNames(): Collection $this->modelNames = $this->modelNames ?? Helpers::collect(); foreach ($this->attributes as $key => $value) { - $castType = gettype($value); + $castTypeNew = gettype($value); + $castTypeOld = gettype($this->original[$key]); + + $original = $this->encodeValueForComparison($this->original[$key], $castTypeOld); + $updated = $this->encodeValueForComparison($value, $castTypeNew); - $updated = $this->encodeValueForComparison($value, $castType); - - $original = $this->encodeValueForComparison($this->original[$key], $castType); - - if ($updated !== $original && $this->granularPropertyIsAllowed($key, $this->modelName)) { + if ($updated !== $original && $this->granularAttributeIsAllowed($key, $this->modelName)) { if (filled($this->modelName)) { $modelName = "{$this->modelName}"; @@ -146,7 +146,7 @@ public function getDirtyModelNames(): Collection } if (!isset($this->modelNames[$modelName])) { - Helpers::debug("ATTRIBUTE CHANGED: {$modelName}"); + Helpers::debug("ATTRIBUTE CHANGED: {$modelName} - old: {$original}({$castTypeOld}) - new: {$updated}({$castTypeNew})"); $this->modelNames[$modelName] = $modelName; } @@ -155,7 +155,7 @@ public function getDirtyModelNames(): Collection } foreach ($this->relations as $name => $changed) { - if ($this->isRelationDirty($name) && $this->granularPropertyIsAllowed($name, $this->modelName)) { + if ($this->isRelationDirty($name) && $this->granularAttributeIsAllowed($name, $this->modelName)) { if (filled($this->modelName)) { $modelName = "{$this->modelName}"; diff --git a/src/Services/Tags.php b/src/Services/Tags.php index 4003709..3c6f7c2 100644 --- a/src/Services/Tags.php +++ b/src/Services/Tags.php @@ -118,7 +118,7 @@ public function makeEdgeTag(Collection|null $models = null): string { $models ??= $this->getTags(); - $format = Helpers::toString(Helpers::configString('edge-flush.tags.format', 'app-%environment%-%sha1%')); + $format = Helpers::toString(Helpers::configString('edge-flush.strategies.tags.format', 'app-%environment%-%sha1%')); return str_replace( ['%environment%', '%sha1%'], @@ -427,7 +427,7 @@ protected function markTagsAsObsolete(Invalidation $invalidation): void { $type = $invalidation->type(); - if ($type !== 'tag') { + if ($type !== 'tag' && $type !== 'model') { return; } @@ -928,15 +928,6 @@ public function canStoreCacheTags(string $url): bool EdgeFlush::cacheControl()->routeIsCachable(); } - protected function attributeMustBeIgnored(Model $model, string $attribute): bool - { - $attributes = Helpers::configArray("edge-flush.invalidations.attributes.ignore", []); - - $ignore = array_merge($attributes[get_class($model)] ?? [], ($attributes['*'] ?? [])); - - return in_array($attribute, $ignore); - } - protected function getAlwaysAddAttributes(Model $model): array { $attributes = Helpers::configArray("edge-flush.invalidations.attributes.always-add", []); diff --git a/src/Support/Helpers.php b/src/Support/Helpers.php index abd3c48..36fc13a 100644 --- a/src/Support/Helpers.php +++ b/src/Support/Helpers.php @@ -15,7 +15,7 @@ class Helpers */ public static function sanitizeUrl(string $url): string { - if (Helpers::configBool('edge-flush.urls.query.fully_cachable')) { + if (Helpers::configBool('edge-flush.routing.urls.query.fully_cachable')) { return $url; } @@ -29,7 +29,7 @@ public static function sanitizeUrl(string $url): string return $url; } - $routes = (array) config('edge-flush.urls.query.allow_routes'); + $routes = (array) config('edge-flush.routing.urls.query.allow_routes'); $list = $routes[$parsed['path']] ?? null; @@ -235,12 +235,12 @@ public static function toBool(mixed $value): bool public static function configBool(string $key, mixed $default = null): bool { - return static::toBool(config($key, $default)); + return static::toBool(static::config($key, $default)); } public static function configArray(string $key, mixed $default = null): array|null { - if (is_null($value = config($key, $default))) { + if (is_null($value = static::config($key, $default))) { return null; } @@ -249,7 +249,7 @@ public static function configArray(string $key, mixed $default = null): array|nu public static function configString(string $key, mixed $default = null): string|null { - if (is_null($value = config($key, $default))) { + if (is_null($value = static::config($key, $default))) { return null; } @@ -258,7 +258,7 @@ public static function configString(string $key, mixed $default = null): string| public static function configInt(string $key, mixed $default = null): int|null { - if (is_null($value = config($key, $default))) { + if (is_null($value = static::config($key, $default))) { return null; } @@ -297,6 +297,15 @@ public static function collect(mixed $var = []): Collection public static function configMixed(string $key, mixed $default = null): mixed { + return static::config($key, $default); + } + + public static function config(string $key, mixed $default = null): mixed + { + if (!config()->has($key)) { + self::debug("Config key not found: $key"); + } + return config($key, $default); } }