<?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; propel</title>
	<atom:link href="http://hudson.su/tag/propel/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>Магические числа и таблицы-справочники в Doctrine/Propel</title>
		<link>http://hudson.su/2010/03/08/magic-numbers-and-reference-tables-in-doctrine-propel/</link>
		<comments>http://hudson.su/2010/03/08/magic-numbers-and-reference-tables-in-doctrine-propel/#comments</comments>
		<pubDate>Mon, 08 Mar 2010 13:34:06 +0000</pubDate>
		<dc:creator>hudson</dc:creator>
				<category><![CDATA[Профессиональное]]></category>
		<category><![CDATA[doctrine]]></category>
		<category><![CDATA[hints]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[propel]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://hudson.su/?p=1086</guid>
		<description><![CDATA[Кросспост моего хабратопика. Коль скоро у вас в проекте используется база данных, то вам рано или поздно потребуются справочные таблицы. Такие таблицы я бы условно разбил на три категории: Небольшие справочники, до 10, реже 20 записей. Например &#8211; таблица статусов чего-нибудь (active&#124;inactive&#124;deleted как минимум). Средние справочники &#8211; от 20 до нескольких сотен записей. Например, таблица [...]]]></description>
			<content:encoded><![CDATA[<p>Кросспост моего <a target="_blank" href="http://hudson.habrahabr.ru/blog/86730/">хабратопика</a>.</p>
<p>Коль скоро у вас в проекте используется база данных, то вам рано или поздно потребуются справочные таблицы. Такие таблицы я бы условно разбил на три категории:</p>
<ol>
<li>Небольшие справочники, до 10, реже 20 записей. <i>Например &#8211; таблица статусов чего-нибудь (active|inactive|deleted как минимум)</i>.</li>
<li>Средние справочники &#8211; от 20 до нескольких сотен записей. <i>Например, таблица типов или категорий чего-либо</i>.</li>
<li>Большие справочники &#8211; от нескольких сотен до сотен тысяч записей. <i>Например список городов и улиц России</i>.</li>
</ol>
<p>Справочники, как правило, заполняются разово при создании и крайне редко пополняются. Но тем не менее, пополнение возможно и наиболее вероятно для третьего типа, менее для второго и редко для первого.</p>
<p>Собственно зачем я это пишу:</p>
<p><span id="more-1086"></span></p>
<p>Раз у вас есть таблица, то есть и классы модели для нее. Все хорошо, пока вам в коде не приходится сослаться на какое-то значение из справочника. Например есть таблица <code>Status</code>:</p>
<pre>
|    id    |     name       |
----------------------------
|    1     |     active     |
|    2     |     inactive   |
|    3     |     deleted    |
</pre>
<p>В связанных таблицах мы имеем <code>HasOne: Status</code>, и foreign key на <code>status.id</code>.</p>
<p>И вот нам понадобилось выбрать все активные записи. Не долго думая мы пишем:</p>
<pre>
$query = Doctrine_Query::create()
  -&gt;select()
  -&gt;from( "Product p, p.Status s" )
  -&gt;where( "s.name = 'active'" )
//...
</pre>
<p>Oops. Джойн хорош, но нам постоянно добавлять его к любому запросу неинтересно. &#8220;Рефакторим&#8221;:</p>
<pre>
$query = Doctrine_Query::create()
  -&gt;select()
  -&gt;from( "Product p" )
  -&gt;where( "p.status_id = 1" )
//...
</pre>
<p>OOOOOooops. По проекту плодятся магические числа:</p>
<pre>
status_id = 2
type_id = 36
city_id = 1234
</pre>
<p><b>Стоп.</b></p>
<p>а) мы не хотим в каждый запрос, который требует связки со справочником пихать join (да и name=&#8221;active&#8221; тоже магическая константа по сути, но вербально понятная).<br />
б) мы не хотим плодить магические числа.</p>
<p>И какой же выход?</p>
<p>Честно говоря, <b>красивого</b> выхода я не вижу. Для справочников типа 1 я применяю следующий подход:</p>
<pre>
// Status
class StatusTable extends Doctrine_Table
{
  const STATUS_ACTIVE   = 1;
  const STATUS_INACTIVE = 2;
  const STATUS_DELETED  = 3;
  ...
}
// Product
class ProductTable extends Doctrine_Table
{
  public function getActive()
  {
    ...
    -&gt;addWhere( "p.status_id = ?", self::STATUS_ACTIVE ) // ну или как-то так <img src='http://hudson.su/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />
  }
  ...
}
</pre>
<p>Этот подход более-менее работает только со справочниками типа 1 (при этом, при добавлении нового статуса попробуй еще вспомнить, что надо добавить еще одну константу, благо это не часто требуется).</p>
<p>Со справочниками типов 2 и 3 вообще не знаю что делать. </p>
<p>А как вы работаете со справочниками?</p>
<p>P.S. не факт что со справочниками типа 3 приходится работать &#8220;точечно&#8221;, поэтому для них может это и не актуально.</p>
]]></content:encoded>
			<wfw:commentRss>http://hudson.su/2010/03/08/magic-numbers-and-reference-tables-in-doctrine-propel/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#8220;CASE WHEN&#8230;&#8221; в Propel без потери hydrate</title>
		<link>http://hudson.su/2009/12/03/case-when-in-propel-without-hydration-lost/</link>
		<comments>http://hudson.su/2009/12/03/case-when-in-propel-without-hydration-lost/#comments</comments>
		<pubDate>Thu, 03 Dec 2009 11:38:21 +0000</pubDate>
		<dc:creator>hudson</dc:creator>
				<category><![CDATA[Профессиональное]]></category>
		<category><![CDATA[hints]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[propel]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://hudson.su/?p=520</guid>
		<description><![CDATA[Постановка задачи: требуется составить Criteria для Propel, который позволяет выполнить запрос с использованием CASE WHEN и при этом не потерять выбираемые колонки и гидрацию объектов. Собственно казалось бы, используем конструкцию $criteria-&#62;addAsColumn(&#8230;) и все. Но не тут то было, при использовании этого запроса теряются все колонки, выбираемые по-умолчанию Propel&#8217;ом. Итак, вот, пример запроса который нам нужно [...]]]></description>
			<content:encoded><![CDATA[<p>Постановка задачи: требуется составить Criteria для Propel, который позволяет выполнить запрос с использованием <strong>CASE WHEN</strong> и при этом не потерять выбираемые колонки и гидрацию объектов.</p>
<p><span id="more-520"></span></p>
<p>Собственно казалось бы, используем конструкцию <strong>$criteria-&gt;addAsColumn(&#8230;)</strong> и все. Но не тут то было, при использовании этого запроса теряются все колонки, выбираемые по-умолчанию Propel&#8217;ом.</p>
<p>Итак, вот, пример запроса который нам нужно выполнить:</p>
<pre>SELECT
    `table`.`id`,
    `table`.`field1`,
    `table`.`field2`,
    CASE
    WHEN
        `table`.`photo_count` &gt; 0
    THEN 1
    WHEN
        `table`.`photo_count` = 0
    THEN 0
    END as has_photo
FROM
    `table`
WHERE
    `table`.`status_id` = 2
AND
    `table`.`type_id` = 1
...
ORDER BY
    has_photo DESC,
    `table`.`created_at` DESC
</pre>
<p>Ключевые особенности &#8211; дополнительное &#8220;поле&#8221; photo_count принимает значение 0 или 1 и по нему осуществляется сортировка. При этом на выходе мы хотим получить Propel-объекты.</p>
<p>На самом деле решение очень простое:</p>
<pre>PropertyPeer::addSelectColumns( $criteria );
$criteria-&gt;addAsColumn(
    "has_photo" ,
    "CASE WHEN " . TablePeer::PHOTO_COUNT . " &gt; 0 THEN 1 " .
    "WHEN " . TablePeer::PHOTO_COUNT . " = 0 THEN 0 END"
);
$criteria-&gt;addDescendingOrderByColumn( "has_photo" );
</pre>
<p>Ключевой особенностью этого решения является первая строка. Просто, не так ли? Тем не менее чтобы найти решение проблемы потребовался не один час, куча нервов. Собственно ответ был найден в trac&#8217;е propel &#8211; <a href="http://propel.phpdb.org/trac/ticket/643">http://propel.phpdb.org/trac/ticket/643</a></p>
<p>с уважением, отдел по борьбе с propel )))</p>
]]></content:encoded>
			<wfw:commentRss>http://hudson.su/2009/12/03/case-when-in-propel-without-hydration-lost/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

