Дополнение для Url для реализации обратных ссылок

Всем привет. Появилось немного времени, сделал первую реализацию обещанных обратных ссылок для phalcon. Для тех, кто не в курсе: стандартная реализации Route в phalcon 1.* не позволяет использовать опциональные параметры и не правильно генерирует обратные ссылки для роутов. Например:

$router
  ->add('/admin(/:controller(/:action(/{id:[0-9]+}(/:params)?)?)?)?', array(
    'module'     => 'backend',
    'controller' => 2,
    'action'     => 4,
    'id'         => 6,
    'params'     => 8,
  ))
  ->setName('backend');

...

echo $this->url->get(array('for'=>'backend', 'controller'=>'users'));

В результате данного кода получим /adminusers? вместо ожидаемого /admin/users. Для многих - это нормально, они не привыкли к опциональным параметрам. Для других (таких, как я) - это плохо.

Теперь немного затравки, чтобы понимать, что дает данный класс для того-же роута: ```php echo $this->url->route('backend'); // /admin echo $this->url->route('backend', array('controller' => 'users')); // /admin/users echo $this->url->route('backend', array('controller' => 'users', 'action' => 'add')); // /admin/users/add echo $this->url->route('backend', array('controller' => 'users', 'action' => 'edit', 'id' => 1)); // /admin/users/edit/1 echo $this->url->route('backend', array( 'controller' => 'users', 'action' => 'info', 'id' => 1, 'params' => array( 'page' => 1, 'limit' => 10, ), )); // /admin/users/info/1/page/1/limit/10 ```

Удобно, правда?) Реализация: https://gist.github.com/aktuba/7702229 . Есть вопросы - задавайте.



7.0k

Sorry, but I do not understand the magic of indexation ```php 'controller' => 2, 'action' => 4, 'params' => 6, ``` What does this index?



6.0k

@Oleg, ты же вроде по-русски говоришь?) Индексы немного поправил, до этого был старый роут, скопипастил его сюда, изменил, а индексы поменять забыл. Сейчас вроде правильные.



7.0k

Конечно, говорю. Мне такая реализация не нравится. Это, конечно же, не значит, что она не имеет права на жизнь. Если это коиу-то подходит - пусть использует. Я за абсолютную однозначность в определениях. У вас же индексация идет в разрез с правилами индексации в Phalcon.



6.0k

Где индексация идет в разрез?) Встроенные классы phalcon вообще не трогаются, индексация стандартная ;)



7.0k

Почему 2 4 6 8, но не 1 2 3 4? Ну это ладно... У вас в корневом примере роутер описан, как такой, что может содержать или не содержать controller, action etc. В этом я вижу неоднозначность. При обратном преобразовании невозможно точно определить роут, так как возможны несколько исходов. Я избегаю такую практику в своей деятельности. В даном случае вижу "силовое назначение" при обратном преобразовании, и, насколько я увидел, опять происходит возврат к нормальной структуре - module/controller/action/params. Так что целесообразности не вижу. Но я за свободу в программировании (пока она не мешает другим, конечно :) ). Так что, если кому-то это принесет пользу - будет хорошо



6.0k

Почему 2 4 6 8, но не 1 2 3 4?

Потому-что в регулярке они под такими параметрами идут. Скобки видишь?

При обратном преобразовании невозможно точно определить роут, так как возможны несколько исходов.

Т.е.? Почему нельзя определить роут? о_О

В даном случае вижу "силовое назначение" при обратном преобразовании, и, насколько я увидел, опять происходит возврат к нормальной структуре - module/controller/action/params.

Ты о чем? Какой "возврат" в формировании урлов? Почему "module/controller/action/params" - "нормальная структура", а "module/controller/action/id" - нет? Можешь чуть подробней рассказать, а то не совсем понятно что ты имеешь в виду.



6.0k

По поводу целесообразности - создано для удобства (не только, но в основном). Например, если сделать такой роут

$router
  ->add('/admin/:controller/:action', array(
    'module'     => 'backend',
    'controller' => 1,
    'action'     => 2,
  ))
  ->setName('backend');

то в урлах всегда будет /admin/users/index, где /index явно лишний. А в некоторых случаях (имею в виду seo, будь оно не ладно) еще и вредным. Если сделать action в роуте опциональным - все будет отлично. Причем, такой роут (с опциональным action) даже работать будет правильно, и ссылки будут формироваться правильно. Но стоит добавить 3-4-5-... опциональных параметров - phalcon впадает в ступор. Потому и появился данный класс.

