Очередность Правил Для Url

всем привет

столкнулся с непонятной для меня ситуацией = движок реагирует на очередность расположения правил формирования URL при распознавании ключей GET-параметров…

то есть вот эти две очередности правил =


'/<sect:[a-z0-9\_\-]+>/<subsect:[a-z0-9\_\-]+>' => 'site/handler',

'/<sect:[a-z0-9\_\-]+>/<page:[a-z0-9\_\-]+>' => 'site/handler',

и


'/<sect:[a-z0-9\_\-]+>/<page:[a-z0-9\_\-]+>' => 'site/handler',

'/<sect:[a-z0-9\_\-]+>/<subsect:[a-z0-9\_\-]+>' => 'site/handler',

по разному трактуют второй ключ подаваемый в массиве для createUrl

в первом случае вторым ключем всегда будет subsect - даже если в createURL подать page

а во втором случае вторым ключем всегда будет page - даже если в createURL подать subsect

это так и должно быть или я туплю?

как проверял =

  1. в методе контроллера сделал так =

print_r(Yii::app()->controller->actionParams)

  1. в представлении создал рядом две ссылки =

<a href="<?php echo Yii::app()->createURL(

        'site/handler',array(

            'sect'=>$_GET['sect'],'subsect'=>'community',)); ?>">

    второй ключ = sect

</a>

<br>

<a href="<?php echo Yii::app()->createURL(

        'site/handler',array(

            'sect'=>$_GET['sect'],'page'=>'community',)); ?>">

    второй ключ = page

</a>

клики и по первой и по второй ссылке привели к отображению =


Array

(

    [sect] => character

    [page] => community

)

p.s. с другой стороны - если убрать правила для URL вообще - то все работает корректно (только все виде строки запроса - чего крайне не хотелось бы)

Для subsect и page у вас одинаковые правила, поэтому, когда приходит url "aaa/bbb", то невозможно определить, что есть что.

а разве само изменение ключа - не является достаточным?

я так понимаю - раз ключ изменился = значит и формирование URL с его обработкой то же поменяется

разве это не так?

p.s. вам не трудно предложить свой вариант правил, которые бы все исправили как надо? ну хотя бы приблизительно

p.s.2 а то ведь получается что в правилах не имеет значение название ключа = важной оказывается только очередность ключей в УРЛ

перенаправил обработку УРЛ с ключем page на другой метод (метод есть в контроллере и абсолютно идентичен handler) =


'/<sect:[a-z0-9\_\-]+>/<subsect:[a-z0-9\_\-]+>' => 'site/handler',

'/<sect:[a-z0-9\_\-]+>/<page:[a-z0-9\_\-]+>' => 'site/handler2',

УРЛы сформировались так =

для subsect = /character/community.html

для page = /character.html?page=community

?????

теперь что не так?

Одно дело сформировать url, другое дело - сопоставить готовому какое-то правило в rules. Процесс останавливается на первом подходящем правиле. Т.к. левые части абсолютно одинаковые, то при определении контроллера/экшена всегда будет срабатывать только первое правило. Неоднозначность можно устранить по-разному, например:




'/<sect:[a-z0-9\_\-]+>/page/<page:[a-z0-9\_\-]+>' => 'site/handler',

'/<sect:[a-z0-9\_\-]+>/sub/<subsect:[a-z0-9\_\-]+>' => 'site/handler',



эва как…

почему-же они абсолютно одинаковые? в одном случае <subsect:[a-z0-9\\-]+> а в другом <page:[a-z0-9\\-]+>

по ключу-то они совершенно разные…

или парсер правил игнорирует subsect и page?

если не сложно - растолкуйте логику

Логика на самом деле простая:




CHtml::link('Ссылка 1', array('site/handler', 'sect'=>'aaa', 'page'=>'bbb'));

CHtml::link('Ссылка 2', array('site/handler', 'sect'=>'aaa', 'subsect'=>'bbb'));



С вышеуказанными правилами создадутся ссылки, ведущие на один адрес "http://site.ru/aaa/bbb". Или не так? При разборе такого адреса подходит как первое правило, так и второе. Названия параметров роли не играют, просто соответствующим $_GET параметрам будут присвоены значения aaa и bbb.

я в шоке = названия параметров роли не играют…

но ведь = просто соответствующим $_GET параметрам будут присвоены значения

так вот и вопрос - каким $_GET параметрам?

вторым по счету или ключам page и subsect?

в моем понимании какой ключ подан(subsect или page), такой же ключ и должен быть в УРЛ

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

но по факту это не так = ибо = названия параметров роли не играют

фигня какая-то

p.s это не к вам

Возможно, код вам лучше объяснит: http://www.yiiframework.com/doc/api/1.1/CUrlRule#parseUrl-detail :)

Суть в том, что Yii берёт URL, затем проходит по каждому правилу (левая часть rules) и делает preg_match (предварительно приведя эти левые части к корректному регулярному выражению). Проблема в том, что preg_match для обоих правил возвращает true (на самом деле процесс останавливается при первом совпадении), т.к. он не может знать, является ли часть "bbb" параметром page или subsect, ведь у них одинаковый паттерн ([a-z0-9\_\-]+).

да вы и без кода мне все в предыдущих постах все растолковали - я усе понял

мне только тогда не понятно = нафига в правилах заморачиваться на указание GET-ключей если они роли не играют?

ведь по сути роль играет очередность правил в левой части

GET-ключи тут вообще ни при чем… CodeIgniter какой-то получается :)

лох номер 1 в моем лице повелся именно на возможность манипулирования ключами в правилах и тут лоха постигла неудача

p.s. спасибо, что не поленились полезть в parseUrl

Параметры играют роль при создании url, а при разборе помогают правильно присвоить значения $_GET[‘sect’], $_GET[‘page’] и т.п.

[color="#FF0000"]да ни фига они не помогают[/color] если на уровне разбора правил из конфига не учитываются указанные ключи( по вашим же словам = Названия параметров роли не играют )

получается, что [color="#0000FF"]в моем случае невозможно[/color] два УРЛа преобразовать

из


/index.php?r=site/handler&sect=character&page=first-character-article

/index.php?r=site/handler&sect=media&subsect=photo

в


/character/first-character-article.html

/media/photo.html

[color="#008000"]с учетом того, что значения GET-ключей sect, subsect и page формируются динамически и не могут быть заранее прописаны в конфиге[/color]

p.s. вы сможете помочь написать мне такие правила?

вот так работает =


'/<sect:(character|community)>/<page:[a-z0-9\_\-]+>' => 'site/handler',

'/<sect:[a-z0-9\_\-]+>/<subsect:[a-z0-9\_\-]+>' => 'site/handler',

но приходится явно указывать значение ключа sect, а так быть не должно

Конкретно в вашем случае не помогают, конечно, но если в rules нет таких неоднозначных правил, то помогают :)

Решить проблему можно по-разному:

  1. Испортить красивые url и сделать их такими:

/character/page/first-character-article.html

/media/sect/photo.html

  1. Если множество значений subsect заранее известно, то поставить это правило первым и перечислить значения в виде [value1|value2|…

  2. Направлять всё в один контроллер, который уже будет сам "догадываться", page там или subsect (или сделать свой класс, наследующий CBaseUrlRule).

Все вот эти приблуды - <key:[…]+> - это тупо именованный регэксп )

Не какие-то волшебные параметры или ключи, а всего-навсего поименованная область.

По вариантам решения andy_s уже кажется вообще всё возможное расписал )

UPD: вот еще полезная штука

не-не-не… УРЛ-ы это святое

это очевидно, но не хотелось бы

а поподробнее = ведь и сейчас все идет в один контроллер и в один метод

Например, искать значения в базе данных. Если нашли статью first-character-article, значит это параметр page, в противном случае не page :) Хотя тут уже вам виднее. Можно вообще все url’ы хранить в таблице БД (url, controller/action).

тю! я-то думал…

ведь сейчас именно так и есть - все лежит в БД и по условию линк подставляется или в subsect или в page

только функция createURL все равно работает не до конца правильно (ну, в моем конечно понимании)

выше я даже написал о том как проверял - когда врукопашную указал второй ключ и его значение - все равно не помогло

видать никуда не деться от этого =


'/<sect:(character|community)>/<page:[a-z0-9\_\-]+>' => 'site/handler',

'/<sect:[a-z0-9\_\-]+>/<subsect:[a-z0-9\_\-]+>' => 'site/handler',

http://www.yiiframework.com/forum/index.php/topic/48468-все-запросы-на-один-метод/

Думаю, это ещё не последние сложности :)




'test1/<param1>' => 'test/index',

'test2/<param2>' => 'test/index',



Тут левая часть у нас шаблон URL, правая — внутренний маршрут (он же роут).

Есть два разных действия: формирование URL и разбор URL.

  1. При формировании мы передаём внутренний маршрут и набор параметров. Например, так:



echo $this->createUrl('test/index', array('param1' => 'paramOne')).'<br>';

echo $this->createUrl('test/index', array('param2' => 'paramTwo')).'<br>';



Yii проходит правила сверху вниз. Сначала смотрим, совпал ли внутренний маршрут из правой части. Далее, переданы ли все именованные параметры, перечисленные в левой части. Если да, используем правило. Если нет, смотрим следующее.

Пример выше выдаст нам:




/test1/paramOne

/test2/paramTwo



  1. При разборе у нас есть URL. Например, /test/paramValue.

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




'test/<param1>' => 'test/index',

'test/<param2>' => 'test/index',



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