<rmcreative>

RSS

CUrlManager::addRules

5 августа 2010

Довольно часто на форумах спрашивали, как добавить свои правила роутинга не из конфига, а, например, из БД или XML, лежащего в модуле.

Теперь это можно сделать при помощи CUrlManager::addRules. Вызывать его необходимо до CWebApplication::processRequest. Всё, что будет добавлено позже будет проигнорировано.

Одним из способов это сделать является использование событий. В данном случае CWebApplication::onBeginRequest.

Например, для подгрузки правил из модулей в main.php пишем:

'onBeginRequest'=>function($event){
  $route=Yii::app()->getRequest()->getPathInfo();
  $module=substr($route,0,strpos($route,'/'));
 
  if(Yii::app()->hasModule($module))
  {
    $module=Yii::app()->getModule($module);
    if(isset($module->urlRules))
    {
      $urlManager=Yii::app()->getUrlManager();
      $urlManager->addRules($module->urlRules);
    }
  }
  return true;
},

Код уже ушёл в SVN.

Комментарии RSS

  1. №2822
    Serge Bezborodov
    Serge Bezborodov 05.08.2010, 12:40:46

    Данная возможность войдет в следующий релиз yii?

  2. №2823
    mc-bear
    mc-bear 05.08.2010, 12:51:23

    уже вошла!

    CHANGELOG

    Version 1.1.4 to be released

    ...

    • Enh: Added CUrlManager::addRules() (Qiang)

    ...

  3. №2826
    test
    test 05.08.2010, 18:53:28

    Александр, не расскажешь поподробнее насчет планов развития, а то ты в твиттере написал совсем коротко)

  4. №2827
    test
    test 05.08.2010, 18:53:45

    я про версии

  5. №2828
    Sam
    Sam 05.08.2010, 20:57:37

    Не, пока рано.

  6. №2832
    Владимир
    Владимир 08.08.2010, 14:24:34

    У меня давно в сайтах используется такое расширение:

    class ASUrlManager extends CUrlManager {
        public $beforeRules = array();
        public $afterRules = array();
     
        public function init() {
            $r = Route::model()->findAll('active = 1');
     
            $this->rules = array_merge($this->rules, $this->beforeRules);
     
            foreach ($r as $rule) {
                $this->rules[$rule->route] = $rule->path;
            }
     
            $this->rules = array_merge($this->rules, $this->afterRules);
            return parent::init();
        }
    }
  7. №2833
    Sam
    Sam 08.08.2010, 16:06:27

    Вот для того, чтобы не делать много раз init(), который довольно ресурсоёмок, можно воспользоваться новым способом.

  8. №2874
    Сергей
    Сергей 13.08.2010, 8:43:49

    спасибо за полезную вещь, только непонятно как правильно вписывать в конфиг файлах, где эти конфиги должны располагаться и после какого кода и до какого?

    К примеру есть модуль Новость располагается он тут modules/news/

    где есть основной файл NewsModule.php я так понял правила нужно где-то в этом файле вписать или как-то по другому?

    Спасибо за разъяснение.

  9. №2875
    Sam
    Sam 13.08.2010, 12:48:23

    В данном примере правила пишутся в свойство urlRules модуля.

  10. №2876
    Сергей
    Сергей 13.08.2010, 15:18:38

    а это как в свойствах?

    извиняюсь за глупый вопрос...

  11. №2877
    Sam
    Sam 13.08.2010, 18:00:19
    class X {
      public $property = …;
    }
  12. №2884
    Сергей
    Сергей 15.08.2010, 17:30:10

    тоесть таким образом можно прописать правила в отдельном каталоге в файле допустим modules/news/config/router.php для каждого конкретно отдельного модуля?

  13. №2885
    Sam
    Sam 15.08.2010, 19:19:22

    Можно.

  14. №2886
    Сергей
    Сергей 16.08.2010, 0:57:56

    можете немного подробнее описать как это сделать, уж извините что задаю много вопросов по одной и той же теме.

    Буду очень вам благодарен за помощь, спасибо

  15. №2887
    Sam
    Sam 16.08.2010, 18:54:56

    По аналогии с кодом в посте. Только вместо загрузки самого модуля надо считать данные из его конфига.

  16. №2892
    Сергей
    Сергей 18.08.2010, 16:16:54

    ох и горе наверное со мной, не получается у меня ни как

    делаю так, в файле modules/news/NewsModule.php приписываю такой код

    class NewsModule extends CWebModule
    {
     
     public $urlRules = array(
                           'news'=>'news/news',
                           'news/edit/<id:d+>'=>'news/edit',
                           'news/create'=>'news/create'
                        );
     
     
     public function init()
     {
      $this->setImport(array(
       $this->id . '.models.*',
       $this->id . '.components.*',
      ));
     }
     
     public function beforeControllerAction($controller, $action)
     {
      if(parent::beforeControllerAction($controller, $action))
      {
       return true;
      }
      else
       return false;
     }
    }

    но когда пытаюсь зайти выдаёт

    CHttpException / 404
    Невозможно обработать запрос

    код что в посте у вас указан прописал в основном конфиге main.php сразу над кодом

    'urlManager'=>array(
         'class' => 'MyUrlManager',
     
        'showScriptName' => false,
        'urlFormat'=>'path',
        'useStrictParsing'=>true,    
        'rules'=>array( 
     
           '/'=>'site',
           'login'=>'user/login',
           'logout'=>'user/logout',
    ...

    извиняюсь за большой код

  17. №2899
    Sam
    Sam 19.08.2010, 22:52:55

    Он должен быть наравне с секцией components, а не в ней.

  18. №2905
    Юрий
    Юрий 20.08.2010, 15:37:35

    Спасибо. Давно искал решение проблемы с модулями и правилами URL.

  19. №3109
    Константин
    Константин 15.09.2010, 12:41:45

    Есть возможность задать обработчик для onBeginRequest не только через конфиг (main.php)? Потому что иметь код в конфиге имхо не очень красиво: 'onBeginRequest' => create_function('$event', 'die("a");')

    Так же как я понял в контроллере задать обработчик начала реквеста тоже не получится, т.к. его вызов (контроллера) происходит уже после этого события?

  20. №3111
    Sam
    Sam 15.09.2010, 22:41:24

    Да, конечно есть. Почитать можно в рецепте «События». В контроллере не получится. Можно, например, в index.php.

  21. №7001
    Андрей
    Андрей 09.11.2012, 20:24:02

    Здравствуйте. Только что использовал ваш метод маршрутизации url для модулей, но 404. Скажите может что-то не так делаю?

    В модуле

    public $urlRules = array(
            'gallery'=>'images/view/index',
            '<category:.*?>'=>'images/view/index'
        );

    В конфиге

    'urlManager'=>array(
     
                'urlFormat'=>'path',
                'showScriptName'=>false,
                'urlSuffix'=>'.html',
                'cacheID' => 'cache',
                'rules'=>require(dirname(__FILE__).'/url.php'),
            ),

    и вставил событие onBeginRequest в точности как у вас в 1 уровне вложенности. Кто нибудь скажите, может что-то я не дописал?

  22. №7076
    fad
    fad 19.11.2012, 15:23:20

    Андрей, нужно убрать rules из конфига 'urlManager' => ...

  23. №7094
    Андрей
    Андрей 20.11.2012, 11:20:06

    увы но нет, я решил проблему, оказывается порядок загрузки модулей тоже влияет, на это. Т.к. правила одного модуля могуг перекрывать правила из другого.

  24. №7110
    fad
    fad 21.11.2012, 17:00:43

    Кто-нибудь не сталкивался с проблемой, когда используются виджеты модуля в другом модуле? Правила берутся только у текущего модуля, а виджет может быть использован в любом модуле, и он не подгрузит нужные правила..

  25. №7322
    Дмитрий Елисеев
    Дмитрий Елисеев 27.12.2012, 11:39:52

    Адрес /blog/index парсер с substr возьмёт, а просто /blog - нет. Можно заменить на

    $domains = explode('/', $route);
    $module = array_shift($domains);

    Про это же и про импорт правил для виджетов затронул тему у себя.

  1. Почта опубликована не будет.

  2. Можно использовать синтаксис Markdown или HTML.

  3. Введите ответ в поле. Щёлкните, чтобы получить другую задачу.