CakePHPでコントローラーとビューをディレクトリ分けする方法を教えてください。


■ディレクトリ構造
/app
 +-controllers/
  +-admin/
   +-top_controller.php
  +-top_controller.php
 +-views/
  +-admin/
   +-top/
    +-index.ctp
  +-top/
  +-index.ctp

■目的
http://localhost/cakephp/でアクセスすると、app/controllers/top_controller.phpが実行して欲しい。
http://localhost/cakephp/adminでアクセスすると、app/controllers/admin/top_controller.phpが実行して欲しい。

■bootstrap.phpに以下を追加しました(長くなるので、コントローラーのみ記載)
App::build(array(
'controllers' => array(
ROOT.DS.APP_DIR.DS.'controllers'.DS.'admin'.DS,
ROOT.DS.APP_DIR.DS.'controllers'.DS,
),
));

■routes.phpに以下を追加しました
Router::connect('/', array('controller' => 'top', 'action' => 'index', 'home'));
Router::connect('/admin', array('controller' => 'top', 'action' => 'index', 'home'));

■問題
http://localhost/cakephp/にアクセスすると、管理用のコントローラーが実行される


書き方に問題があると思うのですが、1.3用の書き方や情報を探す事が出来ずに質問しました。
ご存じの方は教えてください。バージョンは1.3.2を使用しています。

回答の条件
  • 1人2回まで
  • 13歳以上
  • 登録:2010/07/22 05:17:39
  • 終了:2010/07/27 11:21:21

ベストアンサー

id:tdoi No.1

tdoi回答回数174ベストアンサー獲得回数752010/07/26 13:28:26

ポイント300pt

対策、分かりました。

原因はやはりキャッシュでしたね。

デフォルトの設定だと、app/config/core.phpで、

Cache::config('default', array('engine' => 'File'));

という設定されています。

この部分を、

if (preg_match('/\/admin\/.*/i', $_SERVER['REQUEST_URI'])) {
  Cache::config('default', array('engine' => 'File',
				 'duration'=> 3600,
				 'probability'=> 100,
				 'path' => dirname(CACHE) . DS . 'cache_admin' . DS,
				 'prefix' => 'cake_',
				 'lock' => false,
				 'serialize' => true));

 } else {
  Cache::config('default', array('engine' => 'File',
				 'duration'=> 3600,
				 'probability'=> 100,
				 'path' => CACHE,
				 'prefix' => 'cake_',
				 'lock' => false,
				 'serialize' => true));
 }

のように書き換えます。もっと簡略化できると思いますが、一応、core.phpに記載されているサンプル通りに記載しておきます。

ここで設定しているのは、キャッシュファイルの置き場所を、/admin/にアクセスした場合と、通常の場合とで変えています。キャッシュにファイルを使っていない場合は、適宜、変更してください。

上記の場合は、デフォルトだと、app/tmp/cacheがキャッシュディレクトリとして利用されるところを、/admin/のアクセスの場合だけ、app/tmp/cache_admin/を利用するように指定しています。

このように指定して、app/tmp/cacheディレクトリをapp/tmp/cache_adminとしてコピーしておけば、僕の手元では適切なキャッシュが読まれるようになり、この問題を回避できました。

何かの参考になれば。

id:k27w

ありがとうございます。こちらでも動作できました。

core.phpの最下部に例が記載されていたんですね。完全に見逃していました。


これで、appディレクトリを分ける事もなく、同じモデルやコンポーネントを

複製する事もないので、かなり効率的な利用が出来そうです。


コメントの件から丁寧に対応いただき、誠にありがとうございました。

