<?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; hints</title>
	<atom:link href="http://hudson.su/tag/hints/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>ГуРу новости: Пара советов по тестированию контроллеров Symfony2</title>
		<link>http://hudson.su/2011/09/23/guru-novosti-para-sovetov-po-testirovaniyu-kontrollerov-symfony2/</link>
		<comments>http://hudson.su/2011/09/23/guru-novosti-para-sovetov-po-testirovaniyu-kontrollerov-symfony2/#comments</comments>
		<pubDate>Fri, 23 Sep 2011 10:46:12 +0000</pubDate>
		<dc:creator>hudson</dc:creator>
				<category><![CDATA[Профессиональное]]></category>
		<category><![CDATA[controller]]></category>
		<category><![CDATA[hints]]></category>
		<category><![CDATA[repost]]></category>
		<category><![CDATA[Symfony2]]></category>
		<category><![CDATA[SymfonyGuru]]></category>
		<category><![CDATA[тестирование]]></category>

		<guid isPermaLink="false">http://hudson.su/?p=2121</guid>
		<description><![CDATA[В статье рассмотрены 2 вопроса: использование Service Container в тестах контроллеров (преимущественно маршрутизатор/router), а также авторизация тестового пользователя без заполнения формы: http://symfony-gu.ru/blog/ru/symfony2-testing-hints/]]></description>
			<content:encoded><![CDATA[<p>В статье рассмотрены 2 вопроса: использование Service Container в тестах контроллеров (преимущественно маршрутизатор/router), а также авторизация тестового пользователя без заполнения формы:</p>
<p><a title="Пара советов по тестированию контроллеров Symfony2" href="http://symfony-gu.ru/blog/ru/symfony2-testing-hints/" target="_blank">http://symfony-gu.ru/blog/ru/symfony2-testing-hints/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://hudson.su/2011/09/23/guru-novosti-para-sovetov-po-testirovaniyu-kontrollerov-symfony2/feed/</wfw:commentRss>
		<slash:comments>0</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>Assembla: несколько SSH ключей для разных проектов под одним пользователем</title>
		<link>http://hudson.su/2011/05/19/assembla-different-ssh-keys-for-different-projects/</link>
		<comments>http://hudson.su/2011/05/19/assembla-different-ssh-keys-for-different-projects/#comments</comments>
		<pubDate>Thu, 19 May 2011 13:41:18 +0000</pubDate>
		<dc:creator>hudson</dc:creator>
				<category><![CDATA[Профессиональное]]></category>
		<category><![CDATA[assembla]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[hints]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://hudson.su/?p=2007</guid>
		<description><![CDATA[Небольшой хинт по использованию нескольких ключей (для различных проектов) для одного пользователя при работе с git.assembla.com в linux. Вам по прежнему будет нужен уникальный ключ для каждого пользователя. Ниже представлен небольшой workaround, позволяющий менять ключи для работы с различными проектами на assembla.com. 1) разместите где-либо в $PATH скриптик (назовем его gitssh): #!/bin/sh key=$&#40;git config ssh.key&#41; [...]]]></description>
			<content:encoded><![CDATA[<p>Небольшой хинт по использованию нескольких ключей (для различных проектов) для одного пользователя при работе с <strong>git.assembla.com</strong> в linux.</p>
<p><span id="more-2007"></span></p>
<p><span style="text-decoration: underline;">Вам по прежнему будет нужен уникальный ключ для каждого пользователя. </span></p>
<p>Ниже представлен небольшой workaround, позволяющий менять ключи для работы с различными проектами на assembla.com.</p>
<p>1) разместите где-либо в $PATH скриптик (назовем его <strong>gitssh</strong>):</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/bin/sh</span>
<span style="color: #007800;">key</span>=$<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">git</span> config ssh.key<span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-z</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$key</span>&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
  <span style="color: #007800;">git_opts</span>=<span style="color: #ff0000;">&quot;&quot;</span>
<span style="color: #000000; font-weight: bold;">else</span>
  <span style="color: #007800;">git_opts</span>=<span style="color: #ff0000;">&quot;-i <span style="color: #007800;">${key}</span>&quot;</span>
<span style="color: #000000; font-weight: bold;">fi</span>
&nbsp;
<span style="color: #7a0874; font-weight: bold;">exec</span> <span style="color: #c20cb9; font-weight: bold;">ssh</span> <span style="color: #007800;">$git_opts</span> <span style="color: #ff0000;">&quot;$@&quot;</span></pre></div></div>

<p>2) установите переменную GIT_SSH чтобы она указывала на этот скрипт:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">export</span> <span style="color: #007800;">GIT_SSH</span>=gitssh</pre></div></div>

<p>3) выполните настройку ключа для проекта1 в его директории</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">git config ssh.key ~/.ssh/my_cool_project1_key.pub</pre></div></div>

<p>и для проекта2 в его директории</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">git config ssh.key ~/.ssh/my_cool_project2_key.pub</pre></div></div>

<p>Вот и все работает ) Успехов!</p>
<p><a href="http://www.assembla.com/spaces/breakoutdocs/wiki/Different_SSH_keys_for_different_projects" target="_blank">http://www.assembla.com/spaces/breakoutdocs/wiki/Different_SSH_keys_for_different_projects</a></p>
]]></content:encoded>
			<wfw:commentRss>http://hudson.su/2011/05/19/assembla-different-ssh-keys-for-different-projects/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Doctrine2: эмулируем timestampable behavior через lifecycle callback</title>
		<link>http://hudson.su/2011/04/22/doctrine2-emulate-timestampable-behavior-via-lifecycle-callback/</link>
		<comments>http://hudson.su/2011/04/22/doctrine2-emulate-timestampable-behavior-via-lifecycle-callback/#comments</comments>
		<pubDate>Fri, 22 Apr 2011 05:16:38 +0000</pubDate>
		<dc:creator>hudson</dc:creator>
				<category><![CDATA[Профессиональное]]></category>
		<category><![CDATA[doctrine]]></category>
		<category><![CDATA[doctrine2]]></category>
		<category><![CDATA[hints]]></category>
		<category><![CDATA[ORM]]></category>
		<category><![CDATA[snippet]]></category>

		<guid isPermaLink="false">http://hudson.su/?p=1917</guid>
		<description><![CDATA[Ниже рассмотрим простой, но имхо нужный пример по реализации аналога timestampable в Doctrine2. Схема: Vendor\MyBundle\Entity\User: type: entity table: user id: id: type: bigint generator: strategy: AUTO fields: # ... updated: type: datetime nullable: true created: type: datetime nullable: true Далее полагаем что сущности сгенерированы. При создании новой сущности вызывается констуктор, поэтому даты устанавливаем там: &#60;?php [...]]]></description>
			<content:encoded><![CDATA[<p>Ниже рассмотрим простой, но имхо нужный пример по реализации аналога timestampable в Doctrine2.</p>
<p><span id="more-1917"></span><br />
Схема:</p>

<div class="wp_syntax"><div class="code"><pre class="yaml" style="font-family:monospace;">Vendor\MyBundle\Entity\User:
  type: entity
  table: user
  id:
    id:
      type: bigint
      generator:
        strategy: AUTO
  fields:
    # ...
    updated:
      type: datetime
      nullable: true
    created:
      type: datetime
      nullable: true</pre></div></div>

<p>Далее полагаем что сущности сгенерированы. При создании новой сущности вызывается констуктор, поэтому даты устанавливаем там:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #666666; font-style: italic;">// Vendor/MyBundle/Entity/User.php</span>
<span style="color: #000000; font-weight: bold;">class</span> User<span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// ....    </span>
    <span style="color: #009933; font-style: italic;">/**
     * @var datetime $created
     */</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000088;">$created</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * @var datetime $updated
     */</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000088;">$updated</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">created</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">updated</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> \DateTime<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;now&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #666666; font-style: italic;">// ....    </span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Для того чтобы при обновлении сущности updated также обновлялся бы, нам надо воспользоваться lifecycle callback. Модифицируем схему и генерим по ней модель:</p>

<div class="wp_syntax"><div class="code"><pre class="yaml" style="font-family:monospace;">Vendor\MyBundle\Entity\User:
  type: entity
  table: user
  # ...
  lifecycleCallbacks:
    preUpdate: [ preUpdate ]</pre></div></div>

<p>После генерации у вас в классе сущности появится метод preUpdate, который надо слегка модифицировать:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #666666; font-style: italic;">// Vendor/MyBundle/Entity/User.php</span>
<span style="color: #000000; font-weight: bold;">class</span> User<span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// ....    </span>
    <span style="color: #009933; font-style: italic;">/**
     * @orm:preUpdate
     */</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> preUpdate<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">updated</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> \DateTime<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;now&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #666666; font-style: italic;">// ....    </span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Берем и пользуемся )</p>
<blockquote><p>Источник: <a href="http://www.doctrine-project.org/blog/doctrine2-behaviours-nutshell" target="_blank">http://www.doctrine-project.org/blog/doctrine2-behaviours-nutshell</a>. Посмотрите, там еще много интересного.</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://hudson.su/2011/04/22/doctrine2-emulate-timestampable-behavior-via-lifecycle-callback/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Symfony2: аналог preExecute() для контроллера</title>
		<link>http://hudson.su/2011/04/20/symfony2-preexecute-analog/</link>
		<comments>http://hudson.su/2011/04/20/symfony2-preexecute-analog/#comments</comments>
		<pubDate>Wed, 20 Apr 2011 16:42:28 +0000</pubDate>
		<dc:creator>hudson</dc:creator>
				<category><![CDATA[Профессиональное]]></category>
		<category><![CDATA[hints]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[snippet]]></category>
		<category><![CDATA[Symfony2]]></category>

		<guid isPermaLink="false">http://hudson.su/?p=1910</guid>
		<description><![CDATA[Я думаю многих смущает отсутствие preExecute в стандартном контроллере Symfony2. Ниже я приведу возможное решение данного вопроса при помощи внедрения зависимости через Service Container (Оригинал подсмотрен у Szymon Szewczyk). UPDATE 20 января 2012: статья обновлена в соответствии с современными реалиями SF 2.0.9 (фактически изменения коснулись именования тага и события) Итак, начнем с определения службы: YAML: [...]]]></description>
			<content:encoded><![CDATA[<p>Я думаю многих смущает отсутствие preExecute в стандартном контроллере Symfony2. Ниже я приведу возможное решение данного вопроса при помощи внедрения зависимости через Service Container (Оригинал подсмотрен у Szymon Szewczyk).</p>
<blockquote><p><strong>UPDATE 20 января 2012:</strong> статья обновлена в соответствии с современными реалиями SF 2.0.9 (фактически изменения коснулись именования тага и события)</p></blockquote>
<p><span id="more-1910"></span>Итак, начнем с определения службы:</p>
<p><strong>YAML:</strong></p>

<div class="wp_syntax"><div class="code"><pre class="yaml" style="font-family:monospace;"># Vendor\MyBundle\Resources\config.yml
services:
    # ...
    preexecute.listener:
        class: Vendor\MyBundle\Listener\PreExecuteListener
        tags:
            - { name: kernel.event_listener, event: kernel.controller, method: onKernelController }</pre></div></div>

<p><strong>XML:</strong></p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"># Vendor\MyBundle\Resources\config.xml
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;service</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;kernel.listener.pre_execute&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;Vendor\MyBundle\Listener\PreExecuteListener&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;tag</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;kernel.event_listener&quot;</span> <span style="color: #000066;">event</span>=<span style="color: #ff0000;">&quot;kernel.controller&quot;</span> <span style="color: #000066;">method</span>=<span style="color: #ff0000;">&quot;onKernelController&quot;</span> <span style="color: #000066;">priority</span>=<span style="color: #ff0000;">&quot;0&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/service<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>Создадим также определение нашей службы в положенном ей месте:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// Vendor\MyBundle\Listener\PreExecuteListener.php</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">namespace</span> Vendor\MyBundle\Listener<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">use</span> Symfony\Component\EventDispatcher\Event<span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">use</span> Symfony\Component\HttpKernel\HttpKernelInterface<span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">use</span> Symfony\Component\HttpKernel\Event\FilterControllerEvent<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> PreExecuteListener
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> onKernelController<span style="color: #009900;">&#40;</span>FilterControllerEvent <span style="color: #000088;">$event</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>HttpKernelInterface<span style="color: #339933;">::</span><span style="color: #004000;">MASTER_REQUEST</span> <span style="color: #339933;">===</span> <span style="color: #000088;">$event</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>getRequestType<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$controllers</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$event</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>getController<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #666666; font-style: italic;">// контроллер должен существовать</span>
      <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$controllers</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$controller</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$controllers</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        <span style="color: #666666; font-style: italic;">// метод должен существовать</span>
        <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">method_exists</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$controller</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'preExecute'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
          <span style="color: #000088;">$controller</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>preExecute<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
      <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Вот и все! ) Теперь в нужном контроллере объявляем метод <code>preExecute()</code> и наслаждаемся нашими танцами с бубном )</p>
]]></content:encoded>
			<wfw:commentRss>http://hudson.su/2011/04/20/symfony2-preexecute-analog/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>Осторожно! Злой &#8220;bad behavior&#8221;</title>
		<link>http://hudson.su/2011/04/13/bad-bad-behavior/</link>
		<comments>http://hudson.su/2011/04/13/bad-bad-behavior/#comments</comments>
		<pubDate>Wed, 13 Apr 2011 12:52:02 +0000</pubDate>
		<dc:creator>hudson</dc:creator>
				<category><![CDATA[Профессиональное]]></category>
		<category><![CDATA[hints]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[мысли]]></category>

		<guid isPermaLink="false">http://hudson.su/?p=1904</guid>
		<description><![CDATA[Две недели назад включил антиспам-фильтр bad behavior. Спам как ветром сдуло. Также как и доступ для googlebot. Трафик с Google за две недели упал в 4-5 раз. Написал реквест разработчику с просьбой помочь, но не уверен в результате. Вот наглядный пример: bad behavior блокирует доступ к sitemap.xml (генерируемый при помощи XML-Sitemp plugin): В общем, как [...]]]></description>
			<content:encoded><![CDATA[<p>Две недели назад включил антиспам-фильтр <strong>bad behavior</strong>. Спам как ветром сдуло. Также как и доступ для <strong>googlebot</strong>. Трафик с Google за две недели упал в 4-5 раз. Написал реквест разработчику с просьбой помочь, но не уверен в результате.</p>
<p>Вот наглядный пример: bad behavior блокирует доступ к sitemap.xml (генерируемый при помощи XML-Sitemp plugin):</p>
<p><a rel="lightbox" href="http://hudson.su/wp-content/uploads/2011/04/bad-bad-behavior.png"><img class="alignnone size-thumbnail wp-image-1905" title="bad-bad-behavior" src="http://hudson.su/wp-content/uploads/2011/04/bad-bad-behavior-150x150.png" alt="" width="150" height="150" /></a></p>
<p>В общем, как поется в песне &#8211; &#8220;думайте сами, решайте сами &#8211; иметь или не иметь&#8221;&#8230; гемор с трафиком. Или со спамом.</p>
]]></content:encoded>
			<wfw:commentRss>http://hudson.su/2011/04/13/bad-bad-behavior/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Symfony2: выборка случайной записи при помощи Doctrine2 Repository</title>
		<link>http://hudson.su/2011/04/13/symfony2-random-select-with-doctrine2-repository/</link>
		<comments>http://hudson.su/2011/04/13/symfony2-random-select-with-doctrine2-repository/#comments</comments>
		<pubDate>Wed, 13 Apr 2011 10:59:04 +0000</pubDate>
		<dc:creator>hudson</dc:creator>
				<category><![CDATA[Профессиональное]]></category>
		<category><![CDATA[doctrine2]]></category>
		<category><![CDATA[hints]]></category>
		<category><![CDATA[snippet]]></category>
		<category><![CDATA[Symfony2]]></category>

		<guid isPermaLink="false">http://hudson.su/?p=1895</guid>
		<description><![CDATA[Я уже рассматривал в одной из прошлых статей случайные выборки (см.). Сейчас мы самым простым способом интегрируем получение случайной записи в Symfony2 проект при помощи Doctrine2 Repository. Мои entities определены по привычке в YAML формате, поэтому я буду описывать именно его. Итак, укажем нашей сущности использовать кастомный Repository: # src/Vendor/MyBundle/Resources/config/doctrine/metadata/orm/Vendor.MyBundle.Entity.User.dcm.yml Vendor\MyBundle\Entity\User: type: entity table: user [...]]]></description>
			<content:encoded><![CDATA[<p>Я уже рассматривал в одной из прошлых статей случайные выборки (<a href="http://hudson.su/?p=1600" target="_blank">см.</a>). Сейчас мы самым простым способом интегрируем получение случайной записи в Symfony2 проект при помощи Doctrine2 Repository.</p>
<p><span id="more-1895"></span></p>
<p>Мои entities определены по привычке в YAML формате, поэтому я буду описывать именно его. Итак, укажем нашей сущности использовать кастомный Repository:</p>

<div class="wp_syntax"><div class="code"><pre class="yaml" style="font-family:monospace;"># src/Vendor/MyBundle/Resources/config/doctrine/metadata/orm/Vendor.MyBundle.Entity.User.dcm.yml
Vendor\MyBundle\Entity\User:
    type: entity
    table: user
    ...
    repositoryClass: Vendor\MyBundle\Repository\UserRepository
    ...</pre></div></div>

<p>После этого можно создать класс <code>UserRepository.php</code> в директории <code>src/Vendor/MyBundle/Repository</code> или же выполнить команду<code> doctrine:generate:repositories</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">&gt;php app\console doctrine:generate:repositories VendorMyBundle
Generating entity repositories for &quot;VendorMyBundle&quot;
  &gt; OK generating Vendor\MyBundle\Repository\UserRepository
  &gt; SKIP no custom repository for Vendor\MyBundle\Entity\UserData</pre></div></div>

<p>У нас есть класс репозитория. Добавим в него метод выбора случайного юзера:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getRandomUser<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// mapper для результата</span>
    <span style="color: #000088;">$rsm</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ResultSetMapping<span style="color: #339933;">;</span>
    <span style="color: #000088;">$rsm</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">addEntityResult</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Vendor\MyBundle\Entity\User'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'u'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$rsm</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">addFieldResult</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'u'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'id'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'id'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// тут я использую NativeQuery - перевести этот запрос в DQL для меня сейчас слабо )</span>
    <span style="color: #666666; font-style: italic;">// также примем допущение что user не содержит &quot;дыр&quot; в ID</span>
    <span style="color: #000088;">$query</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getEntityManager</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">createNativeQuery</span><span style="color: #009900;">&#40;</span>
      <span style="color: #0000ff;">'SELECT id FROM user JOIN ( SELECT CEIL(RAND() * (SELECT MAX(id) FROM user)) AS id ) AS r2 USING (id)'</span><span style="color: #339933;">,</span>
      <span style="color: #000088;">$rsm</span>
    <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// ищем случайный ID</span>
    <span style="color: #000088;">$user</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$query</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getSingleResult</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;">// на выходе получаем полноценный Vendor\MyBundle\Entity\User (хотя как вариант можно написать маппер на все необходимые поля)</span>
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">find</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p>В контроллере пользуемся репозиторием так:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> someAction<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$em</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'doctrine.orm.entity_manager'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$userRepo</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$em</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getRepository</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'VendorMyBundle:User'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$randomUser</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$userRepo</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getRandomUser</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p>P.S. данный код возможно далек от идеала, тем не менее на пробную работу с репозиторием и native sql мной было потрачено некоторое время, результатами своих изысканий я с вами и делюсь )</p>
]]></content:encoded>
			<wfw:commentRss>http://hudson.su/2011/04/13/symfony2-random-select-with-doctrine2-repository/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Symfony2: доступ к одной службе из другой</title>
		<link>http://hudson.su/2011/04/04/symfony2-access-service-from-custom-service/</link>
		<comments>http://hudson.su/2011/04/04/symfony2-access-service-from-custom-service/#comments</comments>
		<pubDate>Mon, 04 Apr 2011 16:22:44 +0000</pubDate>
		<dc:creator>hudson</dc:creator>
				<category><![CDATA[Профессиональное]]></category>
		<category><![CDATA[hints]]></category>
		<category><![CDATA[Symfony2]]></category>

		<guid isPermaLink="false">http://hudson.su/?p=1882</guid>
		<description><![CDATA[По результатам опроса о чем написать, естественно большинство захотело известий с полей. На большую статью пока не замахиваюсь, но по мере появления интересных сниппетов постараюсь ими делиться. Сегодняшний сниппет посвящается службам (сервисам), а именно &#8211; как получить доступ из пользовательской службы к другой службе в рамках приложения. Положим у нас в нашем пакете есть служба [...]]]></description>
			<content:encoded><![CDATA[<p>По результатам опроса о чем написать, естественно большинство захотело известий с полей. На большую статью пока не замахиваюсь, но по мере появления интересных сниппетов постараюсь ими делиться.</p>
<p>Сегодняшний сниппет посвящается службам (сервисам), а именно &#8211; как получить доступ из пользовательской службы к другой службе в рамках приложения.</p>
<p>Положим у нас в нашем пакете есть служба Company\SuperBundle\Service\CoolService описываемая следующей конфигурацией:</p>
<p><span id="more-1882"></span></p>

<div class="wp_syntax"><div class="code"><pre class="yaml" style="font-family:monospace;"># app/config/config.yml
services:
    giveMeCool:
        class: Company\SuperBundle\Service\CoolService
        arguments: [%arg1%, %arg2%]</pre></div></div>

<p>Все идет хорошо, пока нам не требуется другая служба. Например мне понадобился <code>logger</code>. Вообще говоря это есть в документации, но пришлось повозиться пока я это нашел: другую службу можно указать в аргументах своего сервиса через <code>@svcname</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="yaml" style="font-family:monospace;"># app/config/config.yml
services:
    giveMeCool:
        class: Company\SuperBundle\Service\CoolService
        arguments: [%arg1%, %arg2%, @logger]</pre></div></div>

<p>Соответственно код конструктора службы надо немного модифицировать:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># src/Company/SuperBundle/Service/CoolService.php
</span>  <span style="color: #666666; font-style: italic;">//...</span>
  <span style="color: #666666; font-style: italic;">// services</span>
  <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000088;">$logger</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$arg1</span><span style="color: #339933;">,</span> <span style="color: #000088;">$arg2</span><span style="color: #339933;">,</span> \Symfony\Bundle\ZendBundle\Logger\Logger <span style="color: #000088;">$logger</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">logger</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$logger</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">//...</span></pre></div></div>

<p>Тип сервиса можно указать явно (как в примере), тогда мы сможем как минимум пользоваться подсказками нашей IDE (что в Symfony2 получается не часто).</p>
<h3>Update</h3>
<p>Читатель <strong>Костег</strong> в комментариях предложил более общее решение для данного кейса: можно передавать в пользовательскую службу не отдельные службы, а весь service container разом (мало ли когда и какая из служб вам потребуется):</p>

<div class="wp_syntax"><div class="code"><pre class="yaml" style="font-family:monospace;"># app/config/config.yml
services:
    giveMeCool:
        class: Company\SuperBundle\Service\CoolService
        arguments: [%arg1%, %arg2%, @service_container]</pre></div></div>

<p>Теперь в классе вашей службы вы сможете получить доступ к любой из служб, определенных в рамках вашего приложения: templating, logger, request, routing etc&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># src/Company/SuperBundle/Service/CoolService.php
</span>  <span style="color: #666666; font-style: italic;">//...</span>
  <span style="color: #666666; font-style: italic;">// services</span>
  <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000088;">$serviceContainer</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$arg1</span><span style="color: #339933;">,</span> <span style="color: #000088;">$arg2</span><span style="color: #339933;">,</span> \Symfony\Component\DependencyInjection\Container <span style="color: #000088;">$container</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">serviceContainer</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$container</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">serviceContainer</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'routing'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">//...</span></pre></div></div>

<p>По-моему это уже выглядит достаточно удобно &#8211; во всяком случае к основным критическим данным служба сможет получить доступ без лишних извращений над кодом <img src='http://hudson.su/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://hudson.su/2011/04/04/symfony2-access-service-from-custom-service/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
		<item>
		<title>MySQL &#8211; анализ сложных запросов</title>
		<link>http://hudson.su/2011/03/24/mysql-analyzing-complex-queries/</link>
		<comments>http://hudson.su/2011/03/24/mysql-analyzing-complex-queries/#comments</comments>
		<pubDate>Thu, 24 Mar 2011 07:59:56 +0000</pubDate>
		<dc:creator>hudson</dc:creator>
				<category><![CDATA[Профессиональное]]></category>
		<category><![CDATA[hints]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[optimization]]></category>

		<guid isPermaLink="false">http://hudson.su/?p=1795</guid>
		<description><![CDATA[Перевод статьи про анализ сложных MySQL запросов: &#160; Для данной статьи возьмем запрос из статьи про ORDER BY RAND, так он достаточно интересен для рассмотрения различных аспектов запросов. Он содержит: Подзапросы; Объединения; Особые случаи; JOIN&#8217;ы Сортировку ORDER BY + LIMIT Если вы хотите понять как запрос был создан, посмотрите оригинальную статью ORDER BY RAND. Примечание [...]]]></description>
			<content:encoded><![CDATA[<div>
<p>Перевод статьи про анализ сложных MySQL запросов:</p>
<p><span id="more-1795"></span>&nbsp;</p>
<p>Для данной статьи возьмем запрос из статьи про <a href="http://hudson.su/?p=1600" target="_blank">ORDER BY RAND</a>, так он достаточно интересен для рассмотрения различных аспектов запросов. Он содержит:</p>
<ul>
<li>Подзапросы;</li>
<li>Объединения;</li>
<li>Особые случаи;</li>
<li>JOIN&#8217;ы</li>
<li>Сортировку ORDER BY + LIMIT</li>
</ul>
<p>Если вы хотите понять как запрос был создан, посмотрите оригинальную статью <a href="../?p=1600" target="_blank">ORDER BY RAND</a>.</p>
<blockquote><p>Примечание переводчика: вообще говоря в статье на которую ссылается автор, работа окончена до составления именно этого запроса. Возможно это дополнительный хинт для пытливых умов <img src='http://hudson.su/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p></blockquote>
<p>Рассмотрим результаты EXPLAIN запроса:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #66cc66;">&gt;</span> <span style="color: #993333; font-weight: bold;">EXPLAIN</span> EXTENDED
<span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">SELECT</span> r1<span style="color: #66cc66;">.</span>name <span style="color: #993333; font-weight: bold;">FROM</span> random <span style="color: #993333; font-weight: bold;">AS</span> r1
   <span style="color: #993333; font-weight: bold;">JOIN</span> <span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #66cc66;">&#40;</span>RAND<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">*</span>
                <span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #993333; font-weight: bold;">MAX</span><span style="color: #66cc66;">&#40;</span>id<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">FROM</span> random<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> id
        <span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> r2
  <span style="color: #993333; font-weight: bold;">WHERE</span> r1<span style="color: #66cc66;">.</span>id <span style="color: #66cc66;">&gt;=</span> r2<span style="color: #66cc66;">.</span>id
  <span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> r1<span style="color: #66cc66;">.</span>id <span style="color: #993333; font-weight: bold;">ASC</span>
  <span style="color: #993333; font-weight: bold;">LIMIT</span> <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #993333; font-weight: bold;">UNION</span> <span style="color: #993333; font-weight: bold;">ALL</span>
<span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">SELECT</span> r1<span style="color: #66cc66;">.</span>name <span style="color: #993333; font-weight: bold;">FROM</span> random <span style="color: #993333; font-weight: bold;">AS</span> r1
   <span style="color: #993333; font-weight: bold;">JOIN</span> <span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #66cc66;">&#40;</span>RAND<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">*</span>
                <span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #993333; font-weight: bold;">MAX</span><span style="color: #66cc66;">&#40;</span>id<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">FROM</span> random<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> id
        <span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> r2
  <span style="color: #993333; font-weight: bold;">WHERE</span> r1<span style="color: #66cc66;">.</span>id <span style="color: #66cc66;">&gt;=</span> r2<span style="color: #66cc66;">.</span>id
  <span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> r1<span style="color: #66cc66;">.</span>id <span style="color: #993333; font-weight: bold;">ASC</span>
  <span style="color: #993333; font-weight: bold;">LIMIT</span> <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span>;</pre></div></div>

<p>И собственно сами результаты:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">+----+--------------+------------+--------+---------------+---------+---------+------+---------+----------+------------------------------+
| id | select_type  | table      | type   | possible_keys | key     | key_len | ref  | rows    | filtered | Extra                        |
+----+--------------+------------+--------+---------------+---------+---------+------+---------+----------+------------------------------+
|  1 | PRIMARY      | &lt;derived2&gt; | system | NULL          | NULL    | NULL    | NULL |       1 |   100.00 | Using filesort               |
|  1 | PRIMARY      | r1         | ALL    | PRIMARY       | NULL    | NULL    | NULL | 1000000 |   100.00 | Using where                  |
|  2 | DERIVED      | NULL       | NULL   | NULL          | NULL    | NULL    | NULL |    NULL |     NULL | No tables used               |
|  3 | SUBQUERY     | NULL       | NULL   | NULL          | NULL    | NULL    | NULL |    NULL |     NULL | Select tables optimized away |
|  4 | UNION        | &lt;derived5&gt; | system | NULL          | NULL    | NULL    | NULL |       1 |   100.00 |                              |
|  4 | UNION        | r1         | range  | PRIMARY       | PRIMARY | 4       | NULL |  153726 |   100.00 | Using where                  |
|  5 | DERIVED      | NULL       | NULL   | NULL          | NULL    | NULL    | NULL |    NULL |     NULL | No tables used               |
|  6 | SUBQUERY     | NULL       | NULL   | NULL          | NULL    | NULL    | NULL |    NULL |     NULL | Select tables optimized away |
| NULL | UNION RESULT | &lt;union1,4&gt; | ALL  | NULL          | NULL    | NULL    | NULL |    NULL |     NULL |                              |
+----+--------------+------------+--------+---------------+---------+---------+------+---------+----------+------------------------------+</pre></div></div>

<p>Запрос состоит из 2х SELECT&#8217;ов и UNION&#8217;а. Результат UNION получается за счет объединения id 1 и 4 (<code>union1,4</code>), что можно увидеть в последней строке.</p>
<p>Id 1 это JOIN между временной таблицей <code>derived2</code> и <code>random</code>. Поскольку id остается неизменным, запрос как правило является частью JOIN. deriverd2 это результат id 2 (<code>DERIVED</code>) с его подзапросом id3.</p>
<p>Мы использовали несколько трюков для того чтобы довести до оптимайзера идею, что ему не надо читать данные с диска при выполнении различных частей запроса:</p>
<ul>
<li><a href="http://dev.mysql.com/doc/refman/5.1/en/where-optimizations.html">MAX(id)</a> может быть оптимизирован в данном случае последним значением индекса. Это единичный поиск, который не требует ни сортировки, ни группировки&#8230; (id 3 and 6)</li>
<li>Мы вынесли рассчет <code>RAND() * MAX(id)</code> в подзапрос, чтобы быть уверенными, что оптимизация MAX() действительно имеет место (вычисляется один раз // прим. пер.) (id 2 and 5)</li>
<li>Мы использовали <a href="http://dev.mysql.com/doc/refman/5.0/en/limit-optimization.html">ORDER BY + LIMIT</a> чтобы оптимайзер выполнил <a href="http://dev.mysql.com/doc/refman/5.1/en/where-optimizations.html">INDEX READ</a> и остановился после обнаружения одной строки. (id 1 and 4)</li>
</ul>
<h2>стоимость выборки</h2>
<p>Мы можем доказать нашу теорию при помощи проверки <a href="http://dev.mysql.com/doc/refman/5.0/en/server-status-variables.html">SHOW STATUS</a>.</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #66cc66;">&gt;</span> <span style="color: #993333; font-weight: bold;">FLUSH</span> <span style="color: #993333; font-weight: bold;">STATUS</span>;
<span style="color: #66cc66;">&gt;</span> <span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #66cc66;">...</span>;
<span style="color: #66cc66;">&gt;</span> <span style="color: #993333; font-weight: bold;">SHOW</span> <span style="color: #993333; font-weight: bold;">SESSION</span> <span style="color: #993333; font-weight: bold;">STATUS</span>;</pre></div></div>

<p>Команда <code>FLUSH STATUS</code> сбрасывает значения счетчиков для текущей сессии, команда <code>SHOW SESSION STATUS</code> отображает счетчики:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">| Select_full_join                  | 0         |
| Select_full_range_join            | 0         |
| Select_range                      | 2         |
| Select_range_check                | 0         |
| Select_scan                       | 1         |</pre></div></div>

<p>Мы имеем 2 <code>range scans</code> (ORDER BY + LIMIT), по одному для каждой части нашего UNION и 1 <code>table scan</code> для чтения результатов UNION и отправки их на клиент.</p>
<p>Для того чтобы доказать что мы не используем дорогую сортировку &#8211; проверим счетчики <code>Sort</code>-*:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">| Sort_merge_passes                 | 0         |
| Sort_range                        | 0         |
| Sort_rows                         | 0         |
| Sort_scan                         | 0         |</pre></div></div>

<p>Таблица для тестов содержит 1 миллион строк, но мы читаем всего несколько штук из них:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">## наши временные таблицы:
| Created_tmp_tables                | 3         | 2 вторичные таблицы + UNION RESULT
## тут мы пишем только во временные таблицы в памяти
| Handler_write                     | 4         | (1 строка + 1 строка) для вторичных таблиц + 2 строки для результата UNION
## MAX(id) выполняет Index-lookup для _last_ id
| Handler_read_first                | 2         |
## ... и мы ищем одну строку для random-id внутри JOIN
| Handler_read_key                  | 2         |
| Handler_read_next                 | 0         |
| Handler_read_prev                 | 0         |
| Handler_read_rnd                  | 0         |
## все чтения из временных таблиц не индексированы
| Handler_read_rnd_next             | 5         |
## виртуальная стоимость запроса ... &quot;foobars&quot;
| Last_query_cost                   | 10.499000 |</pre></div></div>

<h2>а что насчет &#8220;старого доброго&#8221; ORDER BY RAND?</h2>
<p>Ради прикола посмотрим на классический запрос еще раз:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">&gt; FLUSH STATUS;
&gt; SELECT name FROM random ORDER BY RAND() LIMIT 1;
&gt; SHOW SESSION STATUS;
&gt; EXPLAIN SELECT name FROM random ORDER BY RAND() LIMIT 1;
+----+-------------+--------+------+---------------+------+---------+------+---------+---------------------------------+
| id | select_type | table  | type | possible_keys | key  | key_len | ref  | rows    | Extra                           |
+----+-------------+--------+------+---------------+------+---------+------+---------+---------------------------------+
|  1 | SIMPLE      | random | ALL  | NULL          | NULL | NULL    | NULL | 1000000 | Using temporary; Using filesort |
+----+-------------+--------+------+---------------+------+---------+------+---------+---------------------------------+</pre></div></div>

<p>В общем дело было так: ALL rows &#8211; все строки &#8211; сортируются во временной таблице и озвращается лишь одна!</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">## цена запроса &quot;несколько&quot; выше :)
| Last_query_cost                   | 210744.186500 |
## у нас используется только одна временная таблица, с намного бОльшим числом строк
| Created_tmp_tables                | 1             |
| Handler_write                     | 1349207       |
## Выполняется один ГИГАНТСКИЙ table-scan для заполнения временной таблицы
| Select_scan                       | 1             |
| Handler_read_rnd_next             | 2349209       |
## и тяжелейшая сортировка
| Sort_merge_passes                 | 19            |
| Sort_range                        | 0             |
| Sort_rows                         | 2             |
| Sort_scan                         | 1             |</pre></div></div>

</div>
<blockquote><p>Источник: <a href="http://jan.kneschke.de/projects/mysql/analyzing-complex-queries/" target="_blank">http://jan.kneschke.de/projects/mysql/analyzing-complex-queries/</a></p>
<p>Перевод как водится мой. Также хочу отметить что не смотря на небольшой объем текста перевод выдался тяжелым с точки зрения понимания. Если видите что я где-то накосячил или не прав &#8211; отпишите в комметариях или в личку. 10nx )</p>
<p>Да, лично для меня статья оказалось полезна в плане использования счетчиков и интерпретации их значений. Надеюсь и вам тоже.
</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://hudson.su/2011/03/24/mysql-analyzing-complex-queries/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ProFTPD &#8211; symlink = mount</title>
		<link>http://hudson.su/2010/12/22/proftpd-symlink-mount/</link>
		<comments>http://hudson.su/2010/12/22/proftpd-symlink-mount/#comments</comments>
		<pubDate>Wed, 22 Dec 2010 14:32:12 +0000</pubDate>
		<dc:creator>hudson</dc:creator>
				<category><![CDATA[Профессиональное]]></category>
		<category><![CDATA[hints]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://hudson.su/?p=1683</guid>
		<description><![CDATA[Потребовалось мне сделать на девелопеском сервере логин для временного человечка, который JavaScript кумекает. Это конечно не проблема, но вот что меня в тупик поставило на некоторое время. Помимо собственно FTP на сервер, человечку нужен был виртуальный хост для его отладочных нужд. Сервер как правило использовался только проверенными людьми, поэтому особо с безопасностью никто особо не [...]]]></description>
			<content:encoded><![CDATA[<p>Потребовалось мне сделать на девелопеском сервере логин для временного человечка, который JavaScript кумекает. Это конечно не проблема, но вот что меня в тупик поставило на некоторое время.</p>
<p>Помимо собственно FTP на сервер, человечку нужен был виртуальный хост для его отладочных нужд. Сервер как правило использовался только проверенными людьми, поэтому особо с безопасностью никто особо не заморачивался. Ан вот приспичило. На счастье, попался мне на просторах интерентов документик <a href="http://www.proftpd.org/docs/howto/Chroot.html" target="_blank">ProFTPD mini howto</a>, в котором подробно разбирается почему демон не хочет работать с прямыми симлинками из хомяка в docroot виртуальника (в моем случае). Собственно остановился я на этом решении:</p>
<blockquote><p><strong>Filesystem Tricks</strong> [...]</p>
<p>To have an exact duplicate of the <code>/var/ftp/incoming directory</code> available in <code>/home/bob/incoming</code> and <code>/home/dave/incoming</code>, use one of these commands:</p>
<p>Linux (as of the 2.4.0 kernel):</p>
<pre>  mount --bind /var/ftp/incoming /home/bob/incoming
  mount --bind /var/ftp/incoming /home/dave/incoming</pre>
</blockquote>
<p>Что я в общем-то и применил.</p>
<p>P.S. Надеюсь дыр в безопасности не добавил )</p>
]]></content:encoded>
			<wfw:commentRss>http://hudson.su/2010/12/22/proftpd-symlink-mount/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

