diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index a49b765..eae4ffc 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -10,16 +10,11 @@ jobs: strategy: fail-fast: false matrix: - php: [8.1, 8.2, 8.3, 8.4] - statamic: [4.*, 5.*] - exclude: - - statamic: 4.* - php: 8.4 + php: [8.2, 8.3, 8.4] + statamic: [5.*] include: - - statamic: 4.* - testbench: ^7.0 - statamic: 5.* - testbench: ^8.0 + testbench: ^9.0 name: PHP ${{ matrix.php }} - Statamic ${{ matrix.statamic }} diff --git a/.gitignore b/.gitignore index f38e6a5..e7f6b27 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ /vendor mix-manifest.json node_modules +.phpunit.cache diff --git a/composer.json b/composer.json index 42bda31..c4ea9a8 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,8 @@ "ext-json": "*", "php": "^7.4|^8.0", "spatie/simple-excel": "^1.0|^2.0|^3.0", - "statamic/cms": "^4.10|^5.0" + "statamic/cms": "^4.10|^5.0", + "doctrine/dbal": "^4.2" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.10", diff --git a/database/migrations/increase_redirect_error_table_url_length.php.stub b/database/migrations/increase_redirect_error_table_url_length.php.stub new file mode 100644 index 0000000..f734100 --- /dev/null +++ b/database/migrations/increase_redirect_error_table_url_length.php.stub @@ -0,0 +1,33 @@ +dropIndex('errors_url_index'); + }); + + Schema::table('errors', function (Blueprint $table): void { + $table->string('url', 2048)->change(); + $table->string('url_md5')->index()->after('url'); + }); + + Error::each(function (Error $error) { + $error->update(['url_md5' => md5($error->url)]); + }); + } + + public function down(): void + { + Schema::table('errors', function (Blueprint $table): void { + $table->dropColumn('url_md5'); + $table->string('url')->index()->change(); + }); + } +} diff --git a/database/migrations/increase_redirect_redirects_table_url_length.php.stub b/database/migrations/increase_redirect_redirects_table_url_length.php.stub new file mode 100644 index 0000000..d18a1ec --- /dev/null +++ b/database/migrations/increase_redirect_redirects_table_url_length.php.stub @@ -0,0 +1,35 @@ +dropIndex('redirects_source_index'); + }); + + Schema::table('redirects', function (Blueprint $table): void { + $table->string('source', 2048)->change(); + $table->string('source_md5')->index()->after('source'); + $table->string('destination', 2048)->change(); + }); + + RedirectModel::each(function (RedirectModel $redirect) { + $redirect->update(['source_md5' => md5($redirect->source)]); + }); + } + + public function down(): void + { + Schema::table('redirects', function (Blueprint $table): void { + $table->dropColumn('source_md5'); + $table->string('source')->index()->change(); + $table->string('destination')->change(); + }); + } +} diff --git a/src/Data/Error.php b/src/Data/Error.php index 82736cb..dbc5fb4 100644 --- a/src/Data/Error.php +++ b/src/Data/Error.php @@ -37,6 +37,9 @@ public function getConnectionName() protected static function booted() { + self::saving(function ($model) { + $model->url_md5 = md5($model->url); + }); self::deleting(function ($error) { $error->hits()->delete(); }); @@ -70,6 +73,6 @@ public function addHit(int $timestamp, array $data = []): ?Hit public static function findByUrl(string $url): ?self { - return self::where('url', $url)->first(); + return self::where('url_md5', md5($url))->where('url', $url)->first(); } } diff --git a/src/Data/Redirect.php b/src/Data/Redirect.php index ff949ba..9cab26d 100644 --- a/src/Data/Redirect.php +++ b/src/Data/Redirect.php @@ -29,6 +29,9 @@ class Redirect implements Localization, RedirectContract /** @var string */ protected $source; + /** @var string */ + protected $source_md5; + /** @var string */ protected $destination; @@ -62,6 +65,11 @@ public function source($source = null) return $this->fluentlyGetOrSet('source')->args(func_get_args()); } + public function source_md5($source_md5 = null) + { + return $this->fluentlyGetOrSet('source_md5')->args(func_get_args()); + } + public function destination($destination = null) { return $this->fluentlyGetOrSet('destination')->args(func_get_args()); diff --git a/src/RedirectServiceProvider.php b/src/RedirectServiceProvider.php index 062ec60..a1313dd 100644 --- a/src/RedirectServiceProvider.php +++ b/src/RedirectServiceProvider.php @@ -22,6 +22,8 @@ use Rias\StatamicRedirect\UpdateScripts\AddDescriptionColumnToRedirectsTable; use Rias\StatamicRedirect\UpdateScripts\AddHitsCount; use Rias\StatamicRedirect\UpdateScripts\ClearErrors; +use Rias\StatamicRedirect\UpdateScripts\IncreaseUrlSizeOnErrors; +use Rias\StatamicRedirect\UpdateScripts\IncreaseUrlSizeOnRedirects; use Rias\StatamicRedirect\UpdateScripts\MoveRedirectsToDefaultSite; use Rias\StatamicRedirect\UpdateScripts\RenameLocaleToSiteOnRedirectsTable; use Rias\StatamicRedirect\Widgets\ErrorsLastDayWidget; @@ -45,14 +47,16 @@ class RedirectServiceProvider extends AddonServiceProvider MoveRedirectsToDefaultSite::class, RenameLocaleToSiteOnRedirectsTable::class, AddDescriptionColumnToRedirectsTable::class, + IncreaseUrlSizeOnRedirects::class, + IncreaseUrlSizeOnErrors::class, ]; protected $scripts = [ - __DIR__.'/../resources/dist/js/cp.js', + __DIR__ . '/../resources/dist/js/cp.js', ]; protected $routes = [ - 'cp' => __DIR__.'/../routes/cp.php', + 'cp' => __DIR__ . '/../routes/cp.php', ]; protected $listen = [ @@ -112,17 +116,19 @@ public function boot() ->bootPermissions(); }); - if (! $this->app->runningInConsole()) { + if (!$this->app->runningInConsole()) { return; } $this->publishes([ __DIR__ . '/../database/migrations/create_redirect_error_tables.php.stub' => database_path('migrations/' . date('Y_m_d_His', time()) . '_create_redirect_error_tables.php'), + __DIR__ . '/../database/migrations/increase_redirect_error_table_url_length.php.stub' => database_path('migrations/' . date('Y_m_d_His', time() + 1) . '_increase_redirect_error_table_url_length.php'), ], 'statamic-redirect-error-migrations'); $this->publishes([ __DIR__ . '/../database/migrations/create_redirect_redirects_table.php.stub' => database_path('migrations/' . date('Y_m_d_His', time()) . '_create_redirect_redirects_table.php'), - __DIR__ . '/../database/migrations/add_description_to_redirect_redirects_table.php.stub' => database_path('migrations/' . date('Y_m_d_His', time()) . '_add_description_to_redirect_redirects_table.php'), + __DIR__ . '/../database/migrations/add_description_to_redirect_redirects_table.php.stub' => database_path('migrations/' . date('Y_m_d_His', time() + 1) . '_add_description_to_redirect_redirects_table.php'), + __DIR__ . '/../database/migrations/increase_redirect_redirects_table_url_length.php.stub' => database_path('migrations/' . date('Y_m_d_His', time() + 2) . '_increase_redirect_redirects_table_url_length.php'), ], 'statamic-redirect-redirect-migrations'); } @@ -141,7 +147,7 @@ protected function getRedirectRepository() protected function bootAddonViews() { - $this->loadViewsFrom(__DIR__.'/../resources/views', 'redirect'); + $this->loadViewsFrom(__DIR__ . '/../resources/views', 'redirect'); return $this; } @@ -160,8 +166,8 @@ protected function bootAddonNav() $nav->tools('Redirect') ->route( config('statamic.redirect.log_errors') - ? 'redirect.index' - : 'redirect.redirects.index' + ? 'redirect.index' + : 'redirect.redirects.index' ) ->icon('git') ->active('redirect') @@ -183,7 +189,7 @@ protected function bootStores() protected function bootDatabase() { - if (! config('statamic.redirect.log_errors')) { + if (!config('statamic.redirect.log_errors')) { return $this; } @@ -207,17 +213,17 @@ protected function ensureDatabaseExists($sqlitePath) { $oldSqlitePath = storage_path('redirect/errors.sqlite'); - if (! file_exists($sqlitePath) && file_exists($oldSqlitePath)) { + if (!file_exists($sqlitePath) && file_exists($oldSqlitePath)) { File::move($oldSqlitePath, $sqlitePath); return; } - if (! file_exists($sqlitePath)) { + if (!file_exists($sqlitePath)) { File::put($sqlitePath, ''); $gitIgnorePath = storage_path('redirect/.gitignore'); - if (! file_exists($gitIgnorePath)) { + if (!file_exists($gitIgnorePath)) { File::put($gitIgnorePath, "*\n!.gitignore"); } } @@ -227,7 +233,7 @@ protected function bootDatabaseForErrors() { if ( config('statamic.redirect.error_connection', 'redirect-sqlite') !== 'redirect-sqlite' && - ! $this->generalConnectionIsBuiltinSqlite() + !$this->generalConnectionIsBuiltinSqlite() ) { return; } @@ -240,6 +246,8 @@ protected function bootDatabaseForErrors() DB::setDefaultConnection('redirect-sqlite'); require_once(__DIR__ . '/../database/migrations/create_redirect_error_tables.php.stub'); (new \CreateRedirectErrorTables())->up(); + require_once(__DIR__ . '/../database/migrations/increase_redirect_error_table_url_length.php.stub'); + (new \IncreaseRedirectErrorTableUrlLength())->up(); DB::setDefaultConnection($defaultConnection); } @@ -247,7 +255,7 @@ protected function bootDatabaseForRedirects() { if ( config('statamic.redirect.redirect_connection', 'stache') !== 'redirect-sqlite' && - ! $this->generalConnectionIsBuiltinSqlite() + !$this->generalConnectionIsBuiltinSqlite() ) { return; } @@ -263,6 +271,8 @@ protected function bootDatabaseForRedirects() (new \CreateRedirectRedirectsTable())->up(); require_once(__DIR__ . '/../database/migrations/add_description_to_redirect_redirects_table.php.stub'); (new \AddDescriptionToRedirectRedirectsTable())->up(); + require_once(__DIR__ . '/../database/migrations/increase_redirect_redirects_table_url_length.php.stub'); + (new \IncreaseRedirectRedirectsTableUrlLength())->up(); DB::setDefaultConnection($defaultConnection); } @@ -282,10 +292,10 @@ protected function generalConnectionIsBuiltinSqlite() protected function registerAddonConfig() { - $this->mergeConfigFrom(__DIR__.'/../config/redirect.php', 'statamic.redirect'); + $this->mergeConfigFrom(__DIR__ . '/../config/redirect.php', 'statamic.redirect'); $this->publishes([ - __DIR__.'/../config/redirect.php' => config_path('statamic/redirect.php'), + __DIR__ . '/../config/redirect.php' => config_path('statamic/redirect.php'), ], 'statamic-redirect-config'); return $this; diff --git a/src/Stache/Redirects/RedirectRepository.php b/src/Stache/Redirects/RedirectRepository.php index 29ec91e..1d2f4b2 100644 --- a/src/Stache/Redirects/RedirectRepository.php +++ b/src/Stache/Redirects/RedirectRepository.php @@ -42,10 +42,25 @@ public function findByUrl(string $siteHandle, string $url): ?Redirect ->where('locale', $siteHandle) ->where(function (RedirectQueryBuilder $query) use ($url) { $query - ->orWhere('source', $url) - ->orWhere('source', str($url)->start('/')) - ->orWhere('source', str($url)->finish('/')) - ->orWhere('source', str($url)->start('/')->finish('/')); + ->orWhere(function (RedirectQueryBuilder $query) use ($url) { + $query->where('source_md5', md5($url)) + ->where('source', $url); + }) + ->orWhere(function (RedirectQueryBuilder $query) use ($url) { + $source = str($url)->start('/'); + $query->where('source_md5', md5($source)) + ->where('source', $source); + }) + ->orWhere(function (RedirectQueryBuilder $query) use ($url) { + $source = str($url)->finish('/'); + $query->where('source_md5', md5($source)) + ->where('source', $source); + }) + ->orWhere(function (RedirectQueryBuilder $query) use ($url) { + $source = str($url)->start('/')->finish('/'); + $query->where('source_md5', md5($source)) + ->where('source', $source); + }); }) ->where('matchType', MatchTypeEnum::EXACT) ->orderBy('order') @@ -86,6 +101,7 @@ public function save($redirect) if (! $redirect->id()) { $redirect->id(StacheFacade::generateId()); } + $redirect->source_md5(md5($redirect->source())); StacheFacade::store('redirects')->save($redirect); diff --git a/src/UpdateScripts/AddDescriptionColumnToRedirectsTable.php b/src/UpdateScripts/AddDescriptionColumnToRedirectsTable.php index 407151e..8a1433c 100644 --- a/src/UpdateScripts/AddDescriptionColumnToRedirectsTable.php +++ b/src/UpdateScripts/AddDescriptionColumnToRedirectsTable.php @@ -3,6 +3,7 @@ namespace Rias\StatamicRedirect\UpdateScripts; use Illuminate\Database\QueryException; +use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Schema; use Statamic\UpdateScripts\UpdateScript; @@ -31,6 +32,18 @@ public function shouldUpdate($newVersion, $oldVersion) public function update() { + $connection = config('statamic.redirect.redirect_connection'); + + if ($connection === 'redirect-sqlite') { + Schema::connection($connection)->table('redirects', function (Blueprint $table): void { + $table->text('description')->nullable()->after('enabled'); + }); + + $this->console()->info('Added description field to the redirects table!'); + + return; + } + Artisan::call('vendor:publish', [ '--tag' => 'statamic-redirect-redirect-migrations', ]); diff --git a/src/UpdateScripts/IncreaseUrlSizeOnErrors.php b/src/UpdateScripts/IncreaseUrlSizeOnErrors.php new file mode 100644 index 0000000..c16f62f --- /dev/null +++ b/src/UpdateScripts/IncreaseUrlSizeOnErrors.php @@ -0,0 +1,61 @@ +hasColumn('errors', 'url_md5'); + } catch (QueryException) { + // Query exception happens when database is not set up + return false; + } + } + + public function update() + { + $errorConnection = config('statamic.redirect.error_connection'); + + if ($errorConnection === 'redirect-sqlite') { + if (Schema::connection($errorConnection)->hasIndex('errors', 'errors_url_index')) { + Schema::connection($errorConnection)->table('errors', function (Blueprint $table): void { + $table->dropIndex('errors_url_index'); + }); + } + + Schema::connection($errorConnection)->table('errors', function (Blueprint $table): void { + $table->string('url', 2048)->change(); + $table->string('url_md5')->index()->nullable()->after('url'); + }); + + Error::each(function (Error $error) { + $error->update(['url_md5' => md5($error->url)]); + }); + + $this->console()->info('Increased url column size in errors table.'); + + return; + } + + Artisan::call('vendor:publish', [ + '--tag' => 'statamic-redirect-error-migrations', + ]); + + $this->console()->info('New migration for Redirects published, make sure to run it!'); + } +} diff --git a/src/UpdateScripts/IncreaseUrlSizeOnRedirects.php b/src/UpdateScripts/IncreaseUrlSizeOnRedirects.php new file mode 100644 index 0000000..104ddc3 --- /dev/null +++ b/src/UpdateScripts/IncreaseUrlSizeOnRedirects.php @@ -0,0 +1,66 @@ +hasColumn('redirects', 'source_md5'); + } catch (QueryException) { + // Query exception happens when database is not set up + return false; + } + } + + public function update() + { + $redirectConnection = config('statamic.redirect.redirect_connection'); + + if ($redirectConnection === 'redirect-sqlite') { + if (Schema::connection($redirectConnection)->hasIndex('redirects', 'redirects_source_index')) { + Schema::connection($redirectConnection)->table('redirects', function (Blueprint $table): void { + $table->dropIndex('redirects_source_index'); + }); + } + + Schema::connection($redirectConnection)->table('redirects', function (Blueprint $table): void { + $table->string('source', 2048)->change(); + $table->string('source_md5')->index()->after('source'); + $table->string('destination', 2048)->change(); + }); + + RedirectModel::each(function (RedirectModel $redirect) { + $redirect->update(['source_md5' => md5($redirect->source)]); + }); + + $this->console()->info('Increased url column size in redirects table.'); + + return; + } + + Artisan::call('vendor:publish', [ + '--tag' => 'statamic-redirect-redirect-migrations', + ]); + + $this->console()->info('New migration for Redirects published, make sure to run it!'); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php index a163502..bdcbe26 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -94,6 +94,9 @@ protected function defineDatabaseMigrations(): void include_once __DIR__ . '/../database/migrations/create_redirect_error_tables.php.stub'; (new \CreateRedirectErrorTables())->up(); + + include_once __DIR__ . '/../database/migrations/increase_redirect_error_table_url_length.php.stub'; + (new \IncreaseRedirectErrorTableUrlLength())->up(); } /**