<?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>hudson@work &#187; symfony</title>
	<atom:link href="http://hudson.su/tag/symfony/feed/" rel="self" type="application/rss+xml" />
	<link>http://hudson.su</link>
	<description>статьи о web-разработке, менеджменте IT проектов и контроле качества</description>
	<lastBuildDate>Fri, 20 Jan 2012 13:15:39 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
		<item>
		<title>Конференция Symfony Camp Ukraine &#8211; Киев, 29 октября 2011</title>
		<link>http://hudson.su/2011/09/10/konferenciya-symfony-camp-ukraine-kiev-29-oktyabrya-2011-2/</link>
		<comments>http://hudson.su/2011/09/10/konferenciya-symfony-camp-ukraine-kiev-29-oktyabrya-2011-2/#comments</comments>
		<pubDate>Sat, 10 Sep 2011 06:21:50 +0000</pubDate>
		<dc:creator>hudson</dc:creator>
				<category><![CDATA[Профессиональное]]></category>
		<category><![CDATA[symfony]]></category>
		<category><![CDATA[symfony camp]]></category>
		<category><![CDATA[Symfony2]]></category>

		<guid isPermaLink="false">http://hudson.su/?p=2109</guid>
		<description><![CDATA[Коллеги, Украинские Symfony-джедаи попросили рассказать о важном событии в жизни коммьюнити &#8211; третьей конференции Symfony Camp, которая пройдет 29го октября сего года в Киеве: Несложно догадаться, что основной мотив данной конференции &#8211; вышедшая не так давно релиз-версия Symfony 2, поэтому приготовьтесь к куче чужого опыта и интересных граблей, на которые до вас уже наступили )) [...]]]></description>
			<content:encoded><![CDATA[<p>Коллеги, Украинские Symfony-джедаи попросили рассказать о важном событии в жизни коммьюнити &#8211; третьей конференции Symfony Camp, которая пройдет 29го октября сего года в Киеве:</p>
<p><a title="Конференция Symfony Camp UA 2011" href="http://2011.symfonycamp.org.ua/" target="_blank"><img src="http://2011.symfonycamp.org.ua/banner/symfonycamp-ua-2011-300x168-3.png" alt="Конференция Symfony Camp UA 2011" width="300" height="168" /></a></p>
<p>Несложно догадаться, что основной мотив данной конференции &#8211; вышедшая не так давно релиз-версия Symfony 2, поэтому приготовьтесь к куче чужого опыта и интересных граблей, на которые до вас уже наступили ))</p>
<p>Полный анонс можете посмотреть на специальной страничке, которую я создал по этому поводу &#8211; <a href="http://hudson.su/symfony-camp-ukraine/" target="_blank">http://hudson.su/symfony-camp-ukraine/</a>.</p>
<p>Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://hudson.su/2011/09/10/konferenciya-symfony-camp-ukraine-kiev-29-oktyabrya-2011-2/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>SymfonyGuru анонс</title>
		<link>http://hudson.su/2011/09/07/symfonyguru-announce/</link>
		<comments>http://hudson.su/2011/09/07/symfonyguru-announce/#comments</comments>
		<pubDate>Wed, 07 Sep 2011 09:01:49 +0000</pubDate>
		<dc:creator>hudson</dc:creator>
				<category><![CDATA[Личное]]></category>
		<category><![CDATA[Профессиональное]]></category>
		<category><![CDATA[symfony]]></category>
		<category><![CDATA[Symfony2]]></category>
		<category><![CDATA[SymfonyGuru]]></category>
		<category><![CDATA[Zend framework]]></category>

		<guid isPermaLink="false">http://hudson.su/?p=2092</guid>
		<description><![CDATA[Коллеги симфонисты, читали моего блога и просто случайные зеваки ) Хочу представить вам мое новое увлечение и, надеюсь, в будущем полезный для web-разработчиков сайт &#8211; symfony-gu.ru. Немного истории. Впервые познакомился с symfony я где-то в 2007м году. Тогда меня этим фреймворком заразил один энтузиаст по имени Руслан. Сам он потом довольно быстро охладел к этой [...]]]></description>
			<content:encoded><![CDATA[<p>Коллеги симфонисты, читали моего блога и просто случайные зеваки ) Хочу представить вам мое новое увлечение и, надеюсь, в будущем полезный для web-разработчиков сайт &#8211; <a title="symfony-gu.ru" href="http://symfony-gu.ru" target="_blank">symfony-gu.ru</a>.</p>
<h2><span id="more-2092"></span>Немного истории.</h2>
<p>Впервые познакомился с symfony я где-то в 2007м году. Тогда меня этим фреймворком заразил один энтузиаст по имени Руслан. Сам он потом довольно быстро охладел к этой забаве, а я же, наоборот &#8211; окончательно сделал выбор между Zend framework и Symfony в пользу последнего. Потом я сменил работу и на новом месте все проекты уже делал только на symfony. 1.0, 1.1, 1.2, 1.3/1.4 версии мелькали перед глазами, только успевай за неутомимым <a href="http://twitter.com/#!/fabpot" target="_blank">Фабиеном</a> и компанией )</p>
<p>Где-то в 2009м году я загорелся идеей сделать коммьюнити-сайт и одновременно блог для себя &#8211; о симфони, для симфонистов, да и просто получить фан для себя и плюс в карму ) Зарегистрировал домен symfony-gu.ru (по аналогии с ныне почившим java-gu.ru). На этом по большому счету все и стало. Я потыкался в популярные CMS&#8217;ки, сделал какую-то уродскую страничку&#8230; и в общем дальше дело не пошло. В то же время я начал активнее заниматься блогом hudson.su и на следующие 2 года это занятие компенсировало мне фэйл с гуру-сайтом.</p>
<blockquote><p>Смешное: в 2010м весной домен благополучно разделегировался и удалился, а весной 2011го я также успешно его зарегистрировал вновь ))</p></blockquote>
<p>С анонсом Symfony2 идеи о коммьюнити-сайте стали посещать меня вновь. И вот, весной я начал делать первый проект на Symfony2 (на Preview release 6) и тогда же в свободное время начал потихоньку писать код для этого проекта. Бешенная смена превью и бета релизов на время отбила у меня желание продолжать что-бы то ни было делать. Потом было лето и косметический ремонт, сделанный единолично без помощников первый раз в жизни ))) И вот к концу августа, уже после релиза Symfony 2.0 я вновь вернулся к старому коду, портировал его под релиз версию. В результате появился тот каркас, который сейчас вы можете видеть по адресу <a title="symfony-gu.ru" href="http://symfony-gu.ru" target="_blank">symfony-gu.ru</a>.</p>
<h2>О проекте.</h2>
<p>Сейчас сайт представляет собой двуязычный блог, написанный на Symfony2 (да, да, кода там кот наплакал )).</p>
<p>Что я буду туда писать:</p>
<ul>
<li>Вероятно буду копипастить новости из официального блога симфони;</li>
<li>Буду искать интересные и полезные треды в майл-листах симфони;</li>
<li>В ходе разработки рассчитываю писать статьи о том какие проблемы встречал и как их решал;</li>
<li>Опять же, в ходе разработки будут создаваться пакеты (bundles), которые я рассчитываю выкладывать в паблик (первые два простеньких пакета уже там));</li>
<li>В перспективе я думаю буду (будем) писать и про другие web-фреймворки, технологии и т.п. Но это пока мечты;</li>
<li>Ну и попробую организовать коммьюнити &#8211; тоже мечта.</li>
</ul>
<p>Собственно велкам. Вопросы и предложения кидайте по доступным каналам связи.</p>
]]></content:encoded>
			<wfw:commentRss>http://hudson.su/2011/09/07/symfonyguru-announce/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>PhpStorm: поддержка Symfony Command Line</title>
		<link>http://hudson.su/2011/05/25/phpstorm-symfony-command-line-usage-with-command-line-tool-support/</link>
		<comments>http://hudson.su/2011/05/25/phpstorm-symfony-command-line-usage-with-command-line-tool-support/#comments</comments>
		<pubDate>Wed, 25 May 2011 08:57:10 +0000</pubDate>
		<dc:creator>hudson</dc:creator>
				<category><![CDATA[Профессиональное]]></category>
		<category><![CDATA[hints]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[phpstorm]]></category>
		<category><![CDATA[symfony]]></category>
		<category><![CDATA[Symfony2]]></category>

		<guid isPermaLink="false">http://hudson.su/?p=1951</guid>
		<description><![CDATA[Начиная с PhpStorm 2.0 можно использовать Symfony command line tool при помощи Command Line Tool Support. Ниже приводится небольшое руководство по использованию. Вам понадобится PhpStorm 2.0 и Symfony 1.1 или более поздней версии (включая Symfony 2.0 BETA &#8211; в оригинальное руководство не входило, но мной проверено). Если у вас нет Symfony, руководство по установке вы [...]]]></description>
			<content:encoded><![CDATA[<p>Начиная с PhpStorm 2.0 можно использовать Symfony command line tool при помощи Command Line Tool Support.</p>
<p>Ниже приводится небольшое руководство по использованию. Вам понадобится <strong>PhpStorm 2.0</strong> и <strong>Symfony 1.1</strong> или более поздней версии (<strong>включая Symfony 2.0 BETA</strong> &#8211; в оригинальное руководство не входило, но мной проверено). Если у вас нет Symfony, руководство по установке вы можете найти <a href="http://www.symfony-project.org/getting-started/1_4/en/03-Symfony-Installation" target="_blank">здесь</a>.</p>
<p><span id="more-1951"></span></p>
<p>В первую очередь нам нужно настроить новый command line tool.</p>
<h3>Загрузка Symfony Commands</h3>
<p>Откройте меню <strong>Settings | Command Line Tool Support</strong> и нажмите в появившемся окне кнопку <strong>Add</strong>. Вам будет предложено три опции, выберите “<strong>Symfony</strong>”:</p>
<p><a rel="lightbox-01" href="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/Screenshot-Choose-Framework-To-Add.png"><img title="Choose Symfony framework to add" src="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/Screenshot-Choose-Framework-To-Add.png" alt="Choose Symfony Framework To Add" width="285" height="119" /></a></p>
<p>Затем укажите путь к файлу $Symfony_home$/data/bin/symfony. Для типичной конфигурации (из руководства симфони) путь будет следующим: $Project_root$/lib/vendor/symfony/data/bin/symfony. Описания команд Symfony будут загружены и сохранены в файл среди прочих настроек проекта. В диалоговом окне настроек это будет выглядеть следующим образом:</p>
<p><a rel="lightbox-02" href="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/symfonyDescriptionInSettings.png"><img title="Symfony description in Settings" src="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/symfonyDescriptionInSettings.png" alt="Symfony description in Settings" width="658" height="108" /></a></p>
<ul>
<li>Поле Tool Path содержит путь к CLI (php и фреймворка) и будет различаться в зависимости от фреймфорка. Для Symfony это &#8220;php  $path_to_symfony$&#8221;  и &#8220;$Zend_Framework_Tool_home$/bin/zf.bat&#8221; для Zend Framework. $PhpExecutable$ &#8211; это макрос, он заменяется на путь к исполнимому файлу CLI PHP, $ProjectFileDir$ это тоже макрос, он заменяется на полный путь к проекту. Макросы позволяют легко перемещать настройки между несколькими IDE.</li>
<li>Полный Tool Path может быть очень длинным и неудобным в наборе, поэтому имеется алиас, который представляет из себя строку, которую можно использовать для вызова CLI вместо Tool Path.</li>
<li>Чекбокс &#8220;Enable&#8221; поможет вам легко включать и отключать команды фреймворка из списка автоподстановки, не удаляя настройки. В данном случае чекбокс включен, таким образом команды Symfony будут отображаться в списке. Нажмите Ctrl +Shift+X или выберите в меню <strong>Tools | Run Command…</strong> и наберите алиас &#8220;s&#8221;:</li>
</ul>
<p><a rel="lightbox-03" href="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/commandList31.png"><img title="Symfony commands list" src="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/commandList31.png" alt="Symfony commands list" width="337" height="187" /></a></p>
<h3>Используем Symfony Command Line</h3>
<p>Теперь создадим простой проект на Symfony c использованием Command Line Tool, как это описано в “Getting  Started” <a href="http://www.symfony-project.org/getting-started/1_4/en/04-Project-Setup" target="_blank">документе</a>.</p>
<h4>Создаем проект Symfony</h4>
<p>Нажимаем Ctrl +Shift+X и набираем:</p>
<p><a rel="lightbox-04" href="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/symfonyGenerateProject.png"><img title="Generate project command" src="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/symfonyGenerateProject.png" alt="Generate project command" width="302" height="44" /></a></p>
<p>Команда имеет два параметра:</p>
<ul>
<li> Обязательный параметр “name”. Мы воспользуемся макросом $ProjectName$, который будет заменен на наименование проекта PhpStorm.</li>
<li>Опциональный параметр “author”.</li>
</ul>
<p>Перед выполнением команды макрос $ProjectName$ будет заменен на имя проекта и алиас “s” будет заменен на Tool Path. В данном случае это будет что-то типа “usr/bin/php  /home/sfproject/lib/vendor/symfony/data/bin/symfony”.</p>
<p>Результат &#8211; будет создан проект:</p>
<p><a rel="lightbox-05" href="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/generateProjectToolwindow2.png"><img title="Toolwindow with generated project" src="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/generateProjectToolwindow2.png" alt="Toolwindow with generated project" width="711" height="208" /></a></p>
<h4>Настройка доступа к базе данных</h4>
<p>Теперь настроим доступ к БД при помощи команды “php symfony  configure:database “mysql:host=localhost;dbname=dbname” root mYsEcret”</p>
<p><a rel="lightbox-06" href="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/confDatabasePopup2.png"><img title="Configuring database command" src="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/confDatabasePopup2.png" alt="Configuring database command" width="508" height="45" /></a></p>
<h4>Создание приложения Frontend</h4>
<p>Давайте создадим приложение frontend без экранирования вывода (что в общем-то сделает его менее защищенным!). Нажмите Ctrl +Shift+X и наберите:</p>
<p><a rel="lightbox-07" href="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/generateAppPopup2.png"><img title="Generate application command" src="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/generateAppPopup2.png" alt="Generate application command" width="346" height="44" /></a></p>
<p>Заметьте, что опции команд также поддерживаются. В примере выше это была опция –escaping-strategy=false.</p>
<p>Результат работы команды:</p>
<p><a rel="lightbox-08" href="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/dbAndAppToolWindows2.png"><img title="Commands output" src="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/dbAndAppToolWindows2.png" alt="Commands output" width="711" height="207" /></a></p>
<h4>Права доступа к директориям</h4>
<p>Следующим шагом является установка прав на директории cache/ и log/. Это также можно сделать при помощи Command Line Tool  Support. Тул попытается выполнить команды (макросы таже доступны). Но имейте в виду, что команды &#8220;chmod&#8221; по-умолчанию нет в windows системах (если вы не используете например cygwin).</p>
<p><a rel="lightbox-09" href="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/chmodPopup1.png"><img title="Chmod command" src="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/chmodPopup1.png" alt="Chmod command" width="347" height="45" /></a></p>
<p>Результат:</p>
<p><a rel="lightbox-10" href="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/chmodAndLsToolwindow21.png"><img title="Chmod and ls output in toolwindow" src="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/chmodAndLsToolwindow21.png" alt="Chmod and ls output in toolwindow" width="556" height="315" /></a></p>
<blockquote>
<h2>Примечание:</h2>
<p>Вообще говоря для установки прав <del>можно</del> нужно использовать команду &#8220;symfony project:permissions&#8221; // hudson@work</p></blockquote>
<p>После этого надо настроить web-сервер, как описано в <a href="http://www.symfony-project.org/getting-started/1_4/en/05-Web-Server-Configuration" target="_blank">документации</a>, и запустить его.</p>
<h3>Тестирование</h3>
<p>Проверьте доступ к новому приложению &#8211; откройте в браузере <a href="http://localhost:8080/index.php/" target="_blank">http://localhost:8080/index.php/</a> и затем проверьте доступ к dev окружению <a href="http://localhost:8080/frontend_dev.php/" target="_blank">http://localhost:8080/frontend_dev.php/</a>.</p>
<p>Если вы видите такую страницу, ваш проект успешно создан:</p>
<p><a rel="lightbox-11" href="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/finalPrintScreen.png"><img title="Project page" src="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/finalPrintScreen.png" alt="Project page" width="600" height="626" /></a></p>
<h3>Добавляем пользовательский task.</h3>
<p>Давайте создадим простой таск &#8220;hello&#8221;. Подразумевается что ранее вы уже настроили команды Symfony, как это описано выше и создали проект.</p>
<p>Нажмите Ctrl+Shift+X и выполните команду:</p>
<p><a rel="lightbox-12" href="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/generateTask2.png"><img title="Generate task command" src="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/generateTask2.png" alt="Generate task command" width="332" height="44" /></a></p>
<p>В директории lib/task будет создан класс “helloTask”.</p>
<p>Откройте класс helloTask в редакторе и выполните следующие несложные изменения в его методе “execute”:</p>
<p><a rel="lightbox-13" href="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/helloTaskContents2.png"><img title="HelloTask class execute function" src="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/helloTaskContents2.png" alt="HelloTask class execute function" width="463" height="153" /></a></p>
<p>Откройте description file для Symfony: выберите <strong>Settings |  Command Line Tool Support</strong> и нажмите кнопку “Open definition in editor”.</p>
<p>Добавьте описание новой команды “hello”:</p>
<p><a rel="lightbox-14" href="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/newCommandDescription.png"><img title="Hello command description" src="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/newCommandDescription.png" alt="Hello command description" width="464" height="261" /></a></p>
<p>Текст описания:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;command<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        hello
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;help<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        My first task with no parameters.
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/help<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/command<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>Для проверки новой команды выполните:</p>
<p><a rel="lightbox-15" href="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/helloList.png"><img title="Hello command" src="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/helloList.png" alt="Hello command" width="336" height="54" /></a></p>
<p>Результат выполнения отобразится в консоли:</p>
<p><a rel="lightbox-16" href="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/helloInvoker2.png"><img title="Hello, invoker!" src="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/helloInvoker2.png" alt="Hello, invoker!" width="607" height="118" /></a></p>
<h4>Решение проблем</h4>
<p>Если у вас возникнут проблемы после редактирования файла описания и нужная вам команда не появится, откройте таб Validation в консоли. Этот таб показывает информацию о проблемах парсинга файла описания:</p>
<p><a rel="lightbox-17" href="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/validationTab.png"><img title="Validation tab" src="http://blogs.jetbrains.com/webide/wp-content/uploads/2011/01/validationTab.png" alt="Validation tab" width="487" height="85" /></a></p>
<p>Вы также можете получить информацию о формате файла описания из схемы .idea/commandlinetools/schemas/frameworkDescriptionVersion1.1.xsd. Этот путь указан в созданном файле описания и редактор выполняет валидацию автоматически с его использованием.</p>
<blockquote><p>Hope this hepls как говорится, ваш hudson@work <img src='http://hudson.su/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://hudson.su/2011/05/25/phpstorm-symfony-command-line-usage-with-command-line-tool-support/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Symfony2 book: Основы Symfony2 и HTTP / Symfony2 and HTTP Fundamentals</title>
		<link>http://hudson.su/2011/05/04/symfony2-book-osnovy-symfony2-i-http-symfony2-and-http-fundamentals/</link>
		<comments>http://hudson.su/2011/05/04/symfony2-book-osnovy-symfony2-i-http-symfony2-and-http-fundamentals/#comments</comments>
		<pubDate>Wed, 04 May 2011 06:49:58 +0000</pubDate>
		<dc:creator>hudson</dc:creator>
				<category><![CDATA[Профессиональное]]></category>
		<category><![CDATA[fundamentals]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[symfony]]></category>
		<category><![CDATA[Symfony2]]></category>
		<category><![CDATA[Symfony2 book]]></category>

		<guid isPermaLink="false">http://hudson.su/?p=1978</guid>
		<description><![CDATA[Данный перевод главы Symfony2 and HTTP Fundamentals публикуется с разрешения автора: Канат Гайлимов Web-разработчик, блогер http://gailimov.info Поздравляем! Изучая Symfony2, вы становитесь на правильный (истинный) путь и будете более продуктивным, всесторонним и популярным веб-разработчиком (на самом деле, 2 последних пункта на ваше усмотрение). Symfony2 построен так, чтобы вернуться к основам: разработаны инструменты, которые позволят вам разрабатывать [...]]]></description>
			<content:encoded><![CDATA[<p>Данный перевод главы <a href="http://symfony.com/doc/2.0/book/http_fundamentals.html" target="_blank">Symfony2 and HTTP Fundamentals</a> публикуется с разрешения автора:</p>
<blockquote><p>Канат Гайлимов<br />
Web-разработчик, блогер<br />
<a href="http://gailimov.info" target="_blank">http://gailimov.info</a></p></blockquote>
<p>Поздравляем! Изучая Symfony2, вы становитесь на правильный (истинный) путь и будете более продуктивным, всесторонним и популярным веб-разработчиком (на самом деле, 2 последних пункта на ваше усмотрение). Symfony2 построен так, чтобы вернуться к основам: разработаны инструменты, которые позволят вам разрабатывать быстрее и создавать более надежные приложения, оставаясь вне вашего пути. Symfony построен на лучших идеях многих технологий: инструменты и концепции, которые вы собираетесь изучать, представляют усилия тысячи людей, в течении многих лет. Другими словами, вы не просто изучаете &#8220;Symfony&#8221;, вы изучаете основы веб, лучшие практики разработки, и как пользоваться многими новыми, удивительные PHP-библиотеки, внутри или независимо от Symfony2. Итак, приготовьтесь.</p>
<p>Оставаясь верной философии Symfony2, эта глава начинается с объяснений основных концепций, общих для веб-разработки: HTTP. Независимо от вашего происхождения или языка программирования, эта глава <strong>обязательна к прочтению</strong> для всех.</p>
<p><span id="more-1978"></span></p>
<h3>HTTP это просто</h3>
<p>HTTP (для гиков Hypertext Transfer Protocol) &#8211; текстовый язык, позволяющий двум машинам общаться между собой. Вот и все! Например, когда мы проверяем последний <a href="http://xkcd.com/" target="_blank">xkcd</a> комикс, осуществляется следующая (приблизительно) беседа:</p>
<p><a rel="lightbox" href="http://hudson.su/wp-content/uploads/2011/05/http-xkcd.png"><img src="http://hudson.su/wp-content/uploads/2011/05/http-xkcd.png" alt="" title="http-xkcd" width="540" height="230" class="alignnone size-full wp-image-1990" /></a></p>
<p>И пока фактический язык используется чуть более формально, он остается простым. HTTP &#8211; термин, использующийся для описания этого простого текстового языка. И независимо от того, как вы разрабатываете в вебе, цель вашего сервера &#8211; понимать простые текстовые запросы, и возвращать простые текстовые ответы.</p>
<p>Symfony2 построен вокруг этой действительности. Понимаете ли вы это или нет, HTTP, это то, что вы используете каждый день. С Symfony2 вы узнаете как справляться с этим.</p>
<h4>Шаг1: клиент посылает запрос</h4>
<p>Каждое общение в сети начинается с запроса. Запрос &#8211; текстовое сообщение, созданное клиентом (например браузер, приложение iPhone и т.д.) в специальном формате, известном как HTTP. Клиент посылает запрос серверу, и затем ожидает ответа.</p>
<p>Давайте взглянем на первую часть взаимодействия (запрос) между браузером и веб-сервером xkcd:</p>
<p><a rel="lightbox" href="http://hudson.su/wp-content/uploads/2011/05/http-xkcd-request.png"><img src="http://hudson.su/wp-content/uploads/2011/05/http-xkcd-request.png" alt="" title="http-xkcd-request" width="420" height="176" class="alignnone size-full wp-image-1983" /></a></p>
<p>В синтаксисе HTTP, этот запрос на самом деле будет выглядеть так:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">GET / HTTP/1.1
Host: xkcd.com
Accept: text/html
User-Agent: Mozilla/5.0 (Macintosh)</pre></div></div>

<p>Это простое сообщение содержит данные о том, какой именно ресурс запрашивается клиентом. Первая строка HTTP-запроса очень важна: она содержит две вещи: URI и метод HTTP.</p>
<p>URI (например, /, /contact, и т.д) это уникальный адрес или место нахождения, идентифицирующее ресурс, который запрашивает клиент. HTTP-метод (например GET) определяет, что вы хотите делать с ресурсом. HTTP-методы являются действиями (глаголы) запроса, и определяют несколько общих способов, которыми вы можете воздейсвовать на ресурс:</p>
<table>
<tr>
<td>GET</td>
<td>Получить ресурс с сервера</td>
</tr>
<tr>
<td>POST</td>
<td>Создать ресурс на сервере</td>
</tr>
<tr>
<td>PUT</td>
<td>Обновить ресурс на сервере</td>
</tr>
<tr>
<td>DELETE</td>
<td>Удалить ресурс с сервера</td>
</tr>
</table>
<p>Имея это в виду, вы можете представить ка будет выглядеть HTTP-запрос для удаления конкретной записи в блоге, например:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">DELETE /blog/15 HTTP/1.1</pre></div></div>

<blockquote>
<p>Примечание.</p>
<p>Фактически существует девять HTTP-методов, определяемых спецификацией HTTP, но многие из них не используются столь широко или не поддерживаются. В действительности, многие современные браузеры, не поддерживают методы PUT и DELETE.</p>
</blockquote>
<p>В дополнение к первой строке, HTTP-запрос содержит другую информацию, называемой заголовками HTTP-запроса. Заголовки могут предостовлять широкий диапазон информации, такую как, запрашиваемый Host, формат ответа принимаемый клиентом (Accept) и приложение используемое клиентов для выполнения запроса (User-Agent). Существует много других заголовков, которые можно найти в <a target="_blank" href="http://en.wikipedia.org/wiki/List_of_HTTP_header_fields">Википедии</a>.</p>
<h4>Шаг2: сервер возвращает ответ</h4>
<p>Как только сервер получил запрос, он знает, какие именно ресурсы требуются клиенту (посредством URI) и что клиент хочет делать с ресурсом (посредством метода). Например, в случае с запросом GET, сервер подготавливает ресурс и возвращает его в виде HTTP-ответа. Рассмотрим ответ от веб-сервера xkcd:</p>
<p><a rel="lightbox" href="http://hudson.su/wp-content/uploads/2011/05/http-xkcd.png"><img src="http://hudson.su/wp-content/uploads/2011/05/http-xkcd.png" alt="" title="http-xkcd" width="540" height="230" class="alignnone size-full wp-image-1990" /></a></p>
<p>В переводе на HTTP, ответ отправленный обратно в браузер будет выглядеть примерно так:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">HTTP/1.1 200 OK
Date: Sat, 02 Apr 2011 21:05:05 GMT
Server: lighttpd/1.4.19
Content-Type: text/html
&nbsp;
&lt;html&gt;
    &lt;!-- HTML for the xkcd comic --&gt;
&lt;/html&gt;</pre></div></div>

<p>HTTP-ответ содержит запрошенный ресурс (в данном случае HTML контент), а также другую информацию о запросе. Первая строка особенно важна и содержит код статуса HTTP-ответа (в данном случае 200). Код статуса сообщает общий результат запроса обратно клиенту. Был ли запрос успешен? Были ли ошибки? Существуют другие коды статуса, которые указывают на успех, ошибку или то, что хочет клиент (например редирект на другую страницу). Полный список можно найти в <a target="_blank" href="http://en.wikipedia.org/wiki/List_of_HTTP_status_codes">Википедии</a>.</p>
<p>Как и запрос, HTTP-ответ содержит различную информацию, известную как HTTP-заголовки. Например, один из важнейших заголовков HTTP-ответа это Content-Type. Тело того же ресурса, может возвратиться в нескольких разных форматах включающих HTML, XML или JSON. Заголовок Content-Type сообщает клиенту в каком формате возвратился ответ.</p>
<p>Существует масса других заголовков, некоторые из которых очень значительны. Например, некоторые заголовки могут быть использованы для создания мощной системы кеширования.</p>
<h4>Запросы, ответы и веб-разработка</h4>
<p>Общение запрос-ответ &#8211; фундаментальный процесс движущий все взаимодействия в сети. И как и все важное и значительное, оно до безобразия просто.</p>
<p>Важный факт во всем этом: независимо от того, какой язык вы используете, приложение какого типа вы создаете (веб, мобильное, JSON API) или какую философию разработки исповедуете, конечная цель приложения это всегда понимание каждого запроса, создание и возврат соответствующего ответа.</p>
<p>Symfony спроектирован так, чтобы соответствовать этой действительности.</p>
<blockquote>
<p>Примечение.</p>
<p>Чтобы узнать больше о спецификации HTTP, прочтите оригинальную <a target="_blank" href="http://www.w3.org/Protocols/rfc2616/rfc2616.html">HTTP 1.1 RFC</a> или <a target="_blank" href="http://datatracker.ietf.org/wg/httpbis/">HTTP Bis</a> статьи, которые отлично разъясняют исходную спецификацию. Великолепным инструментом для проверки заголовков запроса и ответа в браузере, является расширение для Firefox <a target="_blank" href="https://addons.mozilla.org/en-US/firefox/addon/3829/">Live HTTP Headers</a>.</p>
</blockquote>
<h3>Запросы и ответы в PHP</h3>
<p>Итак, как вы можете взаимодействовать с &#8220;запросом&#8221; и создавать &#8220;ответ&#8221; используя PHP? В действительности PHP абстрагирует вас от этого процесса:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">&amp;</span>lt<span style="color: #339933;">;</span>?php
<span style="color: #000088;">$uri</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'REQUEST_URI'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$foo</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$_GET</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'foo'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #990000;">header</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Content-type: text/html'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'The URI requested is: '</span><span style="color: #339933;">.</span><span style="color: #000088;">$uri</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'The value of the &quot;foo&quot; parameter is: '</span><span style="color: #339933;">.</span><span style="color: #000088;">$foo</span><span style="color: #339933;">;</span></pre></div></div>

<p>Как ни странно это звучит, это маленькое приложение фактические берет информацию из HTTP-запроса и использует его для создания HTTP-ответа. Вместо разбора сообщения HTTP-запроса, PHP подготавливает суперглобальные массивы, такие как $_SERVER и $_GET, в которых содержится вся информация запроса. Аналогично, вместо возвращения текстового сообщения в формате HTTP, вы можете использовать функцию header() для создания заголовков ответа и просто вывести контент, который будет содержанием части сообщения ответа. PHP создаст настоящий HTTP-ответ и вернет его клиенту:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">HTTP/1.1 200 OK
Date: Sat, 03 Apr 2011 02:14:33 GMT
Server: Apache/2.2.17 (Unix)
Content-Type: text/html
&nbsp;
The URI requested is: /testing?foo=symfony
The value of the &quot;foo&quot; parameter is: symfony</pre></div></div>

<h3>Запросы и ответы в Symfony</h3>
<p>Symfony предоставляет альтернативу подходу PHP, посредством двух классов, которые позволяют вам взаимодейстовать с HTTP-запросом и ответом более простым путем. Класс <a target="_blank" href="http://api.symfony.com/2.0/Symfony/Component/HttpFoundation/Request.html">Request</a> &#8211; простое объектно-ориентированное представление сообщения HTTP-запроса. С ним, в ваших руках имеется вся информация запроса:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">use</span> Symfony\Component\HttpFoundation\Request<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$request</span> <span style="color: #339933;">=</span> Request<span style="color: #339933;">::</span><span style="color: #004000;">createFromGlobals</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;">// the URI being requested (e.g. /about) minus any query parameters</span>
<span style="color: #000088;">$request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getPathInfo</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;">// retrieve GET and POST variables respectively</span>
<span style="color: #000088;">$request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">query</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'foo'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'bar'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// retrieves an instance of UploadedFile identified by foo</span>
<span style="color: #000088;">$request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">files</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'foo'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getMethod</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>          <span style="color: #666666; font-style: italic;">// GET, POST, PUT, DELETE, HEAD</span>
<span style="color: #000088;">$request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getLanguages</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>       <span style="color: #666666; font-style: italic;">// an array of languages the client accepts</span></pre></div></div>

<p>В качестве бонуса, класс Request выполняет множество черновой работы в фоновом режиме, так что вы можете не беспокоиться об этом. Например, метод isSecure() проверяет три различных значения в PHP, которые указывают установил ли пользователь защищенное соединение (т.е. https).</p>
<p>Symfony также предоставляет класс Response: простое PHP представление сообщения HTTP-ответа. Он позволяет вашему приложению использовать объектно-ориентированный интерфейс для построения ответа, который должен быть возвращен клиенту:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">use</span> Symfony\Component\HttpFoundation\Response<span style="color: #339933;">;</span>
<span style="color: #000088;">$response</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Response<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$response</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setContent</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'&lt;html&gt;&lt;body&gt;&lt;h1&gt;Hello world!&lt;/h1&gt;&lt;/body&gt;&lt;/html&gt;'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$response</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setStatusCode</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">200</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$response</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">headers</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">set</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Content-Type'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'text/html'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// prints the HTTP headers followed by the content</span>
<span style="color: #000088;">$response</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">send</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Если же Symfony не предлагает ничего другого, то у все все равно уже есть инструментарий для легкого доступа к информации запроса и объектно-ориентированный интерфейс для создания ответа. Даже если вы изучите многие сильные возможности Symfony, имейте ввиду, что цель вашего приложения интерпретировать запрос и создавать соотвествующий ответ, основанный на логике вашего приложения.</p>
<blockquote>
<p>Примечание:</p>
<p>Классы Request и Response &#8211; часть автономного компонента включенного в Symfony и называемого HttpFoundation. Этот компонент может быть использован полностью независимо от Symfony и также предоставляет классы для обработки сессий и загрузки файлов.</p>
</blockquote>
<h3>Путешествие от запроса к ответу</h3>
<p>Как и HTTP, объекты Request и Response очень просты. Сложная часть построения приложения описывает то, что происходит между ними. Другими словами, реальная работа настает тогда, когда пишется код интерпретирующий информацию запроса и создающий ответ.</p>
<p>Ваше приложение, вероятно делает много вещей, такие как, отсылка почты, обработка форм, сохранение в базу данных, рендеринг HTML страниц и защита контента. Как вы будете управлять всем этим и по-прежнему держать ваш код организованным и поддерживаемым?</p>
<p>Symfony создан для решения этих проблем, так что вы не должны иметь их.</p>
<h4>Front Contoller</h4>
<p>Традиционно, приложения строятся так, что каждой страницей сайта, является его физический файл.</p>
<ul>
<li>index.php</li>
<li>contact.php</li>
<li>blog.php</li>
</ul>
<p>В этом подходе имеется несколько проблем, в том числе негибкость URL&#8217;ов (что, если вы захотите сменить blog.php на news.php без потери всех ваших ссылок?) и тем, что каждый файл должен вручную включить некоторый набор ключевых файлов, так что безопасность, соединение с базой данных, и &#8220;взгляд&#8221; сайта могут остаться последовательными.</p>
<p>Наилучшее решение &#8211; это использование front controller&#8217;а: единственного PHP-файла, который обрабатывает каждый запрос, входящий в ваше приложение. Например:</p>
<table>
<tr>
<td>/index.php</td>
<td>executes index.php</td>
</tr>
<tr>
<td>/index.php/contact</td>
<td>executes index.php</td>
</tr>
<tr>
<td>/index.php/blog</td>
<td>executes index.php</td>
</tr>
</table>
<blockquote>
<p>Примечание:</p>
<p>С использованием модуля mod_rewrite веб-сервера Apache (или его эквивалента в других веб-серверах), URL&#8217;ы могут быть сокращены до /, /contact и /blog.</p>
</blockquote>
<p>Теперь каждый запрос будет обрабатываться одинаково. Вместо отдельных URL&#8217;ов, выполняющих отдельные PHP файлы, front controller выполняется всегда, и маршрутизация различных URL&#8217;ов производится внутри него. Это решает обе проблемы оригинального подхода. Все современные приложения работают по такому принципу, включая такие приложения, как WordPress.</p>
<h4>Оставайтесь организованным</h4>
<p>Но как вы узнаете внутри вашего front controller&#8217;а, какая страница должна быть отрендерена и выведена? Так или иначе, вы должны проверить входящий URI и выполнить различные части вашего приложения, в зависимости от его значения. Это можно сделать ужасно быстро:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// index.php</span>
&nbsp;
<span style="color: #000088;">$request</span> <span style="color: #339933;">=</span> Request<span style="color: #339933;">::</span><span style="color: #004000;">createFromGlobals</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$path</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getPathInfo</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// the URL being requested</span>
&nbsp;
<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;">$path</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</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: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$response</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Response<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Welcome to the homepage.'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">elseif</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$path</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'/contact'</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$response</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Response<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Contact us'</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;">$response</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Response<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Page not found.'</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">404</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #000088;">$response</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">send</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Решение этой проблемы может быть затруднительным. К счастью, это имено то, для чего создана Symfony.</p>
<h4>Выполнение приложения Symfony</h4>
<p>Когда вы позволите Symfony обрабатывать каждый запрос, жизнь облегчится. Symfony для каждого запроса следует одним и тем же паттернам.</p>
<p><a rel="lightbox" href="http://hudson.su/wp-content/uploads/2011/05/request-flow.png"><img src="http://hudson.su/wp-content/uploads/2011/05/request-flow-300x118.png" alt="" title="request-flow" width="300" height="118" class="alignnone size-medium wp-image-1984" /></a></p>
<p>Входящий запрос интерпретируется роутером и передается методам контроллера, возвращающим объекты Response.</p>
<p>Каждая страница вашего сайта определяется в файле конфигурации роутинга, который направляет различные URL&#8217;ы различными PHP функциям. Работой каждой функции вызываемой <a target="_blank" href="http://symfony.com/doc/2.0/glossary.html#term-controller">контроллером</a>, является использование информации из запроса, наряду с другими инструментами Symfony делающими доступными создание и возвращение объекта Response. Другими словами, контроллер, это то, где проходит ваш код: место, где вы интерпретируете запрос и создаете ответ.</p>
<p>Это так просто! Давайте рассмотрим:</p>
<ul>
<li>Каждый запрос выполняется в файле front controller&#8217;а;</li>
<li>Система роутинга определяет, какая PHP функция будет выполнена, основываясь на информации из запроса и конфигурации роутинга, созданного вами;</li>
<li>PHP функция будет корректно выполнена тогда, когда ваш код создаст и вернет соответствующий объект Response.</li>
</ul>
<h4>Symfony Request в действии</h4>
<p>Давайте рассмотрим этот процесс в действии без погружения в детали. Пускай вы хотите добавить в ваше Symfony приложение страницу /contact. Сперва начнем с добавления записи в ваш конфигурационный файл роутинга.</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">contact:
    pattern:  /contact
    defaults: { _controller: AcmeDemo:Main:contact }</pre></div></div>

<blockquote>
<p>Примечание:</p>
<p>В этом примере, для объявления конфигурации роутинга используется <a target="_blank" href="http://symfony.com/doc/2.0/reference/YAML.html">YAML</a></p>
</blockquote>
<p>Когда кто-нибудь посетит страницу /contact, маршрут совпадет и выполнится специфичный контроллер. Как вы узнаете в <a target="_blank" href="http://symfony.com/doc/2.0/book/routing.html">главе маршрутизация</a>, AcmeDemo:Main:contact это сокращение, указывающее на метод contactAction внутри класса MainController:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> MainController
<span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> contactAction<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #000000; font-weight: bold;">new</span> Response<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'&lt;h1&gt;Contact us!&lt;/h1&gt;'</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>В этом очень простом примере, контроллер просто создает объект Response с HTML содержимым &#8220;&lt;h1&gt;Contact us!&lt;/h1&gt;&#8221;. В <a target="_blank" href="http://symfony.com/doc/2.0/book/controller.html">главе контроллер</a> вы узнаете, как контроллер может вывести шаблон, позволяющий вашему &#8220;презентационному&#8221; коду (т.е. всему, что может быть в HTML) находиться в отдельных файлах шаблона. Это позволяет заботиться только о сложным вещах: взаимодействию с базой данных, обработкой поступивших данных или отправкой email сообщений.</p>
<h3>Symfony2: стройте ваши приложения, а не инструменты</h3>
<p>Теперь вы знаете, что цель любого приложения интерпретация каждого входящего запроса и создание соответствующего ответа. По мере роста приложения, становится все труднее держать ваш код организованным и поддерживаемым. Неизменно остаются вещи повторяющиеся снова и снова: сохранение информации в базу данных, вывод и повторное использование шаблонов, обработка отправок формы, отправка почты, валидация данных пользователя и безопасность.</p>
<p>Хорошая новость, в том, что ни одна их этих проблем не является уникальной. Symfony предоставляет фреймворк, полный инструментов, которые позволят вам строить приложения, а не инструменты. С Symfony2 ничего вас не связывает: вы свободно можете использовать как весь фреймворк, так и только некоторую часть.</p>
<h4>Автономные инструменты: Компоненты Symfony2</h4>
<p>Итак, что такое Symfony? Во первых, Symfony2 коллекция свыше двадцати независимых библиотек, которые могут быть использованы внутри <em>любого</em> PHP проекта. Эти библиотеки, называющиеся компонентами Symfony2, содержат что-то полезное практически для любой ситуации, независимо от того, как разработан ваш проект. Перечислим некоторые:</p>
<ul>
<li>
        <a target="_blank" href="https://github.com/symfony/HttpFoundation">HttpFoundation</a> &#8211; содержит классы Request и Response, также как и другие классы для обработки сессий и загрузки файлов;
    </li>
<li>
        <a target="_blank" href="https://github.com/symfony/Routing">Routing</a> &#8211; мощная и быстрая система маршрутизации, позволяющая вам указывать специфичный URI (например /contact) некоторой информации о том, как будет обработан запрос (например выполнить метод contactAction());
    </li>
<li>
        <a target="_blank" href="https://github.com/symfony/Form">Form</a> &#8211; полнофункциональный и гибкий фреймворк для создания и обработки форм;
    </li>
<li>
        <a target="_blank" href="https://github.com/symfony/Validation">Validation</a> &#8211; система создания правил для данных, а затем проверки представленных пользователем данных на следование этим правилам;
    </li>
<li>
        <a target="_blank" href="https://github.com/symfony/ClassLoader">ClassLoader</a> &#8211; библиотека автозагрузки, позволяющая вызывать классы без непосредственного подключения;
    </li>
<li>
        <a target="_blank" href="https://github.com/symfony/Templating">Templating</a> &#8211; инструмент для рендеринга шаблонов, поддерживает наследование шаблонов (т.е. шаблоны оборачиваются в лайауты) и выполняет другие общие задачи;
    </li>
<li>
        <a target="_blank" href="https://github.com/symfony/Security">Security</a> &#8211; мощная библиотека для поддержки всех видов безопасности внутри приложения;
    </li>
<li>
        <a target="_blank" href="https://github.com/symfony/Translation">Translation</a> &#8211; фреймворк, для перевода текста в вашем приложении.
    </li>
</ul>
<p>Каждый из этих компонентов независим, и может использоваться в любом <em>PHP</em> проекте, независимо от того используется Symfony2 или нет. Каждая часть сделана так, чтобы при необходимости можно было заменить ее.</p>
<h4>Итог: Symfony2 Framework</h4>
<p>Итак, что же такое фреймворк Symfony2? Фреймворк Symfony2 это PHP библиотека, выполняющая две основные задачи:</p>
<ul>
<li>
        Предоставление выбора компонентов (т.е. компонентов Symfony2) и сторонних библиотек (например Swiftmailer для отравки почты);
    </li>
<li>
        Предоставление удобной конфигурации и &#8220;клея&#8221;, связывающего библиотеки друг с другом.
    </li>
</ul>
<p>Цель фреймворка, интеграция независимых инструментов, для обеспечения целостности для разработчиков. Даже в самом фреймворке можно настраивать или заменять бандлы (т.е. плагины).</p>
<p>Symfony2 предоставляет мощный набор инструментов для быстрой разработки веб-приложений без наложения ограничений. Обычные пользователи могут быстро начать разработку с помощью Symfony2, предоставляющей каркас проекта по-умочанию. Для более продвинутых пользователей, пределом могут стать только небеса.</p>
]]></content:encoded>
			<wfw:commentRss>http://hudson.su/2011/05/04/symfony2-book-osnovy-symfony2-i-http-symfony2-and-http-fundamentals/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Symfony2 book: Основы создания страниц / The Basics of Page Creation</title>
		<link>http://hudson.su/2011/04/28/symfony2-book-the-basics-of-page-creation/</link>
		<comments>http://hudson.su/2011/04/28/symfony2-book-the-basics-of-page-creation/#comments</comments>
		<pubDate>Thu, 28 Apr 2011 09:34:25 +0000</pubDate>
		<dc:creator>hudson</dc:creator>
				<category><![CDATA[Профессиональное]]></category>
		<category><![CDATA[bundles]]></category>
		<category><![CDATA[environments]]></category>
		<category><![CDATA[symfony]]></category>
		<category><![CDATA[Symfony2]]></category>
		<category><![CDATA[Symfony2 book]]></category>

		<guid isPermaLink="false">http://hudson.su/?p=1879</guid>
		<description><![CDATA[Создание новой страницы в Symfony2 это простой процесс, состоящий из 2 шагов: Создание маршрута: Маршрут определяет URI (например /about) для вашей страницы, а также контроллер (PHP функция), который Symfony2 должен выполнить, когда URI входящего запроса совпадет шаблоном маршрута; Создание контроллера: Контроллер &#8211; это PHP функция, которая принимает входящий запрос и трансформирует его в объект Response [...]]]></description>
			<content:encoded><![CDATA[<p>Создание новой страницы в <strong>Symfony2</strong> это простой процесс, состоящий из 2 шагов:</p>
<ul>
<li>
    <em>Создание маршрута:</em><br />
Маршрут определяет URI (например <tt>/about</tt>) для вашей страницы, а также контроллер (PHP функция), который Symfony2 должен выполнить, когда URI входящего запроса совпадет шаблоном маршрута;
  </li>
<li>
    <em>Создание контроллера: </em><br />
Контроллер &#8211; это PHP функция, которая принимает входящий запрос и трансформирует его в объект Response (ответ).
  </li>
</ul>
<p>Нам нравится такой подход, потому что он соответствует тому как работает Web. Каждое взаимодействие в Web инициализируется HTTP запросом. Забота вашего приложения &#8211; интерпретировать запрос и вернуть соответствующий ответ. Symfony2 следует этой философии и предлагает вам инструменты и соглашения, для того чтобы ваше приложение оставалось структурированным при росте его сложности.<br />
<span id="more-1879"></span></p>
<h2>Страница &#8220;Hello Symfony!&#8221;</h2>
<p>Давайте начнем с классического приложения &#8220;Hello World!&#8221;. Когда мы закончим, пользователь будет иметь возможность получить персональное приветствие, перейдя по следующему URL:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">http://localhost/app_dev.php/hello/Symfony</pre></div></div>

<p>Вы также сможете заменить &#8220;<tt>Symfony</tt>&#8221; на другое имя и получить новое приветствие. Для создания этой страницы мы<br />
пройдем простой путь из двух шагов.</p>
<blockquote><p>
  Данное руководство подразумевает, что вы уже скачали Symfony2 и настроили ваш вебсервер. URL, указанный выше, подразумевает, что <tt>localhost</tt> указывает на web-директорию вашего нового Symfony2 проекта. Если же вы ещё не выполнили этих шагов, рекомендуется их выполнить, прежде чем вы продолжите читать.
</p></blockquote>
<div id="create-the-bundle">
<h3>Создание Пакета (bundle)</h3>
<p>Прежде чем начать, вам необходимо создать пакет (bundle). В Symfony2 пакет напоминает plugin, за исключением того, что весь код вашего приложения будет расположен внутри такого пакета.<br />
Вообще говоря, пакет &#8211; это не более чем директория (соответствующая тем не менее пространству имен PHP), которая содержит все что относится к какой-то специфической функции (см. <a href="#page-creation-bundles"><em>Система пакетов</em></a>). Для создания пакета с именем <tt>AcmeStudyBundle</tt> (демо-пакет, который мы создадим в ходе прочтения данной статьи), необходимо выполнить следующую команду (из корня проекта):</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">  php app<span style="color: #000000; font-weight: bold;">/</span>console init:bundle <span style="color: #ff0000;">&quot;Acme\StudyBundle&quot;</span> src</pre></div></div>

<p>Далее, нам необходимо убедиться, что пространство имен Acme загружено &#8211; для этого нам надо добавить следующий код в файл <tt>app/autoload.php</tt> file (см. <a href="#autoloading-introduction-sidebar"><em>Автозагрузка</em></a>):</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$loader</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">registerNamespaces</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
    <span style="color: #0000ff;">'Acme'</span>                         <span style="color: #339933;">=&gt;</span> __DIR__<span style="color: #339933;">.</span><span style="color: #0000ff;">'/../src'</span><span style="color: #339933;">,</span>
    <span style="color: #666666; font-style: italic;">// ...</span>
<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Наконец, инициализируем пакет, добавляя его в метод <tt>registerBundles</tt> класса <tt>AppKernel</tt>:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// app/AppKernel.php</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> registerBundles<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$bundles</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #666666; font-style: italic;">// ...</span>
        <span style="color: #000000; font-weight: bold;">new</span> Acme\StudyBundle\AcmeStudyBundle<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// ...</span>
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$bundles</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Теперь, когда мы создали и подключили пакет, мы можем начать создание нашего приложения в нём.
</p></div>
<div id="create-the-route">
<h3>Создание маршрута</h3>
<p>По умолчанию, конфигурационный файл маршрутизатора в приложении Symfony2, располагается в <tt>app/config/routing.yml</tt>. Для конфигурирования маршрутизатора, а также любых прочих конфигураций Symfony2, вы можете также использовать XML или PHP формат:</p>
<ul>
<li><em>YAML</em>

<div class="wp_syntax"><div class="code"><pre class="yaml" style="font-family:monospace;"># app/config/routing.yml
homepage:
    pattern:  /
    defaults: { _controller: FrameworkBundle:Default:index }
&nbsp;
hello:
    resource: &quot;@AcmeStudyBundle/Resources/config/routing.yml&quot;</pre></div></div>

</li>
<li><em>XML</em>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">&lt;!-- app/config/routing.xml --&gt;</span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span></span>
&nbsp;
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;routes</span> <span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://symfony.com/schema/routing&quot;</span></span>
<span style="color: #009900;">    <span style="color: #000066;">xmlns:xsi</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span>
<span style="color: #009900;">    <span style="color: #000066;">xsi:schemaLocation</span>=<span style="color: #ff0000;">&quot;http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
&nbsp;
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;route</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;homepage&quot;</span> <span style="color: #000066;">pattern</span>=<span style="color: #ff0000;">&quot;/&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;default</span> <span style="color: #000066;">key</span>=<span style="color: #ff0000;">&quot;_controller&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>FrameworkBundle:Default:index<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/default<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/route<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;import</span> <span style="color: #000066;">resource</span>=<span style="color: #ff0000;">&quot;@AcmeStudyBundle/Resources/config/routing.xml&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/routes<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

</li>
<li><em>PHP</em>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// app/config/routing.php</span>
<span style="color: #000000; font-weight: bold;">use</span> Symfony\Component\Routing\RouteCollection<span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">use</span> Symfony\Component\Routing\Route<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$collection</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> RouteCollection<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$collection</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">add</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'homepage'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> Route<span style="color: #009900;">&#40;</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;">'_controller'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'FrameworkBundle:Default:index'</span><span style="color: #339933;">,</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: #000088;">$collection</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">addCollection</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$loader</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">import</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;@AcmeStudyBundle/Resources/config/routing.php&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #b1b100;">return</span> <span style="color: #000088;">$collection</span><span style="color: #339933;">;</span></pre></div></div>

</li>
</ul>
<p>Первые строки конфигурации определяют, какой код будет вызван для запроса &#8220;<tt>/</tt>&#8221; (homepage) и служат примером конфигурации маршрута. Последняя часть более интересна &#8211; в ней импортируется другой конфигурационный файл маршрутизатора, который находится внутри <tt>AcmeStudyBundle</tt>:</p>
<ul>
<li><em>YAML</em>

<div class="wp_syntax"><div class="code"><pre class="yaml" style="font-family:monospace;"># src/Acme/StudyBundle/Resources/config/routing.yml
hello:
    pattern:  /hello/{name}
    defaults: { _controller: AcmeStudyBundle:Hello:index }</pre></div></div>

</li>
<li><em>XML</em>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"># src/Acme/StudyBundle/Resources/config/routing.yml
<span style="color: #808080; font-style: italic;">&lt;!-- src/Acme/StudyBundle/Resources/config/routing.xml --&gt;</span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span></span>
&nbsp;
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;routes</span> <span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://symfony.com/schema/routing&quot;</span></span>
<span style="color: #009900;">    <span style="color: #000066;">xmlns:xsi</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span>
<span style="color: #009900;">    <span style="color: #000066;">xsi:schemaLocation</span>=<span style="color: #ff0000;">&quot;http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
&nbsp;
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;route</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;hello&quot;</span> <span style="color: #000066;">pattern</span>=<span style="color: #ff0000;">&quot;/hello/{name}&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;default</span> <span style="color: #000066;">key</span>=<span style="color: #ff0000;">&quot;_controller&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>AcmeStudyBundle:Hello:index<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/default<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/route<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/routes<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

</li>
<li><em>PHP</em>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># src/Acme/StudyBundle/Resources/config/routing.yml
</span><span style="color: #666666; font-style: italic;">// src/Acme/StudyBundle/Resources/config/routing.php</span>
<span style="color: #000000; font-weight: bold;">use</span> Symfony\Component\Routing\RouteCollection<span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">use</span> Symfony\Component\Routing\Route<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$collection</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> RouteCollection<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$collection</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">add</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'hello'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> Route<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/hello/{name}'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
    <span style="color: #0000ff;">'_controller'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'AcmeStudyBundle:Hello:index'</span><span style="color: #339933;">,</span>
<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #b1b100;">return</span> <span style="color: #000088;">$collection</span><span style="color: #339933;">;</span></pre></div></div>

</li>
</ul>
<p>Маршрут состоит из двух основных частей: <tt>шаблон</tt>, с которым сравнивается URI, а также массив <tt>параметров по умолчанию (defaults)</tt>, в котором указывается контроллер, который необходимо выполнить. Синтаксис указателя места заполнения (placeholder) в шаблоне (<tt>{name}</tt>) &#8211; это групповой символ (wildcard). Он означает, что URI <tt>/hello/Ryan</tt>, <tt>/hello/Fabien</tt>, а также прочие, походие на них, будут соответствовать этому маршруту. Параметр, определённый указателем <tt>{name}</tt>, также будет передан в наш контроллер, так что мы сможем использовать его, чтобы поприветствовать пользователя.</p>
<blockquote><p>Система маршрутизации имеет еще множество замечательных функций для создания гибких и функциональных структур URI в нашем приложении. За дополнительной информацией вы можете обратиться по ссылке <a href="http://symfony.com/doc/2.0/book/routing.html" target="_blank"><em>Routing</em></a> (увы, пока без перевода).</p></blockquote>
</div>
<div id="create-the-controller">
<h3>Создание Контроллера</h3>
<p>Когда URI вида <tt>/hello/Ryan</tt> обнаруживается приложением в запросе, маршрут <tt>hello</tt> сработает и будет вызван контроллер <tt>AcmeStudyBundle:Hello:index</tt>. Следующим нашим шагом будет создание этого контроллера. В действительности, контроллер &#8211; это не что иное, как метод PHP класса, который мы создаем, а Symfony выполняет. Это то место, где приложение, используя информацию из запроса, создает запрошенный ресурс. За исключением некоторых особых случаев, результатом работы контроллера всегда является объект Symfony2 <tt>Response</tt>:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// src/Acme/StudyBundle/Controller/HelloController.php</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">namespace</span> Acme\StudyBundle\Controller<span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">use</span> Symfony\Component\HttpFoundation\Response<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> HelloController
<span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> indexAction<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: #b1b100;">return</span> <span style="color: #000000; font-weight: bold;">new</span> Response<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'&lt;html&gt;&lt;body&gt;Hello '</span><span style="color: #339933;">.</span><span style="color: #000088;">$name</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'!&lt;/body&gt;&lt;/html&gt;'</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>Этот контроллер предельно прост: он создает новый объект <tt>Response</tt>, чьим первым аргументом является контент, который будет использован для создания ответа (в нашем случае это маленькая HTML-страница, код которой мы указали прямо в контроллере).<br />
Примите мои поздравления! <img src='http://hudson.su/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> ) После создания маршрута и контроллера, вы уже имеете полноценную страницу! Если вы все настроили корректно, ваше приложение должно поприветствовать вас:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">  http://localhost/app_dev.php/hello/Ryan</pre></div></div>

<p>Опциональным (но как правило востребованным) третьим шагом является создание шаблона.</p>
<blockquote><p>Контроллер &#8211; это главная точка входа для вашего кода и ключевой ингридиет при создании страниц. Больше информации о контроллерах вы можете найти тут: <a href="http://symfony.com/doc/2.0/book/controller.html" target="_blank"><em>Controller Chapter</em></a> (пока также без перевода).</p></blockquote>
</div>
<div id="create-the-template">
<h3>Создание шаблона</h3>
<p>Шаблоны позволяют нам вынести разметку страниц (HTML код как вравило) в отдельный файл и повторно использовать различные части шаблона страницы. Вместо того чтобы писать код внутри контроллера, воспользуемся шаблоном:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// src/Acme/StudyBundle/Controller/HelloController.php</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">namespace</span> Acme\StudyBundle\Controller<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">use</span> Symfony\Bundle\FrameworkBundle\Controller\Controller<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> HelloController <span style="color: #000000; font-weight: bold;">extends</span> Controller
<span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> indexAction<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: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">render</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'AcmeStudyBundle:Hello:index.html.twig'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'name'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$name</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">// render a PHP template instead</span>
        <span style="color: #666666; font-style: italic;">// return $this-&gt;render('AcmeStudyBundle:Hello:index.html.php', array('name' =&gt; $name));</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<blockquote><p>Для того, чтобы использовать метод <tt>render()</tt>, необходимо отнаследоваться от класса <tt><a title="SymfonyBundleFrameworkBundleControllerController" target="_blank" href="http://api.symfony.com/2.0/SymfonyBundleFrameworkBundleControllerController.html">SymfonyBundleFrameworkBundleControllerController</a></tt>, который добавляет несколько методов для быстрого вызова для часто употребляемых функций в контроллере.</p></blockquote>
<p>Метод <tt>render()</tt> создает объект <tt>Response</tt>, заполненный содержанием обработанного (рендереного) шаблона. Как и любой другой контроллер, вы в конце концов вернете объект <tt>Response</tt>.<br />
Обратите внимание, что есть две различные возможности рендеринга шаблонов. Symfony2 по-умолчанию, поддерживает 2 языка шаблонов: классические PHP-шаблоны и простой, но мощный язык шаблонов <a href="http://www.twig-project.org/" target="_blank">Twig</a>. Но не пугайтесь, вы свободны в выборе того или иного из них, кроме того вы можете использовать оба в рамках одного проекта.<br />
Контроллер отображает шаблон <tt>AcmeStudyBundle:Hello:index.html.twig</tt>, который использует следующие соглашения: <em>BundleName</em>:<em>ControllerName</em>:<em>TemplateName</em><br />
Таким образом, <tt>AcmeStudyBundle</tt> &#8211; это имя пакета, <tt>Hello</tt> &#8211; это контроллер и <tt>index.html.twig</tt> это шаблон:</p>
<ul>
<li><em>Twig</em>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code"><pre class="html" style="font-family:monospace;">{# src/Acme/StudyBundle/Resources/views/Hello/index.html.twig #}
{% extends '::layout.html.twig' %}
&nbsp;
{% block body %}
    Hello {{ name }}!
{% endblock %}</pre></td></tr></table></div>

</li>
<li><em>PHP</em>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">&lt;!-- src/Acme/StudyBundle/Resources/views/Hello/index.html.php --&gt;
<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #000088;">$view</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">extend</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'::layout.html.php'</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
&nbsp;
Hello <span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$view</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">escape</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$name</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>!</pre></div></div>

</li>
</ul>
<p>Давайте рассмотрим подробнее шаблон Twig:</p>
<ul>
<li><em>строка 2</em>: Токен <tt>extends</tt> определяет родительский шаблон. Таким образом сам шаблон однозначным<br />
      образом определяет родителя (layout) внутрь которого он будет помещен.
    </li>
<li><em>строка 4</em>: Токен <tt>block</tt> означает, что все внутри него будет помещено в блок с именем <tt>body</tt>.<br />
      Как мы увидим ниже, это уже обязанность родительского шаблона (<tt>layout.html.twig</tt>) &#8211; полностью отобразить блок <tt>body</tt>.
    </li>
</ul>
<p>Родительский шаблон, <tt>::layout.html.twig</tt>, не включает в себя ни имени пакета, ни контроллера (отсюда и двойное двоеточие в начале имени (<tt>::</tt>)). Это означает что шаблон располагается вне пакета в директории <tt>app</tt>:</p>
<ul>
<li><em>Twig</em>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">{# app/Resources/views/layout.html.twig #}
&lt;!DOCTYPE html&gt;
&lt;html&gt;
    &lt;head&gt;
        &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;
        &lt;title&gt;{% block title %}Hello Application{% endblock %}&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
        {% block body %}{% endblock %}
    &lt;/body&gt;
&lt;/html&gt;</pre></div></div>

</li>
<li><em>PHP</em>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">&lt;!-- app/Resources/views/layout.html.php --&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
    &lt;head&gt;
        &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;
        &lt;title&gt;<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #000088;">$view</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'slots'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">output</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'title'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'Hello Application'</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
        <span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #000088;">$view</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'slots'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">output</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'_content'</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
    &lt;/body&gt;
&lt;/html&gt;</pre></div></div>

</li>
</ul>
<p>Базовый шаблон определяет HTML разметку блока <tt>body</tt>, который мы определили в шаблоне <tt>index.html.twig</tt>.<br />
Он также отображает блок <tt>title</tt>, который мы также можем определить в <tt>index.html.twig</tt>. Так как мы не определили блок <tt>title</tt> в дочернем шаблоне, он примет значение по умолчанию &#8211; &#8220;Hello Application&#8221;.<br />
Шаблоны являются мощным инструментом по организации и отображению контента ваших страниц &#8211; HTML разметки, CSS стилей, а также всего прочего, что может потребоваться вернуть контроллеру. Но шаблонизатор &#8211; это просто средство для достижения цели. А цель состоит в том, чтобы каждый контроллер возвращал объект <tt>Response</tt>. Таким образом, шаблоны мощный, но опциональный инструмент для создания контента для объекта <tt>Response</tt>.
</div>
<div id="the-directory-structure">
<h2>Структура директорий</h2>
<p>Мы прочитали всего лишь после нескольких коротких секций, а вы уже уяснили (ведь уяснили же?! правда? <img src='http://hudson.su/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> ) философию создания и отображения страниц в Symfony2. Поэтому без лишних слов мы приступим к изучению того, как организованы и структурированы проекты Symfony2. К концу этой секции вы будете знать где найти и куда поместить различные типы файлов. И более того, будет понимать &#8211; почему! )<br />
Изначально созданный очень гибким, по умолчанию каждое Symfony <a href="http://hudson.su/?p=1863#term-application" target="_blank"><em>приложение</em></a> имеет одну и ту же базовую (и рекомендуемую) структуру директорий:</p>
<ul>
<li><tt>app/</tt>: Эта директория содержит настройки приложения;</li>
<li><tt>src/</tt>: Весь PHP код проекта находится в этой директории;</li>
<li><tt>vendor/</tt>: Здесь размещаются сторонние библиотеки;</li>
<li><tt>web/</tt>: Это корневая директория, видимая web-серверу и содержащая доступные пользователям файлы;</li>
</ul>
<div id="the-web-directory">
<h3>Директория Web</h3>
<p>Web-директория &#8211; это дом для всех публично-доступных статических файлов, таких как изображения, таблицы стилей и JavaScript файлы. Тут также располагаются все <a href="http://hudson.su/?p=1863#term-front-controller" target="_blank"><em>фронт-контроллеры</em></a>:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// web/app.php</span>
<span style="color: #b1b100;">require_once</span> __DIR__<span style="color: #339933;">.</span><span style="color: #0000ff;">'/../app/bootstrap.php'</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">require_once</span> __DIR__<span style="color: #339933;">.</span><span style="color: #0000ff;">'/../app/AppKernel.php'</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">use</span> Symfony\Component\HttpFoundation\Request<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$kernel</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> AppKernel<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'prod'</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$kernel</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">handle</span><span style="color: #009900;">&#40;</span>Request<span style="color: #339933;">::</span><span style="color: #004000;">createFromGlobals</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;">send</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Файл фронт-контроллера (в примере выше &#8211; <tt>app.php</tt>)- это PHP файл, который выполняется, когда используется Symfony2 приложение и в его обязанности входит использование Kernel-класса, <tt>AppKernel</tt>, для запуска приложения.</p>
<blockquote><p>Наличие фронт-контроллера означает возможность использования более гибких URL, отличных от тех, что используются в типичном &#8220;плоском&#8221; PHP-приложении. Когда используется фронт-контроллер, URL формируется следующим образом:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">    http://localhost/app.php/hello/Ryan</pre></div></div>

<p>Фронт-контроллер <tt>app.php</tt> выполняется и URI <tt>/hello/Ryan</tt> направляется внутри приложения с использованием конфигурации маршрутизатора. С использованием правил <tt>mod_rewrite</tt> для Apache вы можете перенаправлять все запросы (на физически не существующие URI) на <tt>app.php</tt>, чтобы явно не указывать его в URL:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">  http://localhost/hello/Ryan</pre></div></div>

</blockquote>
<p>Хотя фронт-контроллеры имеют важное значение при обработке каждого запроса,вам нечасто придется модифицировать их или вообще вспоминать об их существовании. Мы еще вкратце упомянем о них в разделе, где говорится об <a href="#environments">Окружениях</a>.
  </div>
<div id="the-application-app-directory">
<h3>Директория приложения</h3>
<p>Как вы уже видели во фронт-контроллере, класс <tt>AppKernel</tt> &#8211; это точка входа приложения и он отвечает за его конфигурацию. Как таковой, этот класс расположен в директории <tt>app/</tt>. Этот класс должен реализовывать три метода, которые определяются все, что Symfony необходимо знать о вашем приложении. Вам даже не нужно беспокоиться о реализации этих методов, когда начинаете работу &#8211; они уже реализованы с кодом по-умолчанию.</p>
<ul>
<li>
        <tt>registerBundles()</tt>: Возвращает массив всех пакетов, необходимых для запуска приложения (см. секцию <a href="#the-bundle-system">Пакетная система</a>);
      </li>
<li>
        <tt>registerContainerConfiguration()</tt>: Загружает главный конфигурационный файл (см. секцию<br />
        <a href="#application-configuration">Конфигурация приложения</a>);
      </li>
<li>
        <tt>registerRootDir()</tt>: Возвращает корневую директорию приложения (<tt>app/</tt> по умолчанию).
      </li>
</ul>
<p>Изо дня в день вы будете использовать директорию <tt>app/</tt> в основном для того, чтобы модифицировать конфигурацию и настройки маршрутизатора в директории <tt>app/config/</tt> (см. <a href="#application-configuration">Конфигурация приложения</a>).<br />
Также в <tt>app/</tt> содержится кеш (<tt>app/cache</tt>), директория для логов (<tt>app/logs</tt>) и директория для ресурсов уровня приложения (<tt>app/Resources</tt>). Об этих директориях подробнее будет рассказано в других главах.</p>
<blockquote>
<div id="autoloading-introduction-sidebar">
<b>Автозагрузка</b><br />
При инициализации приложения подключается особый файл: <tt>app/autoload.php</tt>. Этот файл отвечает за автозагрузку всех файлов из директорий <tt>src/</tt> и <tt>vendor/</tt>.<br />
С использованием автозагрузки вам больше не придется беспокоиться об использовании выражений <tt>include</tt> или <tt>require</tt>. Вместо этого, Symfony2 использует пространства имен классов, чтобы определить их расположение и автоматически подключить файл класса, в случае если класс вам понадобится:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$loader</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">registerNamespaces</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
  <span style="color: #0000ff;">'Acme'</span>                         <span style="color: #339933;">=&gt;</span> __DIR__<span style="color: #339933;">.</span><span style="color: #0000ff;">'/../src'</span><span style="color: #339933;">,</span>
  <span style="color: #666666; font-style: italic;">// ...</span>
<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>При такой конфигурации, Symfony2 будет искать в директории <tt>src</tt> классы из пространства имен <tt>Acme</tt> (вы скорее всего будете использовать наименование вашей компании). Для того чтобы эта парадигма работала, необходимо чтобы имя класса и путь к нему соответствовали следующему шаблону:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">Class Name:
  Acme\StudyBundle\Controller\HelloController
Path:
  src/Acme/StudyBundle/Controller/HelloController.php</pre></div></div>

<p>Файл <tt>app/autoload.php</tt> конфигурирует автозагрузчик и указывает ему, где искать классы из различных пространств имен и при необходимости может быть гибко настроен. Если вы хотите узнать больше об автозагрузке, смотрите статью в &#8220;поваренной книге&#8221; (без перевода): <a href="http://symfony.com/doc/2.0/cookbook/tools/autoloader.html" target="_blank"><em>How to autoload Classes</em></a>.
</div>
</blockquote></div>
<div id="the-source-src-directory">
<h3>Директория исходных кодов проекта (<tt>src</tt>)</h3>
<p>Если вкратце, директория <tt>src/</tt> содержит весь код приложения. Фактически, во время разработки, большую часть работ вы будете производить именно в этой директории. По умолчанию, директория <tt>src/</tt> нового проекта пуста. Когда вы начинаете разработку, вы постепенно наполняете ее <em>пакетами</em>, которые содержат код приложения.<br />
Но что же собственно из себя представляет сам <a href="http://hudson.su/?p=1863#term-bundle" target="_blank"><em>пакет</em></a>?
  </div>
</div>
<div id="the-bundle-system">
<h2 id="page-creation-bundles">Система пакетов</h2>
<p>Пакет чем-то схож с плагином, но он ещё лучше. Ключевое отличие состоит в том, что <em>всё</em> есть пакет в Symfony2, включая функционал ядра и код вашего приложения.<br />
Пакеты – это граждане высшего сорта в Symfony2. Они дают вам возможность использовать уже готовые пакеты, которые вы можете найти по адресу <a href="http://symfony2bundles.org/" target="_blank">symfony2bundles.org</a>. Вы также можете там выкладывать свои пакеты. Они также дают возможность легко и просто выбрать, какие именно функции подключить в вашем приложении.</p>
<blockquote><p>Здесь мы рассмотрим лишь основы, более детальную информацию по пакетам вы можете найти в главе <a href="http://symfony.com/doc/2.0/book/bundles.html" target="_blank"><em>Пакеты</em></a>.</p></blockquote>
<p>Пакет это просто структурированный набор файлов и директорий, который реализует одну конкретную функцию. Вы можете создать BlogBundle или ForumBundle или же пакет для управления пользователями (такие пакеты уже есть и даже с открытым исходным кодом). Каждая директория содержит все необходимое для реализации этой конкретной функции, включая PHP файлы, шаблоны, стили, клиентские скрипты, тесты и все что ещё потребуется. Каждый аспект реализации функции находится в своём пакете и каждая функция располагается в своем собственном пакете.<br />
Приложение состоит из пакетов, которые объявлены в методе <tt>registerBundles()</tt> класса <tt>AppKernel</tt>.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// app/AppKernel.php</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> registerBundles<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$bundles</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #000000; font-weight: bold;">new</span> Symfony\Bundle\FrameworkBundle\FrameworkBundle<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
        <span style="color: #000000; font-weight: bold;">new</span> Symfony\Bundle\SecurityBundle\SecurityBundle<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
        <span style="color: #000000; font-weight: bold;">new</span> Symfony\Bundle\TwigBundle\TwigBundle<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
        <span style="color: #000000; font-weight: bold;">new</span> Symfony\Bundle\MonologBundle\MonologBundle<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
        <span style="color: #000000; font-weight: bold;">new</span> Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
        <span style="color: #000000; font-weight: bold;">new</span> Symfony\Bundle\DoctrineBundle\DoctrineBundle<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
        <span style="color: #000000; font-weight: bold;">new</span> Symfony\Bundle\AsseticBundle\AsseticBundle<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
        <span style="color: #000000; font-weight: bold;">new</span> Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
        <span style="color: #000000; font-weight: bold;">new</span> JMS\SecurityExtraBundle\JMSSecurityExtraBundle<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;">// register your bundles</span>
        <span style="color: #000000; font-weight: bold;">new</span> Acme\StudyBundle\AcmeStudyBundle<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</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: #990000;">in_array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getEnvironment</span><span style="color: #009900;">&#40;</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;">'dev'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'test'</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;">$bundles</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Symfony\Bundle\WebProfilerBundle\WebProfilerBundle<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: #b1b100;">return</span> <span style="color: #000088;">$bundles</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Используя метод <tt>registerBundles()</tt>, вы получаете полный контроль над теми пакетами, которые используются вашим приложением (включая пакеты, входящие в состав ядра Symfony).</p>
<blockquote><p>Вообще говоря, пакет может располагаться <em>где угодно</em>, если конечно его расположение не мешает автозагрузчику Symfony2. Например, если <tt>AcmeStudyBundle</tt> расположен в директории <tt>src/Acme</tt>, озаботьтесь тем, чтобы пространство имён <tt>Acme</tt> было добавлено в файл <tt>app/autoload.php</tt> и было направлено (mapped) на директорию <tt>src</tt>.</p></blockquote>
<div id="creating-a-bundle">
<h3>Создание пакета</h3>
<p>Чтобы показать вам как проста система пакетов, давайте создадим новый пакет, назовём его <tt>AcmeTestBundle</tt> и активируем его.<br />
В первую очередь, создадим директорию <tt>src/Acme/TestBundle/</tt> и добавим в неё файл <tt>AcmeTestBundle.php</tt>:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// src/Acme/TestBundle/AcmeTestBundle.php</span>
<span style="color: #000000; font-weight: bold;">namespace</span> Acme\TestBundle<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">use</span> Symfony\Component\HttpKernel\Bundle\Bundle<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> AcmeTestBundle <span style="color: #000000; font-weight: bold;">extends</span> Bundle
<span style="color: #009900;">&#123;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<blockquote><p>Наименование <tt>AcmeTestBundle</tt> следует <a href="http://symfony.com/doc/2.0/book/bundles.html#bundles-naming-conventions" target="_blank"><em>соглашениям по именованию пакетов </em></a>.</p></blockquote>
<p>Этот пустой класс – единственное, что необходимо создать для минимальной комплектации пакета. Не смотря на то, что класс пуст, он обладает большим потенциалом и позволяет настраивать поведение пакета.<br />
Теперь, когда мы создали пакет, его нужно активировать в классе <tt>AppKernel</tt>:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// app/AppKernel.php</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> registerBundles<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$bundles</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #666666; font-style: italic;">// ...</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">// register your bundles</span>
        <span style="color: #000000; font-weight: bold;">new</span> Acme\TestBundle\AcmeTestBundle<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// ...</span>
&nbsp;
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$bundles</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>И, хотя наш новый пакет пока ничего не делает, он готов к использованию. Symfony также предлагает интерфейс для командной строки для создания базового каркаса пакета:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">php app/console init:bundle &quot;Acme\TestBundle&quot; src</pre></div></div>

<p>Каркас пакета создаёт базовый контроллер, шаблон и маршрут, которые можно настроить. Мы еще вернёмся к инструментам командной строки позже.</p>
<blockquote><p>
Когда создаёте новый пакет, или используете сторонние пакеты, убедитесь, что пакет активирован в <tt>registerBundles()</tt>.
</p></blockquote></div>
<div id="bundle-directory-structure">
<h3>Структура директории пакета</h3>
<p>Структура директории пакета проста и гибка. По умолчанию, система пакетов следует некоторым соглашениям, которые помогают поддерживать стилевое единообразие во всех пакетах Symfony2. Давайте взглянем на пакет <tt>AcmeStudyoverBundle</tt>, так как он содержит наиболее основные элементы пакета:</p>
<ul>
<li><em>Controller/</em> содержит контроллеры (например <tt>HelloController.php</tt>);</li>
<li><em>Resources/config/</em> место для конфигурационных файлов, включая конфигурацию маршрутизатора (например <tt>routing.yml</tt>);</li>
<li><em>Resources/views/</em> шаблоны, сгруппированные по имени контроллера (например <tt>Hello/index.html.twig</tt>);</li>
<li><em>Resources/public/</em> публично доступные ресурсы (картинки, стили&#8230;), которые будут скопированы или связаны символической ссылкой с <tt>web/</tt> директорией; </li>
<li><em>Tests/</em> содержит все тесты.</li>
</ul>
<p>Пакет может быть как маленьким, так и большим – в зависимости от задачи, которую он реализует. Он содержит лишь те файлы, которые нужны – и ничего более.<br />
В других главах книги вы также узнаете как работать с базой данных, как создавать и валидировать формы, создавать файлы переводов, писать тесты и много чего ещё. Все эти объекты в пакете имеют определенную роль и место.
  </p></div>
</div>
<div id="application-configuration">
<h2>Настройка приложения</h2>
<p>Приложение состоит из набора пакетов, реализующих все необходимые функции вашего приложения. Каждый пакет может быть настроен при помощи конфигурационных файлов, написанных на YAML, XML или PHP. По умолчанию, основной конфигурационный файл расположен в директории <tt>app/config/</tt> и называется <tt>config.yml</tt>, <tt>config.xml</tt> или <tt>config.php</tt>, в зависимости от предпочитаемого вами формата.</p>
<ul>
<li><em>YAML</em>

<div class="wp_syntax"><div class="code"><pre class="yaml" style="font-family:monospace;"># app/config/config.yml
framework:
    charset:       UTF-8
    error_handler: null
    csrf_protection:
        enabled: true
        secret: xxxxxxxxxx
    router:        { resource: &quot;%kernel.root_dir%/config/routing.yml&quot; }
    validation:    { enabled: true, annotations: true }
    templating:    { engines: ['twig'] } #assets_version: SomeVersionScheme
    session:
        default_locale: en
        lifetime:       3600
        auto_start:     true
&nbsp;
# Twig Configuration
twig:
    debug:            %kernel.debug%
    strict_variables: %kernel.debug%</pre></div></div>

</li>
<li><em>XML</em>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">&lt;!-- app/config/config.xml --&gt;</span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;framework:config</span> <span style="color: #000066;">charset</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span> <span style="color: #000066;">error-handler</span>=<span style="color: #ff0000;">&quot;null&quot;</span> <span style="color: #000066;">cache-warmer</span>=<span style="color: #ff0000;">&quot;false&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;framework:router</span> <span style="color: #000066;">resource</span>=<span style="color: #ff0000;">&quot;%kernel.root_dir%/config/routing.xml&quot;</span> <span style="color: #000066;">cache-warmer</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;framework:validation</span> <span style="color: #000066;">enabled</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">annotations</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;framework:session</span> <span style="color: #000066;">default-locale</span>=<span style="color: #ff0000;">&quot;en&quot;</span> <span style="color: #000066;">lifetime</span>=<span style="color: #ff0000;">&quot;3600&quot;</span> <span style="color: #000066;">auto-start</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;framework:templating</span> <span style="color: #000066;">assets-version</span>=<span style="color: #ff0000;">&quot;SomeVersionScheme&quot;</span> <span style="color: #000066;">cache-warmer</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;framework:engine</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;twig&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/framework:templating<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;framework:csrf-protection</span> <span style="color: #000066;">enabled</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">secret</span>=<span style="color: #ff0000;">&quot;xxxxxxxxxx&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/framework:config<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
<span style="color: #808080; font-style: italic;">&lt;!-- Twig Configuration --&gt;</span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;twig:config</span> <span style="color: #000066;">debug</span>=<span style="color: #ff0000;">&quot;%kernel.debug%&quot;</span> <span style="color: #000066;">strict-variables</span>=<span style="color: #ff0000;">&quot;%kernel.debug%&quot;</span> <span style="color: #000066;">cache-warmer</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span></pre></div></div>

</li>
<li><em>PHP</em>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">$container-&gt;loadFromExtension('framework', array(
    'charset'         =&gt; 'UTF-8',
    'error_handler'   =&gt; null,
    'csrf-protection' =&gt; array('enabled' =&gt; true, 'secret' =&gt; 'xxxxxxxxxx'),
    'router'          =&gt; array('resource' =&gt; '%kernel.root_dir%/config/routing.php'),
    'validation'      =&gt; array('enabled' =&gt; true, 'annotations' =&gt; true),
    'templating'      =&gt; array(
        'engines' =&gt; array('twig'),
        #'assets_version' =&gt; &quot;SomeVersionScheme&quot;,
    ),
    'session' =&gt; array(
        'default_locale' =&gt; &quot;en&quot;,
        'lifetime'       =&gt; &quot;3600&quot;,
        'auto_start'     =&gt; true,
    ),
));
&nbsp;
// Twig Configuration
$container-&gt;loadFromExtension('twig', array(
    'debug'            =&gt; '%kernel.debug%',
    'strict_variables' =&gt; '%kernel.debug%',
));</pre></div></div>

</li>
</ul>
<blockquote><p>О том как выбрать какой файл/формат загружать – мы рассмотрим в следующей секции &#8211; <a href=" #environments">Окружения</a>.</p></blockquote>
<p>Каждый параметр верхнего уровня, например <tt>framework</tt> или <tt>twig</tt>, определяет настройки конкретного пакета. Например, ключ <tt>framework</tt> определяет настройки ядра Symfony <tt>FrameworkBundle</tt> и включает настройки маршрутизации, шаблонизатора и прочих ключевых систем.<br />
Пока же нам не стоит беспокоиться о конкретных настройках в каждой секции. Файл настроек по умолчанию содержит все необходимые параметры. По ходу чтения прочей документации вы ознакомитесь со всеми специфическими настройками.</p>
<blockquote><p>
<b>Форматы конфигураций</b><br />
Во всех главах книги все примеры конфигураций будут показаны во всех трех форматах (YAML, XML and PHP). Каждый из них имеет свои достоинства и недостатки. Выбор же формата целиком зависит о ваших предпочтений:</p>
<ul>
<li><em>YAML</em>: Простой, понятный и читабльный;</li>
<li><em>XML</em>: В разы более мощный, нежели YAML. Поддерживается многими IDE (autocompletion;</li>
<li><em>PHP</em>: Очень мощный, но менее читабельный, чем стандартные форматы конфигурационных файлов.</li>
</ul>
</blockquote>
</div>
<div id="environments">
<h2>Окружения</h2>
<p>Приложение можно запускать в различных окружениях. Различные окружения используют один и тот же PHP код (за исключением фронт-контроллера), но могут иметь совершенно различные настройки. Например, <tt>dev</tt> окружение ведет лог ошибок и замечаний, в то время как <tt>prod</tt> окружение логгирует только ошибки. В <tt>dev</tt> некоторые файлы пересоздаются при каждом запросе, но кешируются в <tt>prod</tt> окружении. В то же время, все окружения одновременно доступны на одной и той же машине.<br />
Проект Symfony2 по умолчанию имеет три окружения (<tt>dev</tt>, <tt>test</tt> и <tt>prod</tt>), хотя создать новое окружение не сложно. Вы можете смотреть ваше приложение в различных окружениях просто меняя фронт-контроллеры в браузере. Для того чтобы отобразить приложение в <tt>dev</tt> окружении, откройте его при помощи фронт контроллера app_dev.php:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">  http://localhost/app_dev.php/hello/Ryan</pre></div></div>

<p>Если же вы хотите посмотреть, как поведёт себя приложение в продуктовой среде, вы можете вызвать фронт-контроллер <tt>prod</tt>:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">  http://localhost/app.php/hello/Ryan</pre></div></div>

<blockquote><p>
  Если вы откроете файл <tt>web/app.php</tt>, вы обнаружите, что он однозначно настроен на использование <tt>prod</tt> окружения:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">$kernel = new AppCache(new AppKernel('prod', false));</pre></div></div>

<p>  Вы можете создать новый фронт-контроллер для нового окружения просто скопировав этот файл и изменив <tt>prod</tt> на другое значение.
</p></blockquote>
<p>Так как <tt>prod</tt> окружение оптимизировано для скорости, настройки, маршруты и шаблоны Twig компилируются в плоские PHP классы и кешируются. Когда вы хотите посмотреть изменения в продуктовом окружении, вам потребуется удалить эти файлы чтобы они пересоздались автоматически:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">  rm -rf app/cache/*</pre></div></div>

<blockquote><p>
Тестовое окружение (<tt>test</tt>) используется при запуске автотестов и его нельзя напрямую открыть через браузер. Подробнее об это можно почитать в <a href="http://symfony.com/doc/2.0/book/testing.html" target="_blank"><em>главе про тестирование</em></a>.
</p></blockquote>
<div id="environment-configuration">
<h3>Настройка окружений</h3>
<p>Класс <tt>AppKernel</tt> отвечает за загрузку конфигурационных файлов:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// app/AppKernel.php</span>
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> registerContainerConfiguration<span style="color: #009900;">&#40;</span>LoaderInterface <span style="color: #000088;">$loader</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$loader</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">load</span><span style="color: #009900;">&#40;</span>__DIR__<span style="color: #339933;">.</span><span style="color: #0000ff;">'/config/config_'</span><span style="color: #339933;">.</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getEnvironment</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'.yml'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Мы уже знаем, что расширение <tt>.yml</tt> может быть изменено на <tt>.xml</tt> или <tt>.php</tt>, если вы предпочитаете использовать XML или PHP. Имейте также в виду, что каждое окружение загружает свои собственные настройки. Рассмотрим конфигурационный файл для <tt>dev</tt> окружения.</p>
<ul>
<li><em>YAML</em>

<div class="wp_syntax"><div class="code"><pre class="yaml" style="font-family:monospace;"># app/config/config_dev.yml
imports:
    - { resource: config.yml }
&nbsp;
framework:
    router:   { resource: &quot;%kernel.root_dir%/config/routing_dev.yml&quot; }
    profiler: { only_exceptions: false }
&nbsp;
web_profiler:
    toolbar: true
    intercept_redirects: true
&nbsp;
zend:
    logger:
        priority: debug
        path:     %kernel.logs_dir%/%kernel.environment%.log</pre></div></div>

</li>
<li><em>XML</em>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">&lt;!-- app/config/config_dev.xml --&gt;</span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;imports<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;import</span> <span style="color: #000066;">resource</span>=<span style="color: #ff0000;">&quot;config.xml&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/imports<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;framework:config<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;framework:router</span> <span style="color: #000066;">resource</span>=<span style="color: #ff0000;">&quot;%kernel.root_dir%/config/routing_dev.xml&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;framework:profiler</span> <span style="color: #000066;">only-exceptions</span>=<span style="color: #ff0000;">&quot;false&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/framework:config<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;webprofiler:config</span></span>
<span style="color: #009900;">    <span style="color: #000066;">toolbar</span>=<span style="color: #ff0000;">&quot;true&quot;</span></span>
<span style="color: #009900;">    <span style="color: #000066;">intercept-redirects</span>=<span style="color: #ff0000;">&quot;true&quot;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
&nbsp;
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;zend:config<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;zend:logger</span> <span style="color: #000066;">priority</span>=<span style="color: #ff0000;">&quot;info&quot;</span> <span style="color: #000066;">path</span>=<span style="color: #ff0000;">&quot;%kernel.logs_dir%/%kernel.environment%.log&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/zend:config<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

</li>
<li><em>PHP</em>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// app/config/config_dev.php</span>
<span style="color: #000088;">$loader</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">import</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'config.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$container</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">loadFromExtension</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'framework'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
    <span style="color: #0000ff;">'router'</span>   <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'resource'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'%kernel.root_dir%/config/routing_dev.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    <span style="color: #0000ff;">'profiler'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'only-exceptions'</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: #339933;">,</span>
<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$container</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">loadFromExtension</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'web_profiler'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
    <span style="color: #0000ff;">'toolbar'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #339933;">,</span>
    <span style="color: #0000ff;">'intercept-redirects'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #339933;">,</span>
<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$container</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">loadFromExtension</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'zend'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
    <span style="color: #0000ff;">'logger'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'priority'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'info'</span><span style="color: #339933;">,</span>
        <span style="color: #0000ff;">'path'</span>     <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'%kernel.logs_dir%/%kernel.environment%.log'</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

</li>
</ul>
<p>Ключ <tt>imports</tt> похож по действию на выражение <tt>include</tt> в PHP и гарантирует что главный конфигурационный файл (<tt>config.yml</tt>) будет загружен в первую очередь. Остальной код корректирует конфигурацию по-умолчанию для увеличения порога логгирования и прочих настроек, специфичных для разработки.<br />
Оба окружения &#8211; <tt>prod</tt> и <tt>test</tt> следуют той же модели: каждое окружение импортирует базовые настройки и модифицирует их значения для своих нужд.
  </div>
</div>
<div id="summary">
<h2>Заключение</h2>
<p>Поздравляем! Вы усвоили все фундаментальные аспекты Symfony2 и обнаружили, какими лёгкими и в то же время гибкими они могут быть. И, поскольку на подходе ещё <em>много</em> интересного, обязательно запомните следующие положения:</p>
<ul>
<li>создание страниц – это три простых шага, включающих <strong>маршрут</strong>, <strong>контроллер</strong> и (опционально) <strong>шаблон</strong>;</li>
<li>Каждое приложение должно состоять только из 4х директорий: <strong>web/</strong> (ассеты и фронт-контроллеры), <strong>app/</strong> (настройки), <strong>src/</strong> (пакеты), и <strong>vendor/</strong> (сторонние библиотеки);</li>
<li>Каждая функция в Symfony2 (включая ядро фреймворка) должна располагаться внутри <em>пакета</em>, который представляет собой структурированный набор файлов, реализующих эту функцию;</li>
<li><strong>настройки</strong> каждого пакета располагаются в директории <tt>app/config</tt> и могут быть записаны в формате YAML, XML or PHP;</li>
<li>каждое <strong>окружение</strong> доступно через свой отдельный фронт-контроллер (например <tt>app.php</tt> и <tt>app_dev.php</tt>) и заружает отдельный файл настроек;</li>
</ul>
<p>Далее, каждая глава книги познакомит вас с все более и более мощными инструментами и более глубокими концепциями. Чем больше вы знаете о Symfony2, тем больше вы будете ценить гибкость его архитектуры и его обширные возможности для быстрой разработки приложений.
</p></div>
]]></content:encoded>
			<wfw:commentRss>http://hudson.su/2011/04/28/symfony2-book-the-basics-of-page-creation/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Symfony 2: конфигурирование пакетов</title>
		<link>http://hudson.su/2011/02/18/symfony-2-bundle-configuration/</link>
		<comments>http://hudson.su/2011/02/18/symfony-2-bundle-configuration/#comments</comments>
		<pubDate>Fri, 18 Feb 2011 08:27:05 +0000</pubDate>
		<dc:creator>hudson</dc:creator>
				<category><![CDATA[Профессиональное]]></category>
		<category><![CDATA[bundles]]></category>
		<category><![CDATA[symfony]]></category>
		<category><![CDATA[Symfony2]]></category>
		<category><![CDATA[web разработка]]></category>

		<guid isPermaLink="false">http://hudson.su/?p=1770</guid>
		<description><![CDATA[Для обеспечения большей гибкости, пакет (bundle) может содержать ряд конфигурационных настроек, используя встроенный механизм Symfony2. Простая конфигурация Для простой конфигурации можно воспользоваться разделом parameters, по-умолчанию присутствующим в конфигурации Symfony2. Параметры &#8211; это простые пары ключ-значение; значением может быть любое валидное значение с точки зрения PHP. Каждое наименование параметра должно начинаться с наименования пакета в нижнем [...]]]></description>
			<content:encoded><![CDATA[<p>Для обеспечения большей гибкости, пакет (bundle) может содержать ряд конфигурационных настроек, используя встроенный механизм Symfony2.</p>
<div>
<h2>Простая конфигурация</h2>
<p>Для простой конфигурации можно воспользоваться разделом <tt>parameters</tt>, по-умолчанию присутствующим в конфигурации Symfony2. Параметры &#8211; это простые пары ключ-значение; значением может быть любое валидное значение с точки зрения PHP. Каждое наименование параметра должно начинаться с наименования пакета в нижнем регистре (<tt>hello</tt> для <tt>HelloBundle</tt>, или <tt>sensio.social.blog</tt> для <tt>SensioSocialBlogBundle</tt>).</p>
<p><span id="more-1770"></span>Пользователь может задавать значения в любом конфигурационном файле:</p>
<div>
<ul>
<li><em>YAML</em>
<pre># app/config/config.yml
parameters:
    hello.email.from: fabien@example.com</pre>
</li>
<li><em>XML</em>
<pre>&lt;!-- app/config/config.xml --&gt;
&lt;parameters&gt;
    &lt;parameter key="hello.email.from"&gt;fabien@example.com&lt;/parameter&gt;
&lt;/parameters&gt;</pre>
</li>
<li><em>PHP</em>
<pre>// app/config/config.php
$container-&gt;setParameter('hello.email.from', 'fabien@example.com');</pre>
</li>
<li><em>INI</em>
<pre>[parameters]
hello.email.from = fabien@example.com</pre>
</li>
</ul>
</div>
<p>Получить параметры в коде можно из контейнера:</p>
<pre>$container-&gt;getParameter('hello.email.from');</pre>
<p>Не смотря на то, что этот механизм является достаточно простым, <strong>настоятельно рекомендуется</strong> использовать семантические конфигурации описанные ниже.</p>
</div>
<div>
<h2>Семантическая конфигурация</h2>
<p>Семантическая конфигурация имеет бОльшую гибкость в конфигурировании пакетов и превосходит простые параметры по следующим показателям:</p>
<ul>
<li>Возможность определить больше чем просто параметры (например сервисы);</li>
<li>Лучшая иерархия в конфигурации (вы можете определять вложенные конфигурации);</li>
<li>&#8220;Умные&#8221; слияния (merging), когда несколько файлов конфигурации переопределяют существующую конфигурацию;</li>
<li>Валидация конфигурации (если вы определите XSD файл и используете XML);</li>
<li>Завершение при использовании XSD и XML (<span style="color: #808080"><em>прим. пер: видимо тут имеется в виду автозавершение в IDE на основе XSD структуры XML</em></span>)</li>
</ul>
<div>
<h3>Создание расширения (Extension)</h3>
<p>Для того чтобы использовать семантическую конфигурацию, создайте расширение Dependency Injection, которое наследуется от <tt>Extension</tt>:</p>
<pre>// HelloBundle/DependencyInjection/HelloExtension.php
use SymfonyComponentDependencyInjectionExtensionExtension;

class HelloExtension extends Extension
{
    public function configLoad($config, ContainerBuilder $container)
    {
        // ...
    }

    public function getXsdValidationBasePath()
    {
        return __DIR__.'/../Resources/config/';
    }

    public function getNamespace()
    {
        return 'http://www.example.com/symfony/schema/';
    }

    public function getAlias()
    {
        return 'hello';
    }
}</pre>
<p>Класс, описанный выше определяет пространство имен <tt>hello:config</tt>, доступное в любом конфигурационном файле:</p>
<div>
<ul>
<li><em>YAML</em>
<pre># app/config/config.yml
hello.config: ~</pre>
</li>
<li><em>XML</em>
<pre>&lt;!-- app/config/config.xml --&gt;
&lt;?xml version="1.0" ?&gt;

&lt;container xmlns="http://www.symfony-project.org/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:hello="http://www.example.com/symfony/schema/"
    xsi:schemaLocation="http://www.example.com/symfony/schema/ http://www.example.com/symfony/schema/hello-1.0.xsd"&gt;

   &lt;hello:config /&gt;
   ...

&lt;/container&gt;</pre>
</li>
<li><em>PHP</em>
<pre>// app/config/config.php
$container-&gt;loadFromExtension('hello', 'config', array());</pre>
</li>
</ul>
</div>
<div>Замечание: вы можете создать столько методов <tt>xxxLoad()</tt>, сколько хотите определить конфигурационных блоков для вашего расширения.</div>
</div>
<div>
<h3>Разбор конфигурации</h3>
<p>Всякий раз, когда пользователь включает пространство имен <tt>hello.config</tt><tt> </tt>в конфигурационный файл, вызывается метод <tt>configLoad()</tt> вашего расширения и конфигурация передается в виде массива (Symfony2 автоматически конвертирует XML и YAML в массивы).</p>
<p>Итак, мы имеем следующую конфигурацию:</p>
<div>
<ul>
<li><em>YAML</em>
<pre># app/config/config.yml
hello.config:
    foo: foo
    bar: bar</pre>
</li>
<li><em>XML</em>
<pre>&lt;!-- app/config/config.xml --&gt;
&lt;?xml version="1.0" ?&gt;

&lt;container xmlns="http://www.symfony-project.org/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:hello="http://www.example.com/symfony/schema/"
    xsi:schemaLocation="http://www.example.com/symfony/schema/ http://www.example.com/symfony/schema/hello-1.0.xsd"&gt;

    &lt;hello:config foo="foo"&gt;
        &lt;hello:bar&gt;foo&lt;/hello:bar&gt;
    &lt;/hello:config&gt;

&lt;/container&gt;</pre>
</li>
<li><em>PHP</em>
<pre>// app/config/config.php
$container-&gt;loadFromExtension('hello', 'config', array(
    'foo' =&gt; 'foo',
    'bar' =&gt; 'bar',
));</pre>
</li>
</ul>
</div>
<p>Массив, который будет передаваться в ваш метод будет таким:</p>
<pre>array(
    'foo' =&gt; 'foo',
    'bar' =&gt; 'bar',
)</pre>
<p>Внутри метода <tt>configLoad()</tt> переменная <tt>$container </tt>ссылается на контейнер, который знает лишь об этом пространстве имен. Вы можете манипулировать добавлением сервисов и параметров в нужном вам направлении. Когда метод вызывается первый раз, контейнер знает лишь о глобальных параметрах. При последующих вызовах он содержит конфигурацию, определенную предыдущими вызовами. Таким образом метод должен объединить новые настройки со старыми:</p>
<pre>// only load default services and parameters once
if (!$container-&gt;hasDefinition('xxxxx')) {
    $loader = new XmlFileLoader($container, __DIR__.'/../Resources/config');
    $loader-&gt;load('hello.xml');
}</pre>
<p>Глобальные параметры:</p>
<ul>
<li><tt>kernel.name</tt></li>
<li><tt>kernel.environment</tt></li>
<li><tt>kernel.debug</tt></li>
<li><tt>kernel.root_dir</tt></li>
<li><tt>kernel.cache_dir</tt></li>
<li><tt>kernel.logs_dir</tt></li>
<li><tt>kernel.bundle_dirs</tt></li>
<li><tt>kernel.bundles</tt></li>
<li><tt>kernel.charset</tt></li>
</ul>
<div><strong> Предупреждение</strong>: все имена параметров и сервисов, начинающиеся с подчерка (_) зарезервированы для использования фреймворком и новые не должны определяться в пакетах.</div>
</div>
<div>
<h3>Соглашения по созданию расширений<a title="Permalink to this headline" href="http://docs.symfony-reloaded.org/guides/bundles/configuration.html#extension-conventions"></a></h3>
<p>При создании расширения следуйте этим простым соглашениям:</p>
<ul>
<li>Расширение должно находиться во вложенном пространстве имен <tt>DependencyInjection</tt>;</li>
<li>Расширение должно именоваться при помощи наименования пакета и завершаться суффиксом <tt>Extension</tt> (<tt>HelloExtension</tt> для <tt>HelloBundle</tt>) &#8211; если же вы создаете несколько расширений для одного пакета, просто завершайте их суффиксом <tt>Extension</tt>;</li>
<li>Алиас должен быть уникальным и должен именоваться также при помощи наименования пакета (<tt>hello</tt> для <tt>HelloBundle</tt> или <tt>sensio.social.blog</tt> для <tt>SensioSocialBlogBundle</tt>);</li>
<li>Расширение должно содержать XSD схему.</li>
</ul>
<p>Если вы последуете этим рекомендациям, то ваше расширение автоматически будет зарегистрировано Symfony2. Если этого не произошло, переопределите метод пакета <tt>registerExtensions():</tt></p>
<pre>class HelloBundle extends Bundle
{
    public function registerExtensions(ContainerBuilder $container)
    {
        // register the extension(s) found in DependencyInjection/ directory
        parent::registerExtensions($container);

        // register extensions that do not follow the conventions manually
        $container-&gt;registerExtension(new ExtensionHello());
    }
}</pre>
</div>
<div>
<h3>Конфигурация по-умолчанию</h3>
<p>Как определено ранее, пользователь пакета должен включить пространство имен <tt>hello.config</tt> в конфигурационный файл, для того чтобы вызывался код вашего расширения. Но вы также можете автоматически регистрировать конфигурацию по-умолчанию, переопределяя метод пакета <tt>registerExtensions():</tt></p>
<pre>class HelloBundle extends Bundle
{
    public function registerExtensions(ContainerBuilder $container)
    {
        // will register the HelloBundle extension(s) found in DependencyInjection/ directory
        parent::registerExtensions($container);

        // load some defaults
        $container-&gt;loadFromExtension('hello', 'config', array(/* your default config for the hello.config namespace */));
    }
}</pre>
<div>
<p><strong>Внимание</strong>: Symfony2 старается быть максимально открытым и понятным. Поэтому определение конфигурации по-умолчанию автоматически это наверняка не очень хорошая идея.</p>
<blockquote><p>Оригинал тут: <a href="http://docs.symfony-reloaded.org/guides/bundles/configuration.html" target="_blank">http://docs.symfony-reloaded.org/guides/bundles/configuration.html</a></p>
<p>Перевод как всегда &#8211; мой авторский ))</p></blockquote>
</div>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://hudson.su/2011/02/18/symfony-2-bundle-configuration/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>( PHP CLI &amp; eAccelerator ) != love</title>
		<link>http://hudson.su/2011/02/16/php-cli-and-eaccelerator-ne-love/</link>
		<comments>http://hudson.su/2011/02/16/php-cli-and-eaccelerator-ne-love/#comments</comments>
		<pubDate>Wed, 16 Feb 2011 10:49:18 +0000</pubDate>
		<dc:creator>hudson</dc:creator>
				<category><![CDATA[Профессиональное]]></category>
		<category><![CDATA[eaccelerator]]></category>
		<category><![CDATA[optimization]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[symfony]]></category>
		<category><![CDATA[web разработка]]></category>

		<guid isPermaLink="false">http://hudson.su/?p=1774</guid>
		<description><![CDATA[На днях встал вопрос об оптимизации запуска cron-скриптов. Подавляющая часть &#8211; это таски symfony (т.е. выполняется что-то типа ./symfony namespace:taskname params) и даже в условиях использования nice они создают приличный оверхед на сервер. В ходе разбора полетов решил уяснить, работает ли eAccelerator c php-cli. Собственно с подсказки @ibulatenko забрел на страницу http://eaccelerator.net/wiki/Faq, на которой черным [...]]]></description>
			<content:encoded><![CDATA[<p>На днях встал вопрос об оптимизации запуска cron-скриптов. Подавляющая часть &#8211; это таски symfony (т.е. выполняется что-то типа ./symfony namespace:taskname params) и даже в условиях использования nice они создают приличный оверхед на сервер.</p>
<p>В ходе разбора полетов решил уяснить, работает ли eAccelerator c php-cli. Собственно с подсказки <a href="http://twitter.com/ibulatenko" target="_blank">@ibulatenko</a> забрел на страницу <a href="http://eaccelerator.net/wiki/Faq" target="_blank">http://eaccelerator.net/wiki/Faq</a>, на которой черным по вебу написано в самом низу страницы:</p>
<blockquote><p><strong>Is eAccelerator working with php-cgi or php-cli?</strong><br />
This is not yet supported and it won&#8217;t be supported in the near future. However FastCGI <strong>is</strong> supported.</p></blockquote>
<p>P.S. Судя по всему ни один акселератор не работает при использовании CLI интерфейса (по крайней мере точно известно про XCache, при этом там также написано что поскольку у CLI совершенно другой принцип работы, то и ожидать не стоит).</p>
]]></content:encoded>
			<wfw:commentRss>http://hudson.su/2011/02/16/php-cli-and-eaccelerator-ne-love/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Symfony 2: пакеты, практические рекомендации</title>
		<link>http://hudson.su/2011/02/15/symfony-2-bundles-best-practices/</link>
		<comments>http://hudson.su/2011/02/15/symfony-2-bundles-best-practices/#comments</comments>
		<pubDate>Tue, 15 Feb 2011 07:58:29 +0000</pubDate>
		<dc:creator>hudson</dc:creator>
				<category><![CDATA[Профессиональное]]></category>
		<category><![CDATA[best practices]]></category>
		<category><![CDATA[bundles]]></category>
		<category><![CDATA[symfony]]></category>
		<category><![CDATA[Symfony2]]></category>
		<category><![CDATA[web разработка]]></category>

		<guid isPermaLink="false">http://hudson.su/?p=1747</guid>
		<description><![CDATA[Пакет &#8211; прежде всего это директория, которая имеет строго определенную структуру и может содержать все что угодно (от классов, до контроллеров и web-ресурсов). Не смотря на то что пакеты очень гибки, вы должны следовать некоторым рекомендациям (best practices), если вы хотите выложить его в общий доступ. Об этих практиках мы и поговорим ниже: Наименование пакета [...]]]></description>
			<content:encoded><![CDATA[<p>Пакет &#8211; прежде всего это директория, которая имеет строго определенную структуру и может содержать все что угодно (от классов, до контроллеров и web-ресурсов). Не смотря на то что пакеты очень гибки, вы должны следовать некоторым рекомендациям (best practices), если вы хотите выложить его в общий доступ. Об этих практиках мы и поговорим ниже:</p>
<p><span id="more-1747"></span></p>
<div>
<h2>Наименование пакета<a title="Permalink to this headline" href="http://docs.symfony-reloaded.org/guides/bundles/best_practices.html#bundle-name"></a></h2>
<p>Пакет &#8211; это, помимо всего прочего, также пространство имен. Пространство имен должно соответствовать <a href="http://groups.google.com/group/php-standards/web/psr-0-final-proposal" target="_blank">стандартам совместимости</a> PHP 5.3 для пространств имен и наименований классов: они должны начинаться с сегмента &#8220;поставщика&#8221; (вендора), содержать несколько сегментов категорий (в том числе может не содержать ни одного) и оканчиваться коротким наименованием пространства имен, которое должно, в свою очередь, завершаться суффиксом <tt>Bundle</tt>.</p>
<p>Пространство имен становится пакетом как только вы добавите в него класс пакета (bundle class). Наименование класса пакета должно соответствовать нескольким нехитрым правилам:</p>
<ul>
<li>Использовать только буквы, цифры и подчерк;</li>
<li>Использовать <em>ВерблюжийРегистр (aka CamelCase)</em> для имени</li>
<li>Использовать описательные и короткие наименования (не менее 2х слов)</li>
<li>Использовать в качестве префикса наименование вендора (и опционально &#8211; категории пространства имен)</li>
<li>Использовать суффикс <tt>Bundle</tt>.</li>
</ul>
<p>В таблице ниже приведены несколько примеров правильных пространств имен и наименований классов для пакетов:</p>
<table style="height: 106px" border="1" width="525">
<col width="54%"></col>
<col width="46%"></col>
<thead>
<tr>
<th>Пространство имен</th>
<th>Наименование класса</th>
</tr>
</thead>
<tbody>
<tr>
<td><tt>SensioBundleBlogBundle</tt></td>
<td><tt>SensioBlogBundle</tt></td>
</tr>
<tr>
<td><tt>SensioBundleSocialBlogBundle</tt></td>
<td><tt>SensioSocialBlogBundle</tt></td>
</tr>
<tr>
<td><tt>SensioBlogBundle</tt></td>
<td><tt>SensioBlogBundle</tt></td>
</tr>
</tbody>
</table>
<p>По договоренности, метод <tt>getName()</tt> класса в пакете должен возвращать имя класса.</p>
</div>
<div>
<h2>Структура директорий</h2>
<p>Базовую структуру директорий пакета <tt>HelloBundle</tt> можно представить следующим образом:</p>
<pre>XXX/...
    HelloBundle/
        HelloBundle.php
        Controller/
        Resources/
            meta/
                LICENSE
            config/
            doc/
                index.rst
            translations/
            views/
            public/
        Tests/</pre>
<p>Структура директорий XXX отражает структуру пространства имен пакета.</p>
<p>Следующие файлы являются обязательными:</p>
<ul>
<li><tt>HelloBundle.php</tt>;</li>
<li><tt>Resources/meta/LICENSE</tt>: текст лицензии на код пакета;</li>
<li><tt>Resources/doc/index.rst</tt>: корневой файл документации пакета.</li>
</ul>
<div>
<p>Замечание: следование этим соглашениям обеспечивает работу средств автоматизации.</p>
</div>
<p>Глубина под-директорий должна быть минимально необходимой для используемых классов и файлов (максимум 2 уровня). Больший уровень вложенности может быть использован для малозначимых или же редкоиспользуемых файлов.</p>
<p>Дирктория пакета предназначается только для чтения. Если вам необходимо писать временные файлы &#8211; вы можете сохранять их в директории <tt>cache/ </tt>или <tt>log/</tt>. Вы можете генерировать файлы в директории пакета при помощи различных инструментов, но только в том случае, если генерированные файлы будут частью репозитория.</p>
<p>Следующие классы и файлы имеют определенное расположение:</p>
<table style="height: 168px" border="1" width="520">
<col width="48%"></col>
<col width="52%"></col>
<thead>
<tr>
<th>Тип</th>
<th>Директория</th>
</tr>
</thead>
<tbody>
<tr>
<td>Контроллеры</td>
<td><tt>Controller/</tt></td>
</tr>
<tr>
<td>Файлы с переводами</td>
<td><tt>Resources/translations/</tt></td>
</tr>
<tr>
<td>Шаблоны</td>
<td><tt>Resources/views/</tt></td>
</tr>
<tr>
<td>Модульные и функциональные тесты</td>
<td><tt>Tests/</tt></td>
</tr>
<tr>
<td>Web-ресурсы (доступные публично)</td>
<td><tt>Resources/public/</tt></td>
</tr>
<tr>
<td>Конфигурация</td>
<td><tt>Resources/config/</tt></td>
</tr>
<tr>
<td>Команды</td>
<td><tt>Command/</tt></td>
</tr>
</tbody>
</table>
</div>
<div>
<h2>Классы</h2>
<p>Структура директорий пакета используется как иерархия пространства имен Например, <tt>HelloController </tt>контроллер находится по пути <tt>Bundle/HelloBundle/Controller/HelloController.php и </tt>полное имя класса будет <tt>BundleHelloBundleControllerHelloController</tt>.</p>
<p>Все классы и файлы должны соответствовать <a href="http://docs.symfony-reloaded.org/contributing/code/standards.html" target="_blank">стандартам кодирования Symfony2</a>.</p>
</div>
<div>
<p>Некоторые классы следует рассматривать как фасады (facades) и стараться делать их как можно более короткими, например Commands, Helpers, Listeners и Controllers.</p>
<p>Классы, которые подключаются к Event dispatcher&#8217;у должны иметь суффикс <tt>Listener</tt>.</p>
<p>Классы исключений должны быть расположены во сложенном пространстве имен <tt>Exception</tt>.</p>
</div>
<div>
<h2>Вендоры<a title="Permalink to this headline" href="http://docs.symfony-reloaded.org/guides/bundles/best_practices.html#vendors"></a></h2>
<p>Пакет не должен включать сторонних PHP-библиотек. Вместо этого они должны располагаться в стандартной директории Symfony2, доступной автозагрузчику. Также пакет не должен включать сторонних библиотек на JavaScript, CSS или на других языках.</p>
</div>
<div>
<h2>Тесты<a title="Permalink to this headline" href="http://docs.symfony-reloaded.org/guides/bundles/best_practices.html#tests"></a></h2>
<p>Пакеты должны комплектоваться набором тестов на PHPUnit и расположенными в директории <tt>Tests/</tt>. Тесты должны следовать следующим принципам:</p>
<ul>
<li>Тестовый набор должен выполняться простой командой <tt>phpunit </tt>из демо-приложения;</li>
<li>Функциональные тесты должны быть использованы только для тестирования ответов (response output) и профильных данных, если таковые имеются;</li>
<li>Покрытие кода должно составлять не менее 95% кода вашего пакета.</li>
</ul>
<div>
<p>Замечание: тестовый набор не должен содержать скрипта <tt>AllTests.php</tt>, но должен полагаться на наличие файла <tt>phpunit.xml.dist</tt>.</p>
</div>
</div>
<div>
<h2>Документация</h2>
<p>Все классы и функции должны быть документированы в стиле PHPDoc.</p>
<p>Полная документация также должна быть представлена в формате <a href="http://docs.symfony-reloaded.org/contributing/documentation/format.html"><em>reStructuredText</em></a>, и располагаться в директории <tt>Resources/doc/</tt>; наличие файла <tt>Resources/doc/index.rst</tt> &#8211; <strong>обязательно</strong>!</p>
</div>
<div>
<h2>Контроллеры<a title="Permalink to this headline" href="http://docs.symfony-reloaded.org/guides/bundles/best_practices.html#controllers"></a></h2>
<p>Контроллеры в пакете не должны наследоваться от класса <tt><a title="SymfonyBundleFrameworkBundleControllerController" href="http://api.symfony-reloaded.org/PR6/Symfony/Bundle/FrameworkBundle/Controller/Controller.html">Controller</a></tt>. Они должны реализовывать интерфейс <tt><a title="SymfonyFoundationDependencyInjectionContainerAwareInterface" href="http://api.symfony-reloaded.org/PR6/Symfony/Foundation/DependencyInjection/ContainerAwareInterface.html">ContainerAwareInterface</a></tt> или наследоваться от класса <tt><a title="SymfonyFoundationDependencyInjectionContainerAware" href="http://api.symfony-reloaded.org/PR6/Symfony/Foundation/DependencyInjection/ContainerAware.html">ContainerAware</a></tt>.</p>
<div>
<p>Замечание: Если вы посмотрите на методы класса <tt><a title="SymfonyBundleFrameworkBundleControllerController" href="http://api.symfony-reloaded.org/PR6/Symfony/Bundle/FrameworkBundle/Controller/Controller.html">Controller</a></tt>, вы заметите что они представляют собой &#8220;ярлычки&#8221; для упрощения изучения.</p>
</div>
</div>
<div>
<h2>Шаблоны</h2>
<p>Если пакет включает в себя шаблоны, они должны использовать Twig. Пакет не должен включать в себя главный layout, за исключением случаев, если он представляет собой полноценное рабочее приложение.</p>
</div>
<div>
<h2>Файлы переводов</h2>
<p>Если пакет содержит переводы сообщений, они должны быть определены в формате XLIFF;</p>
<p>If a bundle provides message translations, they must be defined in the XLIFF format; домен должен располагаться после имени пакета (<tt>bundle.hello</tt>).</p>
<p>Пакет не должен переопределять уже существующие сообщения из других пакетов.</p>
</div>
<div>
<h2>Конфигурация</h2>
<p>Конфигурация пакета должна использовать строенный <a href="http://docs.symfony-reloaded.org/guides/bundles/configuration.html" target="_blank">механизм</a> Symfony2. Пакет должен предоставлять все его базовые настройки в виде XML.</p>
<blockquote><p>Оригинал тут <a href="http://docs.symfony-reloaded.org/guides/bundles/best_practices.html" target="_blank">http://docs.symfony-reloaded.org/guides/bundles/best_practices.html</a></p>
<p>Перевод как обычно авторский )</p></blockquote>
</div>
]]></content:encoded>
			<wfw:commentRss>http://hudson.su/2011/02/15/symfony-2-bundles-best-practices/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Symfony 2 для разработчиков на symfony 1.x</title>
		<link>http://hudson.su/2011/02/12/symfony2-for-symfony1-developers/</link>
		<comments>http://hudson.su/2011/02/12/symfony2-for-symfony1-developers/#comments</comments>
		<pubDate>Sat, 12 Feb 2011 12:51:32 +0000</pubDate>
		<dc:creator>hudson</dc:creator>
				<category><![CDATA[Профессиональное]]></category>
		<category><![CDATA[symfony]]></category>
		<category><![CDATA[Symfony2]]></category>
		<category><![CDATA[web разработка]]></category>

		<guid isPermaLink="false">http://hudson.su/?p=1718</guid>
		<description><![CDATA[Symfony 2.0 по сравнению с первой версией фреймворка шагнул далеко вперед. К счастью, MVC архитектура, лежащая в основе его ядра, позволяет использовать те же навыки, что вы использовали, разрабатывая приложения для symfony1 и для Symfony2. App.yml вы конечно тут не увидите, но маршрутизация, контроллеры и шаблоны сохранились. В этой статье мы рассмотрим ключевые отличия между [...]]]></description>
			<content:encoded><![CDATA[<p>Symfony 2.0 по сравнению с первой версией фреймворка шагнул далеко вперед. К счастью, MVC архитектура, лежащая в основе его ядра, позволяет использовать те же навыки, что вы использовали, разрабатывая приложения для symfony1 и для Symfony2. App.yml вы конечно тут не увидите, но маршрутизация, контроллеры и шаблоны сохранились.</p>
<p>В этой статье мы рассмотрим ключевые отличия между symfony1 and Symfony2. Как вы сможете увидеть, многие задачи там решаются несколько иными путями. И вы научитесь ценить эти небольшие изменения, так как они позволят вам разрабатывать стабильный, предсказуемый, тестируемый и независимый код в ваших будущих приложениях на Symfony2.</p>
<p>Итак, расслабьтесь, и внимайте.</p>
<p><span id="more-1718"></span></p>
<div>
<h2>Структура директорий</h2>
<p>Когда вы посмотрите на структуру директорий любого Symfony2 проекта (например <a href="https://github.com/symfony/symfony-sandbox" target="_blank">Symfony2 Sandbox</a>), вы конечно же заметите что структура сильно отличается от того что вы видели раньше. Однако, когда мы копнем поглубже, окажется что изменения не так уж и серьёзны.</p>
<div>
<h3>Директория <tt>app/</tt></h3>
<p>В symfony1 ваш проект мог иметь одно или больше приложений, каждое из которых располагалось в директории <tt>apps/</tt> (например <tt>apps/frontend</tt>). По умолчанию в Symfony2 у вас есть лишь одно приложение, которое расположено в директории <tt>app/</tt>. Как и в symfony1 директория app/ содержит конфигурационные файлы приложения. Также тут содержится кеш приложения, лог и директории для шаблонов, а так же класс <tt>Kernel</tt> (<tt>AppKernel</tt>), который является базовым объектом, представляющим приложение.</p>
<p>В отличие от symfony1 в директории <tt>app/</tt> в основном располагается не PHP-код. Эта директория не содержит модулей или библиотек, как это делает symfony1. Вместо этого, тут расположены конфигурационные файлы и прочие ресурсы (шаблоны, файлы переводов и т.п.).</p>
</div>
<div>
<h3>Директория <tt>src/</tt></h3>
<p>Будем кратки: основной ваш код располагается здесь. В Symfony2 весь код приложения располагается в пакете (bundle, который приблизительно можно сравнить с плагином в symfony1) и, по умолчанию, каждый пакет располагается в директории <tt>src/</tt>. Таким образом, директорию src можно сравнить с директорией plugins в symfony1, но все-таки она дает разработчику больше свободы и гибкости. Также, в случае, если ваши пакеты располагаются в директории src/, сторонние пакеты можно расположить в директории vendor/.</p>
<p>Для того чтобы получить более полную картину о директории src/, давайте вспомним о том как у нас все было организовано в приложении symfony1. Часть вашего кода скорее всего располагалась в одном или более приложений. Как правило код включал в себя модули, но это также могли быть прочие классы, которые вы сочли нужным разместить там. Вы также могли создать файл schema.yml в директории config вашего проекта и создать множество файлов модели. Наконец, для того чтобы не изобретать велосипеды, вы пользовались несколькими сторонними плагинами, которые располагались в директории plugins/. Другими словами, код, заставляющий взлетать ваше приложение, располагался в множестве различных мест.</p>
<p>В Symfony2 жизнь намного проще, потому что <strong>весь </strong>код приложения в Symfony2 должен располагаться внутри пакета (bundle). Следуя аналогии, в symfony1 весь наш код должен был бы быть размещен в одном или нескольких плагинах (что само по себе является неплохой практикой). Полагая что все наши модули, PHP классы, схема, конфигурация маршрутизатора и т.д. переедут в плагин, тогда директория plugins/ из symfony1 будет очень похожа на директорию src/ в Symfony2</p>
<p>Кратко резюмируя, в директории src/ будут расположены ваш код, ассеты, шаблоны и много чего еще, что дает жизнь вашему проекту.</p>
</div>
<div>
<h3>Директория <tt>vendor/</tt></h3>
<p>Директория vendor/ в основном похожа на директорию lib/vendor из symfony1, которая была общепринятым местом хранения всех сторонних библиотек. По умолчанию, вы найдете в этой директории библиотечные файлы Symfony2, а также несколько вспомогательных библиотек, таких как Doctrine2, Twig и Swiftmailer.</p>
</div>
<div>
<h3>Директория <tt>web/</tt></h3>
<p>В директории web/ поменялось не так уж и много. Наиболее заметное изменение &#8211; это отсутствие директорий <tt>css/</tt>, <tt>js/</tt> и <tt>images/</tt>. Не беспокойтесь, это было сделано преднамеренно. Как и в случае с вашим PHP кодом, все ассеты также должны располагаться внутри пакета (bundle). При помощи консольной команды, директория Resources/public каждого пакета копируется или линкуется символической ссылкой в директорию <tt>web/bundles/</tt>. Это позволяет вам упорядоченно хранить ваши ассеты внутри пакета, а также делать их доступными пользователям. Для того чтобы быть уверенными, что все пакеты доступны, выполните следующую команду:</p>
<pre>./app/console_dev assets:install web --symlink</pre>
<div>Отметим также, что эта команда эквивалентна команде symfony1 <tt>- plugin:publish-assets</tt>.</div>
<div>
<h2>Автозагрузка</h2>
<p>Одной из отличительных черт современных фреймворков является то, что разработчику не нужно беспокоиться о подключении файлов. С использованием автозагрузчика вы можете ссылаться на любой класс в вашем проекте и быть уверенными что он доступен. В Symfony2 автозагрузчик был доработан, стал более универсальным, более быстрым и не требующим очистки кеша.</p>
<p>В symfony1 автозагрузчик выполнял поиск PHP классов по всему проекту и кешировал эту информацию в гигантском массиве. Этот массив устанавливал строгое соответствие какой файл содержит тот или иной класс. В продуктовом окружении эта операция требовала очистки кеша при добавлении нового класса или перемещении уже существующего.</p>
<p>В Symfony2 за этот процесс отвечает класс <tt>UniversalClassLoader</tt>. Идея его проста: имя класса (включая пространство имен) должно соответствовать пути к файлу, который содержит класс. Давайте рассмотрим <tt>HelloController </tt>из песочницы Symfony2 в качестве примера:</p>
<pre>namespace SensioHelloBundleController;
use SymfonyBundleFrameworkBundleControllerController;
class HelloController extends Controller
{
    // ...</pre>
<p>Сам файл располагается по пути <tt>src/Sensio/HelloBundle/Controller/HelloController.php</tt>. Как вы видите, расположение файла соответствует пространству имен класса. А именно, пространство имен <tt>SensioHelloBundleController</tt>, сообщает что директория, где будет расположен файл &#8211; <tt>srcSensioHelloBundleController</tt>.</p>
<p>Если файл не будет найден по ожидаемому пути, вы получите ошибку: <tt>Class "SensioHelloBundleControllerHelloController" does not exist.</tt>. В Symfony2 ошибка “class does not exist” означает, что пространство имен класса и его физическое расположение на диске не совпадают. Таким образом, Symfony2 ищет класс в одном единственном месте, которое ему положено. Кроме того, для того чтобы класс был автозагружен, <strong>вам никогда не придется очищать кеш</strong> в Symfony2.</p>
<p>Тем не менее, для того чтобы автозагрузчик работал правильно, ему нужно знать, что пространство имен Sensio расположено в директории src и, например, что пространство имен Doctrine располагается в директории <tt>vendor/doctrine/lib/</tt>. Данные правила полностью контролируются разработчиком (вами) посредством файла <tt>app/autoload.php</tt>.</p>
</div>
<div>
<h2>Консоль</h2>
<p>В symfony1 консоль располагалась в корневой директории вашего проекта и называлась <tt>symfony</tt>.</p>
<p>В Symfony2 консоль располагается в суб-директории приложения и называется <tt>console</tt>.</p>
<p>Консоль обслуживает только одно окружение (например dev, prod). Это поведение отличается от symfony1, где некоторые задачи (task) позволяли вам указать окружение через опцию <tt>env=</tt>. Распространённой практикой является создание отдельного командного файла для каждого окружения. Как правило это означает наличие файла <tt>console</tt> для <tt>prod</tt> и <tt>console_dev</tt> для <tt>dev</tt> окружений.</p>
</div>
<div>
<h2>Приложения</h2>
<p>В проекте на symfony1 обычной практикой было создавать несколько приложений: например frontend и backend.</p>
<p>В проекте на Symfony2 вам нужно создать лишь одно приложение (блог, интранет-портал&#8230;). В большинстве случаев, если вы захотите создать еще одно приложение, вы можете вместо этого создать еще один проект и обеспечить доступность необходимых пакетов между ними.</p>
<p>И если вы хотите разделить frontend и backend функциональность в пакетах, вы можете создать вложенные пространства имен для контроллеров, субдиректории для шаблонов, различную семантику конфигурационных файлов, различные правила маршрутизации и т.д.</p>
<p>Конечно же, наличие нескольких приложений в проекте не будет совершенно неправильным шагом, но это целиком ваш выбор. Второе приложение будет означать новую директорию, например my_app/, с настройками, аналогичными тем, которые находятся в директории app/.</p>
<p>Совет: почитайте определения <a href="http://docs.symfony-reloaded.org/glossary.html#term-project" target="_blank"><em>проекта</em></a>, <a href="http://docs.symfony-reloaded.org/glossary.html#term-application" target="_blank"><em>приложения</em></a>, и <a href="http://docs.symfony-reloaded.org/glossary.html#term-bundle" target="_blank"><em>пакета</em></a> в глоссарии.</p>
</div>
<div>
<h2>Пакеты и плагины</h2>
<p>В проекте symfony1 плагин должен содержать конфигурацию, модули, PHP библиотеки, ассеты и все прочее, относящееся к вашему проекту. В Symfony2 место плагина заняли пакеты (bundles). Пакет даже более функционален нежели плагин, потому что ядро Symfony2 состоит из последовательности пакетов. В Symfony2 пакет это гражданин высшего сорта, настолько гибкий, что даже ядро это пакет.</p>
</div>
<div>
<p>В symfony1 плагин должен быть активирован в классе <tt>ProjectConfiguration</tt>:</p>
<pre>// config/ProjectConfiguration.class.php
public function setup()
{
    $this-&gt;enableAllPluginsExcept(array(/* some plugins here */));
}</pre>
<p>В Symfony2 пакеты активируются внутри ядра приложения:</p>
<pre>// app/AppKernel.php
public function registerBundles()
{
    $bundles = array(
        new SymfonyBundleFrameworkBundleFrameworkBundle(),
        new SymfonyBundleTwigBundleTwigBundle(),
        // ...
        new SensioHelloBundleHelloBundle(),
    );

    return $bundles;
}</pre>
<p>Также необходимо удостовериться что пространство имен <tt>Sensio</tt> присутствует в автозагрузчике:</p>
<pre>// app/autoload.php
$loader = new UniversalClassLoader();
$loader-&gt;registerNamespaces(array(
    'Symfony'                        =&gt; __DIR__.'/../vendor/symfony/src',
    'Sensio'                         =&gt; __DIR__.'/../src',
    // ...
));</pre>
<p>В symfony1 конфигурационные файлы <tt>routing.yml</tt> и <tt>app.yml</tt> загружались автоматически для любого плагина. В Symfony2 маршруты и конфигурация приложения из пакета должны быть подключены вручную. Например, чтобы подключить маршрутизацию из пакеты, вы должны выполнить следующее:</p>
<pre># app/config/routing.yml
hello:
    resource: @HelloBundle/Resources/config/routing.yml</pre>
<p>Таким образом, чтобы получить конфигурацию пакета, вам нужно ее импортировать в конфигурации вашего приложения.</p>
<blockquote><p>Оригинал тут: <a href="http://docs.symfony-reloaded.org/guides/symfony1.html" target="_blank">http://docs.symfony-reloaded.org/guides/symfony1.html</a></p>
<p>Перевод авторский <img src='http://hudson.su/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p></blockquote>
</div>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://hudson.su/2011/02/12/symfony2-for-symfony1-developers/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
		<item>
		<title>Валидация email в стиле Swift Mailer</title>
		<link>http://hudson.su/2010/11/02/email-validation-swift-mailer-style/</link>
		<comments>http://hudson.su/2010/11/02/email-validation-swift-mailer-style/#comments</comments>
		<pubDate>Tue, 02 Nov 2010 08:24:19 +0000</pubDate>
		<dc:creator>hudson</dc:creator>
				<category><![CDATA[Профессиональное]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[snippet]]></category>
		<category><![CDATA[swift mailer]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://hudson.su/?p=1656</guid>
		<description><![CDATA[Довелось на днях играться с email-рассылкой в symfony 1.4 при помощи Swift mailer. Тема массовых рассылок достойна отдельного поста, поэтому пока остановлюсь на валидации email в стиле Swift. Зачем вообще понадобилась такая валидация? Как раз об этом я и собирался рассказать: Имеем цикл по получателям, который чанками (страницами, как вам будет удобнее) обходит всех наших [...]]]></description>
			<content:encoded><![CDATA[<p>Довелось на днях играться с email-рассылкой в symfony 1.4 при помощи Swift mailer. Тема массовых рассылок достойна отдельного поста, поэтому пока остановлюсь на валидации email в стиле Swift. Зачем вообще понадобилась такая валидация? Как раз об этом я и собирался рассказать:</p>
<p><span id="more-1656"></span></p>
<p>Имеем цикл по получателям, который чанками (страницами, как вам будет удобнее) обходит всех наших потенциальных получателей. Каждый чанк формирует свою партию писем посредством <code>Swift_Mailer::batchSend()</code>. И вот допустим ситуацию, когда <span style="text-decoration: line-through">враги сожгли родную хату</span>&#8230; нет не так, враги заменили несколько email на нечто, не соответствующее требованиям RFC. Что произойдет? А то и произойдет &#8211; Swift вызовет исключение и</p>
<p>а) процесс рассылки вообще упадет, если <code>try ... catch</code> у вас нет</p>
<p>б) чанк выпадет из рассылки, если <code>try ... catch</code> у вас есть.</p>
<p>Обе ситуации мне лично не нравятся. Поэтому я решил произвести валидацию адреса до фактического попадания его в чанк.</p>
<p>Первая инкарнация использовала <code>sfValidatorEmail</code> (ну конечно, он предназначен для использования в формах, но если немного попрыгать с бубном и добавить к этому<code> try ... catch</code> &#8211; получается более менее юзабельно (<code>clean()</code> в <code>sfValidatorRegex</code> тоже кастует исключение, ага). Тем не менее тестирование выявило несостоятельность такого подхода, так как <code>sfValidatorEmail</code> в некоторых случаях не отлавливал несоответствия RFC.</p>
<p>Логично в этом месте воспользоваться встроенным в Swift механизмом валидации. Ан не тут то было. Публично доступного валидатора я не нашел, греп по коду выявил что валидация происходит в недрах класса <code>Swift_Mime_Headers_AbstractHeader</code> (да, абстрактного класса), ну или если ближе к народу, то в <code>Swift_Mime_Headers_MailboxHeader</code> (кстати загляните в реализацию &#8211; на мой вкус и цвет это самый большой регэксп на email который я когда либо видел!).</p>
<p>Итого, вот сниппет валидации:</p>
<pre>&lt;?php
...
// энкодер - нужен для инициализации MailboxHeader
$encoder = new Swift_Mime_HeaderEncoder_Base64HeaderEncoder();
...
// цикл по получателям в текущем чанке
foreach( ... )
{
  try
  {
    // собственно валидация. обязательно используйте try/catch
    $header = new Swift_Mime_Headers_MailboxHeader( 'To', $encoder );
    $header-&gt;setNameAddresses( array( $email ) );
    // если тут не упали с исключением, адрес валидный - добавляем в нашу пачку получателей
    ...
  }
  catch( Exception $e )
  {
    // email невалидный - следующая итерация
    continue;
  }
}
...
</pre>
<p>Дочитали до этого места? Прониклись значимостью идеи? А теперь забудьте его&#8230; страшненько оно как-то смотрится!</p>
<p>p.s. если знаете более цивилизованный способ валидации по версии Swift &#8211; напишите пожалуйста )</p>
]]></content:encoded>
			<wfw:commentRss>http://hudson.su/2010/11/02/email-validation-swift-mailer-style/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