2010/07/27 11:20:32
  • id:tdoi
    試してないので恐縮ですが、管理用と一般用のコントローラ名を別々にするしかないのかなと思います。
    App::buildで、コントローラの読みだし先を追加で指定できますが、複数指定した場合には先に見つかったコントローラが利用されるはずですので。

    どうしてもそれが嫌なら、RequestURIなどを自分でパースして、/admin以下だったら、

    App::build(array(
    'controllers' => array(ROOT.DS.APP_DIR.DS.'controllers'.DS.'admins'.DS),
    ));

    を実行して、そうでなければ、

    App::build(array(
    'controllers' => array(ROOT.DS.APP_DIR.DS.'controllers'.DS),
    ));

    を実行すれば、逃げられるとは思います。
  • id:k27w
    コントローラー名を変える方法なら出来ました。
    ただ、用途が「公開用と管理用とを分ける」ですから、コントローラー名が同じ方が分かりやすいです。

    あと、RequestURIで分ける方法ですが、

    switch ($_SERVER['REQUEST_URI']) {
    case '/cakephp/admin':
    App::build(array(
    'controllers' => array(ROOT.DS.APP_DIR.DS.'controllers'.DS.'admin'.DS),
    'views' => array(ROOT.DS.APP_DIR.DS.'views'.DS.'admin'.DS),
    ));
    break;

    default:
    App::build(array(
    'controllers' => array(ROOT.DS.APP_DIR.DS.'controllers'.DS),
    'views' => array(ROOT.DS.APP_DIR.DS.'views'.DS),
    ));
    }

    こんな感じのコードをbootstrap.phpに書いたのですが、キャッシュの影響なのか、どうも不安定です。更新する度にビューの表示が変わるような・・。(それでいて正しいコントローラーを読み込んでいるわけでもない)
  • id:tdoi
    まず、RequestURIへの分岐は正しく動作していることは確認できたと思っていいんですよね?

    その上で、不安定というのがどういうときか分かりませんが、ビューキャッシュとかが絡むと、コントローラ名がキーとして動いていれば、場合によっては危険かもですね。

    個人的には、「公開用と管理用とを分ける」ということは用途が違うので、TestControllerとAdminTestControllerとかと名前が違っても気にならないので、こっちが問題はないと思うのでおススメではありますね。

  • id:k27w
    RequestURIへの分岐は出来ていますね。

    不安定とはその後に「更新する度にビューの表示が変わる」と書きましたが、その事です。

    各コントローラーに
    $this->set('test', '管理画面です');//文字列の部分は要所によって変更

    と言う指定をし、ビューで出力しています。どのコントローラーが読み込まれたかを調べる為に。

    それでhttp://localhost/cakephp/admin
    にアクセスすると、画面には「公開画面です」と表示され、公開画面用のビューが表示されます。

    そしてURLを変更してアクセステストしていると、たまに異なる表示になるので、「キャッシュの問題かな?」と思っています。
    (言葉では説明しにくいので、試していただくのが一番早いとは思いますが・・・)


    とにかく、現状では解決していません。
    ググって調べると1.2用の書き方はあるようですけどね。 1.3で使えないので厳しい限りです。
  • id:tdoi
    僕の環境では起きませんね。

    /app/config/routes.phpで、

    Router::connect('/', array('controller' => 'tests', 'action' => 'index'));
    Router::connect('/admin/', array('controller' => 'tests', 'action' => 'index'));

    と指定。

    /app/config/boostrap.phpに

    if (preg_match('/\/admin\/.*/i', $_SERVER['REQUEST_URI'])) {
    $path = dirname(dirname(__FILE__)) . DS . 'controllers' . DS . 'admin' . DS;
    App::build(array('controllers' => array($path)));
    }

    と追記。

    /app/controllers/tests_controller.phpで、

    function index() {
    $this->set('name', 'normal');
    }

    /app/controllers/admin/tests_controller.phpで、

    function index() {
    $this->set('name', 'admin');
    }

    と記述。

    /app/views/tests/index.ctpで、

    <?php echo $name; ?>

    と記述。

    この状態で、

    http://example.com/にアクセスすれば、normalと、
    http://example.com/admin/にアクセスすれば、adminと表示されますね。

    リロードやURLパラメタを付けるなりしてみましたが、安定して、変化しなかったです。

    何も参考にならないと思いますが、報告まで。
  • id:k27w
    お試しいただきありがとうございます。

    もしかしてですが、tdoiさんはビューファイルを分けていませんよね?
    私は質問に書いたようなディレクトリ構成なのですが、
    ビューの設定を追記するとおかしいようです。(リロードの度に表示が変になる)

    コントローラーのみで、一箇所(tdoiさんの例なら/app/views/tests/index.ctp)
    にすると、コントローラーファイルの切替は出来ているようです。

    ただ、目的が「公開用と管理用を分ける」ですから、表示するビューも分けられないと問題あります。
    自分としてはキャッシュが問題なのかな?っと思っているのですが、もう少し調べてみます。
  • id:k27w
    追記です。やはりキャッシュの問題でした。

    core.phpのConfigure::write('Cache.disable', true)を有効にすると
    ビューのテンプレートも公開用・管理用とで切り替えられます。

    と言う事はキャッシュの仕様?が影響しているのかもしれませんね・・。
  • id:tdoi
    viewsも切り替えるようにしてみたところ起きました。
    ひょっとすると、viewsを切り替えなくて起きるのかもしれませんが。

    viewsもディレクトリを切り替えるようにして、
    For Admin <?php echo $name; ?>

    For Normal <?php echo $name; ?>
    のようにどちらのviewが使われたかを分かる状態で試してみました。

    僕のところの症状だと、viewsは必ず正しく切り替わるが、setした内容が異なるControllerがsetした内容が表示されました。
    また、

    http://example.com/admin/ -> For Admin adminと表示
    この状態で何度かリロードする
    http://example.com/    -> For Normal normalと表示
    ここで、リロードすると、
    http://example.com/    -> For Normal adminと表示

    という手順はかなりの再現率ですね。
  • id:k27w
    そうです。そういう状態になります。

    これをキャッシュしなければ切り替わりますが、キャッシュ機能が使えないのは痛いので、何か対策が必要ですね。

    もし原因や対策が分かりましたら、回答にて教えて下さい。
  • id:tdoi
    ログ出力させてみると、

    $this->set('name', 'normal');

    は実行されてても、adminと出たりしてますね。
    キャッシュがらみな感じですね。
    詳しく調べてないですけど、バグっぽい気もしますね。

    何か分かったら、また、書きますね。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません