フロントコントローラーのルーティング問題を解決したい
悩み
CraftCMSを始めとしてLaravelやsymfonyなどのフレームワークにもある
URLのリライト設定でどうしたらいいか分からないこの問題。
基本的にドキュメントルートにはリクエストを集約するためのindex.php
、
それを制御する.htaccess
があるが、
以下のような構造の場合、ちょっとした問題が発生する。
┣ craft/
┃ ┣ その他のディレクトリ/
┃ ┗ templates/
┃ ┣ index.twig
┃ ┗ about/
┃ ┗ index.twig
┗ htdocs/
┣ cpresources/
┣ index.php
┣ .htaccess
┣ assets/
┗ about/ ← こいつ
┗ assets/
┣ js/
┣ css/
┗ images/
コーディングガイドラインで「下層のassetsはパスを揃えて配置する」パターンである。
CraftCMSの場合、静的ページからhtmlを分離してtemplatesに組み込むという作業フローになるのだが
フロントコントローラの制御によってエラーになってしまうのである。
CraftCMSのデフォルトのhtaccess
<IfModule mod_rewrite.c>
RewriteEngine On
# Send would-be 404 requests to Craft
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/(favicon\.ico|apple-touch-icon.*\.png)$ [NC]
RewriteRule (.+) index.php?p=$1 [QSA,L]
</IfModule>
発生する問題
この時https://shindev.com/about/
へアクセスした場合、
ドキュメントルート配下にassets類を置くためのaboutディレクトリが存在しているため
RewriteCond %{REQUEST_FILENAME} !-d
の条件を満たさずフレームワークを素通りしてしまい、
craft/templates/about/index.twig
が読み込まれない(403エラー)のである。
(要するにhtdocs/about/を参照する流れになる)
ブラウザで描画される/about/(index.html)内に書かれるassets類のパスの指定は
<script src="/about/assets/js/index.min.js"></script>
や
<link rel="stylesheet" href="/about/assets/css/index.css" />
みたいな形で記述されているため、assetsはドキュメントルート配下に設置しなければならないのだが。
みんなどうしてるんだろう
stack exchangeでも聞いてみたけどうまく伝わってなさそう。。。
これ結構ありそうな問題だと思うんだけどな〜
不健康そうな解決策
<IfModule mod_rewrite.c>
RewriteEngine On
# Send would-be 404 requests to Craft
RewriteCond %{REQUEST_FILENAME} !-f
# ↓コメントアウト
# RewriteCond %{REQUEST_FILENAME} !-d
# ↑コメントアウト
RewriteCond %{REQUEST_URI} !^/(favicon\.ico|apple-touch-icon.*\.png)$ [NC]
RewriteRule (.+) index.php?p=$1 [QSA,L]
</IfModule>
これはQiitaの人も言ってるけど何が起きるか分からないのでやらない方がいいかもしれない。
健康そうな解決策
<IfModule mod_rewrite.c>
RewriteEngine On
# Send would-be 404 requests to Craft
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d [NC,OR] # ←add
#↓add
RewriteCond %{REQUEST_URI} (.+)/$
#↑add
RewriteCond %{REQUEST_URI} !^/(favicon\.ico|apple-touch-icon.*\.png)$ [NC]
RewriteRule (.+) index.php?p=$1 [QSA,L]
</IfModule>
こちらを参考に
リクエストがfでない&dでない
または
URIが/
の場合〜
という設定にしたところ大丈夫な感じになった。
例外が思いつかないので一旦これで様子を見てみようと思う。
おわり。
Discussion
考えたことなかったですが、確かにこれはどうやるのがいいんでしょうね。。
割とありそうなパターンかと思うんですが意外にナレッジが少ないのですよねぇ...
↓こことかでもやっぱり
RewriteCond %{REQUEST_FILENAME} !-d
をコメントアウトしましょうという結論で〆られてました。。原則
/craft/templates/xxxxx/
と名前が被ったらダメなことは理解しつつも、今回のような場合どうするのがベターか対策は持っておきたいところです...。