dsj8086 2013-05-07 12:45
浏览 32
已采纳

CakePHP,使用通用控制器进行可选控制器的路由

I'd like to make an application in CakePHP which manages exercises and users results. Users and results are not important in this question.

I want to have a possibility to add an exercise with adding only a specific table and line to .ini config file. Application should route to a GenericExercisesController if specific one doesn't exists. Controller should load a GenericExerciseModel if specific doesn't exists. I'd managed with model loading and partially with routing with controller like this:

In route.php

foreach(Configure::read('exercisesTables') as $exerciseName){
    if( App::import('Controller', Inflector::pluralize($exerciseName))){
        Router::connect('/exercises/'.Inflector::pluralize($exerciseName).'/:action', array('controller' => Inflector::pluralize($exerciseName)));
    }else{
        Router::connect('/exercises/'.Inflector::pluralize($exerciseName).'/:action', array('controller' => 'GenericExercises', 'fakeModel' => $exerciseName));
    }
}

So if I want to load an exercise Foo I should use address:

http://example.com/exercises/Foos/view

And this works fine, doesn't matter if specific controller exists.

Problem begins when I use reverse routing to generate links in views. If exercise Foo have specific controller this works correctly:

print $this->Html->url(array('controller' => Inflector::pluralize($exerciseName), 'action' => 'view')); produces: /exercises/Foos/view

But when exercise Bar doesn't have specific controller then the same code produces: /Bars

This causes a problem, there is no Bars Controller.

Temporarily I'm generating those links manually, but I don't think that this is the best solution:

print $this->Html->url("/".Configure::read('exerciseRoutingPrefix')."/".Inflector::pluralize($exerciseName)."/view");

Maybe someone of you know a better solution. Thank you for reading my question.

UPDATE 1:

Those are routes in route.php defined before foreach in order as they're in file:

Router::connect('/', array('controller' => 'questions', 'action' => 'regulations'));
Router::connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));
Router::connect('/help', array('controller' => 'pages', 'action' => 'faq'));
  • 写回答

1条回答 默认 最新

  • doubinduo3364 2013-05-07 23:37
    关注

    If I understood your question correctly, you could try making a "MyHtmlHelper" which does some magic before parsing your options to the HtmlHelper::link();

    You can do it like so:

    /app/View/Helpes/MyHtmlHelper.php

    Create a helper which extends the "HtmlHelper" like so:

    <?php
    App::uses('HtmlHelper', 'View/Helper');
    class MyHtmlHelper extends HtmlHelper {
        public function link($title, $url = null, $options = array(), $confirmMessage = false) {
            //do your magic here and change the $title, $url or $options accordingly.
            return parent::link($title, $url, $options, $confirmMessage);
        }
    }
    

    Now in your controller, you should include the Helper like so (aliasing) $helpers = array('Html' => array('className' => 'MyHtml')); instead of $helpers = array('Html');.

    I guess you can fill in the blanks on the public function link yourself. If not, feel free to ask more help :)

    Off course it is possible to do this with every other Helper or method you can think off. HtmlHelper::link() is just used as example.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?