<?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>Изучаем Web &#187; ORM</title>
	<atom:link href="http://brotkin.ru/tag/orm/feed/" rel="self" type="application/rss+xml" />
	<link>http://brotkin.ru</link>
	<description>ковыряемся в Internet</description>
	<lastBuildDate>Tue, 10 Jan 2012 21:51:39 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" />
		<item>
		<title>Ko3: знаете ли вы? Часть 3</title>
		<link>http://brotkin.ru/2011/07/15/do-you-know-3/</link>
		<comments>http://brotkin.ru/2011/07/15/do-you-know-3/#comments</comments>
		<pubDate>Fri, 15 Jul 2011 11:37:09 +0000</pubDate>
		<dc:creator>BIakaVeron</dc:creator>
				<category><![CDATA[знаете ли вы]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[date]]></category>
		<category><![CDATA[helpers]]></category>
		<category><![CDATA[ORM]]></category>
		<category><![CDATA[session]]></category>
		<category><![CDATA[template]]></category>

		<guid isPermaLink="false">http://brotkin.ru/?p=285</guid>
		<description><![CDATA[
Если надо использовать функции СУБД (типа SUM() или COUNT()), то по умолчанию Ko3 заключит имя функции в кавычки или апострофы (в зависимости от того, в качестве имени поля будет функция или как выражение where). Чтобы этого избежать, можно применить один из двух методов:
1. Класс Database_Expression. Он создан специально для подобных случаев. Для краткости удобно использовать [...]]]></description>
			<content:encoded><![CDATA[<ol>
<li>Если надо использовать функции СУБД (типа <code>SUM()</code> или <code>COUNT()</code>), то по умолчанию <strong>Ko3</strong> заключит имя функции в кавычки или апострофы (в зависимости от того, в качестве имени поля будет функция или как выражение <em>where</em>). Чтобы этого избежать, можно применить один из двух методов:<br />
1. Класс <strong>Database_Expression</strong>. Он создан специально для подобных случаев. Для краткости удобно использовать <code>DB::expr($expression)</code>, который по сути аналогичен вызову <code>new Database_Expression($expression)</code>. Вот примеры его использования:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// сформирует запрос SELECT COUNT(*) AS `cnt` FROM `blog`</span>
DB<span style="color: #339933;">::</span><span style="color: #004000;">select</span><span style="color: #009900;">&#40;</span>DB<span style="color: #339933;">::</span><span style="color: #004000;">expr</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'COUNT(*) AS `cnt`'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">from</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'blog'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">execute</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// сформирует запрос SELECT * FROM `blog` WHERE `created` &gt; NOW() - INTERVAL 1 DAY</span>
DB<span style="color: #339933;">::</span><span style="color: #004000;">select</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">from</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'blog'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">where</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'created'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'&gt;'</span><span style="color: #339933;">,</span> DB<span style="color: #339933;">::</span><span style="color: #004000;">expr</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'NOW() - INTERVAL 1 DAY'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">execute</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p></code></p>
<p>2. Если заключить в двойные кавычки имена полей внутри функций, то экранирование не произойдет. К сожалению, не подойдет для второго примера, зато сократит длину первого:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">DB<span style="color: #339933;">::</span><span style="color: #004000;">select</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'COUNT(&quot;*&quot;) AS `cnt`'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">from</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'blog'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">execute</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p></code>
</li>
<li>С помощью <strong>Query Builder</strong> можно реализовать множественную вставку записей одним запросом:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">DB<span style="color: #339933;">::</span><span style="color: #004000;">insert</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$table_name</span><span style="color: #009900;">&#41;</span>
    <span style="color: #339933;">-&gt;</span><span style="color: #004000;">columns</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$columns</span><span style="color: #009900;">&#41;</span>
    <span style="color: #339933;">-&gt;</span><span style="color: #004000;">values</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$set1</span><span style="color: #009900;">&#41;</span>
    <span style="color: #339933;">-&gt;</span><span style="color: #004000;">values</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$set2</span><span style="color: #009900;">&#41;</span>
    <span style="color: #339933;">-&gt;</span><span style="color: #004000;">values</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$set3</span><span style="color: #009900;">&#41;</span>
    <span style="color: #339933;">-&gt;</span><span style="color: #004000;">execute</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p></code>
</li>
<li>Частенько бывает необходимо сохранить в шаблоне какие-то переменные (например, в конструкторе или в <code>before()</code>). Но что, если надо (в зависимости от каких-либо условий) поменять текущий шаблон на другой? Казалось бы, мы потеряем часть сохраненных данных? На помощь придет метод <code>set_filename()</code>, по названию которого можно догадаться, что мы устанавливаем новый путь к обрабатываемому шаблону. При этом все свойства шаблона (в том числе и подшаблоны) останутся на месте:
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// было </span>
<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">template</span> <span style="color: #339933;">=</span> View<span style="color: #339933;">::</span><span style="color: #004000;">factory</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'new/template'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// стало</span>
<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">template</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">set_filename</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'new/template'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p></code></p>
<p>При этом помним, что для вызова метода <code>set_filename()</code> необходимо, чтобы искомая переменная была объектом <strong>View</strong>. В случае с <strong>Controller_Template</strong> <code>$this->template</code> из строки во <strong>View</strong> превращается в методе <code>before()</code>.</li>
<li>Методы <code>set()</code> и <code>get()</code> класса <strong>Session</strong> не позволяют работать с переменными-массивами, т.е. надо сперва извлечь весь массив, потом поработать с ним и сохранить обратно. Удобно использовать такой подход:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$data</span> <span style="color: #339933;">=</span> <span style="color: #339933;">&amp;</span> Session<span style="color: #339933;">::</span><span style="color: #004000;">instance</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">as_array</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;">// дальше делаем с массивом, что хотим</span>
<span style="color: #000088;">$data</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'foo'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'bar'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p></code>
</li>
<li>Как мы знаем, методы <code>find()</code> и <code>find_all()</code> моделей <strong>ORM </strong>сбрасывают текущие условия выборки. Часто бывает нужно сохранить их для следующего запроса (например, для пагинатора нужно еще и общее число записей). Для этого есть специальный метод <code>reset()</code>, который позволяет не только сбрасывать модель, но и сохранять ее текущее состояние:
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$user</span> <span style="color: #339933;">=</span> ORM<span style="color: #339933;">::</span><span style="color: #004000;">factory</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'user'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #339933;">-&gt;</span><span style="color: #004000;">where</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'activated'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'='</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">reset</span><span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">FALSE</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// просим ORM не сбрасывать состояние после запроса</span>
<span style="color: #000088;">$total</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">count_all</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$users</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">find_all</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p></code>
</li>
<li>Многие рутинные вещи в <strong>Kohana</strong> уже присутствуют, так что не стоит изобретать свои велосипеды. Например, в классе <strong>Date</strong> есть константы для перевода календарных единиц в секунды (<code>Date::MINUTE</code>, <code>Date::HOUR</code>, <code>Date::YEAR</code> и т.д.). Еще в нем есть очень полезные методы для работы с датой (вычисление количества минут/часов/лет, форматирование даты и т.д.). Также и в хэлпере <strong>Text</strong> полным-полно нужных функций (о них я <a href="http://brotkin.ru/2009/05/06/xelper-text/">писал</a> ранее). </li>
<li>Используете в проекте защиту от <a href="http://wikipedia.org/wiki/Cross_Site_Request_Forgery">CSRF</a>? Тогда методы <code>Security::token()</code> и <code>Security::check($token)</code> Вам в помощь. Первый метод возвращает сгенерированный токен (берет из сессии, если нет &#8211; генерирует новый), а второй осуществляет сравнение с переданным значением <code>$token</code> (можно использовать как правило валидации).</li>
</ol>

<div class="bookmarkz"><a href="http://www.google.com/bookmarks/mark?op=add&bkmk=http://brotkin.ru/2011/07/15/do-you-know-3/&title=Ko3%3A+%D0%B7%D0%BD%D0%B0%D0%B5%D1%82%D0%B5+%D0%BB%D0%B8+%D0%B2%D1%8B%3F+%D0%A7%D0%B0%D1%81%D1%82%D1%8C+3+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/google.png" border="0" width="16" height="16" alt="Google Bookmarks" title="Google Bookmarks"></a> <a href="http://digg.com/submit?url=http://brotkin.ru/2011/07/15/do-you-know-3/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/digg.png" border="0" width="16" height="16" alt="Digg" title="Digg"></a> <a href="http://reddit.com/submit?url=http://brotkin.ru/2011/07/15/do-you-know-3/&title=Ko3%3A+%D0%B7%D0%BD%D0%B0%D0%B5%D1%82%D0%B5+%D0%BB%D0%B8+%D0%B2%D1%8B%3F+%D0%A7%D0%B0%D1%81%D1%82%D1%8C+3+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/reddit.png" border="0" width="16" height="16" alt="Reddit" title="Reddit"></a> <a href="http://del.icio.us/post?url=http://brotkin.ru/2011/07/15/do-you-know-3/&title=Ko3%3A+%D0%B7%D0%BD%D0%B0%D0%B5%D1%82%D0%B5+%D0%BB%D0%B8+%D0%B2%D1%8B%3F+%D0%A7%D0%B0%D1%81%D1%82%D1%8C+3+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/delicious.png" border="0" width="16" height="16" alt="del.icio.us" title="del.icio.us"></a> <a href="http://ma.gnolia.com/beta/bookmarklet/add?url=http://brotkin.ru/2011/07/15/do-you-know-3/&title=Ko3%3A+%D0%B7%D0%BD%D0%B0%D0%B5%D1%82%D0%B5+%D0%BB%D0%B8+%D0%B2%D1%8B%3F+%D0%A7%D0%B0%D1%81%D1%82%D1%8C+3+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web&description=Ko3%3A+%D0%B7%D0%BD%D0%B0%D0%B5%D1%82%D0%B5+%D0%BB%D0%B8+%D0%B2%D1%8B%3F+%D0%A7%D0%B0%D1%81%D1%82%D1%8C+3+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/magnolia.png" border="0" width="16" height="16" alt="Ma.gnolia" title="Ma.gnolia"></a> <a href="http://www.technorati.com/faves?add=http://brotkin.ru/2011/07/15/do-you-know-3/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/technorati.png" border="0" width="16" height="16" alt="Technorati" title="Technorati"></a> <a href="http://www.slashdot.org/bookmark.pl?url=http://brotkin.ru/2011/07/15/do-you-know-3/&title=Ko3%3A+%D0%B7%D0%BD%D0%B0%D0%B5%D1%82%D0%B5+%D0%BB%D0%B8+%D0%B2%D1%8B%3F+%D0%A7%D0%B0%D1%81%D1%82%D1%8C+3+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/slashdot.png" border="0" width="16" height="16" alt="Slashdot" title="Slashdot"></a> <a href="http://myweb2.search.yahoo.com/myresults/bookmarklet?u=http://brotkin.ru/2011/07/15/do-you-know-3/&t=Ko3%3A+%D0%B7%D0%BD%D0%B0%D0%B5%D1%82%D0%B5+%D0%BB%D0%B8+%D0%B2%D1%8B%3F+%D0%A7%D0%B0%D1%81%D1%82%D1%8C+3+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/yahoo.png" border="0" width="16" height="16" alt="Yahoo My Web" title="Yahoo My Web"></a> <a href="http://news2.ru/add_story.php?url=http://brotkin.ru/2011/07/15/do-you-know-3/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/news2ru.png" border="0" width="16" height="16" alt="News2.ru" title="News2.ru"></a> <a href="http://www.bobrdobr.ru/addext.html?url=http://brotkin.ru/2011/07/15/do-you-know-3/&title=Ko3%3A+%D0%B7%D0%BD%D0%B0%D0%B5%D1%82%D0%B5+%D0%BB%D0%B8+%D0%B2%D1%8B%3F+%D0%A7%D0%B0%D1%81%D1%82%D1%8C+3+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/bobrdobr.png" border="0" width="16" height="16" alt="БобрДобр.ru" title="БобрДобр.ru"></a> <a href="http://rumarkz.ru/bookmarks/?action=add&popup=1&address=http://brotkin.ru/2011/07/15/do-you-know-3/&title=Ko3%3A+%D0%B7%D0%BD%D0%B0%D0%B5%D1%82%D0%B5+%D0%BB%D0%B8+%D0%B2%D1%8B%3F+%D0%A7%D0%B0%D1%81%D1%82%D1%8C+3+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/rumarkz.png" border="0" width="16" height="16" alt="RUmarkz" title="RUmarkz"></a> <a href="http://www.vaau.ru/submit/?action=step2&url=http://brotkin.ru/2011/07/15/do-you-know-3/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/vaau.png" border="0" width="16" height="16" alt="Ваау!" title="Ваау!"></a> <a href="http://memori.ru/link/?sm=1&u_data[url]=http://brotkin.ru/2011/07/15/do-you-know-3/&u_data[name]=Ko3%3A+%D0%B7%D0%BD%D0%B0%D0%B5%D1%82%D0%B5+%D0%BB%D0%B8+%D0%B2%D1%8B%3F+%D0%A7%D0%B0%D1%81%D1%82%D1%8C+3+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/memori.png" border="0" width="16" height="16" alt="Memori.ru" title="Memori.ru"></a> <a href="http://www.rucity.com/bookmarks.php?action=add&address=http://brotkin.ru/2011/07/15/do-you-know-3/&title=Ko3%3A+%D0%B7%D0%BD%D0%B0%D0%B5%D1%82%D0%B5+%D0%BB%D0%B8+%D0%B2%D1%8B%3F+%D0%A7%D0%B0%D1%81%D1%82%D1%8C+3+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/rucity.png" border="0" width="16" height="16" alt="rucity.com" title="rucity.com"></a> <a href="http://moemesto.ru/post.php?url=http://brotkin.ru/2011/07/15/do-you-know-3/&title=Ko3%3A+%D0%B7%D0%BD%D0%B0%D0%B5%D1%82%D0%B5+%D0%BB%D0%B8+%D0%B2%D1%8B%3F+%D0%A7%D0%B0%D1%81%D1%82%D1%8C+3+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/moemesto.png" border="0" width="16" height="16" alt="МоёМесто.ru" title="МоёМесто.ru"></a> <a href="http://www.mister-wong.ru/index.php?action=addurl&bm_url=http://brotkin.ru/2011/07/15/do-you-know-3/&bm_description=Ko3%3A+%D0%B7%D0%BD%D0%B0%D0%B5%D1%82%D0%B5+%D0%BB%D0%B8+%D0%B2%D1%8B%3F+%D0%A7%D0%B0%D1%81%D1%82%D1%8C+3+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/mrwong.png" border="0" width="16" height="16" alt="Mister Wong" title="Mister Wong"></a> </div>
]]></content:encoded>
			<wfw:commentRss>http://brotkin.ru/2011/07/15/do-you-know-3/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>ORM в Kohana v3.1</title>
		<link>http://brotkin.ru/2011/02/21/orm-in-kohana-v31/</link>
		<comments>http://brotkin.ru/2011/02/21/orm-in-kohana-v31/#comments</comments>
		<pubDate>Sun, 20 Feb 2011 21:30:03 +0000</pubDate>
		<dc:creator>biakaveron</dc:creator>
				<category><![CDATA[Kohana3]]></category>
		<category><![CDATA[Kohana]]></category>
		<category><![CDATA[kohana 3.1]]></category>
		<category><![CDATA[ORM]]></category>
		<category><![CDATA[версии]]></category>

		<guid isPermaLink="false">http://brotkin.ru/?p=582</guid>
		<description><![CDATA[Вместе с изменениями ядра фреймворка в ветке 3.1.x происходят и изменения в коде модулей. Один из самых популярных (а также наиболее непонятных для новичков) &#8211; это модуль ORM, поэтому просто необходимо прокомментировать произошедшие в нем коррективы. Большинство из них, конечно же, связаны с революцией в валидации Kohana v3.1.
CRUD
Помимо метода save() теперь есть отдельные методы create() [...]]]></description>
			<content:encoded><![CDATA[<p>Вместе с изменениями ядра фреймворка в ветке <strong>3.1.x</strong> происходят и изменения в коде модулей. Один из самых популярных (а также наиболее непонятных для новичков) &#8211; это модуль <strong>ORM</strong>, поэтому просто необходимо прокомментировать произошедшие в нем коррективы. Большинство из них, конечно же, связаны с <a href="http://brotkin.ru/2011/01/10/ko-31-rc1/">революцией в валидации</a> Kohana <strong>v3.1</strong>.</p>
<h2>CRUD</h2>
<p>Помимо метода <code>save()</code> теперь есть отдельные методы <code>create()</code> и <code>update()</code> для добавления новой или обновления старой записи соответственно. Метод <code>save()</code> просто запускает <code>create()</code> или <code>update()</code> в зависимости от <code>$this->loaded()</code>. </p>
<h2>Фильтры</h2>
<p>Как мы помним, ранее валидация в <strong>ORM</strong> держалась на трех китах &#8211; фильтры, правила и коллбэки. После всех тех изменений в ветке <strong>3.1</strong> валидация сводится к использованию правил. Но фильтры остались, изменилась их роль в модели. Я уже писал, что разработчики Kohana считают правильным подгонять данные модели под нужный формат на этапе присвоения значения, а не в момент валидации. И вот результат &#8211; в <strong>ORM v3.1</strong> появилась возможность применять различного рода преобразования перед сохранением значения в поле модели.</p>
<p>Вот как это примерно может выглядеть:</p>
<p><code></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> filters<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: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #009900; font-weight: bold;">TRUE</span>        <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
         <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'trim'</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: #0000ff;">'username'</span>  <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
         <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'strtolower'</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: #0000ff;">'login_count'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'intval'</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: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></code></p>
<p>Теперь фильтры указываются не в свойстве <code>$_filters</code>, а в методе <code>filters()</code>, который должен возвращать массив. Ключами массива являются либо имена полей, либо <strong>TRUE</strong> (т.е. фильтр действует на все поля). Каждому ключу соответствует массив фильтров, фильтры тоже представляют собой массивы вида (фильтр, параметры). В приведенных выше примерах явно указаны только имена фильтров (стандартные функции php), они достаточно просты. Но роль фильтров может быть значительно расширена засчет все тех же контекстов, введенных в валидации <strong>Kohana v3.1</strong>. Давайте представим, что у нас текстовое поле <code>text</code>, которое не должно содержать более 100 символов:</p>
<p><code></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> filters<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: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #0000ff;">'text'</span>   <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
         <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'text::limit_chars'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">':value'</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">100</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">''</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
      <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
   <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>      
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></code></p>
<p>Вуаля! При установке значения будет вызван метод <code>text::limit_chars()</code>, который обрежет значение до 100 символов. Строка &#8216;<em>:value</em>&#8216;, конечно же, является контекстом, который будет заменен на фильтруемое значение. Третьим параметром я передаю пустую строку, т.к. по умолчанию добавится символ &#8220;многоточие&#8221;.</p>
<blockquote><p>В качестве контекстов можно использовать не только &#8216;<em>:value</em>&#8216;, но также &#8216;<em>:model</em>&#8216; (текущая модель) и &#8216;<em>:field</em>&#8216; (имя поля, к которому относится фильтр).</p></blockquote>
<p>Пример выше можно расширить еще больше. Представим, что у нас есть поля <code>text</code> и <code>intro</code>, причем <code>intro</code> является укороченной версией значения из <code>text</code> и мы не хотим заполнять его в явном виде. Создадим фильтр, который будет при заполнении поля <code>text</code> вычислять значение и для <code>intro</code>:</p>
<p><code></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> filters<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: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #0000ff;">'text'</span>   <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
         <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'set_intro'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
      <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
   <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>      
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> set_intro<span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</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;">intro</span> <span style="color: #339933;">=</span> text<span style="color: #339933;">::</span><span style="color: #004000;">limit_chars</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">100</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">''</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #b1b100;">return</span> <span style="color: #000088;">$value</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></code></p>
<blockquote><p>Не забудьте вернуть значение <code>$value</code>, это обязательное требование для фильтров!</p></blockquote>
<p>Все просто &#8211; фильтр вызывает метод <code>set_info()</code> для текущего объекта модели, а тот заполняет вычисляемое поле <code>intro</code>. Получаем что-то вроде <code>Jelly_Field_Expression</code> из <strong>Jelly</strong>.</p>
<h2>Метки (labels)</h2>
<p>Тут изменение достаточно простое &#8211; как и в случае с фильтрами, вместо свойства <code>$_labels</code> надо создавать метод <code>labels()</code>:</p>
<p><code></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> labels<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: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #0000ff;">'text'</span>   <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'article text'</span><span style="color: #339933;">,</span>
   <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></code></p>
<h2>Валидация</h2>
<p>Из валидации убраны фильтры, коллбэки и правила теперь по сути одно и то же. Достигается это за счет использования все тех же контекстов валидации, создавать сложные функции для проверки полей модели. В качестве контекстов доступны &#8216;<em>:field</em>&#8216;, &#8216;<em>:value</em>&#8216;, &#8216;<em>:validation</em>&#8216; (имя поля, его значение и сам объект <strong>Validation</strong> &#8211; эти контексты устанавливаются классом <strong>Validation</strong>) и  &#8216;<em>:model</em>&#8216; (текущая модель <strong>ORM</strong>). В общем, возможности для валидации весьма широки, и грустить об отказе от коллбэков в их изначальном виде не приходится.</p>
<p>Объявляются правила в методе <code>rules()</code>:</p>
<p><code></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> rules<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: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #0000ff;">'username'</span>   <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
         <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'not_empty'</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;">'min_length'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">':value'</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">4</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
         <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'is_unique'</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;">':value'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">':validation'</span><span style="color: #009900;">&#41;</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: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></code></p>
<p>Первое правило просто проверяет поле &#8216;<em>username</em>&#8216; на наличие значения. Обратите внимание, что стандартные правила класса <strong>Valid</strong> можно указывать просто по имени, а не как &#8216;<em>Valid::not_empty</em>&#8216; или <code>array('Valid', 'not_empty')</code>. Параметры в данное правило оставляем пустые, в этом случае автоматически будет передавать проверяемое значение (т.е. контекст &#8216;<em>:value</em>&#8216;). Второе правило проверяет на минимальную длину, и тут уже мы передаем два параметра &#8211; значение и минимальное число символов. Третий параметр по сути является коллбэком, это вызов метода <code>is_unique()</code> с передачей в него значения и объекта <strong>Validation</strong>. </p>
<p>Объект <strong>Validation</strong> нужен для передачи в него текста ошибки, если вдруг коллбэк обнаружит расхождения. Выглядеть это будет примерно так:</p>
<p><code></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> is_unique<span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span><span style="color: #339933;">,</span> <span style="color: #000088;">$validation</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
   <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #339933;">!</span> условие на уникальность<span style="color: #009900;">&#41;</span>
   <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$validation</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">error</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'username'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'username is not unique'</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></code></p>
<p>Чтобы метод <code>is_unique()</code> был более универсальным, в него можно дополнительно передавать контекст &#8216;<em>:field</em>&#8216; и писать ошибку с его использованием. Например, можно будет проверять не только <code>username</code>, но и <code>email</code> &#8211; механизм проверки в принципе ничем не отличается.</p>
<h2>Проверка модели</h2>
<p>Вызов валидации осуществляется все тем же методом <code>check()</code>. Но теперь метод возвращает не <strong>TRUE</strong>/<strong>FALSE</strong>, а бросает исключение <strong>ORM_Validation_Exception</strong>, если найдены ошибки (прямо как в <strong>Jelly</strong>). Соответственно теперь каждая проверка должна быть заключена в блок <code>try...catch()</code>:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">try <span style="color: #009900;">&#123;</span>
   <span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">save</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
catch<span style="color: #009900;">&#40;</span>ORM_Validation_Exception <span style="color: #000088;">$e</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
   <span style="color: #666666; font-style: italic;">// произошла ошибка валидации</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></code></p>
<p>Да-да, из приведенного мной участка кода следует, что метод <code>check()</code> автоматически вызывается при сохранении модели методами <code>save()</code>, <code>create()</code> и <code>update()</code>.</p>
<h2>Работа над ошибками валидации</h2>
<p>Если раньше мы могли получить ошибки через встроенный объект <strong>Validate</strong> модели <strong>ORM</strong> (конструкцией вида <code>$user->validate()->errors()</code>), то теперь для этого надо использовать бросаемое исключение. Для этого в классе <strong>ORM_Validation_Exception</strong> существует метод <code>errors()</code>:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">try <span style="color: #009900;">&#123;</span>
   <span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">save</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
catch<span style="color: #009900;">&#40;</span>ORM_Validation_Exception <span style="color: #000088;">$e</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
   <span style="color: #000088;">$errors</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$e</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">errors</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'validation'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></code></p>
<p>Принцип такой же &#8211; передаем в метод <code>errors()</code> путь к переводу в <code>messages</code>, а также булевский файл, переводить ли результат через <strong>i18n</strong>. Замечу, что можно использовать и <code>$user->validation()->errors('validation')</code> &#8211; этот метод тоже вернет тексты ошибок. Тогда в чем же разница? Об этом &#8211; следующий пункт различий.</p>
<h2>Внешняя валидация</h2>
<p>На форумах часто спрашивают, как проверить данные для нескольких моделей, либо данные для модели + капчу. Раньше эта задача полностью ложилась на плечи разработчика проекта, но сейчас <strong>ORM</strong> предлагает свое решение. В методы <code>check()</code>, <code>save()</code>, <code>create()</code> и <code>update()</code> можно передавать дополнительный объект класса <strong>Validation</strong>, который уже должен быть подготовлен к проверке (т.е. иметь загруженные входящие данные, правила и т.д.). </p>
<p>Перед проверкой самой модели метод дополнительно проверяется этот дополнительный объект <strong>Validation</strong> (если передан), и результат его проверки влияет на общий итог валидации модели. Ошибки будут добавлены в бросаемое исключение, поэтому и рекомендуется извлечение ошибок через объект <strong>ORM_Validation_Exception</strong> &#8211; он просто обладает информацией о внешних ошибках.</p>
<blockquote><p>Таким образом, валидация будет провалена даже если сама модель заполнена корректно, но, к примеру, капча неверна.</p></blockquote>
<p>В связи с возможным наличием &#8220;посторонних&#8221; ошибок, генерация ошибок несколько усложняется. Теперь массив ошибок (до перевода, его можно получить методом <code>errors()</code> без параметров) помимо ошибок самих полей модели содержит массив ошибок внешней валидации под индексом &#8216;<em>_external</em>&#8216;. А сам механизм перевода ошибок выглядит так:</p>
<ul>
<li>Вызываем метод <code>errors($directory, $translate)</code> исключения <strong>ORM_Validation_Exception</strong>, передавая туда в качестве первого параметра имя директории с переводом. Если не хотите брать перевод непосредственно из папки <code>messages</code>, то передайте пустую строку.</li>
<li>Внутри исключения происходит поиск файлов с переводом, учитывая переданный параметр <code>$directory</code>. Предположим, передали <code>$directory = 'valid'</code>. Для валидации полей модели <strong>Model_User</strong> будет ожидаться имя файла <em>messages/valid/user.php</em> (где &#8216;<em>user</em>&#8216; &#8211; имя модели, хранимое в свойстве <code>$_object_name</code>),  если он не найден, то перевод берется из файла <em>messages/validation.php</em>. </li>
<li>Для ошибок внешней валидации будет вычислен путь <em>messages/valid/user/_external.php</em>. Опять же, если такой файл не найден (или в нем нет нужного перевода), идем к дефолтному <em>messages/validation.php</em>. </li>
</ul>
<p>Решение достаточно интересное. С одной стороны, мы можем предусмотреть <em>custom</em>&#8216;ные внешние ошибки для каждой модели, используя файлы <code>_external.php</code>, а с другой &#8211; всегда можно положиться на старый добрый <em>messages/validation.php</em>, в котором уже прописаны все стандартные тексты.</p>
<h2>Прочие отличия от 3.0</h2>
<ul>
<li>Добавлено свойство <code>$_db_group</code>. Оно выполняет функции свойства <code>$_db</code> из ветки <strong>3.0</strong>, т.е. содержит имя профиля <strong>Database</strong> для данной модели. Таким образом, при портировании своих моделей из <strong>3.0</strong> в <strong>3.1</strong> надо помнить об этом изменении, иначе модели будут использовать дефолтную конфигурацию.</li>
<li>Метод <code>add($alias, $far_keys)</code>, который позволяет добавлять связь <strong>HABTM</strong>, в версии <strong>3.1</strong> поддерживает большое число форматов для параметра <code>$far_keys</code> &#8211; это может конкретная модель <strong>ORM</strong> (единственный вариант, доступный в <strong>3.0</strong>), ее первичный ключ, или даже массив ключей (для добавления сразу нескольких связей). Зато исчезла возможность передать дополнительные значения в промежуточную таблицу, вероятно как раз из-за возможного добавления нескольких записей.</li>
<li>Метод <code>remove($alias, $far_keys)</code> работает по тому же принципу &#8211; можно передать один или несколько идентификаторов, а если параметр <code>$far_keys</code> пустой, то удалятся все имеющиеся записи для данной связи.</li>
<li>В метод <code>values($values, $expected)</code> добавлен второй параметр &#8211; список ключей загружаемого массива, которые надо учитывать. Бывает удобно, когда в качестве массива <code>$values</code> выступает <code>$_POST</code> или <code>$_GET</code>. Кстати, хотя в комментариях к этому методу написано, что он поддерживает загрузку данных для связи <em>1-к-1</em> (<code>has_one</code> и <code>belongs_to</code>), реализации данного функционала я не нашел. Шажок назад по сравнению с <strong>3.0</strong>.</li>
<li>Класс <strong>ORM</strong> реализовывает интерфейс <a href="http://php.net/manual/en/class.serializable.php">serializable</a>, в соответствии с которым добавлены методы <code>serialize()</code> и <code>unserialize()</code>. Напомню, что в <strong>3.0</strong> использовались &#8220;магические&#8221; <code>__sleep()</code> и <code>__wakeup()</code>.</li>
<li>Добавлены PhpDoc-комментарии, описывающие методы объектов <strong>Query Builder</strong> (например <code>where()</code> или <code>from()</code>) и &#8220;магические&#8221; методы модели, возвращающие соответствующие защищенные свойства (например, знаете ли вы, что <code>$user->has_many()</code> вернет значение свойства <code>$_has_many</code>?). Правда, в случае с магическими методами <strong>IDE</strong> правильно подсказывать не будет, т.к. методы почему-то описаны как свойства (т.е. с использованием <code>@property</code> вместо <code>@method</code>).</li>
</ul>
<p>В заключение скажу, что изменения достаточно интересные, правда слегка однобокие (все ушло в валидацию). Лично я все жду, когда в <strong>ORM</strong> добавятся алиасы для полей, как в <strong>Jelly</strong>.</p>

<div class="bookmarkz"><a href="http://www.google.com/bookmarks/mark?op=add&bkmk=http://brotkin.ru/2011/02/21/orm-in-kohana-v31/&title=ORM+%D0%B2+Kohana+v3.1+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/google.png" border="0" width="16" height="16" alt="Google Bookmarks" title="Google Bookmarks"></a> <a href="http://digg.com/submit?url=http://brotkin.ru/2011/02/21/orm-in-kohana-v31/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/digg.png" border="0" width="16" height="16" alt="Digg" title="Digg"></a> <a href="http://reddit.com/submit?url=http://brotkin.ru/2011/02/21/orm-in-kohana-v31/&title=ORM+%D0%B2+Kohana+v3.1+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/reddit.png" border="0" width="16" height="16" alt="Reddit" title="Reddit"></a> <a href="http://del.icio.us/post?url=http://brotkin.ru/2011/02/21/orm-in-kohana-v31/&title=ORM+%D0%B2+Kohana+v3.1+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/delicious.png" border="0" width="16" height="16" alt="del.icio.us" title="del.icio.us"></a> <a href="http://ma.gnolia.com/beta/bookmarklet/add?url=http://brotkin.ru/2011/02/21/orm-in-kohana-v31/&title=ORM+%D0%B2+Kohana+v3.1+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web&description=ORM+%D0%B2+Kohana+v3.1+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/magnolia.png" border="0" width="16" height="16" alt="Ma.gnolia" title="Ma.gnolia"></a> <a href="http://www.technorati.com/faves?add=http://brotkin.ru/2011/02/21/orm-in-kohana-v31/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/technorati.png" border="0" width="16" height="16" alt="Technorati" title="Technorati"></a> <a href="http://www.slashdot.org/bookmark.pl?url=http://brotkin.ru/2011/02/21/orm-in-kohana-v31/&title=ORM+%D0%B2+Kohana+v3.1+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/slashdot.png" border="0" width="16" height="16" alt="Slashdot" title="Slashdot"></a> <a href="http://myweb2.search.yahoo.com/myresults/bookmarklet?u=http://brotkin.ru/2011/02/21/orm-in-kohana-v31/&t=ORM+%D0%B2+Kohana+v3.1+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/yahoo.png" border="0" width="16" height="16" alt="Yahoo My Web" title="Yahoo My Web"></a> <a href="http://news2.ru/add_story.php?url=http://brotkin.ru/2011/02/21/orm-in-kohana-v31/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/news2ru.png" border="0" width="16" height="16" alt="News2.ru" title="News2.ru"></a> <a href="http://www.bobrdobr.ru/addext.html?url=http://brotkin.ru/2011/02/21/orm-in-kohana-v31/&title=ORM+%D0%B2+Kohana+v3.1+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/bobrdobr.png" border="0" width="16" height="16" alt="БобрДобр.ru" title="БобрДобр.ru"></a> <a href="http://rumarkz.ru/bookmarks/?action=add&popup=1&address=http://brotkin.ru/2011/02/21/orm-in-kohana-v31/&title=ORM+%D0%B2+Kohana+v3.1+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/rumarkz.png" border="0" width="16" height="16" alt="RUmarkz" title="RUmarkz"></a> <a href="http://www.vaau.ru/submit/?action=step2&url=http://brotkin.ru/2011/02/21/orm-in-kohana-v31/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/vaau.png" border="0" width="16" height="16" alt="Ваау!" title="Ваау!"></a> <a href="http://memori.ru/link/?sm=1&u_data[url]=http://brotkin.ru/2011/02/21/orm-in-kohana-v31/&u_data[name]=ORM+%D0%B2+Kohana+v3.1+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/memori.png" border="0" width="16" height="16" alt="Memori.ru" title="Memori.ru"></a> <a href="http://www.rucity.com/bookmarks.php?action=add&address=http://brotkin.ru/2011/02/21/orm-in-kohana-v31/&title=ORM+%D0%B2+Kohana+v3.1+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/rucity.png" border="0" width="16" height="16" alt="rucity.com" title="rucity.com"></a> <a href="http://moemesto.ru/post.php?url=http://brotkin.ru/2011/02/21/orm-in-kohana-v31/&title=ORM+%D0%B2+Kohana+v3.1+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/moemesto.png" border="0" width="16" height="16" alt="МоёМесто.ru" title="МоёМесто.ru"></a> <a href="http://www.mister-wong.ru/index.php?action=addurl&bm_url=http://brotkin.ru/2011/02/21/orm-in-kohana-v31/&bm_description=ORM+%D0%B2+Kohana+v3.1+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/mrwong.png" border="0" width="16" height="16" alt="Mister Wong" title="Mister Wong"></a> </div>
]]></content:encoded>
			<wfw:commentRss>http://brotkin.ru/2011/02/21/orm-in-kohana-v31/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Развитие Jelly ORM</title>
		<link>http://brotkin.ru/2010/11/26/jelly-future/</link>
		<comments>http://brotkin.ru/2010/11/26/jelly-future/#comments</comments>
		<pubDate>Fri, 26 Nov 2010 13:13:21 +0000</pubDate>
		<dc:creator>biakaveron</dc:creator>
				<category><![CDATA[Kohana3]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[jelly]]></category>
		<category><![CDATA[ko3]]></category>
		<category><![CDATA[ORM]]></category>
		<category><![CDATA[validation]]></category>

		<guid isPermaLink="false">http://brotkin.ru/?p=542</guid>
		<description><![CDATA[Многие заметили, что развитие многообещающего ORM под названием Jelly подзадержалось (последний релиз был еще весной, с тех пор транк разработки содержит только небольшие летние багфиксы. Казалось бы, такой сильный проект загнулся? Как бы не так! Бравые ребята Jonathan Geiger и Paul Banks ушли в подполье и работают в поте лица, просто результатов работы так просто [...]]]></description>
			<content:encoded><![CDATA[<p>Многие заметили, что развитие многообещающего <strong>ORM</strong> под названием <a href="http://jelly.jonathan-geiger.com/">Jelly</a> подзадержалось (последний релиз был еще весной, с тех пор транк разработки содержит только небольшие летние багфиксы. Казалось бы, такой сильный проект загнулся? Как бы не так! Бравые ребята <em>Jonathan Geiger</em> и <em>Paul Banks</em> ушли в подполье и работают в поте лица, просто результатов работы так просто не видать&#8230;</p>
<p>В общем, все события происходят не в транке <a href="http://github.com/jonathangeiger/kohana-jelly.git">проекта</a>, я для исследования взял ветку со страшным названием <a href="https://github.com/jonathangeiger/kohana-jelly/tree/unstable">unstable</a>. Небольшие результаты этих ковыряний я и хочу вам представить, так сказать для затравки перед будущим полноценным релизом.<span id="more-542"></span></p>
<h3>Базовые изменения</h3>
<ul>
<li>Имена полей теперь должны начинаться с префикса <code>Jelly_</code>, т.е. если раньше было <code>Field_BelongsTo</code>, то теперь надо писать <code>Jelly_Field_BelongsTo</code>. Вполне логично, резко уменьшаем вероятность коллизий с другими подключаемыми модулями.</li>
<li>Метода Jelly::select() теперь нет. Его задачи разделены между Jelly::factory() и новым методом Jelly::query(). Первый теперь отвечает за создание пустой модели, плюс имеется возможность передать туда ключ для непосредственной загрузки нужной записи. Тут все стало как в ORM. Для всех остальных действий, связанных с записями в БД, используется Jelly::query(). Он возвращает объект типа Jelly_Builder.<br />
Например, можно удалить несколько записей с учетом примененных условий:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// дело происходит внутри модели, поэтому передаем $this</span>
<span style="color: #666666; font-style: italic;">// а можно передать имя модели к примеру</span>
Jelly<span style="color: #339933;">::</span><span style="color: #004000;">query</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #009900;">&#41;</span>
        <span style="color: #339933;">-&gt;</span><span style="color: #004000;">where</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'expires'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'&lt;'</span><span style="color: #339933;">,</span> <span style="color: #990000;">time</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;">delete</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p></code></p>
<blockquote><p>Впрочем, многие наверняка захотят заменить вызов ->where(&#8230;) на более элегантное ->expired(), используя <a href="http://jelly.jonathan-geiger.com/docs/jelly.extending-builder">расширение объекта Jelly_Builder</a>.</p></blockquote>
</li>
</ul>
<h3>События и Поведения (Events &#038; Behaviors)</h3>
<p>Ага, теперь есть набор заранее определенных событий, возникающих при стандартных действиях (сохранение записей, инициализация моделей и т.д.). Полный список на данный момент такой:</p>
<ul>
<li>builder.call_&lt;метод></li>
<li>builder.before_select</li>
<li>builder.after_select</li>
<li>builder.before_insert</li>
<li>builder.after_insert</li>
<li>builder.before_update</li>
<li>builder.after_update</li>
<li>builder.before_delete</li>
<li>builder.after_delete</li>
<li>meta.before_finalize</li>
<li>meta.after_finalize</li>
<li>model.call_&lt;метод></li>
<li>model.before_validate</li>
<li>model.after_validate</li>
<li>model.before_save</li>
<li>model.after_save</li>
<li>model.before_delete</li>
<li>model.after_delete</li>
</ul>
<p>Имя события состоит из объекта-инициатора (модель, <code>Jelly_Builder</code>, <code>Jelly_Meta</code>) и собственно описания этого события (как правило это префикс <em>before_</em> или <em>after_</em>, и само событие). Чтобы обрабатывать эти события, используется еще одно понятие &#8211; поведение модели (<em>behavior</em>), реализовываемое классом <code>Jelly_Behavior</code>. </p>
<p>Сперва создается собственно класс, описывающий поведение модели. Например, для <code>Model_User</code> он будет называться <code>Model_User_Behavior</code> (на самом деле имя может быть практически любое):<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Model_User_Behavior <span style="color: #000000; font-weight: bold;">extends</span> Jelly_Behavior <span style="color: #009900;">&#123;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> model_before_save<span style="color: #009900;">&#40;</span><span style="color: #000088;">$user</span><span style="color: #339933;">,</span> <span style="color: #000088;">$event</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
             <span style="color: #666666; font-style: italic;">// тут делаем свои проверки, можно писать логи и т.д.</span>
	<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></code></p>
<blockquote><p>Имя метода зависит от имени нужного события (просто заменяем точку на подчеркивание). Параметры тоже могут различаться. Но первый &#8211; обязательно сама модель, а последний &#8211; событие (точнее, не <code>Jelly_Event</code>, а <code>Jelly_Event_Data</code>). Модель нам нужна для получения &#8220;пациента&#8221;, а событие &#8211; для обратной связи (влияние на работу самого события и инициировавшего его процесса). </p></blockquote>
<p>Если что-то нас не устраивает (данные в модели не подходят для сохранения), устанавливаем параметр <code>$event->return</code> в <strong>FALSE</strong>, а <code>$event->stop</code> в <strong>TRUE</strong>. Свойство <code>return</code> содержит результат работы события (успешным считается любое не-<strong>FALSE</strong> значение), а stop означает, что дальше это событие отрабатываться не будет (да-да, можно вешать несколько обработчиков-поведений на одну модель). </p>
<blockquote><p>Помните, что просто установить свойство <code>return</code> в <strong>FALSE</strong> может быть недостаточно, т.к. последующие обработчики это значение могут запросто затереть.</p></blockquote>
<p>Подключать обработчики надо, естественно, в методе <code>initialize($meta)</code>:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$meta</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">behaviors</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
   <span style="color: #0000ff;">'user'</span>  <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Model_User_Behavior<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>

<p></code></p>
<blockquote><p>Ветка <a href="https://github.com/jonathangeiger/kohana-jelly/tree/behaviors">behaviors</a> развивалась еще весной, но сейчас там код, сильно отличающийся от <em>unstable</em>, поэтому я его отбросил. Хотя там были интересные реализации, например <em>SoftDelete</em> для &#8220;мягкого&#8221; удаления записей в БД.</p></blockquote>
<p>Поведения довольно удобная штука, например я за полчаса добавил возможности <em>MPTT</em> из старой своей библиотеки через них. Собственно, разработчики модуля в планах ставят создание поведений для <em>MPTT</em> и <em>ClosureTable</em> (такой способ хранения данных, когда все дерево хранится отдельно в виде пары предок-узел, полностью описывающих всех предков узла до самого корня).</p>
<h3>Изменения в валидации</h3>
<p>Валидация в модели теперь осуществляется своими силами. В модуле появился целый набор классов: <code>Jelly_Validator</code>, <code>Jelly_Validator_Rule</code>, <code>Jelly_Validator_Callback</code> и <code>Jelly_Validator_Filter</code>. Соответственно валидация осуществляется методом <code>validate()</code>, а сам валидатор получить можно через <code>validator($data)</code>, где <code>$data</code> &#8211; необязательный массив данных для проверки (по умолчанию данные берутся из модели). </p>
<p>Появилось понятие &#8220;контекст&#8221; &#8211; это что-то вроде псевдонима для объекта или какого-то значения. Например, при создании модели автоматически создается контекст &#8216;<em>:key</em>&#8216;, содержащий значение ключа, и &#8216;<em>:model</em>&#8216;, содержащий ссылку на текущую модель. Вот пример того, как можно использовать контекст :model:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// поле test, к которому мы хотим добавить callback</span>
<span style="color: #0000ff;">'test'</span>   <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Jelly_Field_String<span style="color: #009900;">&#40;</span>
   <span style="color: #0000ff;">'callbacks'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
         <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">':model'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'test'</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;">':validate'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">':callback'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">':field'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">':value'</span><span style="color: #009900;">&#41;</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>

<p></code><br />
Теперь при валидации поля будет осуществлен вызов метода <code>test()</code> текущей модели (контекст <em>:model</em>) и туда будут переданы объект <code>Jelly_Validator</code> (контекст <em>:validate</em>), текущий объект <code>Jelly_Validator_Callback</code> (<em>:callback</em>), название проверяемого поля и его значение поля (контексты <em>:field</em> и <em>:value</em>). Эти контексты создаются автоматически при проверке каждого поля. Ну и конечно же, можно задавать свои контексты, используя методы <code>context()</code> и <code>contexts()</code> валидатора модели. </p>
<h3>Прочие мелочи</h3>
<p>Добавился класс <code>Jelly_Field_Image</code>. Помимо просто загрузки и сохранения изображения он позволяет сразу создавать превьюшки (указываются в параметрах поля). Можете почитать <a href="http://uk0.us/2010/09/jelly-dobavlyaem-tip-polya-izobrazhenie/">вот тут</a> поподробнее.<br />
В <code>Jelly_Builder</code>&#8216;е появился метод <code>key($value)</code>, который является сокращением от <code>->where($this->unique_key($value), '=', $value)</code>, т.е. позволяет быстро добавить условие по ключу. Удобно.<br />
Также там добавился метод <code>type($type)</code>. С его помощью можно на лету менять тип запроса (<code>Database::SELECT</code>, <code>Database::INSERT</code> и т.д.). </p>
<p>В моделях появлась возможность сбросить все изменения (вернуться к первоначально загруженному состоянию), с помощью метода <code>revert()</code>.</p>
<h3>Неразобранное</h3>
<ul>
<li>Встречал в нескольких местах упоминание поля <code>Jelly_Field_Polymorphic</code> и некоего ключа <code>polymorphic_key</code>. Но вроде бы это все еще не реализовано, работы судя по всему велись/ведутся ветке <a href="https://github.com/jonathangeiger/kohana-jelly/tree/polymorphic">Polymorphic</a>. Либо часть реализации будет лежать на плечах пользователей модуля (?).</li>
<li>Скорее всего для этих же целей вводится понятие &#8220;дочерних&#8221; моделей (<em>children</em>). Класс <code>Jelly_Meta</code> позволяет устанавливать и получать дочерние модели (названия классов) через метод <code>children()</code>. При этом поля, являющиеся <code>Jelly_Field_Polymorphic</code> (они по идее и должны содержать имена моделей), автоматически<br />
добавляют свои значение в свойство <code>$_children</code>.</li>
</ul>
<h3>Процесс идет&#8230;</h3>
<p>Интересностей много. Многое еще наверняка скрыто в недрах этого замечательного модуля. Тем не менее, он выглядит вполне работоспособным. </p>

<div class="bookmarkz"><a href="http://www.google.com/bookmarks/mark?op=add&bkmk=http://brotkin.ru/2010/11/26/jelly-future/&title=%D0%A0%D0%B0%D0%B7%D0%B2%D0%B8%D1%82%D0%B8%D0%B5+Jelly+ORM+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/google.png" border="0" width="16" height="16" alt="Google Bookmarks" title="Google Bookmarks"></a> <a href="http://digg.com/submit?url=http://brotkin.ru/2010/11/26/jelly-future/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/digg.png" border="0" width="16" height="16" alt="Digg" title="Digg"></a> <a href="http://reddit.com/submit?url=http://brotkin.ru/2010/11/26/jelly-future/&title=%D0%A0%D0%B0%D0%B7%D0%B2%D0%B8%D1%82%D0%B8%D0%B5+Jelly+ORM+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/reddit.png" border="0" width="16" height="16" alt="Reddit" title="Reddit"></a> <a href="http://del.icio.us/post?url=http://brotkin.ru/2010/11/26/jelly-future/&title=%D0%A0%D0%B0%D0%B7%D0%B2%D0%B8%D1%82%D0%B8%D0%B5+Jelly+ORM+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/delicious.png" border="0" width="16" height="16" alt="del.icio.us" title="del.icio.us"></a> <a href="http://ma.gnolia.com/beta/bookmarklet/add?url=http://brotkin.ru/2010/11/26/jelly-future/&title=%D0%A0%D0%B0%D0%B7%D0%B2%D0%B8%D1%82%D0%B8%D0%B5+Jelly+ORM+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web&description=%D0%A0%D0%B0%D0%B7%D0%B2%D0%B8%D1%82%D0%B8%D0%B5+Jelly+ORM+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/magnolia.png" border="0" width="16" height="16" alt="Ma.gnolia" title="Ma.gnolia"></a> <a href="http://www.technorati.com/faves?add=http://brotkin.ru/2010/11/26/jelly-future/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/technorati.png" border="0" width="16" height="16" alt="Technorati" title="Technorati"></a> <a href="http://www.slashdot.org/bookmark.pl?url=http://brotkin.ru/2010/11/26/jelly-future/&title=%D0%A0%D0%B0%D0%B7%D0%B2%D0%B8%D1%82%D0%B8%D0%B5+Jelly+ORM+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/slashdot.png" border="0" width="16" height="16" alt="Slashdot" title="Slashdot"></a> <a href="http://myweb2.search.yahoo.com/myresults/bookmarklet?u=http://brotkin.ru/2010/11/26/jelly-future/&t=%D0%A0%D0%B0%D0%B7%D0%B2%D0%B8%D1%82%D0%B8%D0%B5+Jelly+ORM+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/yahoo.png" border="0" width="16" height="16" alt="Yahoo My Web" title="Yahoo My Web"></a> <a href="http://news2.ru/add_story.php?url=http://brotkin.ru/2010/11/26/jelly-future/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/news2ru.png" border="0" width="16" height="16" alt="News2.ru" title="News2.ru"></a> <a href="http://www.bobrdobr.ru/addext.html?url=http://brotkin.ru/2010/11/26/jelly-future/&title=%D0%A0%D0%B0%D0%B7%D0%B2%D0%B8%D1%82%D0%B8%D0%B5+Jelly+ORM+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/bobrdobr.png" border="0" width="16" height="16" alt="БобрДобр.ru" title="БобрДобр.ru"></a> <a href="http://rumarkz.ru/bookmarks/?action=add&popup=1&address=http://brotkin.ru/2010/11/26/jelly-future/&title=%D0%A0%D0%B0%D0%B7%D0%B2%D0%B8%D1%82%D0%B8%D0%B5+Jelly+ORM+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/rumarkz.png" border="0" width="16" height="16" alt="RUmarkz" title="RUmarkz"></a> <a href="http://www.vaau.ru/submit/?action=step2&url=http://brotkin.ru/2010/11/26/jelly-future/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/vaau.png" border="0" width="16" height="16" alt="Ваау!" title="Ваау!"></a> <a href="http://memori.ru/link/?sm=1&u_data[url]=http://brotkin.ru/2010/11/26/jelly-future/&u_data[name]=%D0%A0%D0%B0%D0%B7%D0%B2%D0%B8%D1%82%D0%B8%D0%B5+Jelly+ORM+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/memori.png" border="0" width="16" height="16" alt="Memori.ru" title="Memori.ru"></a> <a href="http://www.rucity.com/bookmarks.php?action=add&address=http://brotkin.ru/2010/11/26/jelly-future/&title=%D0%A0%D0%B0%D0%B7%D0%B2%D0%B8%D1%82%D0%B8%D0%B5+Jelly+ORM+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/rucity.png" border="0" width="16" height="16" alt="rucity.com" title="rucity.com"></a> <a href="http://moemesto.ru/post.php?url=http://brotkin.ru/2010/11/26/jelly-future/&title=%D0%A0%D0%B0%D0%B7%D0%B2%D0%B8%D1%82%D0%B8%D0%B5+Jelly+ORM+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/moemesto.png" border="0" width="16" height="16" alt="МоёМесто.ru" title="МоёМесто.ru"></a> <a href="http://www.mister-wong.ru/index.php?action=addurl&bm_url=http://brotkin.ru/2010/11/26/jelly-future/&bm_description=%D0%A0%D0%B0%D0%B7%D0%B2%D0%B8%D1%82%D0%B8%D0%B5+Jelly+ORM+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/mrwong.png" border="0" width="16" height="16" alt="Mister Wong" title="Mister Wong"></a> </div>
]]></content:encoded>
			<wfw:commentRss>http://brotkin.ru/2010/11/26/jelly-future/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Объявление связей в Jelly</title>
		<link>http://brotkin.ru/2010/11/09/jelly-relationship-fields/</link>
		<comments>http://brotkin.ru/2010/11/09/jelly-relationship-fields/#comments</comments>
		<pubDate>Tue, 09 Nov 2010 14:37:25 +0000</pubDate>
		<dc:creator>biakaveron</dc:creator>
				<category><![CDATA[Kohana3]]></category>
		<category><![CDATA[jelly]]></category>
		<category><![CDATA[ko3]]></category>
		<category><![CDATA[ORM]]></category>
		<category><![CDATA[relations]]></category>

		<guid isPermaLink="false">http://brotkin.ru/?p=538</guid>
		<description><![CDATA[Итак, недавно мы разбирали стандартные поля Jelly, теперь рассмотрим все, что нужно для описания связей. Лично у меня постоянно возникает путаница в названиях и составе свойств для различных типов связей, поэтому будем систематизировать имеющуюся информацию.
Вступление
В качестве подопытного выступает модель Model_User, которую мы будем постепенно связывать с другими моделями. Настройку будем вести от простого к сложному, [...]]]></description>
			<content:encoded><![CDATA[<p>Итак, недавно мы разбирали <a href="http://brotkin.ru/2010/09/11/jelly-fields/">стандартные поля <strong>Jelly</strong></a>, теперь рассмотрим все, что нужно для описания связей. Лично у меня постоянно возникает путаница в названиях и составе свойств для различных типов связей, поэтому будем систематизировать имеющуюся информацию.</p>
<h3>Вступление</h3>
<p>В качестве подопытного выступает модель <code>Model_User</code>, которую мы будем постепенно связывать с другими моделями. Настройку будем вести от простого к сложному, в начале у нас все по умолчанию. По мере освоения материала будем усложнять задачу нестандартными именами полей и связей. Вся работа происходит в статическом методе <code>initialize(Jelly_Meta $meta)</code>, в котором описываются все специфические свойства модели. Прочитайте <a href="http://brotkin.ru/2010/09/11/jelly-fields/">предыдущую статью</a>, если не помните, как инициализируются модели в <strong>Jelly</strong>. Поля связей принципиально ничего не отличаются, только свойства (параметры для конструктора) в них немного другие.</p>
<h3>Связь типа &#8220;Один-ко-многим&#8221; (HasMany)</h3>
<p>Пусть имеется модель <code>Model_User</code>, с которой ассоциируются статьи (один пользователь может иметь несколько статей). </p>
<p>Короткая форма:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">   <span style="color: #0000ff;">'articles'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_HasMany</pre></div></div>

<p></code></p>
<p>В результате будет автоматически вычислено, что на другом конце связи находится модель <code>Model_Article</code>, внешний ключ &#8211; <code>user_id</code>. </p>
<p>Расширенная форма:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">   <span style="color: #0000ff;">'articles'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_HasMany<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #0000ff;">'foreign'</span>   <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'article.user_id'</span>
   <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span></pre></div></div>

<p></code></p>
<p>Здесь мы уже описали имена модели и внешнего ключа, разделив их точкой. Можно укоротить запись:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">   <span style="color: #0000ff;">'articles'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_HasMany<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #0000ff;">'foreign'</span>   <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'article'</span>
   <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span></pre></div></div>

<p></code> </p>
<p>Опустив имя внешнего ключа, мы подразумеваем автоматическое вычисление его имени. В общем, это эквивалентно записи<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">   <span style="color: #0000ff;">'articles'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_HasMany<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #0000ff;">'foreign'</span>   <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'article.user:foreign_key'</span>
   <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span></pre></div></div>

<p></code><br />
<strong>Jelly</strong> возьмет настройки модели <code>Model_User</code> для извлечения имени внешнего ключа. По умолчанию это <em>имя модели + &#8216;_id&#8217;</em> (как и в <strong>ORM</strong>).</p>
<blockquote><p>Изменить имя внешнего ключа для модели можно с помощью метода <code>foreign_key()</code>, например <code>foreign_key('user_key')</code>.</p></blockquote>
<h3>Связь типа &#8220;Один-к-одному&#8221; (HasOne)</h3>
<p>По сути это частный случай связи HasMany, и синтаксис такой же.</p>
<h3>Связь типа &#8220;Много-к-одному&#8221; (BelongsTo)</h3>
<p>Главное отличие (в плане структуры таблицы) от HasMany в том, что внешний ключ расположен <strong>в данной модели</strong>. Для связи <em>пользователь-статьи</em> это означает, что внешний ключ расположен в модели <code>Model_Article</code>, и участвует в определении связи. Соответственно короткая запись:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">   <span style="color: #0000ff;">'user'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_BelongsTo</pre></div></div>

<p></code><br />
означает, что при обращении к <code>$article->user</code> произойдет попытка загрузить модель <code>Model_User</code> по значению ключа <code>user_id</code> в модели <code>Model_Article</code>.<br />
Если предположить, что связь должна называться &#8216;<em>author</em>&#8216;, а внешний ключ называется <code>author_id</code> и ссылается на первичный ключ <code>id</code> в модели <code>Model_User</code>, то получится такое объявление:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">   <span style="color: #0000ff;">'author'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_BelongsTo<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #0000ff;">'foreign'</span>  <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'user.id'</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'column'</span>  <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'author_id'</span><span style="color: #339933;">,</span>
   <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span></pre></div></div>

<p></code></p>
<p>Свойство <code>foreign</code> содержит все, что касается связанной модели (имя и внешний ключ), а <code>column</code> &#8211; имя поля в данной модели. Думаю, всем понятно, почему <code>column</code> отсутствует в связях HasMany и HasOne <img src='http://brotkin.ru/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  Если значение для <code>column</code> не указано, оно генерируется на основании указанного имени модели с прибавкой суффикса &#8216;<em>_id</em>&#8216;, т.е. <em>user_id</em> в данном случае. Обратите внимание, что используется не имя связи, а <strong>имя модели</strong>!</p>
<blockquote><p>Конечно, для свойства <code>foreign</code> можно (и нужно &#8211; это более гибкая запись) использовать &#8216;<em>user.:primary_key</em>&#8216; или просто &#8216;<em>user</em>&#8216;.</p></blockquote>
<h3>Связь &#8220;Много-ко-многим&#8221; (ManyToMany)</h3>
<p>Этот тип связи характеризуется выносом внешних ключей обеих связанных моделей в промежуточную таблицу (как правило, эта таблица только из этих ключей и состоит). Пусть это будет извечное <em>пользователи-роли</em> с промежуточной таблицей <code>roles_users</code>.<br />
Короткая запись:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">   <span style="color: #0000ff;">'role'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_ManyToMany</pre></div></div>

<p></code><br />
В результате связь будет основана на предположении, что на другом конце находится модель <code>Model_Role</code>, а промежуточная таблица <code>roles_users</code> содержит ключи <code>user_id</code> и <code>role_id</code>. Имя промежуточной модели формируется по такому же принципу, что в <strong>ORM</strong>.</p>
<p>Предположим, что роли находятся в таблице <code>rolez</code> (а модель все та же &#8211; <code>Model_Role</code>) с первичным ключом <code>role_id</code>, промежуточная таблица <code>users_roles</code>, а внешние ключи называются <code>user_ke</code>y и <code>role_key</code>. В таком случае надо использовать полную запись связи:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">   <span style="color: #0000ff;">'rolez'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_ManyToMany<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #0000ff;">'foreign'</span>  <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'role.role_id'</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'through'</span>  <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
         <span style="color: #0000ff;">'model'</span>     <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'users_roles'</span><span style="color: #339933;">,</span>
         <span style="color: #0000ff;">'columns'</span>  <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
             <span style="color: #0000ff;">'user_key'</span><span style="color: #339933;">,</span>
             <span style="color: #0000ff;">'role_key'</span>
         <span style="color: #009900;">&#41;</span>
      <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
   <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span></pre></div></div>

<p></code><br />
Итак, если свойство <code>foreign</code> нам уже знакомо (обозначаем настройки для связи с моделью <code>Model_Role</code>, как в HasMany), то свойство <code>through</code> в новинку. Это массив, который в наиболее полном варианте должен содержать ключи &#8216;<em>model</em>&#8216; (имя промежуточной модели <strong>или таблицы</strong>) и &#8216;<em>columns</em>&#8216; (имена внешних ключей для промежуточной таблицы). Порядок перечисления внешних ключей важен &#8211; сперва идет имя внешнего ключа от <strong>текущей</strong> модели (т.е. при объявлении связи в модели <code>Model_Role</code> мы бы их поменяли местами).<br />
Есть и упрощенный вариант &#8211; указать только имя промежуточной модели/таблицы:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">   <span style="color: #0000ff;">'rolez'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_ManyToMany<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #0000ff;">'foreign'</span>  <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'role.role_id'</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'through'</span>  <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'users_roles'</span>
   <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span></pre></div></div>

<p></code><br />
В этом случае внешние ключи будут вычислены как <code>user.:primary_key</code> и <code>role.:primary_key</code>.</p>
<h3>Заключение</h3>
<p>Давайте представим себе, как будет выглядеть условная модель <code>Model_User</code> со связями:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Model_User <span style="color: #000000; font-weight: bold;">extends</span> Jelly_Model
<span style="color: #009900;">&#123;</span>
   <span style="color: #000000; font-weight: bold;">public</span> static <span style="color: #000000; font-weight: bold;">function</span> initialize<span style="color: #009900;">&#40;</span>Jelly_Meta <span style="color: #000088;">$meta</span><span style="color: #009900;">&#41;</span>
   <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$meta</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">name_key</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'username'</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&gt;</span><span style="color: #004000;">sorting</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'username'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'ASC'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&gt;</span><span style="color: #004000;">fields</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
            <span style="color: #0000ff;">'id'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_Primary<span style="color: #339933;">,</span>
            <span style="color: #0000ff;">'username'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_String<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
               <span style="color: #0000ff;">'unique'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #009900; font-weight: bold;">TRUE</span>
            <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
            <span style="color: #0000ff;">'password'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_Password<span style="color: #339933;">,</span>
            <span style="color: #0000ff;">'email'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_Email<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
               <span style="color: #0000ff;">'unique'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #009900; font-weight: bold;">TRUE</span>
            <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
         <span style="color: #666666; font-style: italic;">// user has many articles</span>
            <span style="color: #0000ff;">'articles'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_HasMany<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
               <span style="color: #0000ff;">'foreign'</span>   <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'article.user_id'</span>
            <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
         <span style="color: #666666; font-style: italic;">// user has one profile</span>
            <span style="color: #0000ff;">'profile'</span>  <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_HasOne<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
               <span style="color: #0000ff;">'foreign'</span>  <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'user_profile'</span>
            <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
         <span style="color: #666666; font-style: italic;">// user has and belongs to many roles</span>
            <span style="color: #0000ff;">'roles'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_ManyToMany<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
               <span style="color: #0000ff;">'foreign'</span>  <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'role'</span><span style="color: #339933;">,</span>
               <span style="color: #0000ff;">'through'</span>  <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
                  <span style="color: #0000ff;">'model'</span>     <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'users_roles'</span><span style="color: #339933;">,</span>
                  <span style="color: #0000ff;">'columns'</span>  <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
                     <span style="color: #0000ff;">'user_id'</span><span style="color: #339933;">,</span>
                     <span style="color: #0000ff;">'role_id'</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: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
            <span style="color: #0000ff;">'group'</span>    <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_BelongsTo<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
               <span style="color: #0000ff;">'foreign'</span>   <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'user_group'</span><span style="color: #339933;">,</span>
               <span style="color: #0000ff;">'column'</span>   <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'group_id'</span>
            <span style="color: #009900;">&#41;</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;">-&gt;</span><span style="color: #004000;">foreign_key</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'user_id'</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></code><br />
Думаю, тут все понятно <img src='http://brotkin.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>

<div class="bookmarkz"><a href="http://www.google.com/bookmarks/mark?op=add&bkmk=http://brotkin.ru/2010/11/09/jelly-relationship-fields/&title=%D0%9E%D0%B1%D1%8A%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5+%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9+%D0%B2+Jelly+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/google.png" border="0" width="16" height="16" alt="Google Bookmarks" title="Google Bookmarks"></a> <a href="http://digg.com/submit?url=http://brotkin.ru/2010/11/09/jelly-relationship-fields/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/digg.png" border="0" width="16" height="16" alt="Digg" title="Digg"></a> <a href="http://reddit.com/submit?url=http://brotkin.ru/2010/11/09/jelly-relationship-fields/&title=%D0%9E%D0%B1%D1%8A%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5+%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9+%D0%B2+Jelly+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/reddit.png" border="0" width="16" height="16" alt="Reddit" title="Reddit"></a> <a href="http://del.icio.us/post?url=http://brotkin.ru/2010/11/09/jelly-relationship-fields/&title=%D0%9E%D0%B1%D1%8A%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5+%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9+%D0%B2+Jelly+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/delicious.png" border="0" width="16" height="16" alt="del.icio.us" title="del.icio.us"></a> <a href="http://ma.gnolia.com/beta/bookmarklet/add?url=http://brotkin.ru/2010/11/09/jelly-relationship-fields/&title=%D0%9E%D0%B1%D1%8A%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5+%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9+%D0%B2+Jelly+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web&description=%D0%9E%D0%B1%D1%8A%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5+%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9+%D0%B2+Jelly+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/magnolia.png" border="0" width="16" height="16" alt="Ma.gnolia" title="Ma.gnolia"></a> <a href="http://www.technorati.com/faves?add=http://brotkin.ru/2010/11/09/jelly-relationship-fields/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/technorati.png" border="0" width="16" height="16" alt="Technorati" title="Technorati"></a> <a href="http://www.slashdot.org/bookmark.pl?url=http://brotkin.ru/2010/11/09/jelly-relationship-fields/&title=%D0%9E%D0%B1%D1%8A%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5+%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9+%D0%B2+Jelly+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/slashdot.png" border="0" width="16" height="16" alt="Slashdot" title="Slashdot"></a> <a href="http://myweb2.search.yahoo.com/myresults/bookmarklet?u=http://brotkin.ru/2010/11/09/jelly-relationship-fields/&t=%D0%9E%D0%B1%D1%8A%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5+%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9+%D0%B2+Jelly+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/yahoo.png" border="0" width="16" height="16" alt="Yahoo My Web" title="Yahoo My Web"></a> <a href="http://news2.ru/add_story.php?url=http://brotkin.ru/2010/11/09/jelly-relationship-fields/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/news2ru.png" border="0" width="16" height="16" alt="News2.ru" title="News2.ru"></a> <a href="http://www.bobrdobr.ru/addext.html?url=http://brotkin.ru/2010/11/09/jelly-relationship-fields/&title=%D0%9E%D0%B1%D1%8A%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5+%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9+%D0%B2+Jelly+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/bobrdobr.png" border="0" width="16" height="16" alt="БобрДобр.ru" title="БобрДобр.ru"></a> <a href="http://rumarkz.ru/bookmarks/?action=add&popup=1&address=http://brotkin.ru/2010/11/09/jelly-relationship-fields/&title=%D0%9E%D0%B1%D1%8A%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5+%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9+%D0%B2+Jelly+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/rumarkz.png" border="0" width="16" height="16" alt="RUmarkz" title="RUmarkz"></a> <a href="http://www.vaau.ru/submit/?action=step2&url=http://brotkin.ru/2010/11/09/jelly-relationship-fields/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/vaau.png" border="0" width="16" height="16" alt="Ваау!" title="Ваау!"></a> <a href="http://memori.ru/link/?sm=1&u_data[url]=http://brotkin.ru/2010/11/09/jelly-relationship-fields/&u_data[name]=%D0%9E%D0%B1%D1%8A%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5+%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9+%D0%B2+Jelly+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/memori.png" border="0" width="16" height="16" alt="Memori.ru" title="Memori.ru"></a> <a href="http://www.rucity.com/bookmarks.php?action=add&address=http://brotkin.ru/2010/11/09/jelly-relationship-fields/&title=%D0%9E%D0%B1%D1%8A%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5+%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9+%D0%B2+Jelly+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/rucity.png" border="0" width="16" height="16" alt="rucity.com" title="rucity.com"></a> <a href="http://moemesto.ru/post.php?url=http://brotkin.ru/2010/11/09/jelly-relationship-fields/&title=%D0%9E%D0%B1%D1%8A%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5+%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9+%D0%B2+Jelly+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/moemesto.png" border="0" width="16" height="16" alt="МоёМесто.ru" title="МоёМесто.ru"></a> <a href="http://www.mister-wong.ru/index.php?action=addurl&bm_url=http://brotkin.ru/2010/11/09/jelly-relationship-fields/&bm_description=%D0%9E%D0%B1%D1%8A%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5+%D1%81%D0%B2%D1%8F%D0%B7%D0%B5%D0%B9+%D0%B2+Jelly+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/mrwong.png" border="0" width="16" height="16" alt="Mister Wong" title="Mister Wong"></a> </div>
]]></content:encoded>
			<wfw:commentRss>http://brotkin.ru/2010/11/09/jelly-relationship-fields/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Описание полей Jelly</title>
		<link>http://brotkin.ru/2010/09/11/jelly-fields/</link>
		<comments>http://brotkin.ru/2010/09/11/jelly-fields/#comments</comments>
		<pubDate>Fri, 10 Sep 2010 20:22:06 +0000</pubDate>
		<dc:creator>biakaveron</dc:creator>
				<category><![CDATA[Kohana3]]></category>
		<category><![CDATA[jelly]]></category>
		<category><![CDATA[ko3]]></category>
		<category><![CDATA[ORM]]></category>

		<guid isPermaLink="false">http://brotkin.ru/?p=465</guid>
		<description><![CDATA[Стартовая статья про замечательный модуль Jelly не могла вместить всей многочисленной информации по использованию данного ORM&#8216;а, поэтому планирую продолжать цикл &#8220;точечными&#8221; статьями. В данный момент попробую систематизировать знания, необходимые при объявлении моделей. В общем, поговорим про описание полей Jelly.
Вступление
Для начала вспомним, как мы описываем свойства модели:


class Model_Auth_User extends Jelly_Model
&#123;
	public static function initialize&#40;Jelly_Meta $meta&#41;
   [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://brotkin.ru/2010/04/29/jelly-intro/">Стартовая статья</a> про замечательный модуль <strong>Jelly</strong> не могла вместить всей многочисленной информации по использованию данного <strong>ORM</strong>&#8216;а, поэтому планирую продолжать цикл &#8220;точечными&#8221; статьями. В данный момент попробую систематизировать знания, необходимые при объявлении моделей. В общем, поговорим про описание полей <strong>Jelly</strong>.<span id="more-465"></span></p>
<h3>Вступление</h3>
<p>Для начала вспомним, как мы описываем свойства модели:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Model_Auth_User <span style="color: #000000; font-weight: bold;">extends</span> Jelly_Model
<span style="color: #009900;">&#123;</span>
	<span style="color: #000000; font-weight: bold;">public</span> static <span style="color: #000000; font-weight: bold;">function</span> initialize<span style="color: #009900;">&#40;</span>Jelly_Meta <span style="color: #000088;">$meta</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
		<span style="color: #000088;">$meta</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">name_key</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'username'</span><span style="color: #009900;">&#41;</span>
			<span style="color: #339933;">-&gt;</span><span style="color: #004000;">sorting</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'username'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'ASC'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
			<span style="color: #339933;">-&gt;</span><span style="color: #004000;">fields</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
			<span style="color: #0000ff;">'id'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_Primary<span style="color: #339933;">,</span>
			<span style="color: #0000ff;">'username'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_String<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
				<span style="color: #0000ff;">'unique'</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;">'rules'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
						<span style="color: #0000ff;">'not_empty'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #009900; font-weight: bold;">NULL</span><span style="color: #339933;">,</span>
						<span style="color: #0000ff;">'max_length'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">32</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
						<span style="color: #0000ff;">'min_length'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">3</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
						<span style="color: #0000ff;">'regex'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/^[\pL_.-]+$/ui'</span><span style="color: #009900;">&#41;</span>
					<span style="color: #009900;">&#41;</span>
				<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
			<span style="color: #0000ff;">'password'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_Password<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
				<span style="color: #0000ff;">'hash_with'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>Auth<span style="color: #339933;">::</span><span style="color: #004000;">instance</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'hash_password'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
				<span style="color: #0000ff;">'rules'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
					<span style="color: #0000ff;">'not_empty'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #009900; font-weight: bold;">NULL</span><span style="color: #339933;">,</span>
					<span style="color: #0000ff;">'max_length'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">50</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
					<span style="color: #0000ff;">'min_length'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">6</span><span style="color: #009900;">&#41;</span>
				<span style="color: #009900;">&#41;</span>
			<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
			<span style="color: #0000ff;">'password_confirm'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_Password<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
				<span style="color: #0000ff;">'in_db'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #009900; font-weight: bold;">FALSE</span><span style="color: #339933;">,</span>
				<span style="color: #0000ff;">'callbacks'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
					<span style="color: #0000ff;">'matches'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Model_Auth_User'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'_check_password_matches'</span><span style="color: #009900;">&#41;</span>
				<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
				<span style="color: #0000ff;">'rules'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
					<span style="color: #0000ff;">'not_empty'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #009900; font-weight: bold;">NULL</span><span style="color: #339933;">,</span>
					<span style="color: #0000ff;">'max_length'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">50</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
					<span style="color: #0000ff;">'min_length'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">6</span><span style="color: #009900;">&#41;</span>
				<span style="color: #009900;">&#41;</span>
			<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
			<span style="color: #0000ff;">'email'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_Email<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
				<span style="color: #0000ff;">'unique'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #009900; font-weight: bold;">TRUE</span>
			<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
			<span style="color: #0000ff;">'logins'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_Integer<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
				<span style="color: #0000ff;">'default'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">0</span>
			<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
			<span style="color: #0000ff;">'last_login'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_Timestamp<span style="color: #339933;">,</span>
			<span style="color: #0000ff;">'tokens'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_HasMany<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
				<span style="color: #0000ff;">'foreign'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'user_token'</span>
			<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
			<span style="color: #0000ff;">'roles'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_ManyToMany
		<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></code></p>
<p>Все происходит в статическом методе <code>initialize()</code>, где мы должны сохранить информацию о связанной с моделью таблице (имя таблицы, имена полей, связи). Для разных типов полей есть предопределенные классы, у каждого из них могут быть свои особенности в настройке и работе. Так как более-менее адекватного руководства я не нашел (плохо искал?), на свет появилась данная статья.</p>
<h3>Общие свойства полей (класс <code>Field_Core</code>)</h3>
<p>Все доступные классы полей являются предками класса <code>Field_Core</code>. Таким образом, все поля в моделях <strong>Jelly</strong> работают со следующими свойствами:</p>
<ul>
<li><code>column</code> &#8211; имя поля в БД. Обычно совпадает с именем поля в модели, но это необязательно.<br />
<blockquote><p>Если при создании поля в конструктор передавать строковое значение, а не массив (т.е. <code>new Field_Primary('myid'))</code>, то это значение будет расцениваться как переданное значение свойства <code>column</code>.</p></blockquote>
</li>
<li><code>primary</code> &#8211; флаг первичного ключа (<strong>FALSE</strong> по умолчанию). Обычно явно не указывается, достаточно для нужного поля установить тип <code>Field_Primary</code> (первичный ключ).</li>
<li><code>unique</code> &#8211; флаг уникальности поля (<strong>FALSE</strong> по умолчанию). Автоматически выставляется в <strong>TRUE</strong> для полей <code>Field_Primary</code>. Добавление этого флага означает, что при валидации модели для данного поля будет применен дополнительный <em>callback</em> <code>_is_unique()</code>. Фактически это приводит к дополнительному запросу БД.</li>
<li><code>in_db</code> &#8211; флаг наличия в БД (<strong>TRUE</strong> по умолчанию). Если установить <strong>FALSE</strong>, получим аналог <em>ignored_columns</em> из <strong>ORM</strong>. </li>
<li><code>default</code> &#8211; значение по умолчанию для поля (изначально <strong>NULL</strong>).</li>
<li><code>null</code> &#8211; конвертировать или нет пустые (<code>empty()</code>) значения в <strong>NULL</strong>. По умолчанию <strong>FALSE</strong>.</li>
</ul>
<p>Кроме этих свойств есть еще несколько, не относящихся к СУБД, но важных при описании полей. </p>
<ul>
<li><code>description</code> &#8211; описание поля. Оно напрямую нигде не используется, но может быть использовано, скажем, при построении форм (для расширенной подсказки о назначении поля). По умолчанию содержит пустую строку.</li>
<li><code>name</code> &#8211; имя поля для генерации элемента формы (т.е. HTML-атрибут name). </li>
<li><code>label</code> &#8211; имя поля в более удобном и понятном человеку формате, чем <code>name</code>. Обычно используется для тэгов <em>LABEL</em> формы. Если не указано явно, примет значение свойства <code>column</code>, обработанное методом <code>inflector::humanize()</code>.</li>
<li><code>filters, rules, callbacks</code> &#8211; эти три свойства используются для валидации полей. Там все стандартно, как и в <strong>ORM</strong>.</li>
</ul>
<h3>Логические поля (<code>Field_Boolean</code>)</h3>
<p>Вроде бы тут все ясно &#8211; либо ДА, либо НЕТ. Но разработчики предпочли гибкость, в результате даже в таком простом поле есть что понастраивать:</p>
<ul>
<li><code>true</code> &#8211; значение, которое надо записывать в БД при положительном значении поля (масло масляное, ага). По умолчанию 1.</li>
<li><code>label_true</code> &#8211; описание положительного значения (по умолчанию &#8220;<em>Yes</em>&#8220;). Может быть использовано при выводе значения на экран или для генерации формы.</li>
<li>false &#8211; аналогично свойству true, только действует для отрицательного значения поля. По умолчанию, естественно, равно 0.</li>
<li><code>label_false</code> &#8211; как вы уже наверняка догадались, метка для свойства <code>false</code>. По умолчанию &#8220;<em>No</em>&#8220;.</li>
</ul>
<p>Скорее всего вы эти свойства менять и не будете. Но сама возможность не может не радовать.</p>
<h3>Метка времени (<code>Field_Timestamp</code>)</h3>
<p>Весьма полезный класс, позволяющий обрабатывать разного рода временные значения. Доступны следующие настройки:</p>
<ul>
<li><code>format</code> &#8211; формат метки времени, в котором значение должно храниться в БД. Синтаксис можно посмотреть в описании <a href="http://php.net/manual/en/function.date.php">функции date()</a>. <strong>NULL</strong> по умолчанию, т.е. никакого преобразования не происходит.</li>
<li><code>pretty_format</code> &#8211; формат метки времени, предназначенный для человеческих глаз. Данный формат используется при генерации элемента формы стандартным шаблоном <strong>Jelly</strong>. Согласитесь, не каждого обрадует значение &#8216;<em>2010-09-09</em>&#8216;. Синтаксис аналогичен свойству <code>format</code>. Значение по умолчанию &#8216;r&#8217; (дата в формате RFC 2822, например &#8216;<em>Thu, 09 Sep 2010 12:00:00 +030</em>0&#8242;).</li>
<li><code>auto_now_create</code> &#8211; флаг, отвечающий за автоматическое заполнение поля текущей меткой времени при первоначальном сохранении (т.е. при создании записи). По умолчанию <strong>FALSE</strong>.</li>
<li><code>auto_now_update</code> &#8211; аналогично <code>auto_now_create</code>, но действует при обновлении записи. По умолчанию <strong>FALSE</strong>.</li>
</ul>
<p>Несмотря на все форматы, сама метка времени в поле хранится в виде целого числа (<em>UNIX timestamp</em>), т.е. можно не напрягать голову мыслями о текущем формате времени.</p>
<h3>Числа с плавающей запятой (<code>Field_Float</code>)</h3>
<p>Данный класс располагает специальным свойство places, который определяет количество знаков после запятой в итоговом числе. Если данное свойство отлично от <strong>NULL</strong> и является числом (<code>is_numeric()</code>), то значение будет округлено до <code>places</code> знаков.</p>
<blockquote><p>Стоит обратить внимание, что отрицательные и дробные значения тоже являются числами, и вполне могут быть использованы в данном свойстве. Например, если установить <code>places = 2.3</code>, то значение будет округлено до двух знаков после запятой (дробная часть отбрасывается). Если же значение отрицательное, то округлять будут целую часть числа, например при <code>places = -2.3</code> число <code>12345.6789</code> будет сохранено в базу как <code>12300</code>. Это может быть полезно при форматировании дробных чисел.</p></blockquote>
<h3>Строковые и целочисленные поля (<code>Field_String, Field_Text, Field_Integer</code>)</h3>
<p>Тут все без каких-либо особенностей, просто значение явно преобразовывается в нужный тип (строковый и числовой соответственно).</p>
<blockquote><p>На данный момент я не нашел различий между <code>Field_String</code> и <code>Field_Text</code> в части реализации. В комментариях написано, что <code>Field_Text</code> предназначен для работы с большими текстами, возможно это еще в @TODO.</p></blockquote>
<h3>Поле ограниченного выбора (<code>Field_Enum</code>)</h3>
<p>Данное поле предназначено для работы с неким заранее известным диапазоном значений. Например, это может быть пол (<em>мужской/женский/не указан</em>) или месяц года. Сами значения для выбора указываются в свойстве <code>choices</code> в виде массива. Можно использовать стандартный массив вида <code>array('male', 'female', 'unknown')</code>, а можно использовать осмысленные значения для ключей: <code>array('1' => 'male', 2 => 'female', 0 => 'unknown')</code>. Это удобно при генерации списков выбора (<em>select list</em>), когда пользователю показывается текстовое описание, за которым скрывается конкретный идентификатор значения в БД.</p>
<blockquote><p>
Если указанное пользователем значение в списке <code>choices</code> отсутствует, то оно будет заменено значением из <code>default</code>. </p></blockquote>
<h3>Вычисляемое поле (Field_Expression)</h3>
<p>Очень интересный тип данных. Он позволяет перекладывать на СУБД функции вычисления каких-либо значений на основе полученных из таблицы данных. Например, у нас есть поле `<em>birthday</em>` (дата рождения). Чтобы получить возраст пользователя, создаем вычисляемое поле:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #0000ff;">'age'</span>   <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_Expression<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #0000ff;">'column'</span> <span style="color: #339933;">=&gt;</span> DB<span style="color: #339933;">::</span><span style="color: #004000;">expr</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'(YEAR(CURRENT_DATE)-YEAR(birthday)) - (RIGHT(CURRENT_DATE,5)&lt;RIGHT(birthday,5))'</span><span style="color: #009900;">&#41;</span>
      <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span></pre></div></div>

<p></code></p>
<p>В результате запрос к БД на выборку данных из таблицы будет содержать дополнительное поле &#8216;<em>age</em>&#8216;, заполняемое содержимым нашего выражения. Так как поле физически в таблице не существует, параметр <code>in_db</code> автоматически устанавливается в <strong>FALSE</strong>.</p>
<blockquote><p>Точнее, <strong>должно было</strong> содержать, по задумке авторов. На самом деле у меня <code>Field_Expression</code> не заработал, пока я не внес кое-какие поправки в класс <code>Jelly_Meta_Core</code>. Тикет <a href="http://github.com/jonathangeiger/kohana-jelly/issues#issue/165">создан</a>, жду реакцию разработчиков.</p></blockquote>
<h3>Поле для хранения пароля (Field_Password)</h3>
<p>Пароль по сути ничем не отличается от обычного строкового поля (поэтому <code>Field_Password extends Field_String</code>), за исключением уже привычной нам традиции шифровать значение при сохранении модели. Единственная доступная нам опция &#8211; свойство <code>hash_with</code>, которое содержит имя функции для шифрования (по умолчанию &#8220;<em>sha1</em>&#8221; &#8211; указывать без скобочек!).</p>
<h3>Slug-поле (Field_Slug)</h3>
<p>Долго ломал голову, как же по-русски назвать этот термин, ничего не придумал <img src='http://brotkin.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  <em>Slug</em> &#8211; это такое нормализованная строка, где могут быть использованы только маленькие латинские буквы, дефисы и слэши (я привел мнение разработчиков <strong>Jelly</strong>). Все остальное заменяется на дефисы. Например, строка &#8216;<em>Hello, World!</em>&#8216; будет автоматом преобразована в &#8216;<em>hello-world</em>&#8216;. Никаких свойств нет, хотя в принципе напрашивается как минимум возможность установки собственного диапазона допустимых символов.</p>
<h3>Поле адреса электронной почты (<code>Field_Email</code>)</h3>
<p>Обычное текстовое (<code>Field_Text</code>) поле, только автоматически будет применяться правило <code>Validate::email()</code> при сохранении.</p>
<h3>Прячем объекты и массивы (<code>Field_Serialized</code>)</h3>
<p>Данное поле позволяет работать с сериализованными (serialized) переменными. Зачем это надо? Бывает удобно хранить массивы или целые объекты в БД (например, конфигурация <strong>ACL</strong> или прочие структуры в том же духе). При заполнении значения происходит попытка восстановить (<em>unserialize</em>) объект, а при сохранении записи в БД &#8211; обратная запаковка (сериализация). Единственный минус (и то, возможно, только мне так кажется) &#8211; вызовы <code>serialize()</code> и <code>unserialize()</code> предваряются &#8220;собачкой&#8221; для подавления ошибок. </p>
<h3>Загрузка файлов (<code>Field_File</code>)</h3>
<p>Данное поле применимо для сохранения загруженных пользователем файлов. Имеется два параметра:</p>
<ul>
<li><code>path</code> &#8211; путь к директории для сохранения. Естественно, директория должна быть доступна для записи. Это обязательное поле, у которого нет значения по умолчанию.</li>
<li><code>delete_old_file</code> &#8211; данный флаг используется при замене одного файла другим. Если <strong>TRUE</strong> (а это значение по умолчанию), то при удачной загрузке новый файл заменит старый не только в БД, но и на диске (т.е. старый файл будет удален физически).</li>
</ul>
<blockquote><p>Сам по себе файл лежит на диске, а в поле хранится его имя. Таким образом, доступ к файлу можно получить через <code>$this->path.$this->value</code>.</p></blockquote>
<h3>Пора заканчивать</h3>
<p>На этом стандартные типы полей <strong>Jelly</strong> закончились. Остались неразобранными поля для описания связей, но это уже будет тема для отдельной статьи.</p>

<div class="bookmarkz"><a href="http://www.google.com/bookmarks/mark?op=add&bkmk=http://brotkin.ru/2010/09/11/jelly-fields/&title=%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5+%D0%BF%D0%BE%D0%BB%D0%B5%D0%B9+Jelly+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/google.png" border="0" width="16" height="16" alt="Google Bookmarks" title="Google Bookmarks"></a> <a href="http://digg.com/submit?url=http://brotkin.ru/2010/09/11/jelly-fields/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/digg.png" border="0" width="16" height="16" alt="Digg" title="Digg"></a> <a href="http://reddit.com/submit?url=http://brotkin.ru/2010/09/11/jelly-fields/&title=%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5+%D0%BF%D0%BE%D0%BB%D0%B5%D0%B9+Jelly+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/reddit.png" border="0" width="16" height="16" alt="Reddit" title="Reddit"></a> <a href="http://del.icio.us/post?url=http://brotkin.ru/2010/09/11/jelly-fields/&title=%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5+%D0%BF%D0%BE%D0%BB%D0%B5%D0%B9+Jelly+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/delicious.png" border="0" width="16" height="16" alt="del.icio.us" title="del.icio.us"></a> <a href="http://ma.gnolia.com/beta/bookmarklet/add?url=http://brotkin.ru/2010/09/11/jelly-fields/&title=%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5+%D0%BF%D0%BE%D0%BB%D0%B5%D0%B9+Jelly+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web&description=%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5+%D0%BF%D0%BE%D0%BB%D0%B5%D0%B9+Jelly+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/magnolia.png" border="0" width="16" height="16" alt="Ma.gnolia" title="Ma.gnolia"></a> <a href="http://www.technorati.com/faves?add=http://brotkin.ru/2010/09/11/jelly-fields/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/technorati.png" border="0" width="16" height="16" alt="Technorati" title="Technorati"></a> <a href="http://www.slashdot.org/bookmark.pl?url=http://brotkin.ru/2010/09/11/jelly-fields/&title=%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5+%D0%BF%D0%BE%D0%BB%D0%B5%D0%B9+Jelly+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/slashdot.png" border="0" width="16" height="16" alt="Slashdot" title="Slashdot"></a> <a href="http://myweb2.search.yahoo.com/myresults/bookmarklet?u=http://brotkin.ru/2010/09/11/jelly-fields/&t=%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5+%D0%BF%D0%BE%D0%BB%D0%B5%D0%B9+Jelly+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/yahoo.png" border="0" width="16" height="16" alt="Yahoo My Web" title="Yahoo My Web"></a> <a href="http://news2.ru/add_story.php?url=http://brotkin.ru/2010/09/11/jelly-fields/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/news2ru.png" border="0" width="16" height="16" alt="News2.ru" title="News2.ru"></a> <a href="http://www.bobrdobr.ru/addext.html?url=http://brotkin.ru/2010/09/11/jelly-fields/&title=%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5+%D0%BF%D0%BE%D0%BB%D0%B5%D0%B9+Jelly+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/bobrdobr.png" border="0" width="16" height="16" alt="БобрДобр.ru" title="БобрДобр.ru"></a> <a href="http://rumarkz.ru/bookmarks/?action=add&popup=1&address=http://brotkin.ru/2010/09/11/jelly-fields/&title=%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5+%D0%BF%D0%BE%D0%BB%D0%B5%D0%B9+Jelly+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/rumarkz.png" border="0" width="16" height="16" alt="RUmarkz" title="RUmarkz"></a> <a href="http://www.vaau.ru/submit/?action=step2&url=http://brotkin.ru/2010/09/11/jelly-fields/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/vaau.png" border="0" width="16" height="16" alt="Ваау!" title="Ваау!"></a> <a href="http://memori.ru/link/?sm=1&u_data[url]=http://brotkin.ru/2010/09/11/jelly-fields/&u_data[name]=%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5+%D0%BF%D0%BE%D0%BB%D0%B5%D0%B9+Jelly+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/memori.png" border="0" width="16" height="16" alt="Memori.ru" title="Memori.ru"></a> <a href="http://www.rucity.com/bookmarks.php?action=add&address=http://brotkin.ru/2010/09/11/jelly-fields/&title=%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5+%D0%BF%D0%BE%D0%BB%D0%B5%D0%B9+Jelly+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/rucity.png" border="0" width="16" height="16" alt="rucity.com" title="rucity.com"></a> <a href="http://moemesto.ru/post.php?url=http://brotkin.ru/2010/09/11/jelly-fields/&title=%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5+%D0%BF%D0%BE%D0%BB%D0%B5%D0%B9+Jelly+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/moemesto.png" border="0" width="16" height="16" alt="МоёМесто.ru" title="МоёМесто.ru"></a> <a href="http://www.mister-wong.ru/index.php?action=addurl&bm_url=http://brotkin.ru/2010/09/11/jelly-fields/&bm_description=%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5+%D0%BF%D0%BE%D0%BB%D0%B5%D0%B9+Jelly+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/mrwong.png" border="0" width="16" height="16" alt="Mister Wong" title="Mister Wong"></a> </div>
]]></content:encoded>
			<wfw:commentRss>http://brotkin.ru/2010/09/11/jelly-fields/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>Нестандартные ORM-модели в сессии</title>
		<link>http://brotkin.ru/2010/07/23/custom-orm-session-trouble/</link>
		<comments>http://brotkin.ru/2010/07/23/custom-orm-session-trouble/#comments</comments>
		<pubDate>Fri, 23 Jul 2010 11:41:45 +0000</pubDate>
		<dc:creator>biakaveron</dc:creator>
				<category><![CDATA[Kohana3]]></category>
		<category><![CDATA[ORM]]></category>

		<guid isPermaLink="false">http://brotkin.ru/?p=443</guid>
		<description><![CDATA[Условия:
1. Есть модель ORM, в конструкторе который Вы изменяете важные параметры, например $_table_name.
2. Объекты модели хранятся в сессии.
Ошибка
Как правило, Database_Exception &#8211; те самые важные параметры модели почему-то не переопределены. Хотя Вы их точно в конструкторе прописывали!
В чем дело?
Проблема возникнет, когда Kohana будет извлекать модель из сессии (точнее при создании объекта Session). Дело в том, что [...]]]></description>
			<content:encoded><![CDATA[<h3>Условия:</h3>
<p>1. Есть модель <strong>ORM</strong>, в конструкторе который Вы изменяете важные параметры, например <code>$_table_name</code>.<br />
2. Объекты модели хранятся в сессии.</p>
<h3>Ошибка</h3>
<p>Как правило, Database_Exception &#8211; те самые важные параметры модели почему-то не переопределены. Хотя Вы их точно в конструкторе прописывали!</p>
<h3>В чем дело?</h3>
<p>Проблема возникнет, когда <strong>Kohana</strong> будет извлекать модель из сессии (точнее при создании объекта Session). Дело в том, что модель хранится в сериализованном виде, при десериализации (распаковывании) объекта <strong>ORM</strong> <u>конструктор не вызывается</u>. Так что все Ваши модификации будут пропущены (если говорить про параметр <code>$_table_name</code>, то модель будет обращаться к не той таблице БД).</p>
<p>Чтобы этого избегать, следует использовать <code>protected</code>-метод <code>_initialize()</code>. Он вызывается из конструктора, там по умолчанию происходят все вычисления дефолтовых значений для <code>$_table_name</code>, <code>$_db</code>, свойств связей и т.д. Как раз-таки с этого метода начинается десериализация модели <strong>ORM</strong>, так что все модификации складываем именно в <code>_initialize()</code>. Например, так:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">protected <span style="color: #000000; font-weight: bold;">function</span> _initialize<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">empty</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_table_name<span style="color: #009900;">&#41;</span> AND <span style="color: #009900;">&#40;</span><span style="color: #000088;">$table_name</span> <span style="color: #339933;">=</span> Kohana<span style="color: #339933;">::</span><span style="color: #004000;">config</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'models'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">table</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_table_name <span style="color: #339933;">=</span> <span style="color: #000088;">$table_name</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    parent<span style="color: #339933;">::</span>_initialize<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></code></p>
<p>Такое может возникнуть, когда свойства модели заполняются в зависимости от каких-либо условий (параметр <code>Kohana::$environment</code> или по настройкам конфигов). Раньше я всегда использовал конструктор, теперь вот есть смысл выносить все это в <code>_initialize()</code>. Да, случается нечасто (не так уж много случаев, когда объект <strong>ORM</strong> хранится в сессии целиком), но может стать причиной долгих поисков. В общем, я Вас предупредил <img src='http://brotkin.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>

<div class="bookmarkz"><a href="http://www.google.com/bookmarks/mark?op=add&bkmk=http://brotkin.ru/2010/07/23/custom-orm-session-trouble/&title=%D0%9D%D0%B5%D1%81%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D1%8B%D0%B5+ORM-%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D0%B8+%D0%B2+%D1%81%D0%B5%D1%81%D1%81%D0%B8%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/google.png" border="0" width="16" height="16" alt="Google Bookmarks" title="Google Bookmarks"></a> <a href="http://digg.com/submit?url=http://brotkin.ru/2010/07/23/custom-orm-session-trouble/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/digg.png" border="0" width="16" height="16" alt="Digg" title="Digg"></a> <a href="http://reddit.com/submit?url=http://brotkin.ru/2010/07/23/custom-orm-session-trouble/&title=%D0%9D%D0%B5%D1%81%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D1%8B%D0%B5+ORM-%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D0%B8+%D0%B2+%D1%81%D0%B5%D1%81%D1%81%D0%B8%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/reddit.png" border="0" width="16" height="16" alt="Reddit" title="Reddit"></a> <a href="http://del.icio.us/post?url=http://brotkin.ru/2010/07/23/custom-orm-session-trouble/&title=%D0%9D%D0%B5%D1%81%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D1%8B%D0%B5+ORM-%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D0%B8+%D0%B2+%D1%81%D0%B5%D1%81%D1%81%D0%B8%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/delicious.png" border="0" width="16" height="16" alt="del.icio.us" title="del.icio.us"></a> <a href="http://ma.gnolia.com/beta/bookmarklet/add?url=http://brotkin.ru/2010/07/23/custom-orm-session-trouble/&title=%D0%9D%D0%B5%D1%81%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D1%8B%D0%B5+ORM-%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D0%B8+%D0%B2+%D1%81%D0%B5%D1%81%D1%81%D0%B8%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web&description=%D0%9D%D0%B5%D1%81%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D1%8B%D0%B5+ORM-%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D0%B8+%D0%B2+%D1%81%D0%B5%D1%81%D1%81%D0%B8%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/magnolia.png" border="0" width="16" height="16" alt="Ma.gnolia" title="Ma.gnolia"></a> <a href="http://www.technorati.com/faves?add=http://brotkin.ru/2010/07/23/custom-orm-session-trouble/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/technorati.png" border="0" width="16" height="16" alt="Technorati" title="Technorati"></a> <a href="http://www.slashdot.org/bookmark.pl?url=http://brotkin.ru/2010/07/23/custom-orm-session-trouble/&title=%D0%9D%D0%B5%D1%81%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D1%8B%D0%B5+ORM-%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D0%B8+%D0%B2+%D1%81%D0%B5%D1%81%D1%81%D0%B8%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/slashdot.png" border="0" width="16" height="16" alt="Slashdot" title="Slashdot"></a> <a href="http://myweb2.search.yahoo.com/myresults/bookmarklet?u=http://brotkin.ru/2010/07/23/custom-orm-session-trouble/&t=%D0%9D%D0%B5%D1%81%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D1%8B%D0%B5+ORM-%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D0%B8+%D0%B2+%D1%81%D0%B5%D1%81%D1%81%D0%B8%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/yahoo.png" border="0" width="16" height="16" alt="Yahoo My Web" title="Yahoo My Web"></a> <a href="http://news2.ru/add_story.php?url=http://brotkin.ru/2010/07/23/custom-orm-session-trouble/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/news2ru.png" border="0" width="16" height="16" alt="News2.ru" title="News2.ru"></a> <a href="http://www.bobrdobr.ru/addext.html?url=http://brotkin.ru/2010/07/23/custom-orm-session-trouble/&title=%D0%9D%D0%B5%D1%81%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D1%8B%D0%B5+ORM-%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D0%B8+%D0%B2+%D1%81%D0%B5%D1%81%D1%81%D0%B8%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/bobrdobr.png" border="0" width="16" height="16" alt="БобрДобр.ru" title="БобрДобр.ru"></a> <a href="http://rumarkz.ru/bookmarks/?action=add&popup=1&address=http://brotkin.ru/2010/07/23/custom-orm-session-trouble/&title=%D0%9D%D0%B5%D1%81%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D1%8B%D0%B5+ORM-%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D0%B8+%D0%B2+%D1%81%D0%B5%D1%81%D1%81%D0%B8%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/rumarkz.png" border="0" width="16" height="16" alt="RUmarkz" title="RUmarkz"></a> <a href="http://www.vaau.ru/submit/?action=step2&url=http://brotkin.ru/2010/07/23/custom-orm-session-trouble/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/vaau.png" border="0" width="16" height="16" alt="Ваау!" title="Ваау!"></a> <a href="http://memori.ru/link/?sm=1&u_data[url]=http://brotkin.ru/2010/07/23/custom-orm-session-trouble/&u_data[name]=%D0%9D%D0%B5%D1%81%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D1%8B%D0%B5+ORM-%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D0%B8+%D0%B2+%D1%81%D0%B5%D1%81%D1%81%D0%B8%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/memori.png" border="0" width="16" height="16" alt="Memori.ru" title="Memori.ru"></a> <a href="http://www.rucity.com/bookmarks.php?action=add&address=http://brotkin.ru/2010/07/23/custom-orm-session-trouble/&title=%D0%9D%D0%B5%D1%81%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D1%8B%D0%B5+ORM-%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D0%B8+%D0%B2+%D1%81%D0%B5%D1%81%D1%81%D0%B8%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/rucity.png" border="0" width="16" height="16" alt="rucity.com" title="rucity.com"></a> <a href="http://moemesto.ru/post.php?url=http://brotkin.ru/2010/07/23/custom-orm-session-trouble/&title=%D0%9D%D0%B5%D1%81%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D1%8B%D0%B5+ORM-%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D0%B8+%D0%B2+%D1%81%D0%B5%D1%81%D1%81%D0%B8%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/moemesto.png" border="0" width="16" height="16" alt="МоёМесто.ru" title="МоёМесто.ru"></a> <a href="http://www.mister-wong.ru/index.php?action=addurl&bm_url=http://brotkin.ru/2010/07/23/custom-orm-session-trouble/&bm_description=%D0%9D%D0%B5%D1%81%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D1%8B%D0%B5+ORM-%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D0%B8+%D0%B2+%D1%81%D0%B5%D1%81%D1%81%D0%B8%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/mrwong.png" border="0" width="16" height="16" alt="Mister Wong" title="Mister Wong"></a> </div>
]]></content:encoded>
			<wfw:commentRss>http://brotkin.ru/2010/07/23/custom-orm-session-trouble/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Jelly &#8211; новое слово в ORM?</title>
		<link>http://brotkin.ru/2010/04/29/jelly-intro/</link>
		<comments>http://brotkin.ru/2010/04/29/jelly-intro/#comments</comments>
		<pubDate>Thu, 29 Apr 2010 10:45:02 +0000</pubDate>
		<dc:creator>biakaveron</dc:creator>
				<category><![CDATA[Kohana3]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[jelly]]></category>
		<category><![CDATA[ko3]]></category>
		<category><![CDATA[ORM]]></category>

		<guid isPermaLink="false">http://brotkin.ru/?p=307</guid>
		<description><![CDATA[Если Вы интересуетесь ORM или просто читаете официальный форум Kohana, то наверняка успели обратить внимание на данную библиотеку. Ее разработчик, Jonathan Geiger, решил взять все самое лучшее из ORM и Sprig, дабы создать модуль с блэкджеком под собственные нужды. Поскольку ORMы &#8211; весьма популярная тема (в том числе и на данном сайте), решено ознакомиться с [...]]]></description>
			<content:encoded><![CDATA[<p>Если Вы интересуетесь <strong>ORM</strong> или просто читаете официальный форум <strong>Kohana</strong>, то наверняка успели обратить внимание на данную библиотеку. Ее разработчик, <a href="http://jonathan-geiger.com">Jonathan Geiger</a>, решил взять все самое лучшее из <strong>ORM</strong> и <strong>Sprig</strong>, дабы создать модуль <strike>с блэкджеком</strike> под собственные нужды. Поскольку <strong>ORM</strong>ы &#8211; весьма популярная тема (в том числе и на данном сайте), решено ознакомиться с данной реализацией.<span id="more-323"></span></p>
<p>Итак, <a href="http://github.com/jonathangeiger/kohana-jelly/downloads">скачиваем</a> модуль и начинаем исследование содержимого. Для начала отмечу, что в составе модуля поставляется документация в формате &#8220;родного&#8221; <strong>Userguide</strong>. То есть если в проекте подключены модули <strong>Jelly</strong> и <strong>Userguide</strong>, то в секции <em>Modules</em> документации появится соответствующий раздел <em>Jelly</em>. В документации присутствует и русский перевод (спасибо тебе, Сергей <em>avis</em> Гладковский). Документации вполне достаточно для быстрого старта, особенно если есть опыт работы с <strong>ORM</strong> или <strong>Sprig</strong>.</p>
<h3>Модели</h3>
<p>С чего обычно начинается описание <strong>ORM</strong>-подобных библиотек? Правильно, с моделей! Вот пример из документации:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Model_Post <span style="color: #000000; font-weight: bold;">extends</span> Jelly_Model
<span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">public</span> static <span style="color: #000000; font-weight: bold;">function</span> initialize<span style="color: #009900;">&#40;</span>Jelly_Meta <span style="color: #000088;">$meta</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$meta</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">table</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'posts'</span><span style="color: #009900;">&#41;</span>
             <span style="color: #339933;">-&gt;</span><span style="color: #004000;">fields</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
                 <span style="color: #0000ff;">'id'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_Primary<span style="color: #339933;">,</span>
                 <span style="color: #0000ff;">'name'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_String<span style="color: #339933;">,</span>
                 <span style="color: #0000ff;">'body'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_Text<span style="color: #339933;">,</span>
                 <span style="color: #0000ff;">'status'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_Enum<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
                     <span style="color: #0000ff;">'choices'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'draft'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'review'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'published'</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: #0000ff;">'author'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_BelongsTo<span style="color: #339933;">,</span>
                 <span style="color: #0000ff;">'tags'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_ManyToMany<span style="color: #339933;">,</span>
             <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></code></p>
<p>Очень похоже на <strong>Sprig</strong> &#8211; все необходимые поля объявляются при инициализации (напомню, что <strong>ORM</strong> по умолчанию запрашивает описания полей у базы данных), для каждого вида поля создается свой класс (потомок <code>Jelly_Field</code>). У полей есть свойства <code>$in_db</code> (существует ли данное поле в таблице БД), <code>$primary</code> (булевый флаг, является ли поле первичным ключом), <code>$default</code> (значение по умолчанию) и т.д. &#8211; большинство свойств знакомы нам по <strong>Sprig</strong>. Методом <code>table()</code> устанавливается имя таблицы БД (на самом деле это необязательно, т.к. имя для таблицы соответствует рекомендациям <strong>ORM</strong> и было бы вычислено автоматически).</p>
<h3>Параметры модели</h3>
<p>Все, что описывает модель в части связи с БД (поля, имя таблицы, имя первичного ключа и т.д.), хранится в объекте класса <code>Jelly_Meta</code>. В вышеприведенном примере метод <code>initialize()</code> модели как раз заполнял переменную <code>$meta</code>, которая будет прикреплена к модели <strong>Model_Post</strong>. Эти данные выделены в отдельный объект не просто так &#8211; класс <strong>Jelly</strong> хранит (регистрирует) метаданные всех созданных ранее моделей в свойстве <code>$_models</code>, и в дальнейшем ознакомиться с ними можно будет без необходимости инициализировать саму модель. Достаточно вызвать <code>Jelly::meta('post')</code>, и на выходе получим <em>Meta</em>-объект для модели <strong>Model_Post</strong>.</p>
<h3>CRUD</h3>
<p>Для загрузки, создания, изменения и удаления объектов в <strong>Jelly</strong> используются различные методы (как и в <strong>Sprig</strong>).</p>
<h4>Доступ к записям в БД</h4>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// загрузка записи с идентификатором = 1</span>
<span style="color: #000088;">$post</span> <span style="color: #339933;">=</span> Jelly<span style="color: #339933;">::</span><span style="color: #004000;">select</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'post'</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// то же самое</span>
<span style="color: #000088;">$post</span> <span style="color: #339933;">=</span> Jelly<span style="color: #339933;">::</span><span style="color: #004000;">select</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'post'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">load</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// загрузка всех записей</span>
<span style="color: #000088;">$posts</span> <span style="color: #339933;">=</span> Jelly<span style="color: #339933;">::</span><span style="color: #004000;">select</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'post'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">execute</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// загрузка с условием</span>
<span style="color: #000088;">$approved_posts</span> <span style="color: #339933;">=</span> Jelly<span style="color: #339933;">::</span><span style="color: #004000;">select</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'post'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">where</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'is_approved'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'='</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">execute</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p></code></p>
<p>В первом случае будет извлечена только одна запись, поэтому <code>$post</code> содержит объект <strong>Model_Post</strong>. В случае же вызова <code>execute()</code> на выходе будет объект класса <code>Jelly_Collection</code>, это что-то вроде <code>ORM_Iterator</code> из <strong>ORM</strong> второй ветки <strong>Kohana</strong>.</p>
<blockquote><p>На самом деле, если вызвать метод <code>limit()</code> с параметром 1, то результат будет содержать одну модель, как и в случае с <code>load()</code>. По сути вызов <code>load($id)</code> просто краткая запись от <code>where('id', '=', $id)->limit(1)->execute()</code>.</p></blockquote>
<p>С объектом <code>Jelly_Collection</code> можно работать также, как и с <code>ORM_Iterator</code> или <code>Database_Result</code>: перебирать элементы в цикле, подсчитать общее число записей в нем, преобразовать в массив с помощью метода <code>as_array($key, $value)</code>.</p>
<h4>Новая запись</h4>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// создание нового объекта</span>
<span style="color: #000088;">$post</span> <span style="color: #339933;">=</span> Jelly<span style="color: #339933;">::</span><span style="color: #004000;">factory</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'post'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// заполняем поля по одиночке</span>
<span style="color: #000088;">$post</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">title</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'new post'</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// или разом</span>
<span style="color: #000088;">$post</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">set</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'text'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'new post text'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'created'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">time</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// сохраняем</span>
<span style="color: #000088;">$post</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">save</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p></code></p>
<blockquote><p>Можно использовать и <code>Jelly::insert('post')->set(...)->execute()</code>, но это не так удобно, по сравнению с созданием модели и ее заполнением. Зато быстрее!</p></blockquote>
<h4>Редактирование записи</h4>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$post</span> <span style="color: #339933;">=</span> Jelly<span style="color: #339933;">::</span><span style="color: #004000;">factory</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'post'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// устанавливаем нужные значения</span>
<span style="color: #000088;">$post</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">title</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'edited post'</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// сохраняем. Не забудьте передать идентификатор записи!</span>
<span style="color: #000088;">$post</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">save</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p></code></p>
<p>Похоже на создание новой записи, но тут мы заранее знаем идентификатор записи и меняем значения отдельных ее полей (в данном случае поле `<em>title</em>`) без загрузки самой записи. На самом деле можно было сделать и &#8220;по старинке&#8221;:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$post</span> <span style="color: #339933;">=</span> Jelly<span style="color: #339933;">::</span><span style="color: #004000;">select</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'post'</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$post</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">title</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'edited post'</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// модель загружена из БД, передавать идентификатор в метод save() не надо</span>
<span style="color: #000088;">$post</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">save</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p></code></p>
<h4>Усложнение запросов</h4>
<p>Как и в случае с <strong>ORM</strong>, в <strong>Jelly</strong> для непосредственной работы с базой данных используется <code>Query_Builder</code>, точнее его потомок, <code>Jelly_Builder</code>. Поэтому синтаксис запросов выглядит знакомым, доступны методы <code>where(</code>), <code>join()</code> и т.д.</p>
<p>А теперь представьте себе, что вы часто выбираете записи по определенному условию, например утвержденные администратором/модератором статьи:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$posts</span> <span style="color: #339933;">=</span> Jelly<span style="color: #339933;">::</span><span style="color: #004000;">select</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'post'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">where</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'is_approved'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'='</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">execute</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p></code></p>
<p>В <strong>ORM</strong> такие вещи можно было спрятать в методе модели, примерно так:<br />
<code></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> approved<span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</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;">where</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'is_approved'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'='</span><span style="color: #339933;">,</span> <span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #000088;">$posts</span> <span style="color: #339933;">=</span> ORM<span style="color: #339933;">::</span><span style="color: #004000;">factory</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'post'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">approved</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">find_all</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p></code></p>
<p>Однако в <strong>Jelly</strong> методы <code>select()</code>, <code>insert()</code>, <code>update()</code> и <code>delete()</code> возвращают <code>Jelly_Builder</code>, а не текущую модель, поэтому в модели подобные методы логики приложения создавать бессмысленно. Зато можно создавать свои классы <code>Jelly_Builder</code>, например для модели <code>Model_Post</code> создаем <code>Model_Builder_Post</code> и в нем прописываем нужные методы:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Model_Builder_Post <span style="color: #000000; font-weight: bold;">extends</span> Jelly_Builder <span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> approved<span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</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;">where</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'is_approved'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'='</span><span style="color: #339933;">,</span> <span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></code></p>
<blockquote><p><strong>Jelly</strong> очень гибка и имеет множество настроек. В том числе есть и возможность поменять префикс для моделей и билдеров. Берем заглушку <em>classes/jelly.php</em> (<strong>Jelly</strong> использует ту же тактику избыточного именования моделей, что и <strong>Ko3</strong>) и меняем свойство <code>$_model_prefix</code> под свои нужды, например &#8216;<em>myjelly_</em>&#8216;. В результате все модели и билдеры должны будут храниться в директории <em>classes/myjelly</em>, а имена этих классов начинаться не с &#8216;<em>Model_</em>&#8216;, а с &#8216;<em>Myjelly_</em>&#8216;. Но, конечно, мало кто будет с этим заморачиваться.</p></blockquote>
<h3>Псевдонимы</h3>
<p>Случается, что первичные ключи называются не по &#8220;фэн-шую&#8221;, например <code>post_id</code> или <code>IdPost</code>, а хотелось бы обращаться по привычному имени <code>id</code>. Выход есть &#8211; используйте псевдонимы. Существует два варианта, привычный и инновационный <img src='http://brotkin.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<ol>
<li>В методе <code>fields()</code> модели объявляете имя поля как Вам удобно, и указываете в свойстве &#8216;<em>column</em>&#8216; реальное имя поля. Например, так:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #0000ff;">'id'</span>        <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_Primary<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'column'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'post_id'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span></pre></div></div>

<p></code><br />
В данном способе нет ничего нового, такие псевдонимы доступны как в <strong>ORM</strong>, так и в <strong>Sprig</strong>.</li>
<li>Сперва по всем правилам объявляете поле, а ниже создаете новые поля, &#8220;переадресовывая&#8221; их на ранее созданное. Поясню на примере:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #0000ff;">'post_id'</span>        <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Field_Primary<span style="color: #339933;">,</span>
<span style="color: #0000ff;">'id'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'post_id'</span><span style="color: #339933;">,</span></pre></div></div>

<p></code></p>
<p>Теперь можно использовать <code>$post->id</code>, в результате будет отрабатывать поле &#8216;<em>post_id</em>&#8216;. Можно создать и второй псевдоним, тоже будет работать. А вот по цепочке (<code>id1 -> id -> post_id</code>) не работает, ну и ладно. <img src='http://brotkin.ru/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </li>
</ol>
<blockquote><p>Конечно, рекомендуется использовать метод <code>id()</code> для получения значения первичного ключа модели (в <strong>ORM</strong> его аналогом был метод <code>pk()</code>). Обращаться к именам полей напрямую лучше пореже, дабы не привязываться к потенциально изменчивой структуре БД.</p></blockquote>
<h3>Мета-псевдонимы</h3>
<p>Очень интересное и вкусное нововведение. Обычно при объявлении тех же связей мы пишем реальные имена полей (первичных ключей, внешних ключей и т.д.), аналогичные неудобства при заполнении условий <strong>Query_Builder</strong>&#8216;а (что-то типа <code>where('id', 'IN', $values)</code>). А вот в <strong>Jelly</strong> есть специальные слова, позволяющие указать на нужные поля без их конкретного имени! Вот их перечень:</p>
<ul>
<li><strong>:primary_key</strong> &#8211; тут все понятно, будет заменено на имя первичного ключа.</li>
<li><strong>:foreign_key</strong> &#8211; имя внешнего ключа для других моделей (обычно явно не указывается, поэтому формируется как <code>имя_модели + '_id'</code>).</li>
<li><strong>:name_key</strong> &#8211; имя &#8220;титульного&#8221; поля, например &#8216;<em>username</em>&#8216; для модели <code>User</code> или &#8216;<em>title</em>&#8216; для <code>Post</code> (если конечно Вы соответствующее свойство <code>$name_key</code> указывали в модели). Полезно для получения списка <code>id=>value</code> из набора записей, например <code>$posts->as_array(':primary_key', ':name_key')</code>.</li>
<li><strong>:unique_key</strong>. Данный мета-алиас предназначен для работы с уникальными ключами, в основном через <code>Jelly_Builder</code> (аналог стандартного <code>Query_Builder</code>&#8216;а). По умолчанию в моделях <strong>Jelly</strong> есть только один уникальный ключ &#8211; это конечно первичный ключ. Даже если Вы добавите в свойствах какого-либо поля параметр <code>$unique = TRUE</code>, автоматически оно определяться не будет. Надо создавать свой билдер для модели и в нем прописывать метод <code>unique_key($value)</code>. Вот как он изначально написан в <code>Jelly_Builder</code>:<br />
<code></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> unique_key<span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</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>_meta<span style="color: #339933;">-&gt;</span><span style="color: #004000;">primary_key</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></code></p>
<p>Если мы для модели <code>Model_User</code> захотим сделать уникальными поля <code>email</code> и <code>username</code>, то в класса <code>Model_Builder_User</code> создадим свой метод:</p>
<p><code></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> unique_key<span style="color: #009900;">&#40;</span><span style="color: #000088;">$id</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #339933;">!</span> <span style="color: #990000;">empty</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$id</span><span style="color: #009900;">&#41;</span> AND <span style="color: #990000;">is_string</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$id</span><span style="color: #009900;">&#41;</span> AND <span style="color: #339933;">!</span> <span style="color: #990000;">ctype_digit</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$id</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #b1b100;">return</span> validate<span style="color: #339933;">::</span><span style="color: #004000;">email</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$id</span><span style="color: #009900;">&#41;</span> ? <span style="color: #0000ff;">'email'</span> <span style="color: #339933;">:</span> <span style="color: #0000ff;">'username'</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
		<span style="color: #b1b100;">return</span> parent<span style="color: #339933;">::</span><span style="color: #004000;">unique_key</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$id</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span></pre></div></div>

<p></code></p>
<p>В общем, все как и в старом-добром <strong>Auth</strong>. А дальше уже можно использовать:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$user</span> <span style="color: #339933;">=</span> Jelly<span style="color: #339933;">::</span><span style="color: #004000;">select</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'user'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">where</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">':unique_key'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'='</span><span style="color: #339933;">,</span> <span style="color: #000088;">$_POST</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'login'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">load</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;">// или более короткая запись</span>
<span style="color: #000088;">$user</span> <span style="color: #339933;">=</span> Jelly<span style="color: #339933;">::</span><span style="color: #004000;">select</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'user'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">load</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_POST</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'login'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// еще более короткая запись!</span>
<span style="color: #000088;">$user</span> <span style="color: #339933;">=</span> Jelly<span style="color: #339933;">::</span><span style="color: #004000;">select</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'user'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$_POST</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'login'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p></code></p>
<p>Так как мы определили метод для уникальных полей, вместо <code>id</code> можно передавать имя пользователя или <code>email</code> &#8211; нам по сути неважно. В данном случае мы позволим пользователю входить как по логину, так и адресу эл.почты.</li>
</ul>
<h3>Связи</h3>
<p>Естественно, есть поддержка привычных нам типов связей (используем классы <code>Field_HasOne</code>, <code>Field_HasMany</code>, <code>Field_BelongsTo</code> и <code>Field_ManyToMany</code>). Для настройки связи используются три параметра, которые передаются в конструктор:</p>
<ul>
<li>&#8216;<em>column</em>&#8216; &#8211; имя поля в таблице модели, которое является внешним ключом. Естественно, это доступно только для связей <code>BelongsTo</code>, т.к. в остальных случаях внешний ключ выносится в другую модель (и свойство <code>$in_db</code>, упомянутое выше, для этих видов связей равно <strong>FALSE</strong>). </li>
<li>&#8216;<em>foreign</em>&#8216; &#8211; строка с описанием внешнего ключа. Обычно указывается в виде &#8216;<em>model.field</em>&#8216;, например &#8216;<em>article.id</em>&#8216;. Если данный параметр не указан, то будет автоматически сгенерировано значение исходя из имени связи, с использованием первичного ключа связанной модели. Также можно указать только имя модели, в этом случае к нему будет добавлен первичный ключ.</li>
<li>&#8216;<em>through</em>&#8216; &#8211; этот параметр нужен для связей <code>ManyToMany</code>, чтобы указать промежуточную таблицу. Его можно указать как строку (тогда это должно быть имя промежуточной модели), как массив (поле &#8216;<em>model</em>&#8216; определяет имя промежуточной модели, а &#8216;<em>columns</em>&#8216; &#8211; массив полей с первичными ключами связанных моделей). Если не указывать вообще, сработает автозаполнение, принцип именования промежуточной модели аналогичен <strong>ORM</strong>&#8216;у (<code>Role_User</code> для моделей <code>User</code> и <code>Role</code>).</li>
</ul>
<p>Много текста, мало смысла, поэтому вот несколько примеров описания связей для модели <code>Model_User</code>:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// все по умолчанию, связь с моделью Model_Post по ключу user_id</span>
<span style="color: #0000ff;">'posts'</span>  <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Jelly_Field_HasMany<span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// добавляем отсебятины, пусть внешний ключ называется author_id</span>
<span style="color: #0000ff;">'posts'</span>  <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Jelly_Field_HasMany<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'foreign'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'post.author_id'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// + меняем имя связи</span>
<span style="color: #0000ff;">'articles'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Jelly_Field_HasMany<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'foreign'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'post.author_id'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// добавляем связь для получения отмодерированных статей</span>
<span style="color: #0000ff;">'moderated'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Jelly_Field_HasMany<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'foreign'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'post.moderator_id'</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;">// по умолчанию промежуточная модель Role_User должна содержить ключи role_id и user_id</span>
<span style="color: #0000ff;">'roles'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Jelly_Field_ManyToMany<span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// указываем явно, что в модели Role внешним ключом будет первичный ключ</span>
<span style="color: #0000ff;">'roles'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Jelly_Field_ManyToMany<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'foreign'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'role.role:primary_key'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// используем нестандартное имя промежуточной модели</span>
<span style="color: #0000ff;">'roles'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Jelly_Field_ManyToMany<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'through'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'user_role'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// в данном примере имя промежуточной модели и содержащиеся в ней ключи нестандартные</span>
<span style="color: #0000ff;">'roles'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Jelly_Field_ManyToMany<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'through'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'model'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'user_role'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'columns'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'userId'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'roleId'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p></code></p>
<blockquote><p>Обратите внимание, что при объявлении имен полей в промежуточной модели (параметр <code>['through']['columns']</code>) важен порядок их следования. Сперва указывается внешний ключ от текущей модели (в данном случае это <code>userId</code>), а потом &#8211; от связанной.</p></blockquote>
<h3>Валидация</h3>
<p>При объявлении полей модели есть возможность указать и условия валидации (<code>rules/filters/callbacks</code>, а также <code>label</code>). Тут все в принципе аналогично <strong>Sprig</strong>. Для уникальных полей (свойство <code>$unique == TRUE</code>) автоматически добавляется <em>callback</em>-метод <code>_is_unique()</code> для проверки на наличие проверяемого значения в БД. В случае ошибок при проверке выбрасывается <code>Validate_Exception</code>, поэтому не забывайте оборачивать вызовы <code>validate()</code> и <code>save()</code> в конструкции <code>try ... catch()</code>. Метод <code>validate()</code> возвращает массив проверенных данных в случае успеха.</p>
<h3>Работа с формами</h3>
<p>Каждое поле модели реализует метод <code>input($prefix, $data)</code>, который должен выводить поле ввода/выбора значения (через представление <strong>View</strong>). Первый аргумент (<code>$prefix</code>) позволяет указать свой путь для представления, по умолчанию он &#8216;<em>jelly/field</em>&#8216; (да, в <em>views/jelly/field/</em> можно подсмотреть уже имеющиеся заготовки для стандартных типов данных <strong>Jelly</strong>). Параметр <code>$data</code> позволяет передать в шаблон дополнительные переменные, которые будут добавлены к публичным свойствам поля. Еще в шаблоне будет доступна переменная <code>$field</code>, которая содержит собственно сам выводимый объект <code>Jelly_Field</code>.</p>
<h3>Заключение</h3>
<p>Это был беглый обзор возможностей <strong>Jelly</strong>, основная цель которого &#8211; познакомиться с основами этой замечательной библиотеки. На данный момент могу выделить следующие плюсы и минусы:</p>
<p><strong>+</strong> неплохая <a href="http://jelly.jonathan-geiger.com/docs">документация</a>, причем сразу в комплекте с модулем.<br />
<strong>+</strong> высокая гибкость и настраиваемость, даже выше, чем у <strong>Sprig</strong>.<br />
<strong>+</strong> введение объекта <code>Meta</code> позволяет уменьшить количество запросов к БД, когда нужны только метаданные о моделях.<br />
<strong>-</strong> относительная сложность по сравнению со <strong>Sprig</strong> и тем более <strong>ORM</strong>.</p>
<p>Модуль очень интересный, и в целом сообществу очень понравился (достаточно посмотреть на количество топиков о нем). Разработкой заняты солидные люди, добавляются вспомогательные модули (типа <strong>Jelly-Auth</strong>), в общем обратите на него внимание <img src='http://brotkin.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>

<div class="bookmarkz"><a href="http://www.google.com/bookmarks/mark?op=add&bkmk=http://brotkin.ru/2010/04/29/jelly-intro/&title=Jelly+-+%D0%BD%D0%BE%D0%B2%D0%BE%D0%B5+%D1%81%D0%BB%D0%BE%D0%B2%D0%BE+%D0%B2+ORM%3F+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/google.png" border="0" width="16" height="16" alt="Google Bookmarks" title="Google Bookmarks"></a> <a href="http://digg.com/submit?url=http://brotkin.ru/2010/04/29/jelly-intro/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/digg.png" border="0" width="16" height="16" alt="Digg" title="Digg"></a> <a href="http://reddit.com/submit?url=http://brotkin.ru/2010/04/29/jelly-intro/&title=Jelly+-+%D0%BD%D0%BE%D0%B2%D0%BE%D0%B5+%D1%81%D0%BB%D0%BE%D0%B2%D0%BE+%D0%B2+ORM%3F+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/reddit.png" border="0" width="16" height="16" alt="Reddit" title="Reddit"></a> <a href="http://del.icio.us/post?url=http://brotkin.ru/2010/04/29/jelly-intro/&title=Jelly+-+%D0%BD%D0%BE%D0%B2%D0%BE%D0%B5+%D1%81%D0%BB%D0%BE%D0%B2%D0%BE+%D0%B2+ORM%3F+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/delicious.png" border="0" width="16" height="16" alt="del.icio.us" title="del.icio.us"></a> <a href="http://ma.gnolia.com/beta/bookmarklet/add?url=http://brotkin.ru/2010/04/29/jelly-intro/&title=Jelly+-+%D0%BD%D0%BE%D0%B2%D0%BE%D0%B5+%D1%81%D0%BB%D0%BE%D0%B2%D0%BE+%D0%B2+ORM%3F+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web&description=Jelly+-+%D0%BD%D0%BE%D0%B2%D0%BE%D0%B5+%D1%81%D0%BB%D0%BE%D0%B2%D0%BE+%D0%B2+ORM%3F+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/magnolia.png" border="0" width="16" height="16" alt="Ma.gnolia" title="Ma.gnolia"></a> <a href="http://www.technorati.com/faves?add=http://brotkin.ru/2010/04/29/jelly-intro/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/technorati.png" border="0" width="16" height="16" alt="Technorati" title="Technorati"></a> <a href="http://www.slashdot.org/bookmark.pl?url=http://brotkin.ru/2010/04/29/jelly-intro/&title=Jelly+-+%D0%BD%D0%BE%D0%B2%D0%BE%D0%B5+%D1%81%D0%BB%D0%BE%D0%B2%D0%BE+%D0%B2+ORM%3F+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/slashdot.png" border="0" width="16" height="16" alt="Slashdot" title="Slashdot"></a> <a href="http://myweb2.search.yahoo.com/myresults/bookmarklet?u=http://brotkin.ru/2010/04/29/jelly-intro/&t=Jelly+-+%D0%BD%D0%BE%D0%B2%D0%BE%D0%B5+%D1%81%D0%BB%D0%BE%D0%B2%D0%BE+%D0%B2+ORM%3F+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/yahoo.png" border="0" width="16" height="16" alt="Yahoo My Web" title="Yahoo My Web"></a> <a href="http://news2.ru/add_story.php?url=http://brotkin.ru/2010/04/29/jelly-intro/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/news2ru.png" border="0" width="16" height="16" alt="News2.ru" title="News2.ru"></a> <a href="http://www.bobrdobr.ru/addext.html?url=http://brotkin.ru/2010/04/29/jelly-intro/&title=Jelly+-+%D0%BD%D0%BE%D0%B2%D0%BE%D0%B5+%D1%81%D0%BB%D0%BE%D0%B2%D0%BE+%D0%B2+ORM%3F+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/bobrdobr.png" border="0" width="16" height="16" alt="БобрДобр.ru" title="БобрДобр.ru"></a> <a href="http://rumarkz.ru/bookmarks/?action=add&popup=1&address=http://brotkin.ru/2010/04/29/jelly-intro/&title=Jelly+-+%D0%BD%D0%BE%D0%B2%D0%BE%D0%B5+%D1%81%D0%BB%D0%BE%D0%B2%D0%BE+%D0%B2+ORM%3F+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/rumarkz.png" border="0" width="16" height="16" alt="RUmarkz" title="RUmarkz"></a> <a href="http://www.vaau.ru/submit/?action=step2&url=http://brotkin.ru/2010/04/29/jelly-intro/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/vaau.png" border="0" width="16" height="16" alt="Ваау!" title="Ваау!"></a> <a href="http://memori.ru/link/?sm=1&u_data[url]=http://brotkin.ru/2010/04/29/jelly-intro/&u_data[name]=Jelly+-+%D0%BD%D0%BE%D0%B2%D0%BE%D0%B5+%D1%81%D0%BB%D0%BE%D0%B2%D0%BE+%D0%B2+ORM%3F+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/memori.png" border="0" width="16" height="16" alt="Memori.ru" title="Memori.ru"></a> <a href="http://www.rucity.com/bookmarks.php?action=add&address=http://brotkin.ru/2010/04/29/jelly-intro/&title=Jelly+-+%D0%BD%D0%BE%D0%B2%D0%BE%D0%B5+%D1%81%D0%BB%D0%BE%D0%B2%D0%BE+%D0%B2+ORM%3F+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/rucity.png" border="0" width="16" height="16" alt="rucity.com" title="rucity.com"></a> <a href="http://moemesto.ru/post.php?url=http://brotkin.ru/2010/04/29/jelly-intro/&title=Jelly+-+%D0%BD%D0%BE%D0%B2%D0%BE%D0%B5+%D1%81%D0%BB%D0%BE%D0%B2%D0%BE+%D0%B2+ORM%3F+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/moemesto.png" border="0" width="16" height="16" alt="МоёМесто.ru" title="МоёМесто.ru"></a> <a href="http://www.mister-wong.ru/index.php?action=addurl&bm_url=http://brotkin.ru/2010/04/29/jelly-intro/&bm_description=Jelly+-+%D0%BD%D0%BE%D0%B2%D0%BE%D0%B5+%D1%81%D0%BB%D0%BE%D0%B2%D0%BE+%D0%B2+ORM%3F+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/mrwong.png" border="0" width="16" height="16" alt="Mister Wong" title="Mister Wong"></a> </div>
]]></content:encoded>
			<wfw:commentRss>http://brotkin.ru/2010/04/29/jelly-intro/feed/</wfw:commentRss>
		<slash:comments>34</slash:comments>
		</item>
		<item>
		<title>Ko3: модуль Sprig. Начало работы.</title>
		<link>http://brotkin.ru/2009/11/02/ko3-sprig/</link>
		<comments>http://brotkin.ru/2009/11/02/ko3-sprig/#comments</comments>
		<pubDate>Mon, 02 Nov 2009 08:33:01 +0000</pubDate>
		<dc:creator>biakaveron</dc:creator>
				<category><![CDATA[Kohana3]]></category>
		<category><![CDATA[ORM]]></category>
		<category><![CDATA[sprig]]></category>

		<guid isPermaLink="false">http://brotkin.ru/?p=282</guid>
		<description><![CDATA[Библиотека ORM всегда вызывала множество вопросов как у новичков, так и у более опытных пользователей Kohana. Удобная в использовании, но сложная в изучении, она проскакивает наверное в каждом третьем-четвертом топике официального форума. А знаете ли Вы, что есть и другие библиотеки? Для 2.3.4 есть Auto Modeler от zombor (Jeremy Bush) и его переработанная версия &#8211; [...]]]></description>
			<content:encoded><![CDATA[<p>Библиотека <strong>ORM</strong> всегда вызывала множество вопросов как у новичков, так и у более опытных пользователей <strong>Kohana</strong>. Удобная в использовании, но сложная в изучении, она проскакивает наверное в каждом третьем-четвертом топике официального форума. А знаете ли Вы, что есть и другие библиотеки? Для <em>2.3.4</em> есть <a href="http://dev.kohanaphp.com/projects/automodeler">Auto Modeler</a> от <strong>zombor</strong> (<strong>Jeremy Bush</strong>) и его переработанная версия &#8211; <a href="http://dev.kohanaphp.com/projects/simple-modeler">Simple Modeler</a> от <strong>thejw23</strong>. А поскольку в последнее время мы больше обращаем внимание на <strong>Ko3</strong>, рассмотрим альтернативу <strong>ORM</strong>, созданную самим создателем фреймворка &#8211; <a href="http://github.com/shadowhand/sprig/">Sprig</a> от <strong>Shadowhand</strong> (<strong>Woody Gilk</strong>).</p>
<p>Как мы знаем, основная &#8220;фишка&#8221; <strong>ORM</strong> &#8211; прозрачная работа с таблицами БД. Т.е. мы можем не описывать имеющиеся в таблице поля, а обращаться к ним как к свойствам модели. Это становится возможным благодаря автоматическому запросу (<em>SHOW COLUMNS</em>, если говорить о <strong>MySQL</strong>) к таблице при создании модели, загружающему информацию о структуре таблицы. Впрочем, это не освобождает от необходимости объявлять связи с другими таблицами.</p>
<blockquote><p>Возможно Вы не знаете &#8211; когда Ваша таблица примет окончательные очертания, можно прописать мета-данные о формате полей в статическом свойстве <code>$_column_cache</code> (это массив, используем ключ <code>$this->_object_name</code>), чтобы <strong>ORM</strong> не запрашивал их каждый раз. Проще всего &#8220;подсмотреть&#8221; эти данные (используя <code>var_dump()</code> или <code>Kohana::dump()</code>) и скопировать в <code>$_column_cache</code>.</p></blockquote>
<p>А что же <strong>Sprig</strong>? Тут немного другая философия &#8211; каждое поле таблицы представлено отдельным объектом, потомком абстрактного класса <strong>Sprig_Field</strong>. Казалось бы, что тут выдумывать, поле оно и есть поле, делаем его строковым и не волнуемся ни о чем. Ан нет! Использование отдельных классов имеет ряд преимуществ:</p>
<ul>
<li>Многие типы полей имеют сложившиеся форматы вывода на экран (к примеру, дату обычно не выводят в формате <em>UNIX timestamp</em>). С помощью <strong>Sprig</strong> мы можем настроить форматирование любого используемого типа данных.</li>
<li>Аналогично и с генерацией элементов форм. Никто не будет показывать поле логического типа (т.е. <strong>TRUE</strong>/<strong>FALSE</strong>) в виде текстового &#8211; тут нужен <strong>checkbox</strong>. <strong>Sprig</strong> позволяет описать параметры генерируемого поля, в том числе и перечень допустимых значений (для формирования выпадающего списка).</li>
<li>Есть типовые ограничения (уникальность, <em>NOT NULL</em> и т.д.), которые приходится прописывать для каждого поля в свойствах валидации (<code>$_filters</code>, <code>$_rules</code> и <code>$_callbacks</code>). А в <strong>Sprig</strong> поля имеют дополнительные свойства, описывающие различные аспекты хранения их в БД (и они автоматом используются при валидации). Об этом я напишу чуть позже.</li>
</ul>
<h2>Из чего строится модель</h2>
<p>Каждая модель должна быть потомком класса <strong>Sprig</strong> (кто бы сомневался) и реализовывать метод <code>_init()</code>, в котором собственно и описываются все поля таблицы. Например, вот что происходит в модели <strong>Sprig_Model_User</strong> (включена в дистрибутив <strong>Sprig</strong>):<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">protected <span style="color: #000000; font-weight: bold;">function</span> _init<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>_fields <span style="color: #339933;">+=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
		<span style="color: #0000ff;">'id'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Sprig_Field_Auto<span style="color: #339933;">,</span>
		<span style="color: #0000ff;">'username'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Sprig_Field_Char<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
			<span style="color: #0000ff;">'empty'</span>  <span style="color: #339933;">=&gt;</span> <span style="color: #009900; font-weight: bold;">FALSE</span><span style="color: #339933;">,</span>
			<span style="color: #0000ff;">'unique'</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;">'rules'</span>  <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
				<span style="color: #0000ff;">'regex'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/^[\pL_.-]+$/ui'</span><span style="color: #009900;">&#41;</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>
		<span style="color: #0000ff;">'password'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Sprig_Field_Password<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
			<span style="color: #0000ff;">'empty'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #009900; font-weight: bold;">FALSE</span><span style="color: #339933;">,</span>
		<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
		<span style="color: #0000ff;">'password_confirm'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Sprig_Field_Password<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
			<span style="color: #0000ff;">'empty'</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;">'in_db'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #009900; font-weight: bold;">FALSE</span><span style="color: #339933;">,</span>
			<span style="color: #0000ff;">'rules'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
				<span style="color: #0000ff;">'matches'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password'</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: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
		<span style="color: #0000ff;">'last_login'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Sprig_Field_Timestamp<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
			<span style="color: #0000ff;">'empty'</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;">'editable'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #009900; font-weight: bold;">FALSE</span><span style="color: #339933;">,</span>
		<span style="color: #009900;">&#41;</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: #009900;">&#125;</span></pre></div></div>

<p></code></p>
<p>Поля хранятся в свойстве <code>$_fields</code>. Каждый экземпляр класса <strong>Sprig_Field</strong> может быть создан с передачей дополнительных параметров, так что на стандартные для выбранного типа настройки можно сверху &#8220;накатить&#8221; свои. Так, если автоинкрементное поле `<em>id</em>` создается с настройками по умолчанию (что уж там еще настраивать), то для поля `<em>username</em>` добавлено правило валидации (ключ &#8216;<em>rules</em>&#8216;) и свойства поля из БД &#8211; <em>NOT NULL</em> (ключ &#8216;<em>empty</em>&#8216;) и <em>UNIQUE</em> (ключ &#8216;<em>unique</em>&#8216;). Давайте рассмотрим полный список свойств класса <strong>Sprig_Field</strong>.</p>
<ul>
<li><strong>$empty</strong> &#8211; поддерживает ли поле отсутствие значения. <em>NOT NULL</em> по сути. По умолчанию <strong>FALSE</strong>.</li>
<li><strong>$primary</strong> &#8211; является ли первичным ключем (<em>PRIMARY KEY</em>). По умолчанию <strong>FALSE</strong>.</li>
<li><strong>$unique</strong> &#8211; флаг уникальности (<em>UNIQUE KEY</em>). По умолчанию <strong>FALSE</strong>.</li>
<li><strong>$null</strong> &#8211; все пустые значения (например, пустые строки) автоматически будут преобразованы в <strong>NULL</strong>. По умолчанию FALSE.</li>
<li><strong>$editable</strong> &#8211; разрешено ли изменение даного поля пользователем. Может использоваться для автоинкрементых полей и автоматически генерируемых меток времени. По умолчанию <strong>TRUE</strong>.</li>
<li><strong>$default</strong> &#8211; значение по умолчанию.</li>
<li><strong>$choices</strong> &#8211; массив допустимых значений (что-то вроде эмуляции <em>ENUM</em>).</li>
<li><strong>$column</strong> &#8211; имя поля в БД. По умолчанию сгенерируется на основе имени объекта. Вы можете указать более удобный псевдоним для поля в методе <code>_init()</code>, а реальное имя указать в данном свойстве. Обычно это используется для внешних ключей.</li>
<li><strong>$description</strong> &#8211; описание поля.</li>
<li><strong>$in_db</strong> &#8211; существует ли поле в БД (такие поля в <strong>ORM</strong> помещались в <code>$ignored_columns</code>). По умолчанию <strong>TRUE</strong>.</li>
<li><strong>$label</strong> &#8211; метка поля. Используется для формирования элемента <strong>label</strong> формы, а также при валидации. По умолчанию сгенерируется автоматически, используя метод <code>Inflector::humanize()</code>, который заменяет тире и знаки подчеркивания на пробелы.</li>
<li><strong>$filters</strong> &#8211; массив применяемых фильтров валидации.</li>
<li><strong>$rules</strong> &#8211; массив правил для поля.</li>
<li><strong>$callbacks</strong> &#8211; массив внешних функций (коллбэков).</li>
</ul>
<blockquote><p>Немного в стороне стоят свойства <code>$min_length</code> и <code>$max_length</code>, которые могут быть добавлены в текстовые поля для ограничения длины.
</p></blockquote>
<p>Часто используемые комбинации данных свойств представлены в виде готовых классов-потомков <strong>Sprig_Field</strong>.</p>
<ul>
<li><strong>Sprig_Field_Auto</strong> &#8211; автоинкремент. Первичный ключ, нередактируемый, пустые значения преобразовываются в <strong>NULL</strong>.</li>
<li><strong>Sprig_Field_Boolean</strong> &#8211; логическое поле. Может хранить <strong>NULL</strong>, значение по умолчанию &#8211; <strong>FALSE</strong>. При валидации автоматически применяется фильтр <code>filter_var(FILTER_VALIDATE_BOOLEAN)</code>.</li>
<li><strong>Sprig_Field_Char</strong> &#8211; символьное поле. Можно указать минимальную/максимальную длину.</li>
<li><strong>Sprig_Field_Country</strong> &#8211; поле для кода стран в двухсимвольном (за небольшими исключениями) международном формате. Массив <em>код</em> => <em>расшифровка</em> хранится в свойстве <code>$codes</code>, которое будет скопировано в <code>$choices</code> по умолчанию. Если необходимо предоставить возможность ввода других кодов, установите свойство <code>$prompt</code> в <strong>TRUE</strong>.</li>
<li><strong>Sprig_Field_Email</strong> &#8211; поле для электронной почты, добавлено правило <code>validate::email()</code>.</li>
<li><strong>Sprig_Field_Enum</strong> &#8211; поле, имеющее ограниченное число значений. Если Вы забудете их установить в свойстве <code>$choices</code>, получите <strong>Exception</strong>.</li>
<li><strong>Sprig_Field_Float</strong> &#8211; число с плавающей запятой. Можно настроить количество точек после запятой (свойство <code>$places</code>). </li>
<li><strong>Sprig_Field_Image</strong> &#8211; поле для хранения пути к изображению. При создании необходимо явно указать параметр &#8216;<em>path</em>&#8216; &#8211; путь к директории с картинками. Также можно передать длину и ширину (&#8216;<em>width</em>&#8216; и &#8216;<em>height</em>&#8216;).</li>
<li><strong>Sprig_Field_Integer</strong> &#8211; целочисленное значение. Можно задать &#8216;<em>min_value</em>&#8216; и &#8216;<em>max_value</em>&#8216;.</li>
<li><strong>Sprig_Field_Password</strong> &#8211; поле для хранени паролей. Можно указать метод хэширования в свойстве &#8216;<em>hash_with</em>&#8216; (по умолчанию &#8216;<em>sha1</em>&#8216;).</li>
<li><strong>Sprig_Field_Text</strong> &#8211; поле для многострочных текстовых полей.</li>
<li><strong>Sprig_Field_Timestamp</strong> &#8211; поле для хранения даты/времени. Поддерживаются свойства &#8216;<em>auto_now_create</em>&#8216; и &#8216;<em>auto_now_update</em>&#8216; (автоматическая подстановка значения <code>NOW()</code> при создании и редактировании соответственно, по умолчанию <strong>FALSE</strong>) и &#8216;<em>format</em>&#8216; (формат вывода данных на экран через функцию <code>date()</code>, по умолчанию &#8216;<em>Y-m-d G:i:s A</em>&#8216;).</li>
<li><strong>Sprig_Field_ForeignKey</strong> &#8211; абстрактный класс, базовый для внешних ключей. <strong>NOT_NULL</strong>, но в то же время по умолчанию он не является существующим полем в БД (т.е. <code>$in_db == FALSE</code>). Дело в том, что не для всех типов связей внешний ключ располагается в текущей таблице (ниже рассмотрены доступные классы по типам связей). </li>
<li><strong>Sprig_Field_HasOne</strong> &#8211; класс для описания связи <strong>has_one</strong> (один-к-одному). Поле игнорируемое (<code>$in_db == FALSE</code>) и нередактируемое. Этот класс следует применять для &#8220;старшей&#8221; таблицы в связи, т.к. в той, которая экспортирует свой первичный ключ в связанную таблицу. </li>
<li><strong>Sprig_Field_BelongsTo</strong> &#8211; класс для <strong>belongs_to</strong> (обратная сторона связи <strong>has_one</strong> или <strong>has_many</strong>). В данном случае внешний ключ находится в таблице, так что $in_db == TRUE.</li>
<li><strong>Sprig_Field_HasMany</strong> &#8211; класс для <strong>has_many</strong>. Недоступен для редактирования.</li>
<li><strong>Sprig_Field_ManyToMany</strong> &#8211; поле <strong>HABTM</strong>. Может быть отредактировано, имеется дополнительное свойство $through (как Вы наверное догадываетесь, оно предназначено для имени промежуточной таблицы и по умолчанию формируется из названий связанных таблиц по тому же принципу, что и в <strong>ORM</strong>).</li>
</ul>
<p>Кроме собственно полей, есть свойства для хранения мета-данных модели. По большей части они знакомы нам благодаря <strong>ORM</strong>:</p>
<ul>
<li><strong>$_primary_key</strong> &#8211; имя поля для первичного ключа. Теоретически может быть массивом (в случае составного первичного ключа), но вроде как это еще не полностью поддерживаемая возможность.</li>
<li><strong>$_table</strong> &#8211; имя используемой таблицы.</li>
<li><strong>$_title_key</strong> &#8211; аналог <code>$_primary_val</code> из <strong>ORM</strong>. По умолчанию &#8216;name&#8217;.</li>
<li><strong>$_sorting</strong> &#8211; настройка сортировки по умолчанию. Синтаксис <code>имя поля => направление</code>, например <code>array('created' => 'DESC')</code>.</li>
</ul>
<h2>Создание экземпляра модели и работа с ним</h2>
<p>В отличие от <strong>ORM</strong> в <strong>Sprig</strong> конструктор недоступен для прямого вызова, создавать модели необходимо через статический метод <code>factory($name, array $values = NULL)</code>. Это позволяет не создавать модель каждый раз заново, а использовать уже имеющуюся копию данного класса (эта копия представляет собой проинициализированную модель без каких-либо данных, т.е. происходит экономия на времени работы конструктора, в частности на методе <code>_init()</code>). При этом копии между собой не связаны, так что изменения в одной не повлекут корректировку другой.</p>
<p>Второй параметр <code>$values</code> позволяет передать значения для загрузки в модель. Значения, отсутствующие в списке полей таблицы, будут отброшены. Например, то, что в <strong>ORM</strong> записывалось как <code>ORM::factory('blog', 1)</code>, в <strong>Sprig</strong> будет выглядеть как <code>Sprig::factory('blog', array('id' => 1)</code>. Обратите внимание, что идентификатор будет загружен в модель, но запроса к БД не будет. Налицо все та же &#8220;ленивая загрузка&#8221;. Для явного обращения к БД надо использовать метод load().</p>
<p>Можно присваивать значения полям модели вручную, обращаясь к ним как в <strong>ORM</strong>, например <code>$blog->id = 1</code>. Также имеется метод <code>values(array $values)</code> для изменения сразу нескольких полей.</p>
<blockquote><p>$blog->id вернет значение поля. Если необходим сам объект (в данном случае это Sprig_Field_Auto), используйте методы field($name) или fields().</p></blockquote>
<h2>CRUD</h2>
<p>Метод <code>load()</code> я уже упомянул выше. Однако у него есть параметры, которые могут быть полезными для выборки данных из БД. Так, первым параметром идет объект класса <strong>Database_Query_Builder_Select</strong>, т.е. объект запроса на выборку, создаваемый обычно методом <code>DB::select()</code>. С его помощью можно указать дополнительные условия выборки. Второй параметр &#8211; <code>$limit</code>, позволяет ограничить количество отбираемых записей (по умолчанию 1).</p>
<p>Операции создания/редактирования и удаления в <strong>Sprig</strong> представлены отдельными методами (как мы помним, в <strong>ORM</strong> создание и редактирование были объединены в рамках метода <code>save()</code>).</p>
<ul>
<li>Метод <code>create()</code> создает новую запись в таблице, используя текущие значения. Если есть поле (или поля) типа <strong>Sprig_Field_Timestamp</strong> со свойством <code>$auto_now_create == TRUE</code>, то для него значением текущая метка времени. Далее автоматически будет вызвана валидация данных, так что вызовы метода <code>create()</code>, а также (забегаю вперед) и метода <code>update()</code>, должны заворачиваться в <code>try ... catch()</code>, но об этом ниже, в секции &#8220;Валидация&#8221;. Метод возвращает текущий объект (<code>$this</code>).</li>
<li>Метод <code>update()</code> работает только с измененными данными (свойство $_changed). Кроме того, поля <strong>Sprig_Field_Timestamp</strong> со свойством <code>$auto_now_update == TRUE</code> будут заполнены текущей меткой времени. В целом все аналогично созданию записи &#8211; валидация измененных значений с дальнейшим сохранением в базе.</li>
<li>Метод <code>delete()</code> предназначен для удаления записей, и может быть использован в различных случаях. Если запись была загружена из БД, она будет удалена. Если же объект только что создан и не сохранен в БД, введенные в него значения будут использованы в качестве условия для удаления всех подходящих записей в БД. Если модель пустая, ничего не будет удалено (интересно, как тогда удалить все записи, т.к. метода <code>delete_all()</code> нет).</li>
</ul>
<h2>Настройка формата значений при выводе на экран</h2>
<p>Приятная &#8220;вкусность&#8221;. Для каждого поля можно менять форматирование значения, для чего используется метод <code>verbose($value)</code>. По умолчанию он выводит значение как строку, но есть и отличные от дефолтных методы, например для меток времени и картинок:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// Sprig_Field_Timestamp, использует свойство $format для хранения формата даты</span>
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> verbose<span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">is_integer</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #b1b100;">return</span> <span style="color: #990000;">date</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">format</span><span style="color: #339933;">,</span> <span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
		<span style="color: #b1b100;">else</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #b1b100;">return</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Sprig_Field_Image, выводит полный путь к картинке, используя свойство $path</span>
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> verbose<span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</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;">path</span><span style="color: #339933;">.</span><span style="color: #000088;">$value</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span></pre></div></div>

<p></code></p>
<p>Есть и другие классы с собственными обработчиками (для чисел с плавающей запятой будет произведено форматирование через <code>number_format()</code>, для логических выведение строковых &#8216;<em>TRUE</em>&#8216; или &#8216;<em>FALSE</em>&#8216;, а для <strong>Hasmany</strong> &#8211; вывод значений через запятую).</p>
<h2>Работа с формами</h2>
<p>Выбор элементов форм в зависимости от типа поля &#8211; одно из преимуществ <strong>Sprig</strong>. Каждый объект класса <strong>Sprig_Field</strong> должен реализовывать метод <code>input($name, $value, array $attr = NULL)</code>. По умолчанию будет выведен либо текстовый элемент <strong>input</strong>, либо выпадающий список <strong>select</strong> (если задано свойство <code>$choices</code>):</p>
<p><code></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> input<span style="color: #009900;">&#40;</span><span style="color: #000088;">$name</span><span style="color: #339933;">,</span> <span style="color: #000088;">$value</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span> <span style="color: #000088;">$attr</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">NULL</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #666666; font-style: italic;">// Make the value verbose</span>
		<span style="color: #000088;">$value</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">verbose</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</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;">is_array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">choices</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #b1b100;">return</span> Form<span style="color: #339933;">::</span><span style="color: #004000;">select</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$name</span><span style="color: #339933;">,</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">choices</span><span style="color: #339933;">,</span> <span style="color: #000088;">$value</span><span style="color: #339933;">,</span> <span style="color: #000088;">$attr</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: #b1b100;">return</span> Form<span style="color: #339933;">::</span><span style="color: #004000;">input</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$name</span><span style="color: #339933;">,</span> <span style="color: #000088;">$value</span><span style="color: #339933;">,</span> <span style="color: #000088;">$attr</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></code><br />
Массив <code>$attr</code> позволяет передать дополнительные атрибуты элемента форм (например, &#8216;<em>class</em>&#8216; или &#8216;<em>tabindex</em>&#8216;). Метод возвращает код сгенерированного поля формы. Как видно, метод <code>input()</code> активно использует <code>verbose()</code>, так что не забывайте его менять для создаваемых Вами классов нестандартных полей.</p>
<p>Для того, чтобы лучше понять, как (и зачем) реализовать собственный метод для формирования контролов, приведу методы для картинок и логических полей:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// Sprig_Field_Image</span>
<span style="color: #666666; font-style: italic;">// Вывод поле для загрузки изображения. Если есть значение, то покажет и саму картинку</span>
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> input<span style="color: #009900;">&#40;</span><span style="color: #000088;">$name</span><span style="color: #339933;">,</span> <span style="color: #000088;">$value</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span> <span style="color: #000088;">$attr</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">NULL</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #000088;">$input</span> <span style="color: #339933;">=</span> Form<span style="color: #339933;">::</span><span style="color: #990000;">file</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$name</span><span style="color: #339933;">,</span> <span style="color: #000088;">$attr</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">value</span><span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #000088;">$input</span> <span style="color: #339933;">.=</span> HTML<span style="color: #339933;">::</span><span style="color: #004000;">image</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">verbose</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>
&nbsp;
		<span style="color: #b1b100;">return</span> <span style="color: #000088;">$input</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// Sprig_Field_Boolean</span>
<span style="color: #666666; font-style: italic;">// если установлено свойство $append_label, будет добавлен текст к checkbox'у</span>
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> input<span style="color: #009900;">&#40;</span><span style="color: #000088;">$name</span><span style="color: #339933;">,</span> <span style="color: #000088;">$value</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span> <span style="color: #000088;">$attr</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">NULL</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #000088;">$checkbox</span> <span style="color: #339933;">=</span> Form<span style="color: #339933;">::</span><span style="color: #004000;">checkbox</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$name</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span> <span style="color: #000088;">$value</span><span style="color: #339933;">,</span> <span style="color: #000088;">$attr</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">append_label</span><span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #000088;">$checkbox</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">' '</span><span style="color: #339933;">.</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">label</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
		<span style="color: #b1b100;">return</span>  <span style="color: #000088;">$checkbox</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span></pre></div></div>

<p></code></p>
<p>Также есть метод <code>inputs($labels)</code>, который позволяет разом получить массив контролов. Параметр <code>$labels</code> указывает, использовать ли в качестве ключей данного массива сгенерированный код для меток (<code>$labels = TRUE</code>, по умолчанию), либо просто имена полей. Например, так:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$blog</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">inputs</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$label</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$input</span><span style="color: #009900;">&#41;</span>
    <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$label</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;&lt;br /&gt;&quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$input</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;&lt;br /&gt;&quot;</span><span style="color: #339933;">;</span></pre></div></div>

<p></code></p>
<h2>Валидация</h2>
<p>Раз есть генерация форм, надо как-то обрабатывать введенные данные. Для этого есть возможность установки свойств валидации, кроме того не стоит забывать об автоматически добавляемых фильтров и правил валидации для отдельных стандартных классов (например, проверка корректности <em>email</em> для <strong>Sprig_Field_Email</strong>). Обратимся к все той же модели <strong>Sprig_Model_User</strong>, так там объявлено поле `<em>username</em>` в методе <code>_init()</code>:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">	<span style="color: #0000ff;">'username'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Sprig_Field_Char<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
		<span style="color: #0000ff;">'empty'</span>  <span style="color: #339933;">=&gt;</span> <span style="color: #009900; font-weight: bold;">FALSE</span><span style="color: #339933;">,</span>
		<span style="color: #0000ff;">'unique'</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;">'rules'</span>  <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
			<span style="color: #0000ff;">'regex'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/^[\pL_.-]+$/ui'</span><span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span></pre></div></div>

<p></code><br />
Поскольку внутри используется стандартный класс <strong>Validate</strong>, синтаксис объявления свойств привычен. Сама проверка запускается методом <code>check(array $data = NULL)</code>. Да, в <strong>Sprig</strong> можно (напрямую) передать в модель данные для валидации (тот же массив <code>$_POST</code>), однако это немного другой механизм, отличный от валидации в <strong>ORM</strong> версии <strong>2.3.4</strong>. Во время валидации сама модель не меняется, она предоставляет данные для создания объекта <strong>Validate</strong> (т.е. свойства <code>$label</code>, <code>$filters</code>, <code>$rules</code> и <code>$callbacks</code> соответствующих полей).</p>
<blockquote><p>Если параметр <code>$data</code> не указан, будут проверяться измененные (и несохраненные) данные модели. Таким образом, проверять только что загруженный из БД объект бессмысленно. </p></blockquote>
<p>Метод <code>check()</code> возвращает массив обработанные данные в случае успеха (они могут отличаться от исходных, например из-за фильтрации). А вот если выявлено несоответствие, будет сгенерировано исключение <strong>Validate_Exception</strong>, так что придется оборачивать вызовы <code>check()</code> в блоки <code>try ... catch</code>:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">try
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$object</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">check</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    catch <span style="color: #009900;">&#40;</span>Validate_Exception <span style="color: #000088;">$e</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$errors</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$e</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">array</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">errors</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'validation'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span></pre></div></div>

<p></code></p>
<blockquote><p>Объект <strong>Validate_Exception</strong> содержит свойство <code>$array</code>, в которое помещаются данные при генерации исключения. В данном случае это сам объект <strong>Validate</strong>, так что <code>$e->array->errors()</code> осуществляет запрос ошибок валидации.</p></blockquote>
<h2>Прочие полезные методы</h2>
<ul>
<li>Получить значения объекта как массив можно с помощью метода <code>as_array($verbose)</code>, где параметр <code>$verbose</code> определяет, применять ли метод <code>verbose()</code> на все поля, либо отдавать как есть (по умолчанию).</li>
<li>Проверить, менялось ли какое либо поле или значения модели в целом с момента последнего сохранения или загрузки, можно через метод <code>changed($field)</code>. Если параметр <code>$field</code> не указан, вернется массив измененных полей (имя поля => значение), иначе &#8211; логическое <strong>TRUE</strong> (поле поменялось) или <strong>FALSE</strong>.</li>
<li>Метод <code>loaded()</code> полезен для проверки, был ли объект загружен из БД или он просто создан &#8220;на лету&#8221;.</li>
<li>Метод <code>pk($table)</code> возвращает имя поля для первичного ключа. Если параметр $table указан, то он будет подставлен перед именем поля в качестве названия таблицы (значение TRUE используется для подстановки имени текущей таблицы модели). Также есть метод <code>tk($table)</code>, который возвращает т.н. &#8220;титульный&#8221; ключ, т.е. значение свойства <code>$_title_key</code>.</li>
<li>Для формирования выпадающих списков есть знакомый нам метод <code>select_list($key = NULL, $value = NULL)</code>. Он возвращает массив <code>$key => $value</code> <strong>всех</strong> записей в БД.</li>
<li>Метод <code>table()</code> возвращает имя таблицы модели.</li>
</ul>
<h2>Напоследок</h2>
<ul>
<li>Я нашел зачатки поддержки составных первичных ключей (свойство <code>$_primary_key</code> может быть массивом полей), но пока это не везде работает. Возможно, в следующих коммитах ситуация прояснится.</li>
<li>Также не увидел как использовать напрямую методы <strong>Database_Query_Builder</strong>, например <code>limit()</code> или <code>where()</code>. Возможно, они появятся позже. Единственный доступный способ &#8211; передача параметра <code>$query</code> (в котором можно настроить большинство необходимых условий) в метод <code>load()</code>.</li>
</ul>
<p>Дополнительную информацию Вы можете получить в коротком <a href="http://github.com/shadowhand/sprig/">ReadMe</a> на странице проекта, а также в данном <a href="http://forum.kohanaphp.com/comments.php?DiscussionID=3780&#038;page=2#Item_24">топике форума</a>. Конечно, в данной статье практически ничего не сказано про использование связей в <strong>Sprig</strong>. Это будет темой следующего поста.</p>

<div class="bookmarkz"><a href="http://www.google.com/bookmarks/mark?op=add&bkmk=http://brotkin.ru/2009/11/02/ko3-sprig/&title=Ko3%3A+%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C+Sprig.+%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE+%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B.+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/google.png" border="0" width="16" height="16" alt="Google Bookmarks" title="Google Bookmarks"></a> <a href="http://digg.com/submit?url=http://brotkin.ru/2009/11/02/ko3-sprig/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/digg.png" border="0" width="16" height="16" alt="Digg" title="Digg"></a> <a href="http://reddit.com/submit?url=http://brotkin.ru/2009/11/02/ko3-sprig/&title=Ko3%3A+%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C+Sprig.+%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE+%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B.+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/reddit.png" border="0" width="16" height="16" alt="Reddit" title="Reddit"></a> <a href="http://del.icio.us/post?url=http://brotkin.ru/2009/11/02/ko3-sprig/&title=Ko3%3A+%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C+Sprig.+%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE+%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B.+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/delicious.png" border="0" width="16" height="16" alt="del.icio.us" title="del.icio.us"></a> <a href="http://ma.gnolia.com/beta/bookmarklet/add?url=http://brotkin.ru/2009/11/02/ko3-sprig/&title=Ko3%3A+%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C+Sprig.+%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE+%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B.+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web&description=Ko3%3A+%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C+Sprig.+%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE+%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B.+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/magnolia.png" border="0" width="16" height="16" alt="Ma.gnolia" title="Ma.gnolia"></a> <a href="http://www.technorati.com/faves?add=http://brotkin.ru/2009/11/02/ko3-sprig/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/technorati.png" border="0" width="16" height="16" alt="Technorati" title="Technorati"></a> <a href="http://www.slashdot.org/bookmark.pl?url=http://brotkin.ru/2009/11/02/ko3-sprig/&title=Ko3%3A+%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C+Sprig.+%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE+%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B.+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/slashdot.png" border="0" width="16" height="16" alt="Slashdot" title="Slashdot"></a> <a href="http://myweb2.search.yahoo.com/myresults/bookmarklet?u=http://brotkin.ru/2009/11/02/ko3-sprig/&t=Ko3%3A+%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C+Sprig.+%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE+%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B.+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/yahoo.png" border="0" width="16" height="16" alt="Yahoo My Web" title="Yahoo My Web"></a> <a href="http://news2.ru/add_story.php?url=http://brotkin.ru/2009/11/02/ko3-sprig/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/news2ru.png" border="0" width="16" height="16" alt="News2.ru" title="News2.ru"></a> <a href="http://www.bobrdobr.ru/addext.html?url=http://brotkin.ru/2009/11/02/ko3-sprig/&title=Ko3%3A+%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C+Sprig.+%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE+%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B.+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/bobrdobr.png" border="0" width="16" height="16" alt="БобрДобр.ru" title="БобрДобр.ru"></a> <a href="http://rumarkz.ru/bookmarks/?action=add&popup=1&address=http://brotkin.ru/2009/11/02/ko3-sprig/&title=Ko3%3A+%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C+Sprig.+%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE+%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B.+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/rumarkz.png" border="0" width="16" height="16" alt="RUmarkz" title="RUmarkz"></a> <a href="http://www.vaau.ru/submit/?action=step2&url=http://brotkin.ru/2009/11/02/ko3-sprig/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/vaau.png" border="0" width="16" height="16" alt="Ваау!" title="Ваау!"></a> <a href="http://memori.ru/link/?sm=1&u_data[url]=http://brotkin.ru/2009/11/02/ko3-sprig/&u_data[name]=Ko3%3A+%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C+Sprig.+%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE+%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B.+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/memori.png" border="0" width="16" height="16" alt="Memori.ru" title="Memori.ru"></a> <a href="http://www.rucity.com/bookmarks.php?action=add&address=http://brotkin.ru/2009/11/02/ko3-sprig/&title=Ko3%3A+%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C+Sprig.+%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE+%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B.+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/rucity.png" border="0" width="16" height="16" alt="rucity.com" title="rucity.com"></a> <a href="http://moemesto.ru/post.php?url=http://brotkin.ru/2009/11/02/ko3-sprig/&title=Ko3%3A+%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C+Sprig.+%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE+%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B.+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/moemesto.png" border="0" width="16" height="16" alt="МоёМесто.ru" title="МоёМесто.ru"></a> <a href="http://www.mister-wong.ru/index.php?action=addurl&bm_url=http://brotkin.ru/2009/11/02/ko3-sprig/&bm_description=Ko3%3A+%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C+Sprig.+%D0%9D%D0%B0%D1%87%D0%B0%D0%BB%D0%BE+%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B.+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/mrwong.png" border="0" width="16" height="16" alt="Mister Wong" title="Mister Wong"></a> </div>
]]></content:encoded>
			<wfw:commentRss>http://brotkin.ru/2009/11/02/ko3-sprig/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Ko3: добавляем условные правила валидации</title>
		<link>http://brotkin.ru/2009/10/15/ko3-dobavlyaem-uslovnye-pravila-validacii/</link>
		<comments>http://brotkin.ru/2009/10/15/ko3-dobavlyaem-uslovnye-pravila-validacii/#comments</comments>
		<pubDate>Thu, 15 Oct 2009 10:55:15 +0000</pubDate>
		<dc:creator>biakaveron</dc:creator>
				<category><![CDATA[напильник]]></category>
		<category><![CDATA[Kohana3]]></category>
		<category><![CDATA[ORM]]></category>
		<category><![CDATA[validation]]></category>

		<guid isPermaLink="false">http://brotkin.ru/?p=277</guid>
		<description><![CDATA[Данный пост родился в результате небольшой дискуссии на русскоязычной части форума Kohana. Как мы знаем, в Ko3 настройки валидации описаны в свойствах $_rules, $_callbacks и $_filters. Они загружаются в объект Validate через метод ORM::_validate(), в связи с чем возникает проблема &#8211; как добавлять правила в зависимости от каких-либо условий. Предлагаю одно из возможных решений.
Для тех, [...]]]></description>
			<content:encoded><![CDATA[<p>Данный пост родился в результате небольшой <a href="http://forum.kohanaphp.com/comments.php?DiscussionID=3553&#038;page=1#Item_9">дискуссии</a> на русскоязычной части форума <strong>Kohana</strong>. Как мы знаем, в <strong>Ko3</strong> настройки валидации описаны в свойствах <code>$_rules</code>, <code>$_callbacks</code> и <code>$_filters</code>. Они загружаются в объект <strong>Validate</strong> через метод <code>ORM::_validate()</code>, в связи с чем возникает проблема &#8211; как добавлять правила в зависимости от каких-либо условий. Предлагаю одно из возможных решений.</p>
<blockquote><p>Для тех, кому лень читать указанное обсуждение, опишу вкратце проблему. Есть запись, которую может оставить как зарегистрированный пользователь, так и гость. Вследствие этого в таблице есть как поле <code>`author_id`</code> (только для зарегистрированных пользователей), так и <code>`author`</code> (там хранится имя, как гостя, так и пользователя). Проблема в том, что гость может использовать только незанятые пользователями имена, т.е. появляется дополнительное правило для некоторых записей в таблице. Правило должно применяться как при валидации новой записи, так и при редактировании существующей.</p></blockquote>
<h2>Освежим в памяти теорию</h2>
<p>Один из главных девизов нового модуля <strong>ORM</strong> &#8211; &#8220;ленивая загрузка&#8221;, так что инициализация свойства <code>$_validate</code> начинается только после первого обращения к нему (а это может быть реализовано двумя методами &#8211; <code>check()</code> и <code>validate()</code>). За подготовку объекта <strong>Validate</strong> отвечает метод <code>_validate()</code>, который создает его, добавляет правила (<em>rules</em>), вызовы (<em>callbacks</em>), фильтры (<em>filters</em>) и метки (<em>labels</em>). Данный метод выполняется, когда методы <code>check()</code> и <code>validate()</code> проверяют свойство <code>$_validate</code>, и оно оказывается не заполнено.</p>
<p>Собственно сама проверка начинается после вызова <code>check()</code>. В объект <strong>Validate</strong> автоматически подставляются значения полей модели <strong>ORM</strong> (свойство <code>$_object</code>), включая несуществующие поля (указанные в свойстве <code>$_ignored_columns</code>). Далее выполняется сама проверка (<code>$this->_validate->check()</code>), как результат возвращается <strong>TRUE</strong>.</p>
<h2>Ну уж теперь все ясно!</h2>
<p>Конечно, дополнительные правила надо вставлять где-то в промежутке между проверкой и добавлением основных (общих для всех). Для этого подходит метод <code>_validate()</code>. В своей модели мы можем расширить его, добавив в конце свои условия. Для описанной на форуме проблемы получится что-то вроде такого кода:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// classes/model/post.php</span>
protected <span style="color: #000000; font-weight: bold;">function</span> _validate<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;">// не забываем сперва добавить &quot;родные&quot; правила</span>
    parent<span style="color: #339933;">::</span>_validate<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;">is_null</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">author_id</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_validate<span style="color: #339933;">-&gt;</span><span style="color: #004000;">callback</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'author'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'author_available'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></code></p>
<p>Чем отличается запись гостя от записи зарегистрированного пользователя? Поле <code>`author`</code> заполнено и там, и там, а вот <code>`author_id`</code> (идентификатор пользователя) у гостя должен быть <strong>NULL</strong>. На основании этого рассуждения мы добавляем дополнительную проверку.</p>
<h2>Попутно&#8230;</h2>
<p>В ходе тестов выяснилось, что &#8220;<em>ленивая загрузка</em>&#8221; не отрабатывает, если создавать объект с передачей идентификатора (типа <code>ORM::factory('article', 1)</code>) и сразу вызывать метод <code>check()</code>. Объект не будет загружен из БД, и в результате получим кучу ошибок валидации. Это в принципе логично, т.к. уже сохраненные объекты обычно не проверяют. Если все же надо сделать проверку, используйте явный вызов метода <code>find()</code> (<code>ORM::factory('article')->find(1)</code>), либо проверку методом <code>loaded()</code>.</p>

<div class="bookmarkz"><a href="http://www.google.com/bookmarks/mark?op=add&bkmk=http://brotkin.ru/2009/10/15/ko3-dobavlyaem-uslovnye-pravila-validacii/&title=Ko3%3A+%D0%B4%D0%BE%D0%B1%D0%B0%D0%B2%D0%BB%D1%8F%D0%B5%D0%BC+%D1%83%D1%81%D0%BB%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5+%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB%D0%B0+%D0%B2%D0%B0%D0%BB%D0%B8%D0%B4%D0%B0%D1%86%D0%B8%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/google.png" border="0" width="16" height="16" alt="Google Bookmarks" title="Google Bookmarks"></a> <a href="http://digg.com/submit?url=http://brotkin.ru/2009/10/15/ko3-dobavlyaem-uslovnye-pravila-validacii/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/digg.png" border="0" width="16" height="16" alt="Digg" title="Digg"></a> <a href="http://reddit.com/submit?url=http://brotkin.ru/2009/10/15/ko3-dobavlyaem-uslovnye-pravila-validacii/&title=Ko3%3A+%D0%B4%D0%BE%D0%B1%D0%B0%D0%B2%D0%BB%D1%8F%D0%B5%D0%BC+%D1%83%D1%81%D0%BB%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5+%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB%D0%B0+%D0%B2%D0%B0%D0%BB%D0%B8%D0%B4%D0%B0%D1%86%D0%B8%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/reddit.png" border="0" width="16" height="16" alt="Reddit" title="Reddit"></a> <a href="http://del.icio.us/post?url=http://brotkin.ru/2009/10/15/ko3-dobavlyaem-uslovnye-pravila-validacii/&title=Ko3%3A+%D0%B4%D0%BE%D0%B1%D0%B0%D0%B2%D0%BB%D1%8F%D0%B5%D0%BC+%D1%83%D1%81%D0%BB%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5+%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB%D0%B0+%D0%B2%D0%B0%D0%BB%D0%B8%D0%B4%D0%B0%D1%86%D0%B8%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/delicious.png" border="0" width="16" height="16" alt="del.icio.us" title="del.icio.us"></a> <a href="http://ma.gnolia.com/beta/bookmarklet/add?url=http://brotkin.ru/2009/10/15/ko3-dobavlyaem-uslovnye-pravila-validacii/&title=Ko3%3A+%D0%B4%D0%BE%D0%B1%D0%B0%D0%B2%D0%BB%D1%8F%D0%B5%D0%BC+%D1%83%D1%81%D0%BB%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5+%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB%D0%B0+%D0%B2%D0%B0%D0%BB%D0%B8%D0%B4%D0%B0%D1%86%D0%B8%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web&description=Ko3%3A+%D0%B4%D0%BE%D0%B1%D0%B0%D0%B2%D0%BB%D1%8F%D0%B5%D0%BC+%D1%83%D1%81%D0%BB%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5+%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB%D0%B0+%D0%B2%D0%B0%D0%BB%D0%B8%D0%B4%D0%B0%D1%86%D0%B8%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/magnolia.png" border="0" width="16" height="16" alt="Ma.gnolia" title="Ma.gnolia"></a> <a href="http://www.technorati.com/faves?add=http://brotkin.ru/2009/10/15/ko3-dobavlyaem-uslovnye-pravila-validacii/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/technorati.png" border="0" width="16" height="16" alt="Technorati" title="Technorati"></a> <a href="http://www.slashdot.org/bookmark.pl?url=http://brotkin.ru/2009/10/15/ko3-dobavlyaem-uslovnye-pravila-validacii/&title=Ko3%3A+%D0%B4%D0%BE%D0%B1%D0%B0%D0%B2%D0%BB%D1%8F%D0%B5%D0%BC+%D1%83%D1%81%D0%BB%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5+%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB%D0%B0+%D0%B2%D0%B0%D0%BB%D0%B8%D0%B4%D0%B0%D1%86%D0%B8%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/slashdot.png" border="0" width="16" height="16" alt="Slashdot" title="Slashdot"></a> <a href="http://myweb2.search.yahoo.com/myresults/bookmarklet?u=http://brotkin.ru/2009/10/15/ko3-dobavlyaem-uslovnye-pravila-validacii/&t=Ko3%3A+%D0%B4%D0%BE%D0%B1%D0%B0%D0%B2%D0%BB%D1%8F%D0%B5%D0%BC+%D1%83%D1%81%D0%BB%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5+%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB%D0%B0+%D0%B2%D0%B0%D0%BB%D0%B8%D0%B4%D0%B0%D1%86%D0%B8%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/yahoo.png" border="0" width="16" height="16" alt="Yahoo My Web" title="Yahoo My Web"></a> <a href="http://news2.ru/add_story.php?url=http://brotkin.ru/2009/10/15/ko3-dobavlyaem-uslovnye-pravila-validacii/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/news2ru.png" border="0" width="16" height="16" alt="News2.ru" title="News2.ru"></a> <a href="http://www.bobrdobr.ru/addext.html?url=http://brotkin.ru/2009/10/15/ko3-dobavlyaem-uslovnye-pravila-validacii/&title=Ko3%3A+%D0%B4%D0%BE%D0%B1%D0%B0%D0%B2%D0%BB%D1%8F%D0%B5%D0%BC+%D1%83%D1%81%D0%BB%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5+%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB%D0%B0+%D0%B2%D0%B0%D0%BB%D0%B8%D0%B4%D0%B0%D1%86%D0%B8%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/bobrdobr.png" border="0" width="16" height="16" alt="БобрДобр.ru" title="БобрДобр.ru"></a> <a href="http://rumarkz.ru/bookmarks/?action=add&popup=1&address=http://brotkin.ru/2009/10/15/ko3-dobavlyaem-uslovnye-pravila-validacii/&title=Ko3%3A+%D0%B4%D0%BE%D0%B1%D0%B0%D0%B2%D0%BB%D1%8F%D0%B5%D0%BC+%D1%83%D1%81%D0%BB%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5+%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB%D0%B0+%D0%B2%D0%B0%D0%BB%D0%B8%D0%B4%D0%B0%D1%86%D0%B8%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/rumarkz.png" border="0" width="16" height="16" alt="RUmarkz" title="RUmarkz"></a> <a href="http://www.vaau.ru/submit/?action=step2&url=http://brotkin.ru/2009/10/15/ko3-dobavlyaem-uslovnye-pravila-validacii/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/vaau.png" border="0" width="16" height="16" alt="Ваау!" title="Ваау!"></a> <a href="http://memori.ru/link/?sm=1&u_data[url]=http://brotkin.ru/2009/10/15/ko3-dobavlyaem-uslovnye-pravila-validacii/&u_data[name]=Ko3%3A+%D0%B4%D0%BE%D0%B1%D0%B0%D0%B2%D0%BB%D1%8F%D0%B5%D0%BC+%D1%83%D1%81%D0%BB%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5+%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB%D0%B0+%D0%B2%D0%B0%D0%BB%D0%B8%D0%B4%D0%B0%D1%86%D0%B8%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/memori.png" border="0" width="16" height="16" alt="Memori.ru" title="Memori.ru"></a> <a href="http://www.rucity.com/bookmarks.php?action=add&address=http://brotkin.ru/2009/10/15/ko3-dobavlyaem-uslovnye-pravila-validacii/&title=Ko3%3A+%D0%B4%D0%BE%D0%B1%D0%B0%D0%B2%D0%BB%D1%8F%D0%B5%D0%BC+%D1%83%D1%81%D0%BB%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5+%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB%D0%B0+%D0%B2%D0%B0%D0%BB%D0%B8%D0%B4%D0%B0%D1%86%D0%B8%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/rucity.png" border="0" width="16" height="16" alt="rucity.com" title="rucity.com"></a> <a href="http://moemesto.ru/post.php?url=http://brotkin.ru/2009/10/15/ko3-dobavlyaem-uslovnye-pravila-validacii/&title=Ko3%3A+%D0%B4%D0%BE%D0%B1%D0%B0%D0%B2%D0%BB%D1%8F%D0%B5%D0%BC+%D1%83%D1%81%D0%BB%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5+%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB%D0%B0+%D0%B2%D0%B0%D0%BB%D0%B8%D0%B4%D0%B0%D1%86%D0%B8%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/moemesto.png" border="0" width="16" height="16" alt="МоёМесто.ru" title="МоёМесто.ru"></a> <a href="http://www.mister-wong.ru/index.php?action=addurl&bm_url=http://brotkin.ru/2009/10/15/ko3-dobavlyaem-uslovnye-pravila-validacii/&bm_description=Ko3%3A+%D0%B4%D0%BE%D0%B1%D0%B0%D0%B2%D0%BB%D1%8F%D0%B5%D0%BC+%D1%83%D1%81%D0%BB%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5+%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB%D0%B0+%D0%B2%D0%B0%D0%BB%D0%B8%D0%B4%D0%B0%D1%86%D0%B8%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/mrwong.png" border="0" width="16" height="16" alt="Mister Wong" title="Mister Wong"></a> </div>
]]></content:encoded>
			<wfw:commentRss>http://brotkin.ru/2009/10/15/ko3-dobavlyaem-uslovnye-pravila-validacii/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Ko3: знаете ли вы? Часть 1</title>
		<link>http://brotkin.ru/2009/10/07/do-you-know-1/</link>
		<comments>http://brotkin.ru/2009/10/07/do-you-know-1/#comments</comments>
		<pubDate>Wed, 07 Oct 2009 07:47:37 +0000</pubDate>
		<dc:creator>biakaveron</dc:creator>
				<category><![CDATA[знаете ли вы]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[db]]></category>
		<category><![CDATA[Kohana3]]></category>
		<category><![CDATA[ORM]]></category>

		<guid isPermaLink="false">http://brotkin.ru/?p=272</guid>
		<description><![CDATA[Иногда в голове мелькает мысль, &#8220;а ведь это неочевидно/полезно/любопытно&#8220;, но целый пост на эту тему писать бессмысленно. Поэтому буду периодически публиковать такие вот &#8220;выхлопы&#8221; с накопившимися заметками. Ниже &#8211; первая пачка из данной серии.

&#8220;Ленивая загрузка&#8221; в ORM позволяет делать дополнительную фильтрацию после обращения к &#8220;множественным&#8221; свойствам модели. Например, так мы отфильтруем неподтвержденные комментарии к записи [...]]]></description>
			<content:encoded><![CDATA[<p>Иногда в голове мелькает мысль, &#8220;<em>а ведь это неочевидно/полезно/любопытно</em>&#8220;, но целый пост на эту тему писать бессмысленно. Поэтому буду периодически публиковать такие вот &#8220;выхлопы&#8221; с накопившимися заметками. Ниже &#8211; первая пачка из данной серии.</p>
<ul>
<li>&#8220;Ленивая загрузка&#8221; в <strong>ORM</strong> позволяет делать дополнительную фильтрацию после обращения к &#8220;множественным&#8221; свойствам модели. Например, так мы отфильтруем неподтвержденные комментарии к записи в блоге, а также отберем только второй десяток из них:
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$comments</span> <span style="color: #339933;">=</span> ORM<span style="color: #339933;">::</span><span style="color: #004000;">factory</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'blog'</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">comments</span>
          <span style="color: #339933;">-&gt;</span><span style="color: #004000;">where</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'is_confirmed'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'='</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span>
          <span style="color: #339933;">-&gt;</span><span style="color: #004000;">limit</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">10</span><span style="color: #009900;">&#41;</span>
          <span style="color: #339933;">-&gt;</span><span style="color: #004000;">offset</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">10</span><span style="color: #009900;">&#41;</span>
          <span style="color: #339933;">-&gt;</span><span style="color: #004000;">find_all</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p></code>На все это уйдет только один запрос, т.к. он теперь формируется только после явного вызова <code>find_all()</code>.</li>
<li>Так как библиотеки <strong>Input</strong> теперь нет, очищать данные от <strong>XSS</strong> придется самостоятельно (<code>Security::xss_clean()</code> вам в руки, можно добавить как фильтр в <strong>Validate</strong>). Автоматически <strong>Ko3</strong> лишь убирает лишние слэши (т.е. можем не думать о <strong>magic_quote_qpc</strong>) и все переводы строк приводит к единому виду (&#8220;<em>\n</em>&#8220;). Если надо обратиться к глобальной переменной, но есть сомнения в ее существовании, можно использовать метод <code>arr::get()</code>, он поддерживает установку значения по умолчанию. Например, так: <code>arr::get($_POST, 'text', '');</code></li>
<li>Список подключенных модулей может быть откорректирован в любой точке приложения. Метод <code>Kohana::modules($modules)</code> заново подключит все модули, указанные в массиве <code>$modules</code>. При этом ранее подключенные модули будут отброшены. Если вызвать метод без параметров, он вернет текущий список активных модулей. Таким образом, можно на лету подключить модуль X:<br />
<code>Kohana::modules(arr::merge(Kohana::modules(), array('x' => MODPATH.'x')))</code>. Пути для автозагрузки классов будут заново просчитаны, так что можно добиться изменения порядка активации модулей в списке (это играет роль при работе каскадной файловой системы <strong>Kohana</strong>).</p>
<blockquote><p>Насчет возможной двойной отработки файлов <em>init.php</em> не волнуйтесь &#8211; они подгружаются через <code>require_once()</code>. Тем не менее, сама по себе функция довольно затратная, не стоит ее вызывать бездумно.</p></blockquote>
</li>
<li>Можно кэшировать отдельные участки страницы с помощью класса <strong>Fragment</strong>:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #339933;">!</span> Fragment<span style="color: #339933;">::</span><span style="color: #004000;">load</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'some_page'</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">100</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">echo</span> View<span style="color: #339933;">::</span><span style="color: #004000;">factory</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'some_page_view'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    Fragment<span style="color: #339933;">::</span><span style="color: #004000;">save</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></code></p>
<p>В данном случае мы проверяем наличие кэшированной версии по ключу &#8216;<em>some_page</em>&#8216;, устанавливая срок актуальности (<em>lifetime</em>) в 100 секунд. Если фрагмент не найден, надо его отобразить и сразу добавить в кэш (метод <code>Fragment::save()</code>). Если же в кэше есть нужный нам кусок страницы, он отобразится автоматически. По умолчанию <em>lifetime</em> ставится на 30 секунд. Ах да, кэш &#8211; файловый, пока что нет библиотеки <strong>Cache</strong> а-ля <strong>Kohana v2.3.4</strong>.</li>
<li>Запросы на добавление записей (<em>INSERT</em>) возвращают массив (последний_сгенерированный_id, количество_вставленных_записей), а для редактирования (<em>UPDATE</em>) и удаления (<em>DELETE</em>) &#8211; только количество измененных/удаленных записей.</li>
</ul>

<div class="bookmarkz"><a href="http://www.google.com/bookmarks/mark?op=add&bkmk=http://brotkin.ru/2009/10/07/do-you-know-1/&title=Ko3%3A+%D0%B7%D0%BD%D0%B0%D0%B5%D1%82%D0%B5+%D0%BB%D0%B8+%D0%B2%D1%8B%3F+%D0%A7%D0%B0%D1%81%D1%82%D1%8C+1+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/google.png" border="0" width="16" height="16" alt="Google Bookmarks" title="Google Bookmarks"></a> <a href="http://digg.com/submit?url=http://brotkin.ru/2009/10/07/do-you-know-1/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/digg.png" border="0" width="16" height="16" alt="Digg" title="Digg"></a> <a href="http://reddit.com/submit?url=http://brotkin.ru/2009/10/07/do-you-know-1/&title=Ko3%3A+%D0%B7%D0%BD%D0%B0%D0%B5%D1%82%D0%B5+%D0%BB%D0%B8+%D0%B2%D1%8B%3F+%D0%A7%D0%B0%D1%81%D1%82%D1%8C+1+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/reddit.png" border="0" width="16" height="16" alt="Reddit" title="Reddit"></a> <a href="http://del.icio.us/post?url=http://brotkin.ru/2009/10/07/do-you-know-1/&title=Ko3%3A+%D0%B7%D0%BD%D0%B0%D0%B5%D1%82%D0%B5+%D0%BB%D0%B8+%D0%B2%D1%8B%3F+%D0%A7%D0%B0%D1%81%D1%82%D1%8C+1+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/delicious.png" border="0" width="16" height="16" alt="del.icio.us" title="del.icio.us"></a> <a href="http://ma.gnolia.com/beta/bookmarklet/add?url=http://brotkin.ru/2009/10/07/do-you-know-1/&title=Ko3%3A+%D0%B7%D0%BD%D0%B0%D0%B5%D1%82%D0%B5+%D0%BB%D0%B8+%D0%B2%D1%8B%3F+%D0%A7%D0%B0%D1%81%D1%82%D1%8C+1+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web&description=Ko3%3A+%D0%B7%D0%BD%D0%B0%D0%B5%D1%82%D0%B5+%D0%BB%D0%B8+%D0%B2%D1%8B%3F+%D0%A7%D0%B0%D1%81%D1%82%D1%8C+1+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/magnolia.png" border="0" width="16" height="16" alt="Ma.gnolia" title="Ma.gnolia"></a> <a href="http://www.technorati.com/faves?add=http://brotkin.ru/2009/10/07/do-you-know-1/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/technorati.png" border="0" width="16" height="16" alt="Technorati" title="Technorati"></a> <a href="http://www.slashdot.org/bookmark.pl?url=http://brotkin.ru/2009/10/07/do-you-know-1/&title=Ko3%3A+%D0%B7%D0%BD%D0%B0%D0%B5%D1%82%D0%B5+%D0%BB%D0%B8+%D0%B2%D1%8B%3F+%D0%A7%D0%B0%D1%81%D1%82%D1%8C+1+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/slashdot.png" border="0" width="16" height="16" alt="Slashdot" title="Slashdot"></a> <a href="http://myweb2.search.yahoo.com/myresults/bookmarklet?u=http://brotkin.ru/2009/10/07/do-you-know-1/&t=Ko3%3A+%D0%B7%D0%BD%D0%B0%D0%B5%D1%82%D0%B5+%D0%BB%D0%B8+%D0%B2%D1%8B%3F+%D0%A7%D0%B0%D1%81%D1%82%D1%8C+1+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/yahoo.png" border="0" width="16" height="16" alt="Yahoo My Web" title="Yahoo My Web"></a> <a href="http://news2.ru/add_story.php?url=http://brotkin.ru/2009/10/07/do-you-know-1/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/news2ru.png" border="0" width="16" height="16" alt="News2.ru" title="News2.ru"></a> <a href="http://www.bobrdobr.ru/addext.html?url=http://brotkin.ru/2009/10/07/do-you-know-1/&title=Ko3%3A+%D0%B7%D0%BD%D0%B0%D0%B5%D1%82%D0%B5+%D0%BB%D0%B8+%D0%B2%D1%8B%3F+%D0%A7%D0%B0%D1%81%D1%82%D1%8C+1+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/bobrdobr.png" border="0" width="16" height="16" alt="БобрДобр.ru" title="БобрДобр.ru"></a> <a href="http://rumarkz.ru/bookmarks/?action=add&popup=1&address=http://brotkin.ru/2009/10/07/do-you-know-1/&title=Ko3%3A+%D0%B7%D0%BD%D0%B0%D0%B5%D1%82%D0%B5+%D0%BB%D0%B8+%D0%B2%D1%8B%3F+%D0%A7%D0%B0%D1%81%D1%82%D1%8C+1+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/rumarkz.png" border="0" width="16" height="16" alt="RUmarkz" title="RUmarkz"></a> <a href="http://www.vaau.ru/submit/?action=step2&url=http://brotkin.ru/2009/10/07/do-you-know-1/" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/vaau.png" border="0" width="16" height="16" alt="Ваау!" title="Ваау!"></a> <a href="http://memori.ru/link/?sm=1&u_data[url]=http://brotkin.ru/2009/10/07/do-you-know-1/&u_data[name]=Ko3%3A+%D0%B7%D0%BD%D0%B0%D0%B5%D1%82%D0%B5+%D0%BB%D0%B8+%D0%B2%D1%8B%3F+%D0%A7%D0%B0%D1%81%D1%82%D1%8C+1+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/memori.png" border="0" width="16" height="16" alt="Memori.ru" title="Memori.ru"></a> <a href="http://www.rucity.com/bookmarks.php?action=add&address=http://brotkin.ru/2009/10/07/do-you-know-1/&title=Ko3%3A+%D0%B7%D0%BD%D0%B0%D0%B5%D1%82%D0%B5+%D0%BB%D0%B8+%D0%B2%D1%8B%3F+%D0%A7%D0%B0%D1%81%D1%82%D1%8C+1+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/rucity.png" border="0" width="16" height="16" alt="rucity.com" title="rucity.com"></a> <a href="http://moemesto.ru/post.php?url=http://brotkin.ru/2009/10/07/do-you-know-1/&title=Ko3%3A+%D0%B7%D0%BD%D0%B0%D0%B5%D1%82%D0%B5+%D0%BB%D0%B8+%D0%B2%D1%8B%3F+%D0%A7%D0%B0%D1%81%D1%82%D1%8C+1+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/moemesto.png" border="0" width="16" height="16" alt="МоёМесто.ru" title="МоёМесто.ru"></a> <a href="http://www.mister-wong.ru/index.php?action=addurl&bm_url=http://brotkin.ru/2009/10/07/do-you-know-1/&bm_description=Ko3%3A+%D0%B7%D0%BD%D0%B0%D0%B5%D1%82%D0%B5+%D0%BB%D0%B8+%D0%B2%D1%8B%3F+%D0%A7%D0%B0%D1%81%D1%82%D1%8C+1+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web" rel="nofollow" target="_blank"><img src="http://brotkin.ru/wp-content/plugins/bookmarkz/images/mrwong.png" border="0" width="16" height="16" alt="Mister Wong" title="Mister Wong"></a> </div>
]]></content:encoded>
			<wfw:commentRss>http://brotkin.ru/2009/10/07/do-you-know-1/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>