Вот еще пример: ```php $this->url->get(array('for'=>'backend/default')); $this->url->get(array('for'=>'backend/users')); $this->url->get(array('for'=>'backend/users/new')); $this->url->get(array('for'=>'backend/users/edit', 'id'=>$id)); ```

сравни с ```php $this->url->get(array('for'=>'backend')); $this->url->get(array('for'=>'backend', 'controller'=>'users')); $this->url->get(array('for'=>'backend', 'controller'=>'users', 'action'=>'new')); $this->url->get(array('for'=>'backend', 'controller'=>'users', 'action'=>'edit', 'id'=>$id)); ```

Лично мне второе намного проще воспринимать и поддерживать: я сразу вижу модуль, контроллер, действие и параметры. А в первом случае ничего, кроме названия роута, не видно. Ни в какой модуль пойдет запрос, ни в какой контроллер, ни в какой action...



7.0k

Давайте возьмем ваш образец роута и протестируем во фреймворке : ```php <?php

$url = new Phalcon\Mvc\Url();

$url->setBaseUri('/');

$router = new Phalcon\Mvc\Router();

$router ->add('/admin(/:controller(/:action(/{id:[0-9]+}(/:params)?)?)?)?', [ 'module' => 'backend', 'controller' => 2, 'action' => 4, 'params' => 6, ]) ->setName('backend');

$testRoutes = [ '/admin', '/admin/users', '/admin/users/edit/123', '/admin/config/edit', '/admin/pages/new', '/admin', '/admin/users', '/admin/users/1', '/admin/users/1/edit', '/admin/pages', '/admin/pages/contacts', '/admin/pages/contacts/edit', '/admin/users/info/1/page/1/limit/10', ];

foreach ($testRoutes as $testRoute) {

$router->handle($testRoute);
echo 'Test route : ', $testRoute, '<br>', PHP_EOL;

if ($router->wasMatched()) {
    echo 'Controller : ', $router->getControllerName(), '<br>', PHP_EOL;
    echo 'Action : ', $router->getActionName(), '<br>', PHP_EOL;
} else {
    echo "The route was't matched...<br>", PHP_EOL;
}
echo '<br>', PHP_EOL;

} ``` Имеем результат : ```html Test route : /admin Controller : Action :

Test route : /admin/users Controller : users Action :

Test route : /admin/users/edit/123 Controller : admin Action : users

Test route : /admin/config/edit Controller : config Action : edit

Test route : /admin/pages/new Controller : pages Action : new

Test route : /admin Controller : pages Action : new

Test route : /admin/users Controller : users Action : new

Test route : /admin/users/1 Controller : users Action : new

Test route : /admin/users/1/edit Controller : admin Action : users

Test route : /admin/pages Controller : pages Action : users

Test route : /admin/pages/contacts Controller : pages Action : contacts

Test route : /admin/pages/contacts/edit Controller : admin Action : pages

Test route : /admin/users/info/1/page/1/limit/10 Controller : admin Action : users ``` Возьмем первый же роут - вопрос - куда идем после /admin? Вот это я и не понимаю. Я взял ваши выкладки для тестирования. Поэтому и говорю, что использовать такое не буду. К тому же у меня уже давненько таких проблем с роутерами и не возникает. Понравилось использовать роуты в аннотациях. И, соответственно, с обратными ссылками неурядиц не наблюдается.



6.0k

Вон вы о чем))). Уважаемый, вы будете удивлены, но... Это стандартная работа роутера phalcon. Повторюсь: это работа phalcon, а не моего класса. Не верите?) Удалите мой класс и сравните результаты). Ну а если проставите дефолтные значения - все встанет на свои места ;).

Мой класс дополняет (даже не изменяет, а только дополняет!!!) класс \Phalcon\Mvc\Url, который не имеет вообще никакого отношения к обработке входящих урлов ;). Видимо, сам роут ввел вас в некоторое заблуждение, давайте объясню. Возьмем роут попроще, например: ```php $router ->add('/:controller/:action', array( 'controller' => 1, 'action' => 2, )) ->setName('default'); ```

Проще можно, но смысла нет). Теперь представим, что есть сайт с этим роутом и 30-40 вьюх. Во вьюхах есть какие-то ссылки. Судя по тому, что вы писали выше, скорее всего они выглядят так: ```php <a href="/main/index">Ссылка 1</a> <a href="/post/title">Пост</a> <a href="/comment/view">Комментарий</a> ... ```

или так: ```php <a href="<?= $this->url->get('main/index') ?>">Ссылка 1</a> <a href="<?= $this->url->get('post/title') ?>">Пост</a> <a href="<?= $this->url->get('comment/view') ?>">Комментарий</a> ... ``` Есть еще вариант, когда на каждую ссылку (ну или почти) создается свой роут, но его в расчет не берем, т.к. сути это не меняет. Т.е., фактически, урлы прописаны руками. Что будете делать, когда понадобится, например, добавить к каждой ссылке окончание .html? А если в начале поставить action, а после contoller? Помимо изменения роута придется и пролопатить все 30-40 вьюх (а возможно еще и кучу других файлов), чтобы ручками поменять все ссылки. Верно?

А вот мой вариант. Меняем чуть-чуть роут: ```php $router ->add('(/:controller(/:action)?)?', array( 'controller' => 2, 'action' => 4, )) ->setName('default'); ```

И ссылки ставим вот так: ```php <a href="<?= $this->url->route('default', array('controller'=>'main')) ?>">Ссылка 1</a> <a href="<?= $this->url->route('default', array('controller'=>'post', 'action'=>'title')) ?>">Пост</a> <a href="<?= $this->url->route('default', array('controller'=>'comment', 'action'=>'view')) ?>">Комментарий</a> ```

Что надо сделать, чтобы поменять все эти ссылки на сайте? Всего-лишь поменять роут. Все. Надеюсь я понятно объяснил, но если есть вопросы - задавайте.

P.S.: аннотации воспринимаю очень плохо, поэтому вряд-ли буду дорабатывать класс для них (



7.0k

Да, я увидел вашу идею, но не соглашусь в ее пользе. Такое мое мнение. Есть масса способов произвести рефакторинг ссылок, и не только, в проекте. По крайней мере у меня никогда не возникало такого затруднения. Пока есть linux, vim & sed :) Ну и, к тому же, я придерживаюсь строгости (однозначности) в формировании ссылок. Динамике это не мешает. Happy weekend :)



6.0k

Ну соглашаться я никого не заставляю, как и использовать). Но вообще, довольно странно, когда рефакторинг предпочитают изначально правильному проектированию o_O. И вопрос: можете подробнее рассказать про "строгость (однозначность) в формировании ссылок"? Я считаю, что у меня все строго и однозначно, но похоже в чем-то ошибаюсь. Хотелось-бы понять в чем...



7.0k

К счастью, мне еще не приходилось заниматься переделыванием ссылок. Тем более переименование модулей и контроллеров. И index контроллер, впрочем, как и index action, у меня, как правило, отсутствуют. Как-то все решается на начальной стадии проектирования. Так что потом только добавление при необходимости. Может, везет



6.0k

Ок, это я понял. У каждого свой путь, это нормально. Но я не увидел ответ на "строгость (однозначность) в формировании ссылок". Что под этим подразумевалось? Отсутствие дефолтных контроллеров/действий? Тогда это странный критерий. И если отсутствие дефолтного контроллера я еще как-то могу понять (хоть и с большим трудом), то отсутствие дефолтного action не воспринимаю. Причина: неоднозначность ссылок ;). Получается, что ссылка выглядит (например) как /posts, но дефолтного действия нет, а значит в роутере жестко прописывается action, который может быть чем угодно... В случае наличия дефолтных параметров, они подставляются если отсутствуют в ссылке, т.е. видя /posts понимаешь сразу, что это контроллер Posts и действие index... Как-то так.



7.0k

Я даже не знаю, как вам точно объяснить этот мой принцип. Однозначное трактование... Наверное, это когда каждому модулю/контроллеру/действию соответствует один, и только один маршрут. Маршрут может передавать любые параметры, но эти параметры должны быть строго типизированы. Наверное, как-то так. Дефолтные контроллеры и действия, конечно же есть. Просто я их называю всегда более осмысленно. В URI их всегда можно скрыть.



6.0k

Ясно. Мне данный путь не подходит, я привык автоматизировать свою работу.

Хорошее и правильное решение проблемы и реализация поставленной задачи. Сможешь разместить код в Инкубаторе ( https://github.com/phalcon/incubator ) ? В пространстве \Phalcon\Mvc\Url , как вариант расширения стандартного роутера ;)



6.0k

Рано, нашел пару багов, все времени нет поправить. Как протестирую в боевом окружении - потом постараюсь добавить в инкубатор.



6.0k

Поправил класс, багов пока не нашел: https://github.com/aktuba/phalcon-url В Инкубатор не стал добавлять. Если не сложно, @boston, сделай сам plz.