<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>В лабиринте извилин &#187; symfony</title>
	<atom:link href="http://www.charnad.com/blog/tag/symfony/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.charnad.com</link>
	<description>Блог-центр им. CharnaD</description>
	<lastBuildDate>Wed, 18 Jan 2012 14:52:50 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Symfony: как добавить свой экшен в DoctrineRouteCollection</title>
		<link>http://www.charnad.com/blog/symfony-custom-action-with-doctrineroutecollectio/</link>
		<comments>http://www.charnad.com/blog/symfony-custom-action-with-doctrineroutecollectio/#comments</comments>
		<pubDate>Mon, 04 Jul 2011 11:28:56 +0000</pubDate>
		<dc:creator>CharnaD</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[routing]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://www.charnad.com/?p=1273</guid>
		<description><![CDATA[Я часто сталкивался с необходимостью указать путь к своему экшену, например в link_to. До какого-то времени для меня вполне работал вариант 'module/action?parameter=value'. Однако, в один прекрасный день, количество таких ссылок возросло до нескольких сотен на странице. И они порядком тормозили, потому что роутингу приходилось проверять все указанные роуты, перед тем как использовать default. Решением в [...]]]></description>
			<content:encoded><![CDATA[<p><img class="oppic" src="http://www.charnad.com/blog/wp-content/uploads/pictures/symfony_logo.gif" alt="" />Я часто сталкивался с необходимостью указать путь к своему экшену, например в link_to. До какого-то времени для меня вполне работал вариант 'module/action?parameter=value'. Однако, в один прекрасный день, количество таких ссылок возросло до нескольких сотен на странице. И они порядком тормозили, потому что роутингу приходилось проверять все указанные роуты, перед тем как использовать default. Решением в таких случаях являются именованные роуты, например '@users'. Но вот вопрос, как сделать именованный роут для админ генеренного модуля. Для таких модулей, добавляется DoctrineRouteCollection роут, который на самом деле генерит 7 роутов module_new, module_list и т.д.</p>
<p>Ну и вот мы делаем такой финт ушами:</p>

<div class="wp_syntax"><div class="code"><pre class="yaml" style="font-family:monospace;">modules:
  class: sfDoctrineRouteCollection
  options:
    model:                modules
    module:               modules
    prefix_path:          /modules
    column:               module_id
    with_wildcard_routes: true
    object_actions:       { action1: GET, action2: GET }
  requirements:
    module_id:        \d+</pre></div></div>

<p>В сгенеренный роут я добавил параметр object_action, после чего этот роут будет так же генерить роуты @modules_action1 и @modules_action2, что нам собственно и нужно. А GET - это тип запроса, на который будет отзываться новоделанный роут.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.charnad.com/blog/symfony-custom-action-with-doctrineroutecollectio/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Symfony: Symfony Day 2010 в Кёльне</title>
		<link>http://www.charnad.com/blog/symfony-day-2010-in-cologne/</link>
		<comments>http://www.charnad.com/blog/symfony-day-2010-in-cologne/#comments</comments>
		<pubDate>Mon, 11 Oct 2010 09:40:33 +0000</pubDate>
		<dc:creator>CharnaD</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://www.charnad.com/?p=1210</guid>
		<description><![CDATA[Как, наверное, некоторые из вас знают, 8 октября прошла конференция Symfony Day 2010 в Кёльне, на которой мне посчастливилось присутствовать. Я случайно наткнулся на сайт, http://www.symfonyday.com/, и сразу же решил, что хочу туда. Вход стоил 120 евро, но я успел как early bird за 80. Путь мой начинался с самой восточной границы Германии, и лежал [...]]]></description>
			<content:encoded><![CDATA[<p><img class="oppic" src="http://www.charnad.com/blog/wp-content/uploads/pictures/symfony_logo.gif" alt="" />
<p>Как, наверное, некоторые из вас знают, 8 октября прошла конференция Symfony Day 2010 в Кёльне, на которой мне посчастливилось присутствовать. Я случайно наткнулся на сайт, <a href="http://www.symfonyday.com/">http://www.symfonyday.com/</a>, и сразу же решил, что хочу туда. Вход стоил 120 евро, но я успел как early bird за 80. Путь мой начинался с самой восточной границы Германии<span id="more-1210"></span>, и лежал почти до западной, более 550 километров, причем ночью. Не хотелось тратиться на гостиницу, а тут еще подвернулся вариант с CNL (ночным) поездом, я думал, что это вроде плацкартного. Как выяснилось, место у меня сидячее, в купе едут по 6 человек, спать было почти невозможно. Так что приехал я в Кёльн за 3 часа до конференции весьма измотанный.
<a href="http://www.charnad.com/blog/wp-content/gallery/symfony-day-2010/dsc_7696.jpg" title="" class="shutterset_singlepic90" >
	<img class="ngg-singlepic ngg-left" src="http://www.charnad.com/blog/wp-content/gallery/cache/90__160x120_dsc_7696.jpg" alt="dsc_7696" title="dsc_7696" />
</a>
</p>
<p>На входе в медиа-центре Komed, где происходило действие, красовались флаги Symfony Day. Нам выдали беджики, и мы пошли в зал. Было еще рано, поэтому народу почти не было, зато на экране запустили Twitterwall - прямую трансляцию из Твиттера по хештегу #sfdaycgn, сделанную с помощью node.js. Я не преминул возможностью передать привет всем присутствующим от друзей из Russian Symfony User Group <img src='http://www.charnad.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .
<a href="http://www.charnad.com/blog/wp-content/gallery/symfony-day-2010/dsc_7700.jpg" title="" class="shutterset_singlepic92" >
	<img class="ngg-singlepic ngg-left" src="http://www.charnad.com/blog/wp-content/gallery/cache/92__160x120_dsc_7700.jpg" alt="dsc_7700" title="dsc_7700" />
</a>
</p>
<p>Первым выступал Jonathan Wage, который рассказал о работе Doctrine 2 с Mongo DB. Он вкратце обьяснил что же за зверь такой этот Mongo DB, и привел примеры, как с помощью Doctrine делать самые обычные действия - прочитать/вставить/удалить. 
<a href="http://www.charnad.com/blog/wp-content/gallery/symfony-day-2010/dsc_7702.jpg" title="" class="shutterset_singlepic94" >
	<img class="ngg-singlepic ngg-left" src="http://www.charnad.com/blog/wp-content/gallery/cache/94__160x120_dsc_7702.jpg" alt="dsc_7702" title="dsc_7702" />
</a>
 Доклад был интересным, однако слушал я с трудом. Сказалась ночь в поезде и меня жутко клонило в сон. Не припомню когда я еще проявлял столько воли, чтобы не засыпать и не зевать. Сразу после я побежал заливаться кофе, а вы пока можете посмотреть слайды.
<div style="width:425px" id="__ss_5393200"><object id="__sse5393200" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=symfonyday2010mongodbodm-101008082122-phpapp01&#038;stripped_title=symfony-day-2010-doctrine-mongodb-odm&#038;userName=jwage" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse5393200" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=symfonyday2010mongodbodm-101008082122-phpapp01&#038;stripped_title=symfony-day-2010-doctrine-mongodb-odm&#038;userName=jwage" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object></div>
</p>
<p> Вторым выступал core developer PHP Pierre Joye. 
<a href="http://www.charnad.com/blog/wp-content/gallery/symfony-day-2010/dsc_7704.jpg" title="" class="shutterset_singlepic96" >
	<img class="ngg-singlepic ngg-left" src="http://www.charnad.com/blog/wp-content/gallery/cache/96__160x120_dsc_7704.jpg" alt="dsc_7704" title="dsc_7704" />
</a>
Этот доклад был наполнен юмором. Если доклад Джонатана был вроде утренних новостей, то доклад Пьера как первая развлекательная передача дня. Рассказ был о том, как развивается PHP, какие есть недостатки, и что с этим можно делать. В зале нашелся человек, который до сих пор пользуется PHP4. Угадайте, какую CMF он использует? Правильно, Drupal. А вот вам цитатка:"A lot of idiots use PHP. For example.. (slide) Microsoft". Главным слайдом презентации можно считать "PHP is ugly". Да, разработчик PHP признает, что язык уродлив. Но мы же не художники в конце концов. Нам не о красоте надо думать, а о том, как создавать проекты, которые будут успешно работать. К тому же, если использовать Symfony, то недостатки заметны меньше. Да и помимо Symfony написано достаточно хороших фреймворков, и вряд ли есть большой спрос на новые. 
<a href="http://www.charnad.com/blog/wp-content/gallery/symfony-day-2010/dsc_7705.jpg" title="" class="shutterset_singlepic97" >
	<img class="ngg-singlepic ngg-left" src="http://www.charnad.com/blog/wp-content/gallery/cache/97__160x120_dsc_7705.jpg" alt="dsc_7705" title="dsc_7705" />
</a>
 "Кто вообще писал новый фреймворк за последние два года",- вопрошал Пьер. Руку поднял один человек в зале - Фабьен Потенсьер <img src='http://www.charnad.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  Все засмеялись и заапплодировали. Важной мыслью было то, что PHP уже достиг того когда он почти никогда не является "бутылочным горлышком". "Если вам не хватает производительности PHP - то вы Facebook".
<div style="width:425px" id="__ss_5392819"><object id="__sse5392819" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=phpsymfonyandsoftwarelifecycle-101008073640-phpapp01&#038;rel=0&#038;stripped_title=php-symfony-and-software-lifecycle&#038;userName=pierrej" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse5392819" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=phpsymfonyandsoftwarelifecycle-101008073640-phpapp01&#038;rel=0&#038;stripped_title=php-symfony-and-software-lifecycle&#038;userName=pierrej" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object></div>
</p>
<p>Пока был перерыв перед следующим докладом - я сделал фотографию зала. 
<a href="http://www.charnad.com/blog/wp-content/gallery/symfony-day-2010/dsc_7706.jpg" title="" class="shutterset_singlepic98" >
	<img class="ngg-singlepic ngg-left" src="http://www.charnad.com/blog/wp-content/gallery/cache/98__160x120_dsc_7706.jpg" alt="dsc_7706" title="dsc_7706" />
</a>
 
<a href="http://www.charnad.com/blog/wp-content/gallery/symfony-day-2010/dsc_7708.jpg" title="" class="shutterset_singlepic99" >
	<img class="ngg-singlepic ngg-left" src="http://www.charnad.com/blog/wp-content/gallery/cache/99__160x120_dsc_7708.jpg" alt="dsc_7708" title="dsc_7708" />
</a>
 
<a href="http://www.charnad.com/blog/wp-content/gallery/symfony-day-2010/dsc_7710.jpg" title="" class="shutterset_singlepic100" >
	<img class="ngg-singlepic ngg-left" src="http://www.charnad.com/blog/wp-content/gallery/cache/100__160x120_dsc_7710.jpg" alt="dsc_7710" title="dsc_7710" />
</a>
 
<a href="http://www.charnad.com/blog/wp-content/gallery/symfony-day-2010/dsc_7711.jpg" title="" class="shutterset_singlepic101" >
	<img class="ngg-singlepic ngg-left" src="http://www.charnad.com/blog/wp-content/gallery/cache/101__160x120_dsc_7711.jpg" alt="dsc_7711" title="dsc_7711" />
</a>
 По количеству стульев можно прикинуть, что было человек 150. А выступал третьим Christian Schaefer (Кристиан Шефер), симфони-блоггер. Может я ошибаюсь, но мне показалось, что у него не очень большой опыт подобного рода выступлений - в основном он повторял то, что было написано на слайдах. Тем не менее, слушать было интересно. А речь шла о Unit-тестировании плагинов с помощью PHPUnit. О том, как все правильно настроить, и как тесты запускать.
<div style="width:425px" id="__ss_5401851"><object id="__sse5401851" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=unittestingsymfonypluginswithphpunit-101009132914-phpapp01&#038;stripped_title=unit-testing-symfony-plugins-with-php-unit-5401851&#038;userName=caefer" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse5401851" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=unittestingsymfonypluginswithphpunit-101009132914-phpapp01&#038;stripped_title=unit-testing-symfony-plugins-with-php-unit-5401851&#038;userName=caefer" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object></div>
</p>
<p>После 
<a href="http://www.charnad.com/blog/wp-content/gallery/symfony-day-2010/dsc_7713.jpg" title="" class="shutterset_singlepic102" >
	<img class="ngg-singlepic ngg-left" src="http://www.charnad.com/blog/wp-content/gallery/cache/102__160x120_dsc_7713.jpg" alt="dsc_7713" title="dsc_7713" />
</a>
 третьего доклада был перерыв, и в холле можно было было вкусно покушать. А я же в первую очередь побежал делать эту фотографию. Так же в перерыве познакомились и немного поболтали с Антоном Бобенко, сам он из Украины, работает в Норвегии. Не знаю, был ли кто-нибудь еще из русскоязычных.
<a href="http://www.charnad.com/blog/wp-content/gallery/symfony-day-2010/dsc_7715.jpg" title="" class="shutterset_singlepic103" >
	<img class="ngg-singlepic ngg-left" src="http://www.charnad.com/blog/wp-content/gallery/cache/103__160x120_dsc_7715.jpg" alt="dsc_7715" title="dsc_7715" />
</a>
</p>
<p>Подошло время четвертого доклада, выступал Крис Уолсмит. Довольно вальяжно и, может быть даже, слегка небрежно Крис рассказал о различных техниках, которые можно применить в проекте. 
<a href="http://www.charnad.com/blog/wp-content/gallery/symfony-day-2010/dsc_7717.jpg" title="" class="shutterset_singlepic104" >
	<img class="ngg-singlepic ngg-left" src="http://www.charnad.com/blog/wp-content/gallery/cache/104__160x120_dsc_7717.jpg" alt="dsc_7717" title="dsc_7717" />
</a>
Например, если закончилась сессия, пока редактировалась форма, или как динамически добавлять несколько встроенных форм. Пожалуй, в этом докладе были наиболее полезные советы, которые можно применить на практике. Единственное что под конец каждого примера я уже терялся в коде и не мог полностью понять все детали. 
<a href="http://www.charnad.com/blog/wp-content/gallery/symfony-day-2010/dsc_7719.jpg" title="" class="shutterset_singlepic105" >
	<img class="ngg-singlepic ngg-left" src="http://www.charnad.com/blog/wp-content/gallery/cache/105__160x120_dsc_7719.jpg" alt="dsc_7719" title="dsc_7719" />
</a>
 Тем не менее общую идею уловил и понял. </p>
<div style="width:425px" id="__ss_5396592"><object id="__sse5396592" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=advanced-symfony-techniques-101008164721-phpapp02&#038;stripped_title=advanced-symfony-techniques&#038;userName=kriswallsmith" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse5396592" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=advanced-symfony-techniques-101008164721-phpapp02&#038;stripped_title=advanced-symfony-techniques&#038;userName=kriswallsmith" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object></div>
</p>
<p>Следующим выступал Гейлорд Олке (Gaylord Aulke). 
<a href="http://www.charnad.com/blog/wp-content/gallery/symfony-day-2010/dsc_7721.jpg" title="" class="shutterset_singlepic107" >
	<img class="ngg-singlepic ngg-left" src="http://www.charnad.com/blog/wp-content/gallery/cache/107__160x120_dsc_7721.jpg" alt="dsc_7721" title="dsc_7721" />
</a>
 Этот доклад был, я думаю, не столько для программистов, сколько для работников отдела продаж. Гейлорд рассказал о том, как представить клиенту выбор, покупать готовый сайт, который можно просто запустить, или заказывать разработку, которая займет время, но зато проект будет соответствовать пожеланиям клиента. Есть еще третий вариант - построить проект из модулей. </p>
<p>Последним выступал Фабьен Потенсьер. 
<a href="http://www.charnad.com/blog/wp-content/gallery/symfony-day-2010/dsc_7723.jpg" title="" class="shutterset_singlepic109" >
	<img class="ngg-singlepic ngg-left" src="http://www.charnad.com/blog/wp-content/gallery/cache/109__160x120_dsc_7723.jpg" alt="dsc_7723" title="dsc_7723" />
</a>
 Речь шла о Symfony2, которая должна быть готова к марту 2011. Во-первых, для темплейтов можно будет использовать шаблонизатор Twig. И хотя поддержка чистого PHP останется, Twig гораздо более прост для восприятия и использования непрограммистом. 
<a href="http://www.charnad.com/blog/wp-content/gallery/symfony-day-2010/dsc_7724.jpg" title="" class="shutterset_singlepic110" >
	<img class="ngg-singlepic ngg-left" src="http://www.charnad.com/blog/wp-content/gallery/cache/110__160x120_dsc_7724.jpg" alt="dsc_7724" title="dsc_7724" />
</a>
 Пользователь, как объект, теперь не привязан к сессии, пользовательские данные можно будет хранить в конфиг-файле (например, если нужен только один админ), можно будет одновременно аутентифицировать пользователей через БД, LDAP и конфиг файлы. Формы можно будет показывать с помощью темплейтов, того же твига. В общем масса изменений, все будет супер-круто. Ну и приложу слайд, который будет во всех блогах и отчетах про конференцию <img src='http://www.charnad.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />
<div style="width:425px" id="__ss_5399986"><object id="__sse5399986" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=symfony2-101009070646-phpapp02&#038;stripped_title=the-state-of-symfony2-symfonyday-2010&#038;userName=fabpot" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse5399986" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=symfony2-101009070646-phpapp02&#038;stripped_title=the-state-of-symfony2-symfonyday-2010&#038;userName=fabpot" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object></div>
</p>
<p>Фабьен дольше всех отвечал на вопросы, что в общем неудивительно. Когда все закончилось в холле было бесплатное пиво, небольшой конкурс с призами (я ничего не выиграл), можно было набрать наклеек. Ощущения, конечно, самые позитивные. 
<a href="http://www.charnad.com/blog/wp-content/gallery/symfony-day-2010/dsc_7728.jpg" title="" class="shutterset_singlepic111" >
	<img class="ngg-singlepic ngg-left" src="http://www.charnad.com/blog/wp-content/gallery/cache/111__160x120_dsc_7728.jpg" alt="dsc_7728" title="dsc_7728" />
</a>
  Больше всего понравились выступления Пьера Жойе и Фабьена Потенсьера, а самым полезным я считаю доклад Криса Уолсмита. Приложу еще фотографию Кёльнского собора, раз уж я там был, грех был бы не посмотреть.</p>
<p>Через пару часов я сел на поезд и отправился домой, опять более чем 550 километров сидя, ночью. Поспать мне опять не удалось и после двух бессонных ночей чувствовал я себя.. да почти не чувствовал. Но эти мелочи не могли повлиять на удовольствие, которое я получил на конференции: побыл среди умных людей, послушал выступления и вообще классно провел время.</p>
<p>Для эксперимента еще выложил фотографии на <a href="http://www.flickr.com/photos/54686499@N02/5064087515/in/set-72157625000809289/">flickr</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.charnad.com/blog/symfony-day-2010-in-cologne/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Symfony: иерархический URL</title>
		<link>http://www.charnad.com/blog/symfony-hierarcial-url/</link>
		<comments>http://www.charnad.com/blog/symfony-hierarcial-url/#comments</comments>
		<pubDate>Wed, 15 Sep 2010 12:04:17 +0000</pubDate>
		<dc:creator>CharnaD</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[routing]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://www.charnad.com/?p=1202</guid>
		<description><![CDATA[Наверняка многие имеют некие иерархические данные в своем проекте, будь то категории с подкатегориями, страницы с подстраницами и все такое прочее. Как подобные объекты выводятся пользователю? Обычно с помощью роута типа /category/1, или /page/28, где число - это id объекта, или даже /page/delivery, где используется slug. Но все это не отражает иерархичность наших данных. Иногда [...]]]></description>
			<content:encoded><![CDATA[<p><img class="oppic" src="http://www.charnad.com/blog/wp-content/uploads/pictures/symfony_logo.gif" alt="" />Наверняка многие имеют некие иерархические данные в своем проекте, будь то категории с подкатегориями, страницы с подстраницами и все такое прочее. Как подобные объекты выводятся пользователю? Обычно с помощью роута типа /category/1, или /page/28, где число - это id объекта, или даже /page/delivery, где используется slug. Но все это не отражает иерархичность наших данных. Иногда же хочется /page/delivery/small-items и /page/delivery/large-items. Никто не мешает сделать дополнительный роут с двумя слагами, но ведь их может быть не два, а три, и не три, а пять.<br />
<span id="more-1202"></span></p>
<p>Сразу оговорюсь, речь опять пойдет о плагине. Всю функциональность проекта я стараюсь реализовывать в плагинах, если есть хоть малейший намек на то, что это может потребоваться где-то еще. В конкретном случае модуль для статических страниц (в схеме: заголовок, текст, слаг, метаполя). И вот важный момент, для плагинов можно создать файл PLUGINNAMEConfiguration.class.php. Нам это пригодится тем, что мы будем создавать роуты на лету, начиная как раз с этого файла.</p>
<p>Обычно я убираю названия плагинов/модулей из листингов, но в данном случае ради наглядности и простоты понимания я их оставлю. Плагин называется wePages, модуль wePages_frontend. И вот значит что мы будем делать в конфигурации:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> initialize<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">in_array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'wePages_frontend'</span><span style="color: #339933;">,</span> sfConfig<span style="color: #339933;">::</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'sf_enabled_modules'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">dispatcher</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">connect</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'routing.load_configuration'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'wePagesRouting'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'listenToRoutingLoadConfigurationEvent'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Если наш модуль числится в списке подключенных, то подключаем listener по имени listenToRoutingLoadConfigurationEvent из файла wePagesRouting к событию routing.load_configuration. Проще говоря, когда загрузится конфигурация роутов будет вызвана наша функция.
</p>
<p>Создадим файл /lib/routing/wePagesRouting.class.php, куда поместим нашу функцию.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> wePagesRouting <span style="color: #009900;">&#123;</span>
&nbsp;
  <span style="color: #009933; font-style: italic;">/**
   * Listens to the routing.load_configuration event.
   *
   * @param sfEvent An sfEvent instance
   * @static
   */</span>
  static <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> listenToRoutingLoadConfigurationEvent<span style="color: #009900;">&#40;</span>sfEvent <span style="color: #000088;">$event</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$r</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$event</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getSubject</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// Узнаем максимальную глубину дерева</span>
    <span style="color: #000088;">$maxlvl</span> <span style="color: #339933;">=</span> Doctrine_Query<span style="color: #339933;">::</span><span style="color: #004000;">create</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span>
              <span style="color: #004000;">select</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'MAX(level) as maxlvl'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span>
              <span style="color: #004000;">from</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'wePages'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span> 
              <span style="color: #004000;">execute</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span>
              <span style="color: #004000;">getFirst</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span>
              <span style="color: #004000;">getMaxlvl</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// В конфигурации мы можем указать префикс для роута, </span>
    <span style="color: #666666; font-style: italic;">// например '/page', начинаться же он должен со слеша, </span>
    <span style="color: #666666; font-style: italic;">// что мы и проверяем</span>
    <span style="color: #666666; font-style: italic;">// prefix must have '/' </span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">trim</span><span style="color: #009900;">&#40;</span>sfConfig<span style="color: #339933;">::</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'app_we_pages_plugin_route_prefix'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">''</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$route_pattern</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'/'</span><span style="color: #339933;">.</span><span style="color: #990000;">trim</span><span style="color: #009900;">&#40;</span> sfConfig<span style="color: #339933;">::</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'app_we_pages_plugin_route_prefix'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">''</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'/'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$route_pattern</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// Здесь мы создаем строчку, на соответствие которой в роутинге </span>
    <span style="color: #666666; font-style: italic;">// будет проверятся URL, тут-то и кроется вся магия. </span>
    <span style="color: #666666; font-style: italic;">// Мы создаем роут с количеством слагов равным максимальной </span>
    <span style="color: #666666; font-style: italic;">// глубине дерева, чтобы охватить все страницы, а в качестве </span>
    <span style="color: #666666; font-style: italic;">// значения по умолчанию ставим false, чтобы роут срабатывал </span>
    <span style="color: #666666; font-style: italic;">// и на меньшем количестве слагов</span>
    <span style="color: #000088;">$defaults</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$i</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> <span style="color: #000088;">$i</span> <span style="color: #339933;">&lt;=</span> <span style="color: #000088;">$maxlvl</span><span style="color: #339933;">;</span> <span style="color: #000088;">$i</span><span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$route_pattern</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">'/:slug'</span><span style="color: #339933;">.</span><span style="color: #000088;">$i</span><span style="color: #339933;">;</span>
      <span style="color: #000088;">$defaults</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'slug'</span><span style="color: #339933;">.</span><span style="color: #000088;">$i</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// осталось теперь только подключить роут к уже загруженным, </span>
    <span style="color: #666666; font-style: italic;">// важно чтобы он был первым</span>
    <span style="color: #666666; font-style: italic;">// preprend our routes</span>
    <span style="color: #000088;">$route</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> wePagesRoute<span style="color: #009900;">&#40;</span>
        <span style="color: #000088;">$route_pattern</span><span style="color: #339933;">,</span> 
        <span style="color: #990000;">array_merge</span><span style="color: #009900;">&#40;</span> 
            <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">'module'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'wePages_frontend'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'action'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'show'</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> 
            <span style="color: #000088;">$defaults</span> 
        <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$r</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">prependRoute</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'wePages_frontend'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$route</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Надеюсь, что в комментариях я обьяснил достаточно подробно что мы делаем. Создали роут, который охватывает все страницы сразу, с большим и маленьким количеством слагов.</p>
<p>Обратите внимание, что мы создали объет не sfRoute, а wePagesRoute. Этот класс лежит в соседнем файле wePagesRoute.class.php. Нам ведь надо проверять довольно специфические условия, поэтому стандартный класс не подходит.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> wePagesRoute <span style="color: #000000; font-weight: bold;">extends</span> sfRoute <span style="color: #009900;">&#123;</span>
  <span style="color: #666666; font-style: italic;">// функция проверяет подходит ли данный роут под указанный URL</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> matchesUrl<span style="color: #009900;">&#40;</span><span style="color: #000088;">$url</span><span style="color: #339933;">,</span> <span style="color: #000088;">$context</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// если шаблон роута не совпадает - дальше даже не смотрим</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">false</span> <span style="color: #339933;">===</span> <span style="color: #000088;">$parameters</span> <span style="color: #339933;">=</span> parent<span style="color: #339933;">::</span><span style="color: #004000;">matchesUrl</span><span style="color: #009900;">&#40;</span> <span style="color: #990000;">rtrim</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$url</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'/'</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">,</span> <span style="color: #000088;">$context</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #b1b100;">return</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #666666; font-style: italic;">// преобразуем наши сгенерированные слаги в массив, </span>
    <span style="color: #666666; font-style: italic;">// где ключи - это глубина элемента в дереве,</span>
    <span style="color: #666666; font-style: italic;">// а значения - сами слаги.</span>
    <span style="color: #666666; font-style: italic;">// почему так? у нас же рекурсивный роут и начинается </span>
    <span style="color: #666666; font-style: italic;">// с верхнего уровня, который имеет level = 0</span>
    <span style="color: #666666; font-style: italic;">// соответственно следующие слаги имеют level = 1,2,3..</span>
    <span style="color: #666666; font-style: italic;">// make slug1, slug2.. into array [0] =&gt; 'slug1', [1] =&gt; 'slug2'</span>
    <span style="color: #000088;">$i</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$pages</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$parameters</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'slug'</span><span style="color: #339933;">.</span><span style="color: #000088;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #990000;">strlen</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">trim</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$parameters</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'slug'</span><span style="color: #339933;">.</span><span style="color: #000088;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$pages</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$i</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$parameters</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'slug'</span><span style="color: #339933;">.</span><span style="color: #000088;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
      <span style="color: #000088;">$i</span><span style="color: #339933;">++;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// если выяснилось, что слагов не указано - бросаем это дело</span>
    <span style="color: #666666; font-style: italic;">// If we dont have any slugs - we dont want this anymore</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">empty</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$pages</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #b1b100;">return</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #666666; font-style: italic;">// Второй важный момент</span>
    <span style="color: #666666; font-style: italic;">// Мы берем слаги и уровни, и ищем страницы подходящие под условия. </span>
    <span style="color: #666666; font-style: italic;">// Данный способ не работает, если slug не уникальны.</span>
    <span style="color: #666666; font-style: italic;">// Groupby объединяет элементы с одинаковым уровнем</span>
    <span style="color: #666666; font-style: italic;">// Get pages with these slugs and levels</span>
    <span style="color: #000088;">$data</span> <span style="color: #339933;">=</span> Doctrine_Query<span style="color: #339933;">::</span><span style="color: #004000;">create</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #339933;">-&gt;</span><span style="color: #004000;">from</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'wePages'</span><span style="color: #009900;">&#41;</span>
        <span style="color: #339933;">-&gt;</span><span style="color: #004000;">andWhereIn</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'slug'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array_values</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$pages</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #339933;">-&gt;</span><span style="color: #004000;">andWhereIn</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'level'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array_keys</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$pages</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #339933;">-&gt;</span><span style="color: #004000;">orderBy</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'level ASC, lft ASC'</span><span style="color: #009900;">&#41;</span>
        <span style="color: #666666; font-style: italic;">// this group by removes entries with same level</span>
        <span style="color: #339933;">-&gt;</span><span style="color: #004000;">groupBy</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'level'</span><span style="color: #009900;">&#41;</span>
        <span style="color: #339933;">-&gt;</span><span style="color: #004000;">execute</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// теперь внимательно смотрим, если нашли страниц меньше, </span>
    <span style="color: #666666; font-style: italic;">// чем было указано слагов то URL не совпадает с иерархией в БД, </span>
    <span style="color: #666666; font-style: italic;">// а значит, извините, но вы не по адресу.</span>
    <span style="color: #666666; font-style: italic;">// искали 3 слага - надо найти 3 страницы, и чтобы их level </span>
    <span style="color: #666666; font-style: italic;">// были равны 0,1,2 и не повторялись</span>
    <span style="color: #666666; font-style: italic;">// проблемы начнутся, если слаги могут совпадать, </span>
    <span style="color: #666666; font-style: italic;">// но другого быстрого и простого способа проверить я не придумал</span>
    <span style="color: #666666; font-style: italic;">// If some url parts dont fit - dont want this anymore</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&lt;</span> <span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$pages</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #b1b100;">return</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// если мы не указали в конфигурации префикс </span>
    <span style="color: #666666; font-style: italic;">// и страницы вызываются, как www.site.com/page1</span>
    <span style="color: #666666; font-style: italic;">// то этот роут будет выполнятся довольно часто, </span>
    <span style="color: #666666; font-style: italic;">// поэтому раз уж мы выполнили поиск страниц</span>
    <span style="color: #666666; font-style: italic;">// было бы глупо не передать уже найденный id в метод show,</span>
    <span style="color: #666666; font-style: italic;">// или что там у вас для показа</span>
    <span style="color: #000088;">$parameters</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'page_id'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$data</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getLast</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$parameters</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

</p>
<p>У меня этот метод прекрасно заработал, хотя и не является идеальным решением. Если я хочу создать страницы /team/men, /team/women, то мне придется создавать и страницу /team, и она будет открываться, хотя я, например, хотел бы чтобы она редиректила на /team/men. То есть надо было бы создавать тип страниц "редирект". Что порядком костыльно. Так же, вероятно, будут проблемы с link_to и url_for. Стоит написать свой хелпер для генерации урлов.</p>
<p>Что еще можно сделать? Можно при создании страницы указывать URL напрямую, и хранить его в БД. И точно так же в роуте проверять не соответствие слагов и уровней, а просто искать по полю url. Позволяет обойти проблему с /team/men, хотя и не очень красиво, страница /team, будет выдавать 404. Хотя как я понимаю, проблему с link_to оно все равно не решит.</p>
<p>Все описанные способы являются экспериментальными, где-то может вылезти проблема о которой я не догадывался. Так что воспринимайте это как концепцию, а если вы найдете более удачный способ и напишете мне - я буду благодарен. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.charnad.com/blog/symfony-hierarcial-url/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Symfony: свой фильтр в admin generator</title>
		<link>http://www.charnad.com/blog/symfony-custom-filter-in-admin-generator/</link>
		<comments>http://www.charnad.com/blog/symfony-custom-filter-in-admin-generator/#comments</comments>
		<pubDate>Wed, 08 Sep 2010 18:38:02 +0000</pubDate>
		<dc:creator>CharnaD</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[admin generator]]></category>
		<category><![CDATA[form filter]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://www.charnad.com/?p=1193</guid>
		<description><![CDATA[Кратко о том, как сделать фильтр для админ генератора. В моем проекте используется Doctrine с поведением NestedSet, и фильтр мне нужен был по родительскому полю. Точнее, показать потомков выбранного элемента. Для этого я пошел в папку /lib/filters и открыл файл фильтров для нужной модели. Там будем править метод configure. В моем случае дело происходит в [...]]]></description>
			<content:encoded><![CDATA[<p><img class="oppic" src="http://www.charnad.com/blog/wp-content/uploads/pictures/symfony_logo.gif" alt="" />Кратко о том, как сделать фильтр для админ генератора. В моем проекте используется Doctrine с поведением NestedSet, и фильтр мне нужен был по родительскому полю. Точнее, показать потомков выбранного элемента. Для этого я пошел в папку /lib/filters и открыл файл фильтров для нужной модели. Там будем править метод configure. В моем случае дело происходит в плагине, поэтому метод, который я буду править называется setupInheritance.<br />
<span id="more-1193"></span></p>
<p>
<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span>  setupInheritance<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    parent<span style="color: #339933;">::</span><span style="color: #004000;">setupInheritance</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">widgetSchema</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'parent'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormDoctrineChoiceNestedSet<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'model'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'MODEL_NAME'</span><span style="color: #339933;">,</span>
        <span style="color: #0000ff;">'add_empty'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #009900; font-weight: bold;">true</span>
    <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">validatorSchema</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'parent'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorDoctrineChoice<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'model'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'MODEL_NAME'</span><span style="color: #339933;">,</span> 
        <span style="color: #0000ff;">'required'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #009900; font-weight: bold;">false</span>
    <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Добавили виджет и валидатор. sfWidgetFormDoctrineChoiceNestedSet это простой DoctrineChoice, в котором есть отступы и сортировка в соответствии с иерархией в NestedSet. Теперь наш виджет виден в форме, правда ни на что пока не влияет.</p>
<p>Чтобы на что-то влиять, нам надо добавить его в список полей фильтра в том же файле.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getFields<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$fields</span> <span style="color: #339933;">=</span> parent<span style="color: #339933;">::</span><span style="color: #004000;">getFields</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$fields</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'parent'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'NestedNode'</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$fields</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Здесь надо обратить внимание не только на значение, но и на имя ключа в массиве. В качестве значения можно указывать "Number", "Text", "Date" и некоторые другие. Я не пробовал, но полагаю, что если указать одно из них, то сработает стандартный обработчик поля фильтра, как например addNumberQuery. В нашем случае формат нестандартный и обработчик будем делать сами.
</p>
<p>Кстати говоря, если в данный момент посмотреть на наш проект - нам выбросят исключение, где будет сказано как надо назвать метод, который будет обрабатывать наше поле. В моем случае это addParentColumnQuery. Формат названия функции, скорее всего такой: add_COLUMN_NAME_ColumnQuery.<br />
А собственно вот и она сама:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> addParentColumnQuery<span style="color: #009900;">&#40;</span><span style="color: #000088;">$q</span><span style="color: #339933;">,</span> <span style="color: #000088;">$element</span><span style="color: #339933;">,</span> <span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$parent</span> <span style="color: #339933;">=</span> Doctrine<span style="color: #339933;">::</span><span style="color: #004000;">getTable</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'MODEL_NAME'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">findOneById</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$q</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">andWhere</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'lft &gt; ?'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$parent</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getLft</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">andWhere</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'rgt &lt; ?'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$parent</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getRgt</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Получаем Doctrine_Query в качестве параметра $q, добавляем свои условия и возвращаем. Все легко и просто. <br/><br />
Наздоровье <img src='http://www.charnad.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /><br />
Референс: <a href="http://robert-says.com/2010/03/symfony-how-to-add-a-custom-filter-for-the-admin-listing/">http://robert-says.com/2010/03/symfony-how-to-add-a-custom-filter-for-the-admin-listing/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.charnad.com/blog/symfony-custom-filter-in-admin-generator/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Symfony: Optgroup в DoctrineChoice</title>
		<link>http://www.charnad.com/blog/symfony-optgroup-v-doctrinechoice/</link>
		<comments>http://www.charnad.com/blog/symfony-optgroup-v-doctrinechoice/#comments</comments>
		<pubDate>Wed, 18 Aug 2010 11:11:56 +0000</pubDate>
		<dc:creator>CharnaD</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[doctrine]]></category>
		<category><![CDATA[form]]></category>
		<category><![CDATA[symfony]]></category>
		<category><![CDATA[widget]]></category>

		<guid isPermaLink="false">http://www.charnad.com/?p=1186</guid>
		<description><![CDATA[Потребовалось мне сделать optgroup в виджете choice, и не просто так, а с условием. Если у объекта есть дочерние элементы - то он становится optgroup, а иначе его можно выбрать. За основу я взял sfWidgetFormDoctrineChoiceNestedSet, который можно взять из плагина sfDoctrineNestedSetPlugin. Я скопировал код, добавил в запрос условие: $query->addWhere('level = ?', 0); Это потому, что [...]]]></description>
			<content:encoded><![CDATA[<p><img class="oppic" src="http://www.charnad.com/blog/wp-content/uploads/pictures/symfony_logo.gif" alt="" />Потребовалось мне сделать optgroup в виджете choice, и не просто так, а с условием. Если у объекта есть дочерние элементы - то он становится optgroup, а иначе его можно выбрать. За основу я взял sfWidgetFormDoctrineChoiceNestedSet, который можно взять из плагина <a href="http://www.symfony-project.org/plugins/sfDoctrineNestedSetPlugin">sfDoctrineNestedSetPlugin</a>. Я скопировал код, добавил в запрос условие:</p>
<pre class="php">$query->addWhere('level = ?', 0);</pre>
<p>Это потому, что все, что ниже уровнем мы будем получать через getChildren. Иначе нам пришлось бы двигать итератор Doctrine_Collection, что более сложно, заумно, и вовсе у меня не получилось (next($objects) почему-то не дает эффекта).<br />
Сделать optgroup в choice совсем несложно, надо лишь сделать элемент массивом. Ну а что получилось собственно внутри поста.<br />
<span id="more-1186"></span><br />
Я еще раз повторюсь, что это код sfWidgetFormDoctrineChoiceNestedSet, за малым изменением.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> weDoctineOptgroupSelectWidget <span style="color: #000000; font-weight: bold;">extends</span> sfWidgetFormDoctrineChoice <span style="color: #009900;">&#123;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getChoices<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$choices</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">false</span> <span style="color: #339933;">!==</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getOption</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'add_empty'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$choices</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">''</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">true</span> <span style="color: #339933;">===</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getOption</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'add_empty'</span><span style="color: #009900;">&#41;</span> ? <span style="color: #0000ff;">''</span> <span style="color: #339933;">:</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getOption</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'add_empty'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">null</span> <span style="color: #339933;">===</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getOption</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'table_method'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$query</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span> <span style="color: #339933;">===</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getOption</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'query'</span><span style="color: #009900;">&#41;</span> ? Doctrine_Core<span style="color: #339933;">::</span><span style="color: #004000;">getTable</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getOption</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'model'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">createQuery</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">:</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getOption</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'query'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #666666; font-style: italic;">// force manual sorting according to root_id then by lft</span>
      <span style="color: #000088;">$query</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">addOrderBy</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'root_id asc'</span><span style="color: #009900;">&#41;</span>
          <span style="color: #339933;">-&gt;</span><span style="color: #004000;">addOrderBy</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'lft asc'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #666666; font-style: italic;">// Viktoras: we need to fetch only top level, as we'll get the children with getChildren()</span>
      <span style="color: #000088;">$query</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">addWhere</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'level = ?'</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #000088;">$objects</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$query</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">execute</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$tableMethod</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getOption</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'table_method'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #000088;">$results</span> <span style="color: #339933;">=</span> Doctrine_Core<span style="color: #339933;">::</span><span style="color: #004000;">getTable</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getOption</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'model'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #000088;">$tableMethod</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
      <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$results</span> instanceof Doctrine_Query<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$objects</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$results</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">execute</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$results</span> instanceof Doctrine_Collection<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$objects</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$results</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$results</span> instanceof Doctrine_Record<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$objects</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Doctrine_Collection<span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getOption</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'model'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$objects</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$results</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$objects</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000088;">$method</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getOption</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'method'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$keyMethod</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getOption</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'key_method'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$objects</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$object</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #666666; font-style: italic;">// indent item by 4 spaces per level</span>
      <span style="color: #666666; font-style: italic;">// Viktoras: here we check for children and make entry an array if they exists</span>
      <span style="color: #000088;">$node</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$object</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getNode</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$node</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">hasChildren</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$node</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getChildren</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$child</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
          <span style="color: #000088;">$choices</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$object</span><span style="color: #339933;">-&gt;</span><span style="color: #000088;">$method</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$child</span><span style="color: #339933;">-&gt;</span><span style="color: #000088;">$keyMethod</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #990000;">str_repeat</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'&amp;nbsp;'</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$child</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'level'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">*</span> <span style="color: #cc66cc;">4</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$child</span><span style="color: #339933;">-&gt;</span><span style="color: #000088;">$method</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
      <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$choices</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$object</span><span style="color: #339933;">-&gt;</span><span style="color: #000088;">$keyMethod</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #990000;">str_repeat</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'&amp;nbsp;'</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$object</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'level'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">*</span> <span style="color: #cc66cc;">4</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$object</span><span style="color: #339933;">-&gt;</span><span style="color: #000088;">$method</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$choices</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>И выглядит это вот так:<br />
<img src="http://img405.imageshack.us/img405/8427/12ece8ab6752487cafefb3c.png"></p>
]]></content:encoded>
			<wfw:commentRss>http://www.charnad.com/blog/symfony-optgroup-v-doctrinechoice/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Symfony Tips: #1</title>
		<link>http://www.charnad.com/blog/symfony-tips-1/</link>
		<comments>http://www.charnad.com/blog/symfony-tips-1/#comments</comments>
		<pubDate>Thu, 01 Jul 2010 15:50:21 +0000</pubDate>
		<dc:creator>CharnaD</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[admin generator]]></category>
		<category><![CDATA[symfony]]></category>
		<category><![CDATA[symfony tips]]></category>

		<guid isPermaLink="false">http://www.charnad.com/?p=1178</guid>
		<description><![CDATA[Бывает, что находишь какое-то решение в Гугле, а потом когда я сталкиваешься с похожей ситуацией - второй раз уже не можешь найти. Поэтому я буду записывать моменты, которые мне были полезны и могут понадобиться еще, будет что-то вроде рубрики Symfony tips. Как вообще убрать фильтры в admin generator? config: filter: class: false Как повесить иконку [...]]]></description>
			<content:encoded><![CDATA[<p><img class="oppic" src="http://www.charnad.com/blog/wp-content/uploads/pictures/symfony_logo.gif" alt="" />Бывает, что находишь какое-то решение в Гугле, а потом когда я сталкиваешься с похожей ситуацией - второй раз уже не можешь найти. Поэтому я буду записывать моменты, которые мне были полезны и могут понадобиться еще, будет что-то вроде рубрики Symfony tips.</p>
<p><strong>Как вообще убрать фильтры в admin generator?</strong></p>

<div class="wp_syntax"><div class="code"><pre class="yml" style="font-family:monospace;">config:
  filter:
    class: false</pre></div></div>

</p>
<p><strong>Как повесить иконку своему кастомному object_action?</strong></p>

<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;"><span style="color: #cc00cc;">#sf_admin_container</span> ul li<span style="color: #6666ff;">.sf_admin_action_</span>#<span style="color: #cc00cc;">#ACTION_NAME</span>## a
<span style="color: #00AA00;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">background</span><span style="color: #00AA00;">:</span> <span style="color: #993333;">url</span><span style="color: #00AA00;">&#40;</span><span style="color: #ff0000; font-style: italic;">/images/icons/icon.png</span><span style="color: #00AA00;">&#41;</span> <span style="color: #993333;">no-repeat</span> <span style="color: #cc66cc;">0</span> <span style="color: #cc66cc;">0</span><span style="color: #00AA00;">;</span>
<span style="color: #00AA00;">&#125;</span></pre></div></div>

</p>
<p><strong>Как недопустить ввода пустой строки в админке?</strong></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">validatorSchema</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'name'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setOption</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'trim'</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

</p>
<p><strong>Fatal error: Call to undefined function include_component()</strong><br />
Вы, скорее всего, указали в settings.yml standart_helpers, и забыли добавить в список Partial.</p>

<div class="wp_syntax"><div class="code"><pre class="yml" style="font-family:monospace;">all: 
  .settings: 
    standard_helpers:       [I18N, Partial]</pre></div></div>
</p>
]]></content:encoded>
			<wfw:commentRss>http://www.charnad.com/blog/symfony-tips-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Symfony: выборочная I18n для объектов Doctrine [Перевод]</title>
		<link>http://www.charnad.com/blog/symfony-vyborochnaya-i18n-dlya-obektov-doctrine/</link>
		<comments>http://www.charnad.com/blog/symfony-vyborochnaya-i18n-dlya-obektov-doctrine/#comments</comments>
		<pubDate>Tue, 08 Jun 2010 00:44:59 +0000</pubDate>
		<dc:creator>CharnaD</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[I18n]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[symfony]]></category>
		<category><![CDATA[перевод]]></category>

		<guid isPermaLink="false">http://www.charnad.com/?p=1085</guid>
		<description><![CDATA[Мне потребовалось сделать мультиязычный сайт аж на 5 языках. В целом тут нет ничего сложного, кроме того, что пользователю надо будет заполнять 5 форм на разных языках. Логичный вывод - сделать обязательным только один язык, например английский. Остальные заполняются по желанию, а для незаполненных показывается на том же английском. Промучившись некоторое время с рецептами от [...]]]></description>
			<content:encoded><![CDATA[<p><img class="oppic" src="http://www.charnad.com/blog/wp-content/uploads/pictures/symfony_logo.gif" alt="" />Мне потребовалось сделать мультиязычный сайт аж на 5 языках. В целом тут нет ничего сложного, кроме того, что пользователю надо будет заполнять 5 форм на разных языках. Логичный вывод - сделать обязательным только один язык, например английский. Остальные заполняются по желанию, а для незаполненных показывается на том же английском. Промучившись некоторое время с рецептами от Календаря Адвента, и не добившись успеха, я нашел пост [<a href="http://www.miximum.fr/tutos/449-optional-translation-form-for-i18n-objects-with-symfony-and-doctrine#comment-14308">Optional translation form for I18n objects with Symfony and Doctrine</a>], который мне помог. Я считаю, что полезным будет сделать его перевод. Так же я добавлю некоторые свои комментарии. (Перевод вольный, эстеты идут лесом)<span id="more-1085"></span></p>
<p>Некоторые люди утверждают, что Symfony - это подарок богов. Другие считают, что это преувеличение. Но как ни крути, в версиях 1.3/1.4 добавилось много нового и полезного, что может сэкономить вам вермя.<br />
Представим проект, где есть разные заметки (новости, интервью, и т.д.). И они могут быть на разных языках. И это довольно просто сделать с actAs: I18n. Но есть небольшая сложность: переводы должны быть опциональны, чтобы можно было написать статью только на французском, английском или немецком.
</p>
<p>Некоторые материалы по теме: <a href="http://prendreuncafe.com/blog/post/2009/11/29/Embedding-Relations-in-Forms-with-Symfony-1.3-and-Doctrine">раз</a>, <a href="http://symfonyguide.wordpress.com/2009/09/28/symfony-forms-saving-process/">два</a>, <a href="http://vousavezchoisi.com/img/formsdiagram.png">три</a>, <a href="http://www.symfony-project.org/more-with-symfony/1_4/en/06-Advanced-Forms#chapter_06_ignoring_embedded_forms">четыре</a>, <a href="http://www.ze-technology.com/2009/06/05/tests-fonctionnels-avec-symfony-gerer-lidentification/">пять</a>.</p>
<h3>Итак, начнем со схемы.</h3>

<div class="wp_syntax"><div class="code"><pre class="yml" style="font-family:monospace;">Article:
  actAs:
    Timestampable: ~
    I18n:
      fields: [ title, body ]
      actAs:
        Sluggable: { fields: [ title ], uniqueBy: [ lang, title ] }
&nbsp;
  columns:
    title: { type: string(255), notnull: true }
    body: { type: clob, notnull: true }
    author: { type: string(255), notnull: false }
&nbsp;
News:
  inheritance:
    extends: Article
    type: concrete</pre></div></div>

<p>А так же фикстуры:</p>

<div class="wp_syntax"><div class="code"><pre class="yml" style="font-family:monospace;">News:
  n1:
    author: 'Lenta.ru'
    Translation:
      ru:
        title: 'Нет вестей с Титана'
        body: |
          Титан – это шестой и самый крупный спутник Сатурна.
&nbsp;
  n2:
    author: 'Bash.org'
    Translation:
      en:
        title: '#921792'
        body: |
          &lt;Thomas&gt; if women think they arent meant to cook
          &lt;Thomas&gt; why do they have milk and eggs inside them?</pre></div></div>

<p>Загружаем все это добро в базу данных:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">php symfony doctrine:build <span style="color: #660033;">--all</span> <span style="color: #660033;">--and-load</span>
php symfony generate:app backend
php symfony doctrine:generate-admin backend News</pre></div></div>

<p>Загляните в только что построенный модуль админки. Нажмите кнопку "редактировать" и оп.. а где все наши переводы? Если вы еще не в курсе, actAs:I18n разделяет таблицу на 2 части, в первой содержатся общие поля, не зависящие от перевода, а во второй те, которые требуют перевода.</p>

<div class="wp_syntax"><div class="code"><pre class="txt" style="font-family:monospace;">mysql&gt; SELECT * FROM news;
+----+-------------+---------------------+---------------------+
| id | author      | created_at          | updated_at          |
+----+-------------+---------------------+---------------------+
|  1 | Lenta.ru    | 2010-01-29 12:14:46 | 2010-01-29 12:14:46 | 
|  2 | Bash.org    | 2010-01-29 12:14:46 | 2010-01-29 12:14:46 | 
+----+-------------+---------------------+---------------------+
&nbsp;
mysql&gt; SELECT id, lang, title FROM news_translation;
+----+------+-----------------------------------------------------+
| id | lang | title                                               |
+----+------+-----------------------------------------------------+
|  1 | ru   | Титан – это шестой и самый крупный спутник Сатурна. | 
|  2 | en   | &lt;Thomas&gt; if women think they arent meant to cook ...| 
+----+------+-----------------------------------------------------+</pre></div></div>

<p>Чтобы нам было доступно редактирование переводов - надо воспользоваться функцией embedI18n.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// lib/form/doctrine/NewsForm.class.php</span>
<span style="color: #000000; font-weight: bold;">class</span> NewsForm <span style="color: #000000; font-weight: bold;">extends</span> BaseNewsForm
<span style="color: #009900;">&#123;</span>
  <span style="color: #009933; font-style: italic;">/**
   * @see ArticleForm
   */</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    parent<span style="color: #339933;">::</span><span style="color: #004000;">configure</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">embedI18n</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'en'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Вуа ля. Редактировать можно!
</p>
<h3>Немного приберемся</h3>
<p>Наш код сейчас не так хорош, как мог бы быть:<br />
Каждый раз, когда мы будем добавлять новый тип статьи - нам надо будет менять метод configure;<br />
Каждый раз, когда мы будем добавлять/удалять новый язык для статей - нам надо будет менять все формы.</p>
<p>К счастью, с Symfony 1.3, наследование форм повторяет наследование моделей. Смотрите, NewsForm наследует BaseNewsForm, которая в свою очередь наследует ArticleForm.</p>

<div class="wp_syntax"><div class="code"><pre class="yml" style="font-family:monospace;"># config/app.yml
all:
  cultures:
    enabled:
      ru: Russian
      en: English</pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// lib/form/doctrine/NewsForm.class.php</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Revert the changes we added there</span>
<span style="color: #000000; font-weight: bold;">class</span> NewsForm <span style="color: #000000; font-weight: bold;">extends</span> BaseNewsForm
<span style="color: #009900;">&#123;</span>
  <span style="color: #009933; font-style: italic;">/**
   * @see ArticleForm
   */</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    parent<span style="color: #339933;">::</span><span style="color: #004000;">configure</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// lib/form/doctrine/ArticleForm.class.php</span>
<span style="color: #000000; font-weight: bold;">class</span> ArticleForm <span style="color: #000000; font-weight: bold;">extends</span> BaseArticleForm
<span style="color: #009900;">&#123;</span>
  <span style="color: #009933; font-style: italic;">/**
   * Available languages
   *
   * @var array $languages
   **/</span>
  <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000088;">$langages</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">languages</span> <span style="color: #339933;">=</span> sfConfig<span style="color: #339933;">::</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'app_cultures_enabled'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$langs</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array_keys</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">languages</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">embedI18n</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$langs</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">languages</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$lang</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$label</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">widgetSchema</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$lang</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setLabel</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$label</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Перезагрузите теперь страницу. Вы можете теперь добавлять/удалять языки независимо от количества типов статей.</p>
<h3>Редактируем переводы</h3>
<p>
Давайте теперь попробуем нашу форму для статей. Когда вы попробуете редактировать какую-нибудь новость, то... постыдная неудача. Нельзя сохранить, потому что нет английского или русского перевода. Давайте добавим условие, что если в форме есть пустые поля - мы эти формы не сохраняем.<br />
Для этого мы перекроем метод doBind.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// lib/form/doctrine/ArticleForm.class.php</span>
<span style="color: #000000; font-weight: bold;">class</span> ArticleForm <span style="color: #000000; font-weight: bold;">extends</span> BaseArticleForm
<span style="color: #009900;">&#123;</span>
  <span style="color: #009933; font-style: italic;">/**
   * Available languages
   *
   * @var array $languages
   **/</span>
  <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000088;">$langages</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">languages</span> <span style="color: #339933;">=</span> sfConfig<span style="color: #339933;">::</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'app_cultures_enabled'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$langs</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array_keys</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">languages</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">embedI18n</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$langs</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">languages</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$lang</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$label</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">widgetSchema</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$lang</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setLabel</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$label</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #009933; font-style: italic;">/**
   * Cleans and binds values to the current form
   *
   * Ignore i18n forms when all their fields are empty
   *
   * @see sfForm::doBind
   **/</span>
  <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000000; font-weight: bold;">function</span> doBind<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span> <span style="color: #000088;">$values</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">languages</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$lang</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$label</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">embeddedI18nFormIsEmpty</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$lang</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
      <span style="color: #009900;">&#123;</span>
        <span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span>
          <span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$lang</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span>
          <span style="color: #000088;">$this</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$lang</span><span style="color: #009900;">&#93;</span>
        <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    parent<span style="color: #339933;">::</span><span style="color: #004000;">doBind</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #009933; font-style: italic;">/**
   * Check if every fields, except for id and lang, are empty
   **/</span>
  <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000000; font-weight: bold;">function</span> embeddedI18nFormIsEmpty<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span> <span style="color: #000088;">$values</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$key</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">in_array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$key</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'id'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'lang'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #b1b100;">continue</span><span style="color: #339933;">;</span>
&nbsp;
      <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">''</span> <span style="color: #339933;">!==</span> <span style="color: #990000;">trim</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
      <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>В перекрытом методе doBind, мы проверяем каждую I18n форму, и, если надо делаем ей unset. Теперь все сохраняется как надо, однако же...</p>
<p>Загляните в базу данных, вас там ждет сюрприз.</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;">mysql<span style="color: #66cc66;">&gt;</span> <span style="color: #993333; font-weight: bold;">SELECT</span> id<span style="color: #66cc66;">,</span> lang<span style="color: #66cc66;">,</span> slug <span style="color: #993333; font-weight: bold;">FROM</span> news_translation;
<span style="color: #66cc66;">+</span><span style="color: #808080; font-style: italic;">----+------+------------------------------------------------------+</span>
<span style="color: #66cc66;">|</span> id <span style="color: #66cc66;">|</span> lang <span style="color: #66cc66;">|</span> slug                                                 <span style="color: #66cc66;">|</span>
<span style="color: #66cc66;">+</span><span style="color: #808080; font-style: italic;">----+------+------------------------------------------------------+</span>
<span style="color: #66cc66;">|</span>  <span style="color: #cc66cc;">1</span> <span style="color: #66cc66;">|</span> en   <span style="color: #66cc66;">|</span>                                                      <span style="color: #66cc66;">|</span> 
<span style="color: #66cc66;">|</span>  <span style="color: #cc66cc;">1</span> <span style="color: #66cc66;">|</span> ru   <span style="color: #66cc66;">|</span> Титан – это шестой и самый крупный спутник Сатурна<span style="color: #66cc66;">.</span>  <span style="color: #66cc66;">|</span> 
<span style="color: #66cc66;">|</span>  <span style="color: #cc66cc;">2</span> <span style="color: #66cc66;">|</span> en   <span style="color: #66cc66;">|</span> <span style="color: #66cc66;">&lt;</span>Thomas<span style="color: #66cc66;">&gt;</span> <span style="color: #993333; font-weight: bold;">IF</span> women think they arent meant <span style="color: #993333; font-weight: bold;">TO</span> cook <span style="color: #66cc66;">...</span> <span style="color: #66cc66;">|</span> 
<span style="color: #66cc66;">+</span><span style="color: #808080; font-style: italic;">----+------+------------------------------------------------------+</span></pre></div></div>

<p>Где-то в процессе сохранения, Symfony создала пустой объект перевода. И вот решение для этой проблемы.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// lib/form/doctrine/ArticleForm.class.php</span>
&nbsp;
  <span style="color: #666666; font-style: italic;">// Add this at the beginnig of the class:</span>
  <span style="color: #009933; font-style: italic;">/**
   * I18n ignored forms
   **/</span>
  <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000088;">$I18nFormsIgnored</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #666666; font-style: italic;">// update the doBind method:</span>
  <span style="color: #009933; font-style: italic;">/**
   * Unset i18n forms values when every field is empty
   **/</span>
  <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000000; font-weight: bold;">function</span> doBind<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span> <span style="color: #000088;">$values</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">languages</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$lang</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$label</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">embeddedI18nFormIsEmpty</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$lang</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
      <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">I18nFormsIgnored</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$lang</span><span style="color: #339933;">;</span>
        <span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span>
          <span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$lang</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span>
          <span style="color: #000088;">$this</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$lang</span><span style="color: #009900;">&#93;</span>
        <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    parent<span style="color: #339933;">::</span><span style="color: #004000;">doBind</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #666666; font-style: italic;">// And override the doUpdateObject method:</span>
  <span style="color: #009933; font-style: italic;">/**
   * Updates the values of the object with the cleaned up values.
   *
   * @param  array $values An array of values
   *
   * @see sfFormDoctrine::doUpdateObject()
   */</span>
  <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000000; font-weight: bold;">function</span> doUpdateObject<span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    parent<span style="color: #339933;">::</span><span style="color: #004000;">doUpdateObject</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">I18nFormsIgnored</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$lang</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">object</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Translation</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$lang</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$lang</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p>На этот раз все сохраняется как надо!
</p>
<p>(Здесь я пропускаю абзац про убирание поля Slug. Там есть сложность с тем, что формы перевода не наследуются. Если вам интересно - посмотрите в оригинальной статье. Я считаю, что основное здесь - как раз перекрытие методов doBind и doUpdateObject.<br />
Тесты, приведенные автором можно посмотреть у него в статье, а можно <a href="http://pastie.org/995806">тут</a> и <a href="http://pastie.org/995807">тут</a>).</p>
<p>На этом все. Надеюсь вам пригодится мой перевод.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.charnad.com/blog/symfony-vyborochnaya-i18n-dlya-obektov-doctrine/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Symfony: плагин sfPropelToggler 1.0.0b</title>
		<link>http://www.charnad.com/blog/symfony-plagin-sfpropeltoggler-100b/</link>
		<comments>http://www.charnad.com/blog/symfony-plagin-sfpropeltoggler-100b/#comments</comments>
		<pubDate>Sat, 16 May 2009 11:58:36 +0000</pubDate>
		<dc:creator>CharnaD</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[sfPropelToggler]]></category>
		<category><![CDATA[symfony]]></category>
		<category><![CDATA[togglers]]></category>
		<category><![CDATA[переключатели]]></category>
		<category><![CDATA[плагин]]></category>

		<guid isPermaLink="false">http://www.charnad.com/?p=511</guid>
		<description><![CDATA[Не так давно я писал про тогглеры (переключатели) в Symfony. Вчера я поработал над ними и существенно упростил их принцип работы, теперь они доступны в качестве плагина. Сразу же дам ссылку, вы можете их скачать в виде PEAR package и просто zip-архив. Дальше я расскажу как этим плагином пользоваться. Вообще, по правилам PEAR все инструкции [...]]]></description>
			<content:encoded><![CDATA[<p><img class="oppic" src="http://www.charnad.com/blog/wp-content/uploads/pictures/symfony_logo.gif" alt=""/>Не так давно я писал про <a href="http://www.charnad.com/blog/symfony-pereklyuchateli/">тогглеры (переключатели) в Symfony</a>. Вчера я поработал над ними и существенно упростил их принцип работы, теперь они доступны в качестве плагина. Сразу же дам ссылку, вы можете их скачать в виде <a href="http://www.charnad.com/files/sfpropeltoggler/sfPropelTogglerPlugin-1.0.0b.tgz">PEAR package</a> и просто <a href="http://www.charnad.com/files/sfpropeltoggler/sfPropelTogglerPlugin-1.0.0b.zip">zip-архив</a>. Дальше я расскажу как этим плагином пользоваться.<span id="more-511"></span></p>
<p>Вообще, по правилам PEAR все инструкции написаны в README. Но там по-английски. А тут я приведу русскую инструкцию. Итак.<br />
1. Надо или установить плагин, как PEAR пакет, или распаковать архив в папку plugins. Папка с плагином должна называться sfPropelTogglerPlugin. После этого вызовите команду symfony 'plugin:publish-assets' чтобы картинки из плагина скопировались в папку web/sfPropelTogglerPlugin. Если ничего не скопировалось - проверьте название папки плагина.<br />
2. В settings.yml вашего приложения впишите в пункт enabled_modules: [default, sfPropelToggler]. Если вы этого не сделаете - будет выскакивать ошибка о том, что модуль не активирован.<br />
3. В том файле, где будете подключать тогглер напишите</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">use_helper<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Toggler'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>4. Собственно сам переключатель может быть вставлен 2мя способами. Первый:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">echo</span> toggler<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'table'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'table_name'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'field'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'field_name'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'id'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$item</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'state'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$item</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getState</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Где table -имя таблицы, field - поле, id - первичный ключ записи, а state - текущее состояние переключателя.<br />
Второй способ через объект:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">echo</span> object_toggler<span style="color: #009900;">&#40;</span><span style="color: #000088;">$object</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'field_name'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Где object - объект Пропела, а field_name - поле, которе будем переключать.
</p>
<p>На этом этапе у вас все должно заработать. Если же нет - спрашивайте в комментариях.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.charnad.com/blog/symfony-plagin-sfpropeltoggler-100b/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Symfony: порядок записей в таблице</title>
		<link>http://www.charnad.com/blog/symfony-poryadok-zapisej-v-tablice/</link>
		<comments>http://www.charnad.com/blog/symfony-poryadok-zapisej-v-tablice/#comments</comments>
		<pubDate>Sat, 02 May 2009 10:17:27 +0000</pubDate>
		<dc:creator>CharnaD</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[symfony]]></category>
		<category><![CDATA[работа]]></category>

		<guid isPermaLink="false">http://www.charnad.com/?p=488</guid>
		<description><![CDATA[Этим постом я отвечаю на вопрос в комментариях о том, как я реализовал стрелки вверх и вниз для категорий. Перейдем к делу У меня в базе данных введен в таблице специальный столбик, называемый order_num. Он как раз и определяет порядковый номер записи в таблице. По нажатию на кнопке вверх (я называю эту процедуру promote), порядковый [...]]]></description>
			<content:encoded><![CDATA[<p><img class="oppic" src="http://www.charnad.com/blog/wp-content/uploads/pictures/symfony_logo.gif" alt=""/>Этим постом я отвечаю на вопрос в комментариях о том, как я реализовал стрелки вверх и вниз для <a href="http://www.charnad.com/blog/symfony-kategorii-i-podkategorii/">категорий</a>. Перейдем к делу<span id="more-488"></span></p>
<p>У меня в базе данных введен в таблице специальный столбик, называемый order_num. Он как раз и определяет порядковый номер записи в таблице. По нажатию на кнопке вверх (я называю эту процедуру promote), порядковый номер текущей записи меняется местами с порядковым ближайшим большим порядковым номером. Обратная процедура (demote) меняет с ближайшим меньшим.</p>
<p>Обращу ваше внимание на то, что этот пример сделан не для категорий а для контентных страниц (что сути не меняет), к тому же учитывается parent_id, то есть можно менять порядок внутри категории не затрагивая другие.</p>
<p><strong>Promote:</strong></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> executePromote<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<span style="color: #000088;">$page_id</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getRequestParameter</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'page_id'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$connection</span> <span style="color: #339933;">=</span> Propel<span style="color: #339933;">::</span><span style="color: #004000;">getConnection</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$promoting_RS</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$connection</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">query</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;SELECT order_num, parent_id FROM static_pages WHERE page_id='<span style="color: #006699; font-weight: bold;">{$page_id}</span>'&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$promoting</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$promoting_RS</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">fetch</span><span style="color: #009900;">&#40;</span>PDO<span style="color: #339933;">::</span><span style="color: #004000;">FETCH_ASSOC</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$promoting_num</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$promoting</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'order_num'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$promoting_parent</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$promoting</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'parent_id'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$promoting_num</span> <span style="color: #339933;">&lt;</span> <span style="color: #cc66cc;">2</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">redirect</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'static_pages/index'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #000088;">$demoting_num_RS</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$connection</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">query</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;SELECT MAX(order_num) AS order_num, page_id FROM static_pages WHERE parent_id='<span style="color: #006699; font-weight: bold;">{$promoting_parent}</span>' AND order_num &lt; '<span style="color: #006699; font-weight: bold;">{$promoting_num}</span>' GROUP BY NULL&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$demoting</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$demoting_num_RS</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">fetch</span><span style="color: #009900;">&#40;</span>PDO<span style="color: #339933;">::</span><span style="color: #004000;">FETCH_ASSOC</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$demoting_num</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$demoting</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'order_num'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$query</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;UPDATE static_pages SET order_num = CASE
   WHEN page_id = '&quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$page_id</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;' THEN '&quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$demoting_num</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;'
   WHEN parent_id='<span style="color: #006699; font-weight: bold;">{$promoting_parent}</span>' AND order_num='<span style="color: #006699; font-weight: bold;">{$demoting_num}</span>' THEN '&quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$promoting_num</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;'
   END
   WHERE page_id = &quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$page_id</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot; OR (parent_id=<span style="color: #006699; font-weight: bold;">{$promoting_parent}</span> AND order_num=<span style="color: #006699; font-weight: bold;">{$demoting_num}</span>)&quot;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$connection</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">query</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$query</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">redirect</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'static_pages/index'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">return</span> sfView<span style="color: #339933;">::</span><span style="color: #004000;">NONE</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

</p>
<p>Мы берем id из запроса, потом запросом ищем максимальный order_num, который меньше текущего, и потом запросом меняем их местами. Не забудьте ставить WHERE в UPDATE. На основе этого, думаю demote легко дописать самому. <br /> P.S> Поле не должно быть UNIQUE, я так и не придумал как одним запросом менять значения между собой в UNIQUE поле. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.charnad.com/blog/symfony-poryadok-zapisej-v-tablice/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Symfony: переключатели</title>
		<link>http://www.charnad.com/blog/symfony-pereklyuchateli/</link>
		<comments>http://www.charnad.com/blog/symfony-pereklyuchateli/#comments</comments>
		<pubDate>Fri, 24 Apr 2009 14:20:35 +0000</pubDate>
		<dc:creator>CharnaD</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[symfony]]></category>
		<category><![CDATA[togglers]]></category>
		<category><![CDATA[переключатели]]></category>
		<category><![CDATA[работа]]></category>

		<guid isPermaLink="false">http://www.charnad.com/?p=482</guid>
		<description><![CDATA[Давно я не брал в руки шашек. То есть не писал про symfony. А разработка продолжается. Сайт фактически готов, остаются мелкие доделки, доработка напильником и все такое. О "переключателях" или "тогглерах"(togglers), или не знаю как еще их назвать я уже давно хотел написать. Ну вот и пришло время, получайте. Итак что же за переключатели такие? [...]]]></description>
			<content:encoded><![CDATA[<p><img class="oppic" src="http://www.charnad.com/blog/wp-content/uploads/pictures/symfony_logo.gif" alt="" /> Давно я не брал в руки шашек. То есть не писал про symfony. А разработка продолжается. Сайт фактически готов, остаются мелкие доделки, доработка напильником и все такое. О "переключателях" или "тогглерах"(togglers), или не знаю как еще их назвать я уже давно хотел написать. Ну вот и пришло время, получайте.<span id="more-482"></span></p>
<p>Итак что же за переключатели такие? Допустим у нас есть сайт, а у него база данных, а в базе данных таблица, а в таблице поле, которое принимает только 2 значения - 0 и 1. Такие поля делаются типа TINYINT(1). Берем пример из жизни. Одно такое поле отвечает за то, разрешено ли пользователю входить в систему или нет. И если вдруг надо нам попереключать часть пользователей, то надо залезать в свойства каждого и менять, потом сохранять. А мне захотелось жить красивее и придумал я переключатели.</p>
<p><img style="margin-right: 10px;" src="http://www.charnad.com/blog/wp-content/uploads/pictures/togglers/overview.png" alt="Список пользователей"/></p>
<p>Вот так примерно выглядит список пользователей. Зеленая галочка и красный крестик и есть переключатели. Что сделать чтобы переключить пользователя? Просто кликнуть на них! По клику отправляется AJAX запрос, меняет поле в базе данных и по результатам меняет картинку. Красиво, удобно, быстро. А теперь о том, как это сделано.</p>
<p>Для каждого пользователя в таблице нам надо вставить партиал (partial), который будет отображать картинку. Для формирования таблицы мы foreach перебираем пользователей и вот код partial для переключателя.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">&lt;div id=&quot;active_<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$user</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'id'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&quot;&gt;
  <span style="color: #000000; font-weight: bold;">&lt;?php</span> include_partial<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'activity'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'id'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$user</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'id'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'state'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$user</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'is_active'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #000000; font-weight: bold;">?&gt;</span>
&lt;/div&gt;</pre></div></div>

<p>Как видно в него мы передаем 2 параметра, это id пользователя и его текущий статус. В самом партиалле находится следующий код:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span> 
<span style="color: #000088;">$field</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'IsActive'</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span>
&lt;div align=&quot;center&quot; id=&quot;<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$field</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'_'</span><span style="color: #339933;">.</span><span style="color: #000088;">$id</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&quot;&gt;
<span style="color: #000000; font-weight: bold;">&lt;?php</span>
include_component<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'main'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'toggler'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
  <span style="color: #0000ff;">'id'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$id</span><span style="color: #339933;">,</span>
  <span style="color: #0000ff;">'table'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'sfGuardUser'</span><span style="color: #339933;">,</span>
  <span style="color: #0000ff;">'state'</span> <span style="color: #339933;">=&gt;</span> sfGuardUserPeer<span style="color: #339933;">::</span><span style="color: #004000;">retrieveByPK</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$id</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getIsActive</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
  <span style="color: #0000ff;">'field'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$field</span>
<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span>
&lt;/div&gt;</pre></div></div>

<p>Здесь $field - имя поля в базе данных. В партиалле создается div с названием $field_$id, куда будет присылаться ответ. Ну а дальше вызывается компонент main/toggler, который и будет собственно переключать. Компоненту мы передаем id пользователя, имя таблицы, текущее состояние и имя поля.
</p>
<p>На этом подключение переключателя к модулю завершено. То есть вам надо всего лишь вызвать partial из шаблона, а в partiall'e подправить названия поля и таблицы. Все очень просто и быстро. Ну а собственно что в компоненте main/toggler? А там вот что:<br />
<strong>components.class.php</strong></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> executeToggler<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<span style="color: #666666; font-style: italic;">//i just call _toggler.php partial</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p><strong>_toggler.php</strong></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #000088;">$update</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$field</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'_'</span><span style="color: #339933;">.</span><span style="color: #000088;">$id</span><span style="color: #339933;">;</span>
sfApplicationConfiguration<span style="color: #339933;">::</span><span style="color: #004000;">getActive</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">loadHelpers</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Javascript'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$image_name</span> <span style="color: #339933;">=</span> <span style="color: #990000;">intval</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$state</span><span style="color: #009900;">&#41;</span>? <span style="color: #0000ff;">'active.png'</span> <span style="color: #339933;">:</span> <span style="color: #0000ff;">'inactive.png'</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">echo</span> link_to_remote<span style="color: #009900;">&#40;</span>image_tag<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/images/icons/admin/'</span><span style="color: #339933;">.</span><span style="color: #000088;">$image_name</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span> <span style="color: #009900;">&#40;</span>
   <span style="color: #0000ff;">'url'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'main/toggle?id='</span><span style="color: #339933;">.</span><span style="color: #000088;">$id</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'&amp;table='</span><span style="color: #339933;">.</span><span style="color: #000088;">$table</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'&amp;field='</span><span style="color: #339933;">.</span><span style="color: #000088;">$field</span><span style="color: #339933;">,</span>
   <span style="color: #0000ff;">'update'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$update</span>
<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></div></div>

<p>Мы формируем $update - поле, куда вернем ответ. А в виде ответа мы возвращаем... переключатель. Нам надо подгрузить хелпер Javascript (обратите внимание, что надо с большой буквы писать, иначе ничего не получится. симфони требует соблюдения регистра). И с помощью хелпера генерим аяксовую ссылку на экшен, который уже и будет переключать.</p>
<p>Что же получается? Итак общая картинка такая. Мы подключаем partial, который вызывает компонент, который генерит шаблон выдавая нам аяксовую ссылку на действие (action). А экшен переключает нам поле, и рендерит тот же самый компонент.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> executeToggle<span style="color: #009900;">&#40;</span>sfWebRequest <span style="color: #000088;">$request</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">isXmlHttpRequest</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">renderText</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Error. XMLHttpRequests only.'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
  <span style="color: #000088;">$id</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getParameter</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'id'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$table</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getParameter</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'table'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$field</span> <span style="color: #339933;">=</span>  <span style="color: #000088;">$request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getParameter</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'field'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$peer</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">normalizeName</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$table</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'Peer'</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000088;">$method</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ReflectionMethod<span style="color: #009900;">&#40;</span><span style="color: #000088;">$peer</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'retrieveByPK'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$object</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$method</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">invoke</span><span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">NULL</span><span style="color: #339933;">,</span> <span style="color: #000088;">$id</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000088;">$setter</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'set'</span><span style="color: #339933;">.</span><span style="color: #990000;">ucfirst</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">strtolower</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$field</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$getter</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'get'</span><span style="color: #339933;">.</span><span style="color: #990000;">ucfirst</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">strtolower</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$field</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000088;">$object</span><span style="color: #339933;">-&gt;</span><span style="color: #000088;">$setter</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$state</span> <span style="color: #339933;">=</span> <span style="color: #339933;">!</span><span style="color: #000088;">$object</span><span style="color: #339933;">-&gt;</span><span style="color: #000088;">$getter</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">save</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">renderPartial</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'main/toggler'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'id'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$id</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'state'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$state</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'table'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$table</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'field'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$field</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000000; font-weight: bold;">function</span> normalizeName<span style="color: #009900;">&#40;</span><span style="color: #000088;">$name</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #000088;">$name</span> <span style="color: #339933;">=</span> <span style="color: #990000;">preg_replace</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/[^a-zA-Z0-9]/'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">' '</span><span style="color: #339933;">,</span> <span style="color: #000088;">$name</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$name</span> <span style="color: #339933;">=</span> <span style="color: #990000;">ucwords</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">strtolower</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$name</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$name</span> <span style="color: #339933;">=</span> <span style="color: #990000;">str_replace</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">' '</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">,</span> <span style="color: #000088;">$name</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #b1b100;">return</span> <span style="color: #000088;">$name</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Принимаем только аяксовые запросы, из запроса получаем таблицу, поле и имя Propel Peer-класса для управления таблицей. Имя таблицы мы "нормализуем", т.к. симфони не использует, например, подчеркиваний в названии Peer-классов. Ну а дальше, с помощью рефлексии мы вызываем метод для того, чтобы получить объект, над которым производим действия. Геттеры и сеттер имеют стандартные названия и их рефлексить нам не надо. После чего в ответ рендерим тот же самый компонент, который вернет нам картинку с аяксовой ссылкой на то же самое действие.
</p>
<p>Я догадываюсь, что это не так просто понять. Если будет совсем не в моготу - задавайте вопросы в комментариях.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.charnad.com/blog/symfony-pereklyuchateli/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Symfony: теги</title>
		<link>http://www.charnad.com/blog/symfony-tegi/</link>
		<comments>http://www.charnad.com/blog/symfony-tegi/#comments</comments>
		<pubDate>Sun, 15 Mar 2009 15:24:00 +0000</pubDate>
		<dc:creator>CharnaD</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://www.charnad.com/?p=416</guid>
		<description><![CDATA[Продолжаю серию постов про разработку на симфони. На этот раз задача состояла в том, чтобы сделать администрирование тегов. Задача:" все теги можно редактировать на одной странице, теги можно только редактировать и удалять, если тег после редакции совпадает с уже существующим - они склеиваются". Ну что ж, поехали. Почти сразу у меня возникла идея использовать input_in_place_editor. [...]]]></description>
			<content:encoded><![CDATA[<p><img class="oppic" src="http://www.charnad.com/blog/wp-content/uploads/pictures/symfony_logo.gif" alt=""/>Продолжаю серию постов про разработку на симфони. На этот раз задача состояла в том, чтобы сделать администрирование тегов. Задача:" все теги можно редактировать на одной странице, теги можно только редактировать и удалять, если тег после редакции совпадает с уже существующим - они склеиваются". Ну что ж, поехали.<span id="more-416"></span></p>
<p>Почти сразу у меня возникла идея использовать input_in_place_editor. То есть табличка, в ней теги, тыкаешь на ячейку, появляется поле редактирования, изменения происходят аяксово. С самим in_place_editor возникло немало сложностей из-за его опций. Сделать табличку и насовать в каждую ячейку по эдитору несложно. Не забудьте, надо облачить это все в див, который будет обновляться. Мы же хотим показывать сохраненный тег.</p>
<p>Первое, с чем мне пришлось столкнуться - эффект затухания. Это очень красиво, когда наводишь на элемент, который можно редактировать, фон загорается цветом, и медленно затухает, когда уводишь мышку. Изначально фон загорается желтым, а так как админка у меня выдержана в цветах Админ-генератора, то есть синем, то и цвет надо поменять. Однако, изменив цвет на <span style="background-color: white;">'#eef'</span>, я обломался. Затухания не было. Фон сначала загорался, а потом через время менял свой цвет на изначальный. И только позже, случайно я догадался расписать цвет полностью на <span style="background-color: white;">'#efefff'</span>.</p>
<p>Следующим моментом стало изменение текстов сохранения. То есть тот текст, который написан на элементе пока идет аякс запрос. Нашел опцию, поставил значение, и... ничего не работает. Оказалось, что некоторые опции (а они задаются ассоциативным массивом) надо задавать особенно. Например опцию 'save_text' надо не просто заключать в кавычки (потому что это строка), а еще и добавлять кавычки внутри самой строки. Иначе это дело парсится без кавычек. Тупизм, неужели создаетли Protoype'а не могли сами ставить кавычки? Приходится теперь писать так:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #0000ff;">'savingText'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'\'Сохранение...\''</span></pre></div></div>

</p>
<p>Кнопочку удаления так же сделал дивом, но это просто. Position: relative, height: 0px, align: right; Надо заметить, что на время редактирования тега, кнопочку надо скрывать, иначе она уезжает вниз и портит вид. А делается это с помощью опции 'onEnterEditMode'. Вот так:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #0000ff;">'onEnterEditMode'</span> <span style="color: #339933;">=&gt;</span> 
<span style="color: #0000ff;">&quot;function(form, value) { $('delete_&quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$tag</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'tag_id'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;').hide(); }&quot;</span></pre></div></div>

</p>
<p>Ну и наконец, сделать надо было системку, которая находит дубликаты тегов. А сделал я так: при сохранении тега, я нахожу ВСЕ теги с таким названием. Если такой тег один (которы мы только что сохранили), то все прекрасно, а если нет, тогда в цикле генерим 2 запроса. Один UPDATE, другой DELETE. UPDATE'ом, все товары, которые были привязаны к дубликату тега перепривязываем к самому первому найденному. Он в итоге остается у нас единственным. А DELETE'ом, удаляем дубликаты. Вот так вот:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$criteria</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Criteria<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$criteria</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">add</span><span style="color: #009900;">&#40;</span>TagsPeer<span style="color: #339933;">::</span><span style="color: #004000;">TITLE</span><span style="color: #339933;">,</span> <span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$duplicates</span> <span style="color: #339933;">=</span> TagsPeer<span style="color: #339933;">::</span><span style="color: #004000;">doSelect</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$criteria</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">//В качестве итогового тега берем самый первый</span>
<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$duplicates</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #000088;">$original</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$duplicates</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$query_update</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;UPDATE tags_bouquets SET tag_id='{<span style="color: #006699; font-weight: bold;">$original-&gt;getTagId</span>()}' WHERE tag_id IN(&quot;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$query_delete</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;DELETE FROM tags WHERE tag_id IN (&quot;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$pass_first</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #339933;">;</span>
  <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$duplicates</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$duplicate</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$pass_first</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$pass_first</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$query_update</span> <span style="color: #339933;">.=</span> <span style="color: #000088;">$duplicate</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getTagId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">','</span><span style="color: #339933;">;</span>
      <span style="color: #000088;">$query_delete</span> <span style="color: #339933;">.=</span> <span style="color: #000088;">$duplicate</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getTagId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">','</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>   
  <span style="color: #009900;">&#125;</span>
  <span style="color: #000088;">$query_delete</span> <span style="color: #339933;">=</span> <span style="color: #990000;">rtrim</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$query_delete</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">','</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">');'</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$query_update</span> <span style="color: #339933;">=</span> <span style="color: #990000;">rtrim</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$query_update</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">','</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">');'</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$conn</span> <span style="color: #339933;">=</span> Propel<span style="color: #339933;">::</span><span style="color: #004000;">getConnection</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$conn</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">query</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'BEGIN; '</span><span style="color: #339933;">.</span><span style="color: #000088;">$query_update</span><span style="color: #339933;">.</span><span style="color: #000088;">$query_delete</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'COMMIT;'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getUser</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setFlash</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'notice_duplicated'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'Были найдены и удалены дубликаты тега '</span><span style="color: #339933;">.</span><span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

</p>
<p>Результат на картинке. Легкая синева - это как раз затухание фона, я специально мышкой повозил.<br />
<img src="http://www.charnad.com/blog/wp-content/uploads/pictures/flower_tags.png" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.charnad.com/blog/symfony-tegi/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Symfony: категории и подкатегории</title>
		<link>http://www.charnad.com/blog/symfony-kategorii-i-podkategorii/</link>
		<comments>http://www.charnad.com/blog/symfony-kategorii-i-podkategorii/#comments</comments>
		<pubDate>Fri, 06 Mar 2009 09:39:40 +0000</pubDate>
		<dc:creator>CharnaD</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[symfony]]></category>
		<category><![CDATA[работа]]></category>

		<guid isPermaLink="false">http://www.charnad.com/?p=394</guid>
		<description><![CDATA[Этот пост не совсем про симфони. На самом деле я опишу, как реализовывал категории и подкатегории для сайта над которым тружусь уже около месяца. Но так как сам сайт создается на symfony, то без нее тут никуда. Задача стояла примерно такая: для удобной навигации и поиска по товарам их нужно отнести к различным категориям и [...]]]></description>
			<content:encoded><![CDATA[<p><img class="oppic" src="http://www.charnad.com/blog/wp-content/uploads/pictures/symfony_logo.gif" alt=""/>Этот пост не совсем про симфони. На самом деле я опишу, как реализовывал категории и подкатегории для сайта над которым тружусь уже около месяца. Но так как сам сайт создается на symfony, то без нее тут никуда. Задача стояла примерно такая: для удобной навигации и поиска по товарам их нужно отнести к различным категориям и подкатегориям. Количество как первых, так и вторых может быть бесконечно. Единственное ограничение - уровень вложенности, он равен двум. В тех.задании категории и подкатегории были описаны двумя таблицами. Я думаю, что если бы последовал этому - я бы сэкономил пару-тройку часов, однако же, мне пришла в голову идея сделать все в одной таблице. Ведь по сути эти сущности ничем не отличаются, только что подкатегории имеют родительские категории.</p>
<p><span id="more-394"></span></p>
<p>По моему плану в поле, обозначающем предка в базе данных у всех должен стоять id родительской категории, а у собственно родительских - 0. Сказано - сделано, создана таблица, заполнена тестовыми данными. Заказчик обрисовал в ТЗ форму редактирования примерно так:</p>
<div><img src="http://www.charnad.com/blog/wp-content/uploads/pictures/categories_task.png" alt="" align="center" /></div>
<p>Стрелочки вверх и вниз редактируют порядок категорий. Плюсики - добавление категории или подкатегории.</p>
<p>Обрисовав примерную форму в Admin Generator'e в симфони, я скопировал все сгенерированные файлы в папку модуля, удалил generator.yml, то есть дальше модуль был полностью под моим контролем. Конечно, симфони генерит много необязательного кода, чтобы его убрать требуется время. Например мне сейчас совсем не нужна интернационализация, поэтому я старательно убрал все __() функции и подключения хелперов. Так же сократил количество файлов, мне не нужны были партиаллы header, footer, а некоторые я просто объединил. В итоге у меня оказалось всего 3 партиалла и 2 файла темплейтов.</p>
<p>Тут, собственно, и начинается самое интересное. Чтобы не переписывать шаблоны полностью, я не хотел терять функционала Propel'a и доставал все значения из базы именно им. Но вот тут возник вопрос: "Как вывести массив объектов, возвращенных Пропелом, так, чтобы подкатегории шли сразу за своей категорией?". Решение я придумал довольно быстро - нужно было построить дерево. И вот что я сделал:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$tree</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$array</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$element</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
   <span style="color: #000088;">$parentId</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$element</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getParentId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$parentId</span> <span style="color: #339933;">==</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$tree</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'root'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$element</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getCatId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$element</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$tree</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'branches'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$parentId</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$element</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Поясню. Если в массиве встречается элемент, у которого $parentId == 0, значит это родительская категория и мы кладем ее среди корневых элементов в $tree['root'][-ид-категории-]. Если же $parentId не 0, значит это подкатегория, и мы кладем ее в одну из веток $tree['branches']['-ид-родителя'][]. Поэтому теперь в темплейте, я могу писать 2 вложенных foreach. Во внешнем я перебираю $tree['root'], а во внутреннем $tree['branches'][-ид-текущего-родителя-]. Код приводить не буду - там много лишних деталей, суть же, надеюсь, я передал достаточно понятно.<br />
Отступ для подкатегорий, кстати, делается так:</p>

<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;"><span style="color: #cc00cc;">#sf_admin_container</span> <span style="color: #6666ff;">.sf_admin_subcat_row_0</span> td<span style="color: #3333ff;">:first-child </span><span style="color: #00AA00;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">padding-left</span><span style="color: #00AA00;">:</span> <span style="color: #933;">20px</span><span style="color: #00AA00;">;</span>
<span style="color: #00AA00;">&#125;</span>
<span style="color: #cc00cc;">#sf_admin_container</span> <span style="color: #6666ff;">.sf_admin_subcat_row_1</span> td<span style="color: #3333ff;">:first-child </span><span style="color: #00AA00;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">padding-left</span><span style="color: #00AA00;">:</span> <span style="color: #933;">20px</span><span style="color: #00AA00;">;</span>
<span style="color: #00AA00;">&#125;</span>
<span style="color: #cc00cc;">#sf_admin_container</span> <span style="color: #6666ff;">.sf_admin_subcat_row_0</span> td <span style="color: #00AA00;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">background-color</span><span style="color: #00AA00;">:</span> <span style="color: #cc00cc;">#eef</span><span style="color: #00AA00;">;</span>
<span style="color: #00AA00;">&#125;</span></pre></div></div>

<p>То есть применяем padding-left: 20px только для :first-child.</p>
<p>Следующим трудным моментом стало редактирование/сохранение/создание категорий. Дело все в том, что в данном модуле используется одна форма для редактирования существующих категорий или создания новой и используется функция get..OrCreate (.. - название модели). Так делается в админ генераторе по умолчанию. Идея эта хороша, однако тут мне надо было обрабатывать создание новой категории особенным способом. Если в запросе создания передается cat_id, значит мы создаем подкатегорию, а эта cat_id будет родительской, а если не передаем, значит создается родительская категория. Все было хорошо до тех пор, пока мне не пришлось передавать тот самый параметр cat_id. Проблема была в том, что он терялся среди редиректов и сабмитов. Поэтому при запросе на создание я делал setFlash('force_create', $cat_id). Причем тут 'force_create'? При том, что если я хочу создать категорию и передаю id - симфони ловит его и пытается послать меня не подкатегорию создавать, а родительскую редактировать. Потому что так работает get..OrCreate. Мне пришлось ее редактировать, чтобы при hasFlash('force_create') она создавала новую категорию. Ну и потом при сохранении я достаю этот Flash и вставляю как родительский id. Звучит, наверное, просто, но нервов пришлось потратить много, пока разобрался почему терялся id, как его не терять и как избежать конфликтов. Трудно все-таки, когда одна функция создает категории, подкатегории и редактирует существующие.</p>
<p>На этом приключения еще не закончились. Нужно было сделать управление порядком категорий и подкатегорий. Тут я позаимствовал код, который использовался для создания порядка в статических страницах и модифицировал с учетом того, что порядковый номер может быть одинаковый. Ведь у нас может быть первая подкатегория во многих категориях. В итоге я пришек к такому запросу, который апдейтил сразу оба значения</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$query</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;UPDATE categories SET order_num = CASE
       WHEN cat_id = '&quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$cat_id</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;' THEN '&quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$demoting_num</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;'
       WHEN parent_id='<span style="color: #006699; font-weight: bold;">{$promoting_parent}</span>'
          AND order_num='<span style="color: #006699; font-weight: bold;">{$demoting_num}</span>' THEN '&quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$promoting_num</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;'
       END
       WHERE cat_id IN (&quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$cat_id</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;)
          OR (parent_id=<span style="color: #006699; font-weight: bold;">{$promoting_parent}</span> AND order_num=<span style="color: #006699; font-weight: bold;">{$demoting_num}</span>)&quot;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Вот так весело прошел день моей работы. В результате я получил вот такую симпатичную формочку</p>
<p><img src="http://www.charnad.com/blog/wp-content/uploads/pictures/categories_result.png" alt="" /></p>
<p>Если вам понравился этот рассказ - пожалуйста, обязательно напишите комментарий. Дайте мне знать, что вам хочется чтобы я писал что-то подобное еще. Ну или не пишите, если не хотите, чтобы я продолжал.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.charnad.com/blog/symfony-kategorii-i-podkategorii/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Symfony: динамический роутинг</title>
		<link>http://www.charnad.com/blog/symfony-dinamicheskij-routing/</link>
		<comments>http://www.charnad.com/blog/symfony-dinamicheskij-routing/#comments</comments>
		<pubDate>Wed, 25 Feb 2009 12:31:07 +0000</pubDate>
		<dc:creator>CharnaD</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://www.charnad.com/?p=388</guid>
		<description><![CDATA[Продолжаю посты про symfony. Сегодня сделаем динамический роутинг. То есть будем добавлять правила роутинга из php, минуя routing.yml. Это нужно, например, если вы хотите делать страницы вида http://site.com/page1, где page1 может быть создана, может быть удалена и прочее. Дело в том, что указать какой-то общий шаблон нельзя, потому что иначе он будет конфликтовать с дефолтным [...]]]></description>
			<content:encoded><![CDATA[<p><img style="margin-right: 10px;" src="http://www.charnad.com/blog/wp-content/uploads/pictures/symfony_logo.gif" alt="" align="left" /><br />
Продолжаю посты про symfony. Сегодня сделаем динамический роутинг. То есть будем добавлять правила роутинга из php, минуя routing.yml. Это нужно, например, если вы хотите делать страницы вида http://site.com/page1, где page1 может быть создана, может быть удалена и прочее. Дело в том, что указать какой-то общий шаблон нельзя, потому что иначе он будет конфликтовать с дефолтным /:module. Что делать? А вот что. <span id="more-388"></span><br />
Идею я подсмотрел на одном из забугорных блогов, за что большое <a href="http://www.dfwtek.com/blog/129-dynamic-routes-in-symfony12.html">автору</a> спасибо. </p>
<p>Собственно для тех, кто не хочет ждать, а хочет кода - кладем это дело в frontendConfiguration.php:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> frontendConfiguration <span style="color: #000000; font-weight: bold;">extends</span> sfApplicationConfiguration <span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>  <span style="color: #009900;">&#123;</span>
  <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">dispatcher</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">connect</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'routing.load_configuration'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'registerRoutes'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'listenToRoutingLoadConfigurationEvent'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> registerRoutes <span style="color: #009900;">&#123;</span>
  static <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> listenToRoutingLoadConfigurationEvent<span style="color: #009900;">&#40;</span>sfEvent <span style="color: #000088;">$event</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #000088;">$routing</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$event</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getSubject</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000088;">$criteria</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Criteria<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$criteria</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">clearSelectColumns</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$criteria</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">addSelectColumn</span><span style="color: #009900;">&#40;</span>StaticPagesPeer<span style="color: #339933;">::</span><span style="color: #004000;">LINK_NAME</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$pages</span> <span style="color: #339933;">=</span> StaticPagesPeer<span style="color: #339933;">::</span><span style="color: #004000;">doSelectStmt</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$criteria</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$pages</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">fetch</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$link</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$routing</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">prependRoute</span><span style="color: #009900;">&#40;</span>
      <span style="color: #0000ff;">'static_'</span><span style="color: #339933;">.</span><span style="color: #000088;">$link</span><span style="color: #339933;">,</span>
      <span style="color: #000000; font-weight: bold;">new</span> sfRoute<span style="color: #009900;">&#40;</span>
       <span style="color: #0000ff;">'/'</span><span style="color: #339933;">.</span><span style="color: #000088;">$link</span><span style="color: #339933;">,</span>
      <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
          <span style="color: #0000ff;">'module'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'main'</span><span style="color: #339933;">,</span> 
          <span style="color: #0000ff;">'action'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'static'</span><span style="color: #339933;">,</span> 
          <span style="color: #0000ff;">'page'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$link</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">//with slash</span>
     <span style="color: #000088;">$routing</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">prependRoute</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'static_'</span><span style="color: #339933;">.</span><span style="color: #000088;">$link</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'_with_slash'</span><span style="color: #339933;">,</span>
        <span style="color: #000000; font-weight: bold;">new</span> sfRoute<span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'/'</span><span style="color: #339933;">.</span><span style="color: #000088;">$link</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'/'</span><span style="color: #339933;">,</span>
          <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'module'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'main'</span><span style="color: #339933;">,</span> 
          <span style="color: #0000ff;">'action'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'static'</span><span style="color: #339933;">,</span> 
          <span style="color: #0000ff;">'page'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$link</span><span style="color: #009900;">&#41;</span>
     <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Тут я из базы выбираю поля link_name, и создаю правила на их основе. Каким образом это дело крепится к инициализации роутов - я не знаю. На остальные вопросы отвечу в комментариях.</p>
<hr />
]]></content:encoded>
			<wfw:commentRss>http://www.charnad.com/blog/symfony-dinamicheskij-routing/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Symfony: человеческое расположение админки</title>
		<link>http://www.charnad.com/blog/symfony-chelovecheskoe-raspolojenie-adminki/</link>
		<comments>http://www.charnad.com/blog/symfony-chelovecheskoe-raspolojenie-adminki/#comments</comments>
		<pubDate>Sun, 22 Feb 2009 23:00:45 +0000</pubDate>
		<dc:creator>CharnaD</dc:creator>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://www.charnad.com/?p=381</guid>
		<description><![CDATA[Тем, кто изучает симфони известно, что админку часто делают через "generate:app backend". То есть мы создаем приложение внутри нашего проекта. Это прекрасно, но есть одно НО. Чтобы нам зайти в админку требуется писать http://project/backend.php/some-admin-pages. Можно конечно обьяснять заказчикам, что мол понимаете, это другое приложение внутри проекта, другой фронт-контроллер, так надо. Но лучше сделать иначе. Скажу [...]]]></description>
			<content:encoded><![CDATA[<p><img style="margin-right: 10px;" src="http://www.charnad.com/blog/wp-content/uploads/pictures/symfony_logo.gif" alt="" align="left" /></p>
<p>Тем, кто изучает симфони известно, что админку часто делают через "generate:app backend". То есть мы создаем приложение внутри нашего проекта. Это прекрасно, но есть одно НО. Чтобы нам зайти в админку требуется писать http://project/backend.php/some-admin-pages. Можно конечно обьяснять заказчикам, что мол понимаете, это другое приложение внутри проекта, другой фронт-контроллер, так надо. Но лучше сделать иначе. Скажу сразу, этот метод взят с официального форума симфони. Но найти его проблематично.</p>
<p>Метод таков:</p>
<ol>
<li>Создаем папку "admin" внутри папки "web". Копируем туда .htaccess из той же "web", и заменяем<br />
RewriteRule ^(.*)$ index.php [QSA,L]<br />
на<br />
RewriteRule ^(.*)$ ../backend.php [QSA,L]
</li>
<li>Идем в настройки роутинга для backend (app/backend/config/routing.yml) и добавляем папку /admin/ ко всем роутам. Например:
<p># default rules<br />
homepage:<br />
  url: /admin/<br />
  param: { module: default, action: index }
</li>
<li>Меняем no_script_name на "on" в настройках backend (app/backend/config/settings.yml):<br />
prod:<br />
.settings:<br />
no_script_name: on
</li>
<li>Чистим кеш и заходим в папку: http://project/admin/ без проблем.</li>
]]></content:encoded>
			<wfw:commentRss>http://www.charnad.com/blog/symfony-chelovecheskoe-raspolojenie-adminki/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Документация Symfony</title>
		<link>http://www.charnad.com/blog/documentacia-symfony/</link>
		<comments>http://www.charnad.com/blog/documentacia-symfony/#comments</comments>
		<pubDate>Wed, 18 Feb 2009 09:35:44 +0000</pubDate>
		<dc:creator>CharnaD</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://www.charnad.com/?p=367</guid>
		<description><![CDATA[Сейчас по долгу службы я работаю над движком для одного сайта. И сделать я его решил с использованием фреймворка, о котором слышал много хорошего. Я говорю о Symfony. Заниматься копипастом хвалебных речей с других сайтов я не буду, сам писать подобное так же не буду. Скажу только, что поначалу мне было трудно разобраться. Я даже [...]]]></description>
			<content:encoded><![CDATA[<p><img style="margin-right: 10px;" src="http://www.charnad.com/blog/wp-content/uploads/pictures/symfony_logo.gif" alt="" align="left" />
<p>Сейчас по долгу службы я работаю над движком для одного сайта. И сделать я его решил с использованием фреймворка, о котором слышал много хорошего. Я говорю о Symfony. Заниматься копипастом хвалебных речей с других сайтов я не буду, сам писать подобное так же не буду. Скажу только, что поначалу мне было трудно разобраться. Я даже хотел все бросить и писать на своей простой MVC системке, но в итоге не бросил. Упорно читал мануалы, стал понимать принципы построения приложения с использованием симфони. Собственно тут я хочу лишь выложить ссылки, которые могут помочь тем, кто будет изучать symfony.</p>
<p>Конечно, ссылка номер 1 это ссылка на главный сайт: <a href="http://www.symfony-project.org/">http://www.symfony-project.org/<br />
</a>Там большое количество документации, которые стоит осилить. Я пожалел времени, начал рубить сплеча, однако сейчас все равно пришел к тому, что надо читать мануалы и я их читаю. И всем придется, кто хочет понять всю мощь этого фреймворка.</p>
<p>
Ссылка номер 2 - это ссылка на главный гайд "симфонистов" <a href="http://www.symfony-project.org/book/1_2/">The Book</a> (<a href="http://www.symfony-project.org/get/pdf/book-1.2-en.pdf">PDF</a>). Книга на английском. Методично рассказывается о всех сторонах фреймворка.</p>
<p>
Ссылка номер 3 - это практическое руководство, так называемые <a href="http://www.symfony-project.org/askeet/1_0/en/">Askeet</a> (<a href="http://www.symfony-project.org/get/pdf/askeet-1.0-en.pdf">PDF</a>) и <a href="http://www.symfony-project.org/jobeet/1_2/Propel/en/">Jobeet</a> (<a href="http://www.symfony-project.org/get/pdf/jobeet-1.2-propel-en.pdf">PDF</a>). Они обе используют <a href="http://propel.phpdb.org/trac/">Propel</a> в качестве ORM вендора (на есть вариант и для Doctrine). Имейте ввиду, что Askeet был написан для Symfony 1.0, а Jobeet для 1.2. В сети есть <a href="http://symfony.artsofte.ru/theme/list/title/Переводы">переводы</a> некоторых глав на русский.
</p>
<p>Это то, что стоит читать в первую очередь. Возможно я найду время перевести некоторые главы на русский, но не обещаю. Удачи вам в изучении.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.charnad.com/blog/documentacia-symfony/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

