TL;DR: ユーザーが入力するURLスラッグが、Webアプリケーションのルートや予約語と衝突しないようバリデーションするCakePHP 5.xプラグインを公開しました。

どういうプラグイン?
Webアプリケーションで、ユーザーにプロフィールページのURLスラッグを自由に設定させたいことってありますよね。例えば example.com/nojimage のような感じで。
でも、ユーザーが admin や login、api のようなスラッグを登録してしまうと、システムのルートと衝突して大変なことになります。
SlugGuard は、こういったスラッグの衝突を防ぐための CakePHP 5.x プラグインです。以下の3つのバリデーションルールを提供します。
- SlugValidator - スラッグのフォーマットチェック(小文字英数字とハイフンのみ、先頭末尾は英数字)
- IsNotReservedSlug - 約710個の予約語(
admin,login,api,settings等)との衝突チェック - IsNotRouteConflict - CakePHPに登録されたルートとの動的な衝突チェック
インストール
composer require elstc/cakephp-slug-guard
bin/cake plugin load Elastic/SlugGuard
プラグインをロードしたら、マイグレーションを実行して予約語テーブルを作成します。
bin/cake migrations migrate --plugin Elastic/SlugGuard
bin/cake slug_guard sync
sync コマンドで、組み込みの約710個の予約語がデータベースにインポートされます。admin, dashboard, login, api から facebook, twitter, github のようなSNS名まで、よくある予約語が一通り入っています。
使い方
予約語・ルート衝突チェック(Application Rule)
テーブルクラスの buildRules で IsNotReservedSlug と IsNotRouteConflict を追加します。
use Elastic\SlugGuard\Model\Rule\IsNotReservedSlug;
use Elastic\SlugGuard\Model\Rule\IsNotRouteConflict;
// Table クラス内
public function buildRules(RulesChecker $rules): RulesChecker
{
$rules->add(new IsNotReservedSlug('slug'), 'reservedSlug', [
'errorField' => 'slug',
'message' => 'このスラッグは予約されています',
]);
$rules->add(new IsNotRouteConflict('slug'), 'routeConflict', [
'errorField' => 'slug',
'message' => 'このスラッグはルートと衝突します',
]);
return $rules;
}
コンストラクタの引数にチェック対象のフィールド名を渡します。slug 以外のフィールド(例えば username)にも使えます。
スラッグフォーマットチェック(Validator)
SlugValidator は Validator の provider として使います。小文字英数字とハイフンのみ許可し、長さの制約もかけられます。
use Elastic\SlugGuard\Validation\SlugValidator;
// Table クラス内
public function validationDefault(Validator $validator): Validator
{
$validator->setProvider('slugValidator', SlugValidator::class);
$validator->add('slug', 'validSlug', [
'rule' => ['isValid'],
'provider' => 'slugValidator',
'message' => '小文字英数字とハイフンのみ使用できます',
]);
return $validator;
}
デフォルトは4〜24文字ですが、長さを変更することもできます。
// 最小3文字、最大32文字に変更
$validator->add('slug', 'validSlug', [
'rule' => ['isValid', 3, 32],
'provider' => 'slugValidator',
]);
予約語の管理
CLIコマンドで予約語の追加・削除・一覧表示ができます。
# 予約語の一覧表示
bin/cake slug_guard list
# 検索
bin/cake slug_guard list --search admin
# 予約語の追加
bin/cake slug_guard add my-reserved-word
# 予約語の削除
bin/cake slug_guard remove my-reserved-word
# ファイルからインポート(1行1スラッグ、# でコメント)
bin/cake slug_guard import path/to/custom-slugs.txt
# アプリケーションのルートから自動抽出して予約語に追加
bin/cake slug_guard routes | bin/cake slug_guard add
# 設定ファイルとDBの同期(dry-run対応)
bin/cake slug_guard sync --dry-run
設計のポイント
ルートとの動的衝突チェック
IsNotRouteConflict は、CakePHPに登録されたルートの第1セグメントを動的に取得して衝突チェックを行います。ルーティング設定を変更しても、自動的に反映されるので管理が楽です。
予約語のDB管理
予約語は reserved_slugs テーブルで管理しています。スラッグ文字列をそのまま主キーにしているので、存在チェックが高速です。CLIコマンドでの追加・削除に加えて、ファイルからのインポートやstdin入力にも対応しているので、運用時の柔軟性があります。
余談
機構自体はだいぶ昔から持っていて、実際のプロジェクトで何度も必要になっていたのですが、なかなかプラグインとして切り出せないでいました。 AIエージェントのおかげで、プラグイン化のためのコード整理やドキュメント作成が一気にできて、ようやく公開できる形になりました。
今回のプラグインで言えば、CLIコマンドの実装はほぼおまかせです。
というわけで、ユーザーにスラッグを自由入力させるアプリケーションを作るとき、予約語チェックは地味だけど忘れると面倒なことになる部分です。SlugGuard を入れておけば、フォーマットチェック・予約語チェック・ルート衝突チェックをまとめて面倒見てくれるので、安心してスラッグ入力機能を実装できます。
CakePHP 5.x + PHP 8.2 以上で使えますので、ぜひ試してみてください。