TIP: Use Markdown or, <pre> for multi line code blocks / <code> for inline code.
These forums are read-only and for archival purposes only!
Please join our new forums at discourse.kohanaframework.org
Роут с бесконечным уровнем вложенности каталогов.
  • Добрый день.

    Возможно уже существует решение, но я не могу придумать его сам.

    Есть структура в папке controller admin admin/settings

    В admin лежат контроллеры админки. И базовые, скажем так, классы, для подразделов. В подразделе (например settings) лежат контроллеры страниц подраздела. Работает это таким образом.

    Если запрашивается ссылка /admin/settings/ то отрабатывает базовый контроллер, если же /admin/settings/users, то это уже контроллер users в папке settings.

    Реализуют это сейчас два роута:

    //поддиректории в admin Route::set('subadmin', '(< directory >)/< controller >(/< action >)(/page< page >)(/< id >)(/< id2 >)', array ( 'controller' => '[a-z]+', 'page' => '[0-9]+', 'action' => '[\pL]+', //'directory' => 'admin(/settings){1}' 'directory' => 'admin/[\pL]+', 'page' => '[0-9]+', )) ->defaults(array( 'directory' => 'admin', 'controller' => 'main', 'action' => 'index', )); //роут для админки Route::set('admin', 'admin(/< controller >(/< action >(/page< page >)(/< id >)(/< id2 >)))', array( 'directory' => 'admin', 'page' => '[0-9]+', )) ->defaults(array( 'directory' => 'admin', 'controller' => 'main', 'action' => 'index', ));

    А что мне делать, если я хочу третий уровень? Например по ссылке /admin/settings/users/client/ должен отработать контроллер Client который лежит в папке /admin/settings/users/. Т.е. логика та же, что со вторым уровнем, но чтобы она повторялась на любой уровень вложенности.
    Не писать же мне роуты на каждый случай? subsettings, subusers...

    Меня устроит решение с бесконечным уровнем вложенности и с другой логикой.

  • правило для проверки параметра directory подкорректировать

  • как-то так: 'directory' => '[\w-/]+' только наверное имеет смысл сделать жадную проверку

  • @WinterSilence, это для роута admin ? И тогда я могу удалить subadmin?

    А жадная как будет выглядеть?

  • У меня не получается сделать. Есть у кого-то еще идеи или готовое решение?

  • @ButscH, спасибо, но не то. В данном случае интересно было только регулярное выражение..

    'directory' => '.+?'

    Дальше автор приводит пример двух роутов, в которых жестко задан путь

    'directory' => 'content/library'

    Я же хочу, чтобы работало по логике описанной мной выше и без создания дополнительных роутов. Я создал роут admin, а дальше в директории admin делаю подкаталоги, и они сразу доступны, как описано в первом посте темы.

  • Вообще @seyfer ты мне кажется ты мало рассуждаешь логически, т.к. ты сам представь работу твоего роута, как роутер поймет что есть что.

    Вот скажи, что будет в этой строке директорией, что контроллером, что экшеном dir1/dir2/dir3/controller и что в этой dir1/dir2/dir3/controller/action.

    Если сам не догадаешься, вот тебе подстказка:

    dir1/dir2/dir3/controller Directory: dir1/dir2 Controller: dir3 Action: controller (Экшен мы не указывали, роут сработал не верно)

    dir1/dir2/dir3/controller/action Directory: dir1/dir2/dir3 Controller: controller Action: action

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

    В общем это не самый умный роут.

    Тебе нужно логическое разделение на переход от директории к контроллеру, например: dir1/dir2/dir3/controller.action или dir1/dir2/dir3/controller-action, (< directory >/)< controller >(-< action >(/page< page >)(/< id >)(/< id2 >)) хотя бы так.

  • @ButscH +1

    @seyfer освой регулярные выражения http://ru.wikipedia.org/wiki/Регулярные_выражения всю жизнь за тебя другие люди проблемы решать не будут, мы скорее по части посоветовать, но знания то всё равно нужны ^^

  • Почему не рассматриваются коллбэки?

  • @ButscH, я как раз таки очень много рассуждаю логически по долгу работы.

    Ты видимо не понял задачу. Прочитай еще раз первый пост. Если бы не возникла проблема, я бы не писал. Я хочу именно по той логике, которую я описал в первом посте.

    dir1/dir2/dir3/controller Directory: dir1/dir2 Controller: dir3 Action: controller (Экшен мы не указывали, роут сработал не верно)

    Вот тебе тоже подумать. Конкретно под приведенный пример роута ссылка

    Так работает. Есть папка админ, есть папка settings, так работает.

    /admin/settings/seancesettings

    Теперь я создаю папку seance в settings и переношу туда контроллер. Так не работает

    /admin/settings/seance/settings/

    И так не работает

    /admin/settings/seance/settings/index

    Потому, что

     protected _directory => string(14) "admin/settings"
        protected _controller => string(6) "seance"
        protected _action => string(8) "settings"
        protected _uri => string(30) "admin/settings/seance/settings"
    

    А settings это контроллер, я не хочу указывать action. А даже если указать, то

    protected _directory => string(14) "admin/settings"
        protected _controller => string(6) "seance"
        protected _action => string(8) "settings"
        protected _uri => string(36) "admin/settings/seance/settings/index"
    

    То же самое. И так мы видим, что проблема все таки есть.

    Теперь рассмотрим пример советчика учить регулярки.

    @WinterSilence сказал

    '[\w-/]+'

    , ок

    Ссылка /admin/settings/seance/settings/ открылась, ура. А вот ни один экшн не работает. Потому, что контроллером считается

     protected _directory => string(30) "admin/settings/seance/settings"
        protected _controller => string(6) "update"
        protected _action => string(5) "index"
        protected _uri => string(37) "admin/settings/seance/settings/update"
    

    И последний вариант из статьи, приведенной @ButscH, которому все время что-то кажется, или он не умеет уважительно общаться с собеседником.

    .+?

    не открылась ссылка admin/settings/seance/settings, ведь не работает так, сказал же.

    protected _directory => string(14) "admin/settings"
        protected _controller => string(6) "seance"
        protected _action => string(8) "settings"
        protected _uri => string(30) "admin/settings/seance/settings"
    

    Но ты конечно умнее всех.

    Пока что лучший вариант от @WinterSilence -

    '[\w-/]+'

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

  • @biakaveron , они есть в 3.2 ?

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

  • Тебе нужно логическое разделение на переход от директории к контроллеру, например: dir1/dir2/dir3/controller.action или dir1/dir2/dir3/controller-action, (< directory >/)< controller >(-< action >(/page< page >)(/< id >)(/< id2 >)) хотя бы так.

    Неужели нельзя решить без этого? Может каллбеками например.

  • как роутер поймет что есть что

    Этого я и хочу добиться. Через коллбек можно попробовать таким образом. Распарсить урл. Посмотреть является ли предпоследний сегмент папкой, если да, то последний - контроллер. Если нет, то последний - экшн. А все что перед предпоследним - папки. В общем логику написать можно. Спасибо @biakaveron.

  • Вопрос как будут вести себя роуты с каллбеками с включенным

    Route::cache(TRUE);
  • С анонимками не должно работать. А если это отдельный статический метод, проблем не должно возникнуть

  • @biakaveron - а почему нет? там вроде только при кешировании проблемы были

  • @WinterSilence

    В смысле? Route::cache() кеширует роуты, в случае с анонимками сейчас это невозможно (насколько я помню). Статический метод можно передать в колбэк в виде массива или строки - все замечательно кешируется.

  • @biakaveron я имел ввиду если не кешировать данный роут, то и проблем не будет, 1 роут не столь критичен

  • А как ты узнаешь, закешировался ли нужный? Или всегда его добавлять? Но тогда нужный порядок выдержать не получится

  • @biakaveron if (Route::cache()) { //Роут } например сделать отдельную проверку для данного роута

  • @WinterSilence зачем все эти сложности, если можно элементарно вынести из анонимной функции в статическую и жить спокойно?

  • @DimkOf это уже другой вопрос и к теме анонимные функции не работают в роутах не относится. а по поводу зачем, ну чтобы лишний класс с этим методом не создавать например. вообще по моему было бы логично если в роутинге бы проверялось не только соответствие условию но и наличие самого контроллера и экшена, это в некоторых случаях бы помогло избежать кучи лишних роутов. + роут по умолчанию обязательным сделать.

  • Я хочу уточнить по поводу статики. Имеется ввиду так?

    Route::set('testing', function($uri) { return MyUriClass::myRouteMethod($uri); }, 'foo/bar' );

    На вход $uri что будет подаваться? Часть из 'foo/bar' или все урл, при поиске маршрута? 'foo/bar' тут выступает как default ?

  • @seyfer Это тогда уже не статика, а анонимка получается )) Можно передать вторым параметром массив.

  • оо, спасибо за сайт!

    @biakaveron, кохана 101, а какая собственно версия, для какой версии доки? Всегда последняя?

  • 3.2. Для 3.3 хотел отдельную ветку сделать, но времени не хватает даже старые черновики страниц добить, не то чтобы версии актуализировать )) Код в виде Userguide, можно подключить локально (только поиска и комментов не будет) - https://github.com/biakaveron/kohana101-ru

  • Сделал callback

    Route::set("sub", array( "Route_Subdirectory", "route" ), '(< directory >)/< controller >(/< action >)(/page< page >)(/< id >)(/< id2 >)' )->defaults(array( 'directory' => 'index', 'controller' => 'main', 'action' => 'index', ));

    Вызывается так Парсинг урла дает результат

    array(5) ( "directory" => string(9) "admin/log" "controller" => string(3) "asb" "action" => string(4) "info" "page" => string(0) "" "id" => string(6) "834512" )

    Паттерн (< directory >)/< controller >(/< action >)(/page< page >)(/< id >)(/< id2 >)

    Урл /admin/log/asb/info/834512

    Все хорошо, подпапки стали открываться бесконечно вложенные, только вот проблема с параметрами. Не могу получить ни page ни id

    $this->request->param("id"); NULL

    В каком виде надо вернуть параметры?

  • ПОМОГИТЕ :)

  • у вас в урле нет параметра page, он должен выглядеть как /admin/log/asb/pageinfo/834512

    для id и id2 задайте паттерн типа [0-9]+

    второй id2 сделайте вложеным в первый, мне кажется, что так будет логичней.

  • @DimkOf , Я вижу. В конкретно этом примере нету page, но если он есть, он так же NULL как и id. Добавление паттерна на page и id не помогает получать params, не работает.

    Вопрос тут не про форму, а про содержание, работоспособность.

    Как видно я возвращаю параметры с коллбека, они парсятся, но потом почему-то не доступны.

    Смежная тема http://forum.kohanaframework.org/discussion/11920/cant-get-params-from-callback-route-k3-2

  • а в колбеке у массива ключи соответствуют названиям параметров?

  • @DimkOf

    вы же видите пример в первом посте. именно поэтому я в замешательстве

  • @seyfer, я ради теста попробовал вот так:

    Route::set('test', 'test(/< page >)(/< page2 >)(/< id >)(/< id2 >)')
        ->filter(array('Test', 'route'))
        ->defaults(array(
            'controller' => 'welcome',
            'action'     => 'test',
        ));
    
    
    class Test {
    
        public static function route($uri)
        {
            return array(
                'controller'    => 'Welcome',
                'action'        => 'test',
                'page'          => 'page',
                'id'            => '111',
            );
        }
    }
    

    контроллер Welcome

    public function action_test()
    {
        $this->response->body(Debug::vars($this->request->param()));
    }
    

    возвращает:

    array(2) (
        "page" => string(4) "page"
        "id" => string(3) "111"
    )
    

    все как и должно быть.

    Поэтому не понимаю, почему у Вас не получается...

  • @DimkOf, что за метод filter() ? О какой версии коханы идет речь?

    Посмотрите мой вызов, у меня он записан иначе, версия 3.2. Может на 3.3. и работает.

  • @seyfer в общем, чувак, ты запутал сам себя и тебе стоит после Request найти контроллер, который запускается и дебажить в нем в before $this->request и смотреть на параметры, которые он вернул.

  • @ButscH, я себя не запутал. Дебаг делал, параметров в реквесте нет.

    Вот ссылка /admin/log/asb/index/page2/1/2

    Мой роут возвращает

    array(6) ( "directory" => string(9) "admin/log" "controller" => string(3) "asb" "action" => string(5) "index" "page" => string(1) "2" "id" => string(1) "1" "id2" => string(1) "2" )

    Все абсолютно верно.

    Вот дебаг реквеста

    object Request(20) { protected _requested_with => NULL protected _method => string(3) "GET" protected _protocol => string(8) "HTTP/1.1" protected _secure => bool FALSE protected _referrer => NULL protected _route => object Route(5) { protected _callback => array(2) ( 0 => string(18) "Route_Subdirectory" 1 => string(5) "route" ) protected _uri => string(65) "(< directory >)/< controller >(/< action >)(/page< page >)(/< id >)(/< id2 >)" protected _regex => array(0) protected _defaults => array(3) ( "directory" => string(5) "index" "controller" => string(4) "main" "action" => string(5) "index" ) protected _route_regex => NULL } protected _routes => array(0) protected _response => object Response(5) { protected _status => integer 200 protected _header => object HTTP_Header(0) { } protected _body => string(0) "" protected _cookies => array(0) protected _protocol => string(8) "HTTP/1.1" } protected _header => object HTTP_Header(0) { } protected _body => NULL protected _directory => string(9) "admin/log" protected _controller => string(3) "asb" protected _action => string(5) "index" protected _uri => string(29) "admin/log/asb/index/page2/1/2" protected _external => bool FALSE protected _params => array(0) protected _get => array(0) protected _post => array(0) protected _cookies => array(1) ( "session" => NULL ) protected _client => object Request_Client_Internal(2) { protected _previous_environment => NULL protected _cache => NULL } }

    Как мы видим - сработал мой роут. Массив PARAMS - Пустой.

  • Наверное эта фишка не работает в 3.2 ? Хотя заявлена..

  • @seyfer Может стоит показать свой callback?

  • @ButscH , какая разница, если результат на выходе такой, какой нужен?

    array(6) ( "directory" => string(9) "admin/log" "controller" => string(3) "asb" "action" => string(5) "index" "page" => string(1) "2" "id" => string(1) "1" "id2" => string(1) "2" )

    И по дебагу запроса видно, что отработал именно мой роут.

  • return $result; наверно стоит заменить на return $finalResult; в методе Route_Subdirectory::route() если я все верно понял

  • @ButscH - да, там опечатка. Невнимательность. Спасибо.

  • Как ни странно, это не работает у меня в 3.3.

    Во первых должно быть через фильтр, во вторых названия папок с большой буквы. Меняется в двух местах и объявление роута.

  • Стоит ли оформить в виде модулей для разных версий?

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion