We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Баг в Router

Я снова с новым багом к вам). В этот раз баг в роутере.

Работающий роут:

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

Не работающий роут:

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

Проверка:

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

Результат первого роута: /admin/users Результат второго роута: /adminusers?

Внимание, вопрос: ЧТО ДЕЛАТЬ?! Исходники фреймворка так и не смотрел, но не верю я, что специально заложили всего 2 уровня вложенности в регулярное выражение. Есть идеи, как обойти данный баг?

Скажи какого результата хочешь добиться. Какого типа ссылки и какие параметры.

PS. Общение на русском тут не особо поддерживается, может в группе тему создашь https://vk.com/phalconphp ?



10.2k

Нужны ссылки:

/admin /admin/users /admin/users/edit/123 /admin/config/edit /admin/pages/new и т.д.

Т.е., любые ссылки, начинающиеся с /admin, далее может быть какой-либо роут, за ним может появится действие, ну и возможны любые параметры...

По поводу vk - я пас, не перевариваю вконтакте.

Про vk понял.

Хочешь все ссылки с /admin/**** отправлять в один action, а там уже разруливать? Есть такая тема с группами роутов, когда можно казать базовый преффикс, и дальше уже рулить, но как понимаю это не совсем то: https://docs.phalcon.io/en/latest/reference/routing.html#groups-of-routes



10.2k

Правильнее - это совсем не то. Мне надо по определенному префиксу (/admin) отправлять в определенный модуль (backend). В разные контроллеры, в разные действия. Сегодня потратил на эту задачу больше 4х часов - не смог решить. Даже если сформировать готовую регулярку, возникают проблемы. А подменять класс роута мне не хочется, и так уже мало что осталось от самого фреймворка.

Буду подбирать другой фреймворк. Выйдет 2-я версия phalcon - может попробую использовать еще раз.

А вы слышали про Префиксы к маршрутам? В документации есть конкретные примеры, зачем пихать admin в URL, если можно указать единый префикс?

Из доков

$blog = new \Phalcon\Mvc\Router\Group(array(
    'module' => 'blog',
    'controller' => 'index'
));
$blog->setPrefix('/blog')


10.2k

Да вы шутите... Реально думаете, что человек способен потратить несколько часов не изучить документацию от и до?! Как группы (которые в реале как-раз и пихают префикс к урлам) помогут в моей проблеме? Вы бы хоть протестировали... Вот пример для тестов: нужна возможность обрабатывать и генерировать(!!!) следующие урлы:

/admin /admin/users /admin/users/1 /admin/users/1/edit /admin/pages /admin/pages/contacts /admin/pages/contacts/edit

Роут должен быть только 1(!), чтобы можно было генерировать урлы подобным образом:

$this->url->get(array('for'=>'admin', 'controller'=>'users')); $this->url->get(array('for'=>'admin', 'controller'=>'users', 'action' => 'edit', 'id' => 1)); $this->url->get(array('for'=>'admin', 'controller'=>'pages', 'action' => 'edit', 'id' => 'contacts'));

Ну как, помогут тут группы?

Чудак человек, гвозди тоже можно забивать микроскопом. Группа связывает твой /admin с модулем backbend и неким контроллером по умолчанию. Дальше ты только перечисляешь нужные actions.

И не стоит рассчитывать что можно задать мега регулярку, которая опишет все возможные варианты. Что в фалконе, что в других фреймворках - чем проще тем лучше, даже если придётся наплодить раутов.



10.2k

Во, еще один... Ты хоть попробуй реализовать, для начала. Мне не нужна мегарегулярка, мне нужна 1 регулярка, которая решает задачу выше. Реализуешь? В kohana делается элементарно, как и в других fw. Более того, даже в phalcon это реализуется, но только на обработку запроса, на генерацию урла уже не работает правильно, о чем было сказано в самом начале. Или это так и задумано - обработать можно, а сгенерировать нет?)

Щяс поставлю на таблетку IDE и буду реализовывать, вроде мне больше нечем в полночь заняться. Нет уж батенька, вы уж сами. Попробуй так:

'controller' => 1,
'action'     => 2,
'params'     => 3,

Циферки, это позиции не slug в URL, а параметров.



10.2k

Ну тогда хотя-бы перестаньте умничать и начните хотя-бы читать... Например, самый первый пост, там тоже "циферки". Повторить, что не работает это в phalcon или смысла нет?

Уважаемый, не делайте мне больную голову! Циферки циферкам рознь или вам одинаково давали в детстве ремня за 2 и 5?! Я не большой специалист по впиханию невпихуемого и именно в этом вашем случае боюсь техника, наука и медицина бессильны.



10.2k

Т.е., вы не посмотрев роут поставили с потолка свои циферки и довольны?)) Вы не большой специалист вообще везде, похоже. Даю основу: данные циферки - результат preg_match. Дальше справитесь? Нет?! Ок, в роуте скобочки видите? Вопросительные знаки видите? Ну уже хорошо...

Так вот, для особо одаренных. Роуты правильно разбирают урл, но не могут сгенерировать по ним ссылку. Специально для тупых индивидуумов, которые прикрываются таблетками, хотя просто имеют кривые, ни на что не способные, руки: класс роутов в phalcon не может правильно сгенерировать ссылку для роута, который правильно разбирает урл.

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

Я не особо разбираюсь в регулярках, но что у меня получилось

$url = '/admin/controller/action/params1/param2';
$pattern = '|/admin(/[a-zA-Z]{1,}(/[a-zA-Z]{1,}(/[a-zA-Z\d]{1,})?)?)?|i';
preg_match($pattern, $url, $matches);

print_r($matches);

Вывод

Array
(
    [0] => /admin/controller/action/params1
    [1] => /controller/action/params1
    [2] => /action/params1
    [3] => /params1
)


10.2k

Что логично, не находишь? Ты не обособил controller, action и параметры. Правильная, для твоего случая, регулярка:

|/admin(/([a-zA-Z]{1,})(/([a-zA-Z]{1,})(/([a-zA-Z\d]{1,}))?)?)?|i

Но даже это не вариант, т.к. route в phalcon формируется иначе:

#^/admin(/([a-zA-Z0-9\_\-]+)(/([a-zA-Z0-9\_\-]+)((/.*)*)?)?)?$#

Для сравнения, вот регулярка для данного роута, которая формируется в kohana:

#^/admin(?:/(?P<controller>[^/.,;?\n]++)(?:/(?P<action>[^/.,;?\n]++)(?:/(?P<params>[^/.,;?\n]++))?)?)?$#uD

Т.е. бага в роутере или в конструкторе URL'a?



10.2k

Честно? Без понятия. Если бы исходники были в виде php-кода, я бы быстро разобрался и назвал точное местоположение проблемы. А вот в си-коде мне ковыряться совсем не хочется. Судя по исходникам фреймворка, проблема в функции phalcon_replace_paths (https://github.com/phalcon/cphalcon/blob/master/ext/mvc/url.c#L342). Или в получаемой регулярке (https://github.com/phalcon/cphalcon/blob/master/ext/mvc/url.c#L330). Как бы там ни было, дальше я уже не копался.

Ты сильно не злись на людей, все мы разные и все по разному эмоциональны. Кто-то не сдерживается)



10.2k

Да я не злюсь на людей. Злюсь только на некоторых, которые много глупостей говорят ;)

** edited: перепишу ответ покультурнее

Ты, @aktuba, сам тролль. Хочешь со мной поспорить?! Иди кури исходники, глупый мальчик. Я с фалконом работаю с 0.9.0, и твоя "проблема" мне отлично известна: Phalcon не любит опциональные сегменты в URL. Ты бы хоть задумался на минутку, тебе ж не с потолка советуют...

https://github.com/phalcon/cphalcon/blob/3031810422479bbd3338f5c09dcc683253b95940/ext/kernel/framework/router.c#L155 https://github.com/phalcon/cphalcon/blob/3031810422479bbd3338f5c09dcc683253b95940/ext/kernel/framework/router.c#L189

При генерации ссылки фалкон замещает сегменты заключенные в "(...)" и "{...}" в регулярном выражении на значения. Поэтому из "#^/admin(/([a-zA-Z0-9_-]+)(/([a-zA-Z0-9_-]+)((/.))?)?)?$#" получается /adminusers, т.к. слеш во втором "(/([a-zA-Z0-9_-]+)" включен в скобки и замещается вместе со всем сегментом. Вот тебе твоя "бага", умник.

Это особенность Phalcon: его рауты проще и регулярные выражения используются в основом для валидации сегментов пути, а не их разбора. Внимательней учи матчасть, прежде чем хамить, программист-самородок. Вся твоя затея с мега-ссылкой - вот это глупость и тебе неоднократно на нее указали.

Используй префиксы (по усмотрению) и определи отдельно рауты для /admin, /admin/users и /admin/pages - это решение. Да, это целых +3 строчки кода, зато целые сутки съэкономленного времени.

OFFTOPIC

Альтернативно есть kohana для особо одаренных, но это уже не к нам, а в другой медпункт, там где ты "Я - Наполеон, я - торт!" - это нормально.



10.2k

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

Т.е., если роут может разобрать урл, но не может его-же собрать - это особенность. То, что роут правильно определяет вложенность в регулярке при разборе урла, но наглухо не понимает вложенность при генерации урла - особенность. Ну ок. Для нормальных людей - это баг разработчиков.

Это особенность, когда при разборе урла смотрим содержимое сегментов:

https://github.com/phalcon/cphalcon/blob/3031810422479bbd3338f5c09dcc683253b95940/ext/kernel/framework/router.c#L322

а при генерации - нет:

https://github.com/phalcon/cphalcon/blob/3031810422479bbd3338f5c09dcc683253b95940/ext/kernel/framework/router.c#L193 https://github.com/phalcon/cphalcon/blob/3031810422479bbd3338f5c09dcc683253b95940/ext/kernel/framework/router.c#L35

Ну и т.д. Да, это __особенность_фреймворка__, а не кривые руки разработчиков. Ок.

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

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

А ты ведешь себя вроде как вчера слез с ветки, получил в голову прилетевшим "PHP для чайников" и (вот они плоды эволюции!!) сидишь-пытаешься впихнуть квадратное в треугольное и возмущаешься что все вокруг дебилы. Мдя...

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

Wrap it up, you naughty boy, don't waste my time!!



10.2k

Ну значит "веб девелопмент менеджер в одной из крупнейших зарубежных IT компаний" сможет объяснить, почему в одном случае фреймворк знает вложенность, а в другом забывает о ней?) Я вот, в отличии от тебя, просто не использую (и не даю подчиненным использовать) кривые инструменты. Видимо, "в одной из крупнейших зарубежных IT компаний" это норма, когда используется инструмент, который не может выполнить то, что заявлено в его-же документации: "The regular expression syntax used is the same as the PCRE regular expressions".

Ах, ну да, это же особенность фреймворка: заявить о фиче, но сделать ее не рабочей). Удачи "мегаумному дебилу", который в упор не хочет признавать очевидный баг.

Вы, ребята, оба хороши. Зря вы так друг другу хамите. Вы столько энергии на эту полемику потратили — давно бы форкнули и исправили.

По сабжу: очевидно, это баг (ну или по кр мере особенность, которая не очевидна).

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



10.2k

Да я сегодня весь день этим занимался. Только что вот стер все, что накодил за день (. Слишком много надо менять. Router->handle обрабатывает текущий урл, вместо того, чтобы опрашивать объекты Route на валидность переданного урла, поэтому просто подменить регулярки не получилось (.

По поводу обратных урлов - они полезны. Во-первых, позволяют держать все ссылки в едином стиле (например, https://domain.com/admin или /admin или //domain.com/admin). Во-вторых, иногда надо передать готовую ссылку куда-либо (в e-mail, например). Если фреймворк не может генерировать ссылки сам, приходится писать что-то наподобии $url = $this->config->application->domain.'/remember'; вместо $url = $this->url->route('auth', array('controller'=>'remember'));. Согласись, второе явно приятнее читать и поддерживать.

@aktuba очень прошу не переводить диалог в обсуждение личностей и любые перепалки, тут это не приветствуется.

Если явно виден баг а работе роутера - надо сделать полный пример с его демонстрацией и оформить в https://github.com/phalcon/cphalcon/issues

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

PS. Если интонаций не изменится - тема будет первой которая будет удалена за превышенный уровень неадеквата. Тут не роисся что бы видеть во всех врагов и считать что все вокруг всем обязаны. Не можешь адекватно объяснять суть проблемы и разбираться в поиске решения - есть 100500 других фреймворков с необходимо правильным реализованым функционалом. Плюс Phalcon без проблем поддерживает любые части и компоненты сторонних фреймворков.



10.2k

@boston, я никогда не грубил тем, кто со мной общается культурно. Это можно увидеть и в данной ветке. Что касается проблемы - она описана досканально тут, включая ссылки и регулярки. Более конкретно описать сложно: роутер в phalcon не поддерживает в полной мере PCRE в части формирования обратных урлов. И да, я считаю что чем меньше роутов - тем стабильнее и быстрее работает приложение. Использовать 2 роута для /admin и /admin/users - вот это не оптимально, лишняя итерация в цикле, лишнее формирование регулярки и пр. Ну и создавать ссылки не очень удобно, постоянно держать в голове отдельный роут для отдельных контроллеров/действий:

$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));
и т.д.

Все это легко, когда роут работает правильно:

$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));

Согласись, с подобным проще работать.

Готовый вариант не получилось сделать. Пытался заменить пару методов в Router, Route и Url, но не прокатило - что-нибудь, но отваливается. Из работающих, удобных и простых реализаций могу привести только kohana 3.2:

https://github.com/kohana/core/blob/3.2/develop/classes/kohana/route.php#L227 https://github.com/kohana/core/blob/3.2/develop/classes/kohana/route.php#L457

По поводу PS: честно говоря, мне все-равно, удалена будет тема или нет. Как уже говорил - отвечаю адекватно собеседникам. И тему я начинал с просьбой подсказать, как обойти проблему. Хамить мне в ответ на просьбу - вот где не адекватное поведение.

@aktuba, согласен, выглядит проще. А если сделать отдельный срвис с единственным методом - формирование нужных ссылок, и в нём использовать регулярку из kohana? Т.е. никак не завязываться на существующие классы Phalcon?



10.2k

А по сути так и пытался: добавил поле regex в \Phalcon\Mvc\Router\Route, в методе add прописывал в это поле регурялку от коханы и в \Phalcon\Mvc\Url пытался собрать из нее урл. Но, то ли плохо смотрел работу add, то ли уже просто глаз замылился и не видел проблем - приложение переставало работать вообще. По всем роутам выкидывало 404-ю ошибку. Плюс, как-то криво конвертнул код генерации урлов - тоже непонятные траблы были. К вечеру уже сдался и забил на это.

Будет время, посмотрю еще раз на неделе. В теории, можно вообще не трогать класс Route, а в Url брать подходящий роут и из него генерировать регулярку и тут-же ссылку. Но, во-первых это будет сильно медленнее работать, во-вторых нарушается целостность, когда одна сущность отвечает за определенный вид данных. В общем, посмотрю и отпишусь.

Часть Си компонентов в Phalcon взаимодействует друг с другом через API (экспортируемый в PHP), а часть напрямую на уровне Си кода. Тот же Phalcon\Mvc\Url использует функции ядра Phalcon для генерации ссылок. @Phalcon-у не раз на это указывали (сложно наследовать компненты), но его аргумент - в оптимизации операций на уровне Си. Последний раз когда был разговор про Zephir проскальзывала здравая мысль портировать на него основные компоненты Phalcon и тогда или патчи и собирай свой extension или предлагай изменения в основную ветку... Но это будет не скоро.

<off topic>

Давай рассмотрим как работает типичное приложение:

  1. инициализация (PHP using exported C components): конфигурация, создание сервисов в Di, запуск Phalcon\Mvc\Application
  2. Dispatch (C components unless extended): перебор routes и если найдено то вытягивание параметров из ссылки и передача управления в нужный Controller

Routing в Phalcon похож на используемый в Symfony, Laravel, F3, Slim и т.д. Это надо учитывать. Поддержка PCRE заявлена и работает на этапе разбора ссылок.

Если ты переопределяешь любой из компонентов используемых в диспатчере, твой PHP код будет работать медленнее, чем оптимизированный Си код (он экспортирует в PHP только результат работы). Как минимум на лишний десяток routes которые можно просто добавить.

Проблема: Phalcon\Mvc\Url не работает как хотелось бы при обратной компновке ссылок.

  1. Controller action (PHP using exported C components): твоя бизнесс-логика
  2. Компоновка Response и отправка его клиенту (C components using PHP bindings and templates)

Чисто субъективно, bottleneck из за лишних routes в пункте 2 - это смешно, следом идет самый громоздкий этап работы - бизнесс-логика (если это не Hello World!). В общей картине, проблема не такая уж и большая, правда?

Жизненное предназначение настоящих программистов в создании и решении проблем. Поэтому варианты:

</off topic>

  1. Написать свой Url класс и подменить им стандартный сервис или использовать паралельно, как предложил @boston. Наиболее логичный вариант. Судя по твоим примерам все ссылки у тебя стандартные, так?

/:module/:controller/:action/:params /:module/:controller/:action /:module/:controller /:module

Сложно генерировать?

  1. Или, использовать стандартный механизм /:module/:controller/:action/:params, https://docs.phalcon.io/en/latest/reference/routing.html#default-behavior Еще один логичный вариант.

Или прописать дополнительные routes и ...

  1. Вынести admin в отдельный поддомен и тогда редко используемые routes совершенно не будут мещать чаще используемым. Или...
  2. Router обрабатывает routes в порядке их добавления, следовательно можно добавить /admin/* routes последними. Пару-тройку милисекунд админ может потерпеть.

Я бы советовал не заморачиваться, если проблема не решается в течении одного дня (эта уже тут с пятницы).



10.2k

Если ты переопределяешь любой из компонентов используемых в диспатчере, твой PHP код будет работать медленнее, чем оптимизированный Си код (он экспортирует в PHP только результат работы). Как минимум на лишний десяток routes которые можно просто добавить.

Без сомнения. Но если нужный функционал не работает - приходится идти на подобные издержки.

Чисто субъективно, bottleneck из за лишних routes в пункте 2 - это смешно, следом идет самый громоздкий этап работы - бизнесс-логика (если это не Hello World!). В общей картине, проблема не такая уж и большая, правда?

В приложении, которое надо сделать и забыть (читай - во время тестов) - вообще не проблема. В приложении, которое придется поддерживать и, возможно, рефакторить - большая проблема.

Сложно генерировать? Или, использовать стандартный механизм /:module/:controller/:action/:params Вынести admin в отдельный поддомен и тогда редко используемые routes совершенно не будут мещать чаще используемым. Или...

Вообще не вариант. Ни один более-менее серьезный проект без обратных ссылок я реализовывать не буду. Причина - usecase-ы, с которыми я уже набивал себе шишки:

  1. Видоизменить ссылку: domain.com/user/username => username.domain.com
  2. Изменение порядка параметров в ссылке: domain.com/user/username/edit => domain.com/username/edit, domain.com/user/username/edit => domain.com/user/edit
  3. Изменение типов ссылок: domain.com/category/page => domain.com/category/page.html, domain.com/category/page => domain.com/page.html

И их комбинации. Без правильной генерации ссылок эти действия превращаются в ад, когда можно либо что-то пропустить, либо наоборот заменить лишнее. Не говоря о титаническом ручном труде. Это, мягко говоря, не способствует легкости использования фреймворка.

Router обрабатывает routes в порядке их добавления, следовательно можно добавить /admin/* routes последними. Пару-тройку милисекунд админ может потерпеть.

Разве не наоборот? Последние добавленные роуты обрабатываются первыми вроде как: "Since you can add many routes as you need using add(), the order in which routes are added indicate their relevance, lastest routes added have more relevance than first added. Internally, all defined routes are traversed in reverse order until Phalcon\Mvc\Router finds the one that matches the given URI and processes it, while ignoring the rest.". И это не решает проблему генерации ссылок.

Я бы советовал не заморачиваться, если проблема не решается в течении одного дня (эта уже тут с пятницы).

Проблема, в тестовом приложении, была решена моментально, тупыми ссылками (/admin, /admin/users и пр.). Но если не решить проблему на будущее - я не могу использовать фреймворк в реальных проектах.

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



10.2k

Приглашаю всех обсудить реализацию здесь: https://forum.phalcon.io/discussion/1262/-url-