<?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; relations</title>
	<atom:link href="http://brotkin.ru/tag/relations/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>Объявление связей в 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>Ko3: модуль Sprig. Связи</title>
		<link>http://brotkin.ru/2009/12/21/ko3-sprig2-2/</link>
		<comments>http://brotkin.ru/2009/12/21/ko3-sprig2-2/#comments</comments>
		<pubDate>Mon, 21 Dec 2009 20:30:19 +0000</pubDate>
		<dc:creator>biakaveron</dc:creator>
				<category><![CDATA[Kohana3]]></category>
		<category><![CDATA[relations]]></category>
		<category><![CDATA[sprig]]></category>

		<guid isPermaLink="false">http://brotkin.ru/?p=284</guid>
		<description><![CDATA[Итак, продолжаем изучать теорию по использованию модуля Sprig. Напомню, что в предыдущей статье я описал общие правила описания моделей. Но ведь сама по себе модель, отделенная от своих &#8220;соседей&#8221;, не несет большого смысла и практической ценности. Поэтому необходимо рассмотреть возможности Sprig в части работы с взаимосвязями моделей. 
Сообщаем о наличии связей в модели
Как мы помним, [...]]]></description>
			<content:encoded><![CDATA[<p>Итак, продолжаем изучать теорию по использованию модуля <strong>Sprig</strong>. Напомню, что в предыдущей статье я описал общие правила описания моделей. Но ведь сама по себе модель, отделенная от своих &#8220;соседей&#8221;, не несет большого смысла и практической ценности. Поэтому необходимо рассмотреть возможности <strong>Sprig</strong> в части работы с взаимосвязями моделей. <span id="more-284"></span></p>
<h2>Сообщаем о наличии связей в модели</h2>
<p>Как мы <a href="http://brotkin.ru/2009/11/02/ko3-sprig/">помним</a>, в модуле <strong>Sprig</strong> все используемые поля таблицы объявляются в методе <code>_init()</code>, и поля связей тут не исключение. Есть четыре класса для описания различных типов связей (тут все похоже на <a href="http://brotkin.ru/2009/04/18/orm-svyazi/">связи в ORM</a>, так что я сильно их расписывать не буду):</p>
<ul>
<li>Sprig_Field_HasOne</li>
<li>Sprig_Field_HasMany</li>
<li>Sprig_Field_BelongsTo</li>
<li>Sprig_Field_ManyToMany</li>
</ul>
<p>Названия говорят сами за себя. Поскольку в каждой связи участвует две стороны, нет смысла рассматривать классы по отдельности, так что давайте возьмем следующую ситуацию:</p>
<p>1. Есть записи в блоге (модель <code>blog</code>).<br />
2. Есть тэги, которые вешаются на записи блога (модель <code>tag</code>).<br />
3. Есть пользователи (модель <code>user</code>).<br />
4. Есть статистика по пользователям блога. Т.к. она не относится непосредственно к модели пользователя (мы предполагаем, что есть и другие модули, где используется <code>user</code>), выделяем ее в отдельную модель (<code>userinfo</code>).</p>
<p>В упрощенном виде схема получится примерно такая:<br />
<div id="attachment_287" class="wp-caption aligncenter" style="width: 510px"><a href="http://brotkin.ru/wp-content/uploads/sprig_example.png"><img src="http://brotkin.ru/wp-content/uploads/sprig_example.png" alt="Схема таблиц" title="Схема таблиц" width="500" height="471" class="size-full wp-image-287" /></a><p class="wp-caption-text">Схема таблиц</p></div></p>
<p>Тут использованы соглашения по умолчанию для <strong>ORM</strong> (первичный ключ называется `<em>id</em>`, внешние ключи формируются как <code>название модели + суффикс `_id`</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;">// пользователи</span>
<span style="color: #000000; font-weight: bold;">class</span> Model_User <span style="color: #000000; font-weight: bold;">extends</span> Sprig
<span style="color: #009900;">&#123;</span>
	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: #339933;">,</span>
			<span style="color: #0000ff;">'email'</span>         <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Sprig_Field_Email<span style="color: #339933;">,</span>
			<span style="color: #0000ff;">'userinfo'</span>      <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Sprig_Field_HasOne<span style="color: #339933;">,</span>
			<span style="color: #0000ff;">'articles'</span>       <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Sprig_Field_HasMany<span style="color: #339933;">,</span>
		<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// статьи</span>
<span style="color: #000000; font-weight: bold;">class</span> Model_Article <span style="color: #000000; font-weight: bold;">extends</span> Sprig
<span style="color: #009900;">&#123;</span>
	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;">'title'</span>           <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Sprig_Field_Char<span style="color: #339933;">,</span>
			<span style="color: #0000ff;">'text'</span>           <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Sprig_Field_Text<span style="color: #339933;">,</span>
			<span style="color: #0000ff;">'user'</span>          <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Sprig_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> Sprig_Field_ManyToMany<span style="color: #339933;">,</span>
		<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// тэги</span>
<span style="color: #000000; font-weight: bold;">class</span> Model_Tag <span style="color: #000000; font-weight: bold;">extends</span> Sprig
<span style="color: #009900;">&#123;</span>
	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;">'name'</span>      <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Sprig_Field_Char<span style="color: #339933;">,</span>
			<span style="color: #0000ff;">'articles'</span>    <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Sprig_Field_ManyToMany<span style="color: #339933;">,</span>
		<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// доп. информация о пользователях</span>
<span style="color: #000000; font-weight: bold;">class</span> Model_Userinfo <span style="color: #000000; font-weight: bold;">extends</span> Sprig
<span style="color: #009900;">&#123;</span>
	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;">'data'</span>   <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Sprig_Field_Text<span style="color: #339933;">,</span>
			<span style="color: #0000ff;">'user'</span>   <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Sprig_Field_BelongsTo<span style="color: #339933;">,</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>Условно все поля можно разбить на две категории &#8211; реальные поля и псевдополя. Примеры реальных полей &#8211; `<em>id</em>`, `<em>email</em>` и `<em>username</em>` в модели <strong>Model_User</strong>, они присутствуют в таблице. Псевдополя являются результатом наличия связей с другими моделями. Например, поля `<em>articles</em>` и `<em>userinfo</em>`, которые не могут быть сохранены в БД в явном виде. Для них свойство <code>$in_db</code> установлено в <strong>FALSE</strong>. Не стоит путать внешний ключ (например, `<em>user_id</em>` в таблице `<em>articles</em>`) с псевдополем `<em>user</em>` &#8211; в первом случае мы просто работаем с численным значением, второй вариант дает возможность получить связанный объект. </p></blockquote>
<h2>HasOne</h2>
<p>Примером данной связи будет наличие доп. информации у пользователя. В модели <strong>Model_User</strong> объявлено псевдополе <code>$userinfo</code>:</p>

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

<p>Так как никаких дополнительных параметров при создании псевдополя не передавалось, то при обращении к нему будут автоматически вычислены следующие свойства связи:</p>
<ul>
<li>Имя связанной модели `<em>model</em>` будет `<em>userinfo</em>` (по названию псевдополя).</li>
<li>Имя внешнего ключа в той модели (`<em>column</em>`) определится как `<em>user_id</em>` (<code>имя текущей модели + '_id'</code>).</li>
</ul>
<blockquote><p>
Схема определения имени внешнего ключа не является жестко фиксированной &#8211; используется метод <code>fk($table = NULL)</code> модели. Вы можете его переопределить, чтобы, к примеру, возвращать &#8216;<em>user_key</em>&#8216;. Кроме того, если в Вашей модели используется нестандартный первичный ключ (например &#8216;<em>key</em>&#8216;), то по умолчанию метод <code>pk()</code> будет возвращать что-то вроде &#8216;<em>user_key</em>&#8216; вместо &#8216;<em>user_id</em>&#8216; &#8211; будьте внимательны!</p></blockquote>
<p>Теоретически, теперь мы можем попробовать обратиться к свойству <code>$user->userinfo</code>:</p>
<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> Sprig<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: #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: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">userinfo</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;">-&gt;</span><span style="color: #004000;">data</span><span style="color: #339933;">;</span></pre></div></div>

<p></code></p>
<p>К сожалению, результата не будет. Что-то не так? Методом проб и ошибок определяем, что метод load() не возвращает ожидаемое (а мы предполагаем модель <strong>Userinfo</strong>, где поле &#8216;<em>user_id</em>&#8216; равно 1). А проблема вот в чем &#8211; надо объявить данную связь на другой ее стороне, т.е. собственно в модели <strong>Userinfo</strong>. Это связь типа <strong>BelongsTo</strong>, так что имеет смысл перейти к ней.</p>
<h2>BelongsTo</h2>
<p>Через данный тип связи объявляем, что каждый объект <strong>Userinfo</strong> привязан к родительскому объекту <strong>User</strong>, в нашем случае через поле &#8216;<em>user_id</em>&#8216;. Так как пока что все свойства рассматриваемых моделей (ключи, имена связей и т.д.) максимально простые, то и объявление будет коротким:<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> Sprig_Field_BelongsTo<span style="color: #339933;">,</span></pre></div></div>

<p></code></p>
<p>Автоматически заполняются свойства связи:</p>
<ul>
<li>&#8216;<em>model</em>&#8216; &#8211; имя связанной модели, в данном случае &#8216;<em>user</em>&#8216;.</li>
<li>&#8216;<em>column</em>&#8216; &#8211; имя поля внешнего ключа, получаем через метод <code>fk()</code> модели <strong>Model_User</strong> (по умолчанию вернет &#8216;<em>user_id</em>&#8216;).</li>
</ul>
<p>Поскольку данный тип связи используется не только для <strong>HasOne</strong>, но и с <strong>HasMany</strong>, аналогичное объявление мы сделали в модели <strong>Model_Article</strong> для связи с <strong>Model_User</strong>:<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> Sprig_Field_BelongsTo<span style="color: #339933;">,</span></pre></div></div>

<p></code></p>
<p>Теперь можно вызывать <code>$userinfo->user->load()->username</code>, причем обратную сторону связи в данном случае прописывать необязательно. Таким образом, делаем вполне логичный вывод &#8211; <strong>связь обязательно должна быть прописана в пассивной модели (т.е. в модели, в которую переходит внешний ключ)</strong>.</p>
<h2>HasMany</h2>
<p>Собственно тут тоже ничего сложного, вот так в <strong>Model_User</strong> объявлено, что каждый пользователь может понаписать множество статей в блоге:<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> Sprig_Field_HasMany<span style="color: #339933;">,</span></pre></div></div>

<p></code></p>
<p>&#8220;На автопилоте&#8221; определяется свойство &#8216;<em>model</em>&#8216; &#8211; имя модели, получаем как название связи в единственном числе (через <code>Inflector::singular()</code>) &#8211; &#8216;<em>article</em>&#8216;. Свойство &#8216;<em>column</em>&#8216; бессмысленно, т.к. в результате данной связи в таблице никаких полей не добавляется.</p>
<h2>ManyToMany</h2>
<p>Тут тоже все просто и скучно, в модели <strong>Model_Article</strong> объявляем о тэгах:<br />
<code></p>

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

<p></code></p>
<ul>
<li>Свойство &#8216;<em>model</em>&#8216; получится как &#8216;<em>tag</em>&#8216; (имя связи в единственном числе).</li>
<li>Свойство &#8216;<em>through</em>&#8216; (имя промежуточной таблицы) вычисляется аналогично <strong>ORM</strong>: берем имена таблиц (в данном случае это &#8216;<em>articles</em>&#8216; и &#8216;<em>tags</em>&#8216;), ставим по алфавиту и разделяем знаком подчеркивания, т.е. &#8216;<em>articles_tags</em>&#8216; в итоге.</li>
<li>Свойство &#8216;<em>column</em>&#8216; не заполняется ввиду неактуальности. </li>
</ul>
<blockquote><p>Что любопытно &#8211; после вычисления свойства &#8216;<em>through</em>&#8216; для пары статья-тэг становится доступным статическое свойство <code>Sprig::$_relations['article_tag']</code>, которое содержит имя промежуточной таблицы. Таким образом, если из модели <strong>Model_Tag</strong> обратиться к свойству <code>articles</code>, промежуточная таблица будет взята оттуда. Теоретически это должно позволить менять одну из главных настроек связи <strong>ManyToMany</strong> только в одном месте, но у меня это не вызвало особого интереса. Наверное проще указать &#8216;<em>through</em>&#8216; вручную в двух моделях, зато это будет предсказуемо.
</p></blockquote>
<h2>Ленивая загрузка</h2>
<p>Наверняка вы обратили внимание на метод <code>load()</code>, который иногда используется после обращения к связанным объектам. Очевидно, что данный метод вызывает загрузку записей, т.е. непосредственно <code>$user->userinfo</code>, к примеру, вернет только экземпляр <strong>Database_Query_Builder_Select</strong> с примененными параметрами выборки (с условием <code>where('user_id', '=', 1)</code>). В общем, <em>lazy loading</em> к вашим услугам! Правда, это актуально только для <strong>HasOne</strong> и <strong>BelongsTo</strong>.</p>
<p>Идем дальше. Наверняка вы помните, как осуществляется выборка связанных объектов в <strong>ORM</strong>. К примеру, <code>$user->articles->where('approved', '=', 1)->find_all()</code> позволяет выбрать только утвержденные статьи пользователя. Однако в <strong>Sprig</strong> не все так просто. К сожалению, непосредственный вызов <code>$user->articles</code> приведет к выборке всех статей пользователя, метод <code>where()</code> здесь просто некуда &#8220;воткнуть&#8221;. Единственное, что предлагается нам &#8211; все тот же метод <code>load()</code>. В результате то, что в <strong>ORM</strong> получается достаточно элегантно, в <strong>Sprig</strong> выглядит несколько неуклюже:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$query</span> <span style="color: #339933;">=</span> 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;">where</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'user_id'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'='</span><span style="color: #339933;">,</span> <span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">pk</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;">where</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'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;">;</span>
<span style="color: #000088;">$articles</span> <span style="color: #339933;">=</span> Sprig<span style="color: #339933;">::</span><span style="color: #004000;">factory</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'article'</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;">$query</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">FALSE</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p></code><br />
Сперва подготовили условия (авторство и наличие флага &#8220;утверждено&#8221;), потом подставили в метод <code>load()</code>. Не забудьте про второй параметр, т.к. по умолчанию количество записей ограничивается одной. Впрочем, можно установить нужный лимит записей, например для разбивки на страницы (т.е. для пагинатора).</p>
<blockquote><p>
Это актуально и для безусловных выборок. Например, получаем всех пользователей:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$users</span> <span style="color: #339933;">=</span> Sprig<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;">-&gt;</span><span style="color: #004000;">load</span><span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">NULL</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">FALSE</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p></code></p></blockquote>
<p>Да, это работает. Но теряется вся красота и прозрачность, которая сопутствует <strong>ORM</strong>. Надеюсь, это будет исправлено в следующих коммитах.</p>
<h2>Усложняем задачу</h2>
<p>Конечно, далеко не всегда получается использовать именования таблиц, полей и т.д., которые по умолчанию подходят под соглашения, будь то <strong>ORM</strong> или <strong>Sprig</strong>. Поэтому давайте изменим рассматриваемую схему, которая во второй редакции будет выглядеть вот так:<br />
<a href="http://brotkin.ru/wp-content/uploads/sprig_modern_example.png"><img src="http://brotkin.ru/wp-content/uploads/sprig_modern_example.png" alt="" title="усложненная схема" width="500" height="471" class="aligncenter size-full wp-image-290" /></a></p>
<p>Список изменений следующий.</p>
<ul>
<li>Таблица <em>articles_tags</em> переименована в <em>arttags</em>.</li>
<li>Первичный ключ в <em>articles</em> теперь называется <em>articleid</em>.</li>
<li>Внешний ключ <em>user_id</em> переименован в <em>author_id</em>.</li>
</ul>
<p>Теперь посмотрим, как изменятся коды моделей. Для начала разберемся с переименованием первичного ключа. Обычно (и в <strong>ORM</strong> мы используем такой подход) для этого есть специальное свойство <code>$_primary_key</code>. Но одна из особенностей <strong>Sprig</strong> &#8211; некоторые типы полей могут быть заранее обозначены как часть первичного ключа (их свойство <code>$primary</code> установлено в <strong>TRUE</strong>). Это действительно для поля <strong>Sprig_Field_Auto</strong>, поэтому поле `<em>articleid</em>` будет добавлено в свойство <code>$_primary_key</code> автоматически. Другое дело, что в методе <code>_init()</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> _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;">'articleid'</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: #339933;">...</span></pre></div></div>

<p></code></p>
<blockquote><p>Стоит обратить внимание, что текущая версия <strong>Sprig</strong> не осуществляет проверку при добавлении поля в список первичного ключа, так что в случае прописывания свойства <code>$_primary_key</code> вручную скорее всего одно и то же поле будет добавлено туда дважды.</p></blockquote>
<p>Идем дальше. Для связи с пользователем модель <strong>Article</strong> теперь использует внешний ключ `<em>author_id</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;">'user'</span>	<span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Sprig_Field_BelongsTo<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;">'author_id'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span></pre></div></div>

<p></code></p>
<p>Как мы видим, чтобы переопределить дефолтные названия для внешних ключей, надо использовать параметр <code>column</code>. Сделаем еще одно изменение &#8211; пусть доступ к модели <strong>User</strong> будет осуществляться по псевдополю &#8216;<em>author</em>&#8216; (т.е. <code>$article->author</code> вместо <code>$article->user</code>, что более логично). Для этого надо переименовать имя поля, а также явно указать название связанной модели, которое ранее вычислялось автоматически:</p>
<p><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> Sprig_Field_BelongsTo<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'model'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'user'</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: #009900;">&#41;</span><span style="color: #339933;">,</span></pre></div></div>

<p></code></p>
<p>Ну и напоследок &#8211; указываем в явном виде новое имя промежуточной модели для связи <strong>ManyToMany</strong>:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #0000ff;">'tags'</span><span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> Sprig_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;">'arttags'</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>Прописали? Проверяем, работает?! Ан нет, не работает. Вспомните алгоритм вычисления наименования внешнего ключа &#8211; по умолчанию все зависит от первичого ключа. Поэтому <strong>JOIN</strong> таблиц <em>arttags</em> и <em>tags</em> будет осуществляться по некорректному полю &#8216;<em>article_articleid</em>&#8216;. Как этого избежать, я уже упоминал &#8211; надо переопределить метод <code>fk()</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> fk<span style="color: #009900;">&#40;</span><span style="color: #000088;">$table</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;">$key</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'article_id'</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$table</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$table</span> <span style="color: #339933;">===</span> <span style="color: #009900; font-weight: bold;">TRUE</span><span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #000088;">$table</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_table<span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
		<span style="color: #b1b100;">return</span> <span style="color: #000088;">$table</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'.'</span><span style="color: #339933;">.</span><span style="color: #000088;">$key</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #b1b100;">return</span> <span style="color: #000088;">$key</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></code><br />
Конечно, не самое красивое решение. Во первых, приходится копировать исходный метод полностью, а хотелось бы в полной мере попользоваться наследованием, дабы в своем методе (условно говоря) вычислить переменную <code>$key</code> (или сохранить ее в каком-нибудь свойстве с говорящим названием <code>$_foreign_key</code>) и далее вызвать <code>parent::fk()</code>. Кроме того, вдруг в какой-нибудь другой таблице внешний ключ будет переходить под другим названием? Единственное приходящее мне в данный момент решение &#8211; добавление <code>switch ... case</code> с перечислением известных вариантов значений для переменной <code>$table</code> (по крайней мере для <strong>ManyToMany</strong> метод <code>fk()</code> всегда использует данный параметр). Вспоминается поговорка про мышей и кактус <img src='http://brotkin.ru/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<h2>На этом все</h2>
<p>Согласитесь, налицо существенные недостатки и никаких преимуществ перед <strong>ORM</strong>. Так почему я пишу о данном модуле, а не придумываю новый повод написать очередную статью про <strong>ORM</strong>? Намекну, что главная сила <strong>Sprig</strong> не в связях. <strong>Sprig</strong> удобен тем, что мы унифицируем работу с полями модели/таблицы &#8211; генерацию и обработку форм в первую очередь. Но это уже тема для следующей &#8211; итоговой &#8211; статьи, в которой я покажу, что нам собственно делать с предоставляемыми возможностями.</p>

<div class="bookmarkz"><a href="http://www.google.com/bookmarks/mark?op=add&bkmk=http://brotkin.ru/2009/12/21/ko3-sprig2-2/&title=Ko3%3A+%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C+Sprig.+%D0%A1%D0%B2%D1%8F%D0%B7%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/12/21/ko3-sprig2-2/" 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/12/21/ko3-sprig2-2/&title=Ko3%3A+%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C+Sprig.+%D0%A1%D0%B2%D1%8F%D0%B7%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/12/21/ko3-sprig2-2/&title=Ko3%3A+%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C+Sprig.+%D0%A1%D0%B2%D1%8F%D0%B7%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/12/21/ko3-sprig2-2/&title=Ko3%3A+%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C+Sprig.+%D0%A1%D0%B2%D1%8F%D0%B7%D0%B8+-+%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%A1%D0%B2%D1%8F%D0%B7%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/12/21/ko3-sprig2-2/" 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/12/21/ko3-sprig2-2/&title=Ko3%3A+%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C+Sprig.+%D0%A1%D0%B2%D1%8F%D0%B7%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/12/21/ko3-sprig2-2/&t=Ko3%3A+%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C+Sprig.+%D0%A1%D0%B2%D1%8F%D0%B7%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/12/21/ko3-sprig2-2/" 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/12/21/ko3-sprig2-2/&title=Ko3%3A+%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C+Sprig.+%D0%A1%D0%B2%D1%8F%D0%B7%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/12/21/ko3-sprig2-2/&title=Ko3%3A+%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C+Sprig.+%D0%A1%D0%B2%D1%8F%D0%B7%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/12/21/ko3-sprig2-2/" 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/12/21/ko3-sprig2-2/&u_data[name]=Ko3%3A+%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C+Sprig.+%D0%A1%D0%B2%D1%8F%D0%B7%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/12/21/ko3-sprig2-2/&title=Ko3%3A+%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C+Sprig.+%D0%A1%D0%B2%D1%8F%D0%B7%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/12/21/ko3-sprig2-2/&title=Ko3%3A+%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C+Sprig.+%D0%A1%D0%B2%D1%8F%D0%B7%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/12/21/ko3-sprig2-2/&bm_description=Ko3%3A+%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C+Sprig.+%D0%A1%D0%B2%D1%8F%D0%B7%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/12/21/ko3-sprig2-2/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>ORM. Связи</title>
		<link>http://brotkin.ru/2009/04/18/orm-svyazi/</link>
		<comments>http://brotkin.ru/2009/04/18/orm-svyazi/#comments</comments>
		<pubDate>Sat, 18 Apr 2009 16:18:52 +0000</pubDate>
		<dc:creator>biakaveron</dc:creator>
				<category><![CDATA[cправочник]]></category>
		<category><![CDATA[Kohana]]></category>
		<category><![CDATA[ORM]]></category>
		<category><![CDATA[relations]]></category>
		<category><![CDATA[учебник]]></category>

		<guid isPermaLink="false">http://brotkin.ru/?p=210</guid>
		<description><![CDATA[И снова здравствуйте. В прошлый раз мы рассмотрели основы ORM &#8211; так сказать фундамент, без которого трудно понять его философию и полноценно использовать в своих проектах. Сегодня я расскажу как связать ORM-объекты между собой.
С чего начать?
Перед построением моделей обязательно понимание структуры таблиц в БД, с которой наши модели неразрывно связаны. И если отдельно взятую таблицу [...]]]></description>
			<content:encoded><![CDATA[<p>И снова здравствуйте. В прошлый раз мы рассмотрели основы <strong>ORM</strong> &#8211; так сказать фундамент, без которого трудно понять его философию и полноценно использовать в своих проектах. Сегодня я расскажу как связать <strong>ORM</strong>-объекты между собой.</p>
<h2>С чего начать?</h2>
<p>Перед построением моделей обязательно понимание структуры таблиц в БД, с которой наши модели неразрывно связаны. И если отдельно взятую таблицу мы уже научились проецировать в модель <strong>ORM</strong>, то теперь надо их связать между собой. Давайте сперва рассмотрим теорию. Существует три вида связей между таблицами, описание которых мы сейчас и рассмотрим. А потом перейдем к использованию предоставляемых нам <strong>ORM</strong>&#8216;ом возможностей.</p>
<h3>Один-к-одному (1-1)</h3>
<p>Это достаточно редкий вид связи, когда каждой записи в первой таблице соответствует только одна запись из второй, и наоборот. Теоретически эти таблицы могут быть объединены в одну (первичные ключи в них совпадают), но зачастую в целях оптимизации их разбивают на части. Например, если имеется таблица со списком статей и стоит выбор, где хранить информацию со статистикой просмотра этих статей, вполне логичным решением будет создание отдельной таблицы со связью <em>один-к-одному</em>. В этом случае дополнительная таблица выглядит как &#8220;пристройка&#8221; к основной. Если говорить в терминах фреймворка, то мы можем создавать вспомогательные таблицы вокруг таблицы <em>users</em> из состава модуля <strong>Auth</strong> (например, я ранее упоминал о таблице <em>user_details</em> с дополнительными анкетными данными пользователей). Опять же, в этом случае нам не придется вносить изменения как в модель, так и в структуру таблицы.</p>
<p>Предположим, у нас есть схема из этих двух таблиц:<br />
<div id="attachment_211" class="wp-caption aligncenter" style="width: 494px"><a href="http://brotkin.ru/wp-content/uploads/1-1.png"><img src="http://brotkin.ru/wp-content/uploads/1-1.png" alt="Связь один-к-одному" title="Связь один-к-одному" width="484" height="287" class="size-full wp-image-211" /></a><p class="wp-caption-text">Связь один-к-одному</p></div><br />
Первичный ключ <em>id</em> из таблицы <em>users</em> перешел в таблицу <em>user_details</em>, только был переименован в <em>user_id</em>. В принципе, он мог бы называться также &#8211; <em>id</em>, но даже в случае со связью один-к-одному из двух таблиц можно выделить главную. Поэтому, называя ключ <em>user_id</em>, видно, какая из таблиц зависимая, и откуда в ней появился первичный ключ.</p>
<p>Создадим заготовки для моделей:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// models/User.php</span>
<span style="color: #000000; font-weight: bold;">class</span> User_Model <span style="color: #000000; font-weight: bold;">extends</span> ORM <span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #009900;">&#125;</span>
<span style="color: #666666; font-style: italic;">// models/User_Detail.php</span>
<span style="color: #000000; font-weight: bold;">class</span> User_Detail_Model <span style="color: #000000; font-weight: bold;">extends</span> ORM <span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// Relationships</span>
    protected <span style="color: #000088;">$has_one</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'user'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    protected <span style="color: #000088;">$primary_key</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'user_id'</span><span style="color: #339933;">;</span></pre></div></div>

<p></code></p>
<blockquote><p>Скорее всего у вас подключен модуль <strong>Auth</strong> и модель <em>User_Model</em> уже существует. Поскольку мы его будем рассматривать как сторонний (точнее как часть фреймворка), вносить в него изменения нежелательно и даже бессмысленно. А если модели нет, создаете заготовку как в моем примере &#8211; модель будет совершенно работоспособна, но ничего конкретного мы в нее не вносим. Пусть вспомогательные модели под нее подстраиваются.</p></blockquote>
<p>В модели <em>User_Details</em> всего две строчки. Первая описывает собственно связь. Все связи модели хранятся в свойствах в виде массивов. Каждому типу связи соответствует свой массив. В данном случае мы заполняем свойство <strong>$has_one</strong>. Таких связей может быть несколько, например так:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">protected <span style="color: #000088;">$has_one</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'user'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'anything_else'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p></code><br />
Вторая строчка описывает имя первичного ключа. По умолчанию свойство <strong>$primary_key</strong> установлено в &#8216;<em>id</em>&#8216;, как и рекомендует нам документация по <strong>ORM</strong>, однако мы можем обговорить имя ключа, чем и воспользуемся. При связи один-к-одному такое часто бывает. Кроме этих двух строк ничего не надо. Пишем где-нибудь в контроллере:<br />
<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;">$ud</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_details'</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: #666666; font-style: italic;">// обращаемся к нему как к обычному свойству объекта</span>
<span style="color: #000088;">$user</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$ud</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">user</span><span style="color: #339933;">;</span></pre></div></div>

<p></code><br />
Обратите внимание, что хотя связь между таблицами в принципе равнозначная, из модели <em>User_Model</em> мы так получить <em>User_Details</em> не сможем (ведь в ней не описана эта связь в свойстве <strong>$has_one</strong>). Еще один важный момент: как мы связь назвали при ее описании в свойстве <strong>$has_one</strong>, под таким именем она нам будет доступна. Теперь понятно, что было бы, если бы внешние ключи назывались не <em>user</em> или <em>article</em>, а <em>user_id</em> и <em>article_id</em>?</p>
<blockquote><p>Еще одно примечание. В официальной документации в качестве примера приводится связь между моделью <em>Blog_Post_Model</em> и <em>User_Model</em> из соображений, что одному посту в блоге соответствует один пользователь (автор). Я с этим категорически не согласен, т.к. связь <em>один-к-одному</em> должна быть одинаковой на обоих концах, а у пользователя может быть несколько постов, так что там связь типа <em>один-ко-многим</em>. Такая вот оппозиция <img src='http://brotkin.ru/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p></blockquote>
<h3>Один-ко-многим (1-N)</h3>
<p>Данная связь означает, что каждой записи в одной таблице может соответствовать несколько записей из другой таблицы. Это самая распространенная связь между таблицами. На схеме ниже рассмотрено взаимодействие между темами на форуме и комментариями к ним:<br />
<div id="attachment_212" class="wp-caption aligncenter" style="width: 509px"><a href="http://brotkin.ru/wp-content/uploads/1-n.png"><img src="http://brotkin.ru/wp-content/uploads/1-n.png" alt="Связь один-ко-многим" title="Связь один-ко-многим" width="499" height="229" class="size-full wp-image-212" /></a><p class="wp-caption-text">Связь один-ко-многим</p></div><br />
На основании данной схемы описываем модели <em>Post_Model</em> и <em>Comment_Model</em>:<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> Post_Model <span style="color: #000000; font-weight: bold;">extends</span> ORM <span style="color: #009900;">&#123;</span>
	protected <span style="color: #000088;">$db</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'forum'</span><span style="color: #339933;">;</span>
	protected <span style="color: #000088;">$has_many</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'comments'</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;">class</span> Comment_Model <span style="color: #000000; font-weight: bold;">extends</span> ORM <span style="color: #009900;">&#123;</span>
	protected <span style="color: #000088;">$db</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'forum'</span><span style="color: #339933;">;</span>
	protected <span style="color: #000088;">$belongs_to</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</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: #009900;">&#125;</span></pre></div></div>

<p></code><br />
Думаю, здесь надо объяснить немного поподробнее. Сперва насчет переменной <strong>$db</strong> &#8211; в ней до вызова конструктора хранится имя профиля из файла(ов) <em>config/database.php</em>. <a href="http://brotkin.ru/2009/02/21/svoya-cms-prefiksy/">Я уже писал</a> о том, что в каждом отдельно взятом модуле хочу сделать свои префиксы для таблиц. Поэтому на схеме таблицы названы с префиксом &#8216;<em>forum_</em>&#8216;. Конечно, можно было использовать свойство <em>$table_name</em> и указать имя таблицы, но тогда это пришлось бы делать для каждой модели. Кроме того, такой подход заставит нас переделывать все модели, если префикс поменяется (в идеале подобный выбор предоставляется пользователю во время инсталляции проекта). Другой вариант еще хуже &#8211; назвать модели в соответствии с именами таблиц, т.е. <em>Forum_Post_Model</em> и <em>Forum_Comment_Model</em>. Недостатки те же, да еще и имя класса увеличилось. Поэтому остановимся на префиксах. Если у вас их нет (или вдруг вы от них отказались), то просто не используйте опцию <em>table_prefix</em> в настройках профиля подключения к БД &#8211; и больше ничего менять не придется.</p>
<p>Далее &#8211; новые для нас свойства <strong>$has_many</strong> и <strong>$belongs_to</strong>. Их использование ничем не отличается от <strong>$has_one</strong>. Для таблицы, которая как бы является родительской (комментарии принадлежат статье, а не статьи комментарию) используем <strong>$has_many</strong> (дословно &#8211; &#8220;<em>имеет много</em>&#8220;), для &#8220;дочерней&#8221; таблицы &#8211; <strong>$belongs_to</strong> (&#8220;<em>относится к</em>&#8220;). На уровне структуры таблиц это сопровождается добавлением первичного ключа родительской таблицы (в нашем случае это <em>forum_posts.id</em>) в дочернюю в виде внешнего ключа <em>post_id</em>. Типичный механизм &#8211; имя таблицы в единственном числе (<em>post</em>, т.к. префикс мы привычно отбрасываем) плюс суффикс &#8216;<em>_id</em>&#8216;. Опять же, не всегда получается называть поля как мы хотим, поэтому ниже я покажу дополнительные свойства для жесткого указания имен внешних ключей.</p>
<blockquote><p>Часто люди путаются при заполнении связей модели, где употреблять имя в единственном числе, а где во множественном. Следует рассуждать логически: статья имеет много комментариев, следовательно <strong>$has_many = array(&#8216;comments&#8217;)</strong>. Аналогично комментарий относится к статье, т.е. <strong>$belongs_to(&#8216;post&#8217;)</strong>. Связи <em>один-к-одному</em> всегда в единственном числе. Проще всего запомнить &#8211; если в названии связи есть слово <strong>many</strong>, то употребляем множественное число (т.е. связь неоднозначная, на противоположном ее конце несколько объектов).</p></blockquote>
<p>Использование аналогично связи <em>один-к-одному</em>, только будьте готовы к тому, что на в результате можем получить массив записей:<br />
<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> 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: #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: #b1b100;">echo</span> <span style="color: #000088;">$post</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">text</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;&lt;br /&gt;&quot;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// получаем комментарии топика</span>
<span style="color: #666666; font-style: italic;">// !! это не ORM-объект, а ORM_Iterator !!</span>
<span style="color: #000088;">$comments</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$post</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">comments</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// далее в цикле пробегаемся по комментариям топика</span>
<span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$comments</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$comment</span><span style="color: #009900;">&#41;</span>
    <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$comment</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">text</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;&lt;br /&gt;&quot;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// а теперь получаем топик, которому принадлежит комментарий №2</span>
<span style="color: #000088;">$comment</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;">'comment'</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$comment</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">post</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">id</span><span style="color: #339933;">;</span></pre></div></div>

<p></code><br />
Запомните, если связь неоднозначная, т.е. мы ждем несколько объектов, связанных с нашим, в результате получим не <strong>ORM</strong>-объект, а экземпляр класса <strong>ORM_Iterator</strong>. Для простоты можете рассматривать его как массив <strong>ORM</strong>-объектов нужного вам класса. Если же вас смущает использование непонятного класса, описание которого отсутствует (на данный момент) в официальной документации &#8211; можете просто превратить его в настоящий массив с помощью метода <strong>as_array()</strong>.</p>
<h3>Много-ко-многим (M-N)</h3>
<p>Этот тип связи появляется, когда между связанными таблицами нет однозначности в обе стороны, т.е. каждой строке из одной таблицы может соответствовать несколько записей из другой, и наоборот. Типичный пример &#8211; у пользователя может быть несколько ролей (так было в модуле <strong>Auth</strong>, идущем в составе Kohana <em>2.3.x</em>), каждая роль может быть присвоена нескольким пользователям. Поэтому простым перекидыванием первичного ключа из одной таблицы в другую связь не наладить &#8211; нет однозначности. Решение &#8211; создание промежуточной таблицы (<em>pivot table</em>) между ними, в которую добавляются первичные ключи обеих таблиц. Обычно кроме этих полей в ней ничего нет.<br />
<div id="attachment_213" class="wp-caption aligncenter" style="width: 510px"><a href="http://brotkin.ru/wp-content/uploads/m-n.png"><img src="http://brotkin.ru/wp-content/uploads/m-n.png" alt="Связь много-ко-многим" title="Связь много-ко-многим" width="500" height="188" class="size-full wp-image-213" /></a><p class="wp-caption-text">Связь много-ко-многим</p></div></p>
<p>Имя для промежуточной таблицы составляется из расставленных в алфавитном порядке названий связанных таблиц, объединенных знаком подчеркивания. Первичный ключ состоит из внешних ключей таблиц <em>users</em> и <em>forum_roles</em> (<em>user_id</em> и <em>role_id</em> соответственно). По сути таблица <em>roles_users</em> служит только для хранения пар пользователь-роль, чтобы из одной таблицы можно было &#8220;перескочить&#8221; в другую. Давайте посмотрим, как это выглядит в терминах Kohana:<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> User_Model <span style="color: #000000; font-weight: bold;">extends</span> ORM <span style="color: #009900;">&#123;</span>
	protected <span style="color: #000088;">$has_and_belongs_to_many</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'roles'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> Role_Model <span style="color: #000000; font-weight: bold;">extends</span> ORM <span style="color: #009900;">&#123;</span>
	protected <span style="color: #000088;">$db</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'forum'</span><span style="color: #339933;">;</span>
	protected <span style="color: #000088;">$has_and_belongs_to_many</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'users'</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>$has_and_belongs_to_many</strong> (часто на форумах используется термин <em>HABTM</em>, аббревиатура от данного названия). Обратите внимание, что промежуточная таблица <em>roles_users</em> вообще не участвует в процессе создания моделей <strong>ORM</strong>, главное &#8211; чтобы ее имя и названия полей соответствовали требования <strong>ORM</strong> (либо были указаны явно). В результате получим всех администраторов системы (<em>id</em>=1):<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$role</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;">'role'</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: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$role</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">users</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$user</span><span style="color: #009900;">&#41;</span>
   <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">username</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>
<blockquote><p>И все-таки, насколько неудобно использовать <em>id</em> при создании объектов! Насколько более понятны и близки нам &#8220;говорящие&#8221; поля, такие как username или name. Естественно, разработчики предусмотрели способ передавать при создании экземпляра модели не идентификатор, а произвольную строку. Для этого надо переопределить метод <strong>unique_key($id)</strong>. Можете просто поковырять модель <em>User_Model</em> в модуле <strong>Auth</strong>, там это уже сделано.</p></blockquote>
<p>Но что же делать, если в промежуточной таблице необходимо хранить не только внешние ключи? Например, в рассматриваемом нами случае с ролями могут присутствовать поля <em>created</em> (время добавления роли) и <em>expired</em> (время окончания действия роли). В таком случае вместо одной связи много-ко-многим между двумя таблицами мы получаем две связи один-ко-многим между тремя:<br />
<div id="attachment_214" class="wp-caption aligncenter" style="width: 509px"><a href="http://brotkin.ru/wp-content/uploads/m-n_2.png"><img src="http://brotkin.ru/wp-content/uploads/m-n_2.png" alt="Во что превратилась связь много-ко-многим" title="Во что превратилась связь много-ко-многим" width="499" height="171" class="size-full wp-image-214" /></a><p class="wp-caption-text">Во что превратилась связь много-ко-многим</p></div><br />
Соответственно код моделей будет такой:<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> User_Model <span style="color: #000000; font-weight: bold;">extends</span> ORM <span style="color: #009900;">&#123;</span>
	protected <span style="color: #000088;">$has_many</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'assigned_roles'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> Role_Model <span style="color: #000000; font-weight: bold;">extends</span> ORM <span style="color: #009900;">&#123;</span>
	protected <span style="color: #000088;">$db</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'forum'</span><span style="color: #339933;">;</span>
	protected <span style="color: #000088;">$has_many</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'assigned_roles'</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;">class</span> Assigned_Role_Model <span style="color: #000000; font-weight: bold;">extends</span> ORM <span style="color: #009900;">&#123;</span>
	protected <span style="color: #000088;">$db</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'forum'</span><span style="color: #339933;">;</span>
	protected <span style="color: #000088;">$belongs_to</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'users'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'roles'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></code><br />
В этом случае мы рассматриваем такую связь как две: наличие нескольких назначенных ролей пользователю и возможность назначения роли несколько раз (предполагается, что различным пользователям). Кстати, никто не мешает комбинировать оба варианта (только класс и таблица должны называться <em>forum_roles_users</em>, иначе запрос не сформируется).</p>
<h3>&#8220;Сквозное&#8221; один-ко-многим</h3>
<p>Рассмотренный выше вариант преобразования <em>HABTM</em> в два <em>has_many</em> доступен в более компактном виде. Посмотрите на такую запись:<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> User_Model <span style="color: #000000; font-weight: bold;">extends</span> ORM <span style="color: #009900;">&#123;</span>
	protected <span style="color: #000088;">$has_many</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'roles'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'assigned_roles'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> Role_Model <span style="color: #000000; font-weight: bold;">extends</span> ORM <span style="color: #009900;">&#123;</span>
	protected <span style="color: #000088;">$db</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'forum'</span><span style="color: #339933;">;</span>
	protected <span style="color: #000088;">$has_many</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'users'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'assigned_roles'</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;">class</span> Assigned_Role_Model <span style="color: #000000; font-weight: bold;">extends</span> ORM <span style="color: #009900;">&#123;</span>
	protected <span style="color: #000088;">$db</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'forum'</span><span style="color: #339933;">;</span>
	protected <span style="color: #000088;">$belongs_to</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'users'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'roles'</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>$has_many</strong> мы записываем как промежуточную модель (`<em>assigned_roles</em>`), так и &#8220;конечную&#8221; (`<em>roles</em>` и `<em>users</em>`) как бы с использованием псевдонимов (<em>aliasing</em>). Теперь можно обращаться как к <strong>$user->roles</strong>, так и к <strong>$user->assigned_roles</strong>.</p>
<blockquote><p>
Это конечно удобно, но взамен мы теряем возможность использовать псевдонимы для &#8220;настоящих&#8221; связей один-ко-многим. Даже не знаю, стоило ли оно того. Впрочем, в версии 2.4 для &#8220;сквозных&#8221; связей будет предусмотрено отдельное свойство <strong>$has_many_through</strong>.</p></blockquote>
<h2>Работа со связями</h2>
<p>Как заполнять таблицы мы знаем. А как создавать связи между конкретными записями? Как добавить пользователю <em>X</em> роль <em>Y</em>, добавить комментарий <em>№4</em> именно в топик <em>№13</em>? Все довольно просто. Сейчас мы рассмотрим доступные нам возможности.</p>
<ul>
<li>В случае связи <em>один-к-одному</em> все достаточно просто: в дочернюю таблицу необходимо подставить ключ из родительской. Например, при сохранении анкетных данных в поле <em>$user_details->user_id</em> надо подставить что-то вроде <em>$user->id</em>, где <em>$user</em> &#8211; <strong>ORM</strong>-модель сохраняемого пользователя. Аналогичные действия надо предпринять при сохранении объекта, связанного с другим через <strong>$belongs_to</strong>.</li>
<li>Несколько сложнее добавление связи в случае <em>много-ко-многим</em>. Для этого в <strong>ORM</strong> добавили специальный метод <strong>add()</strong>. Использовать надо так:<br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// создаем объект пользователя с id=$id</span>
<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: #339933;">,</span> <span style="color: #000088;">$id</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// добавляем ему роль с id=$roleid</span>
<span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">add</span><span style="color: #009900;">&#40;</span>ORM<span style="color: #339933;">::</span><span style="color: #004000;">factory</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'role'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$roleid</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>has()</strong>, а для удаления связи &#8211; <strong>remove()</strong>. Оба они также принимают в качестве параметра проверяемый/удаляемый объект.</p>
<blockquote><p>Возвращаясь к удобству переопределения метода <strong>unique_value($id)</strong>: насколько <strong>ORM::factory(&#8216;role&#8217;, &#8216;admin&#8217;)</strong> читабельнее, чем <strong>ORM::factory(&#8216;role&#8217;, 1)</strong>!</p></blockquote>
</li>
<li>Специальный метод для удаления связи существует только для много-ко-многим. Если вы удалите топик, комментарии к нему <strong>Kohana</strong> удалять не будет. Либо об этом позаботитесь вы сами (программно), либо (что проще) об этом позаботится СУБД, если вы при создании таблиц будете использовать конструкции типа <em>ON DELETE CASCADE</em>.</li>
</ul>
<h2>Custom&#8217;изация ORM-моделей</h2>
<p>Итак, если какие-то параметры (названия таблиц, ключей и т.д.) у нас отличаются от ожидаемых по правилам <strong>ORM</strong>, есть несколько способов вручную указать, что и куда подставлять. Часть свойств я упоминал в предыдущей статье, сейчас расскажу про оставшиеся, отвечающие за взаимодействие с другими моделями.</p>
<p><strong>$load_with</strong>. Позволяет указать, какие модели загружать вместе с данной автоматически. Представляет из себя массив связей. Например, чтобы при создании модели <em>User_Detail</em> загружались еще и данные этого пользователя, просто указываем <em>$load_with = array(&#8216;user&#8217;)</em>. Совместная загрузка будет работать только с однозначными связями, т.е. если указываемая модель была занесена нами в <strong>$has_one</strong> или <strong>$belongs_to</strong>. Поэтому в модели <em>Comment_Model</em> мы можем указать загрузку модели <em>Post_Model</em>, но не наоборот. По сути мы сразу вызываем <em>join</em>-запрос, не дожидаясь &#8220;ленивой&#8221; загрузки связанной модели в дальнейшем. Рекомендую не увлекаться этим свойством, т.к. не все загружаемые вместе с текущим объектом модели вам пригодятся.</p>
<p><strong>$foreign_key</strong>. Массив указанных вручную внешних ключей для модели. Используется только для связей один-ко-многим (в других случаях внешних ключей по сути нет). Если в дочерней модели имя поля, являющегося внешним ключом, не соответствует концепии <strong>ORM</strong> (т.е. не <em>имя_родительской_модели</em> + суффикс &#8216;<em>_id</em>&#8216;), то необходимо указать в данном свойстве истинное имя поля. Предположим, что в рассмотренной нами выше схеме внешний ключ таблицы <em>forum_comments</em> называется <em>new_post_id</em>:<br />
<div id="attachment_215" class="wp-caption aligncenter" style="width: 510px"><a href="http://brotkin.ru/wp-content/uploads/1-n_2.png"><img src="http://brotkin.ru/wp-content/uploads/1-n_2.png" alt="Схема комментарии - топики с измененным внешним ключом" title="Схема комментарии - топики с измененным внешним ключом" width="500" height="254" class="size-full wp-image-215" /></a><p class="wp-caption-text">Схема комментарии - топики с измененным внешним ключом</p></div><br />
Очевидно, что при попытке доступа к соединенной таблице в <strong>ORM</strong> произойдет ошибка, т.к. в <em>join</em> будет вставлено не <em>new_post_id</em>, а <em>post_id</em>. Поэтому будем использовать свойство <strong>$foreign_key</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;">class</span> Post_Model <span style="color: #000000; font-weight: bold;">extends</span> ORM <span style="color: #009900;">&#123;</span>
	protected <span style="color: #000088;">$db</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'forum'</span><span style="color: #339933;">;</span>
	protected <span style="color: #000088;">$has_many</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'comments'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	protected <span style="color: #000088;">$foreign_key</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'comments'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'new_post_id'</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;">class</span> Comment_Model <span style="color: #000000; font-weight: bold;">extends</span> ORM <span style="color: #009900;">&#123;</span>
	protected <span style="color: #000088;">$db</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'forum'</span><span style="color: #339933;">;</span>
	protected <span style="color: #000088;">$belongs_to</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'post'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	protected <span style="color: #000088;">$foreign_key</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'post'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'new_post_id'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></code><br />
Обратите внимание, что имя внешнего ключа надо прописывать в обеих моделях! Если в модели <em>Post_Model</em> вы это не сделаете, то при попытке получить все комментарии топика (что-то вроде <em>$post->comments</em>) произойдет ошибка <strong>SQL</strong>-запроса. Возможно, не совсем логичное решение разработчиков, т.к. при изменении внутренней структуры дочерней модели изменения придется внести и в родительскую. Также запомните, что ключи в массиве <strong>$foreign_key</strong> должны совпадать с указанными в связях, т.е. &#8216;<em>post</em>&#8216; для <em>Comment_Model</em> и &#8216;<em>comments</em>&#8216; для <em>Post_Model</em>.</p>
<blockquote><p>Свойство появилось только в версии <em>2.3.2</em>!</p></blockquote>
<p>Ну, и напоследок &#8211; <strong>псевдонимы</strong> (<strong>aliasing</strong>).<br />
Иногда имя таблицы, с которой связывается текущая таблица, не выражает ту роль, которую она играет. Типичный пример &#8211; таблица <em>users</em>. Пользователь может быть автором, модератором, редактором, голосующим и т.д. Кроме того, в рамках одной таблицы может быть несколько внешних ключей к одной и той же таблице. Как быть в этом случае? Помогут псевдонимы:<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> Article_Model <span style="color: #000000; font-weight: bold;">extends</span> ORM <span style="color: #009900;">&#123;</span>
	<span style="color: #666666; font-style: italic;">// у статьи может быть автор и редактор, причем это разные люди</span>
	protected <span style="color: #000088;">$belongs_to</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'author'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'user'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'redactor'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'user'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></code><br />
Как видите, все достаточно просто. Сначала пишем имя связи (т.е. роль, которую играет модель), а далее &#8211; само имя модели (причем в зависимости от типа связи оно может быть в единственном или множественном числе, как я уже упоминал). Используя эти псевдонимы, в контроллере мы можем вызывать &#8220;<em>магические</em>&#8221; свойства <em>$article->author</em> и <em>$article->redactor</em>.</p>
<blockquote><p>Предположим, в модели также описана связь с категориями, для которой не нужны псевдонимы. Не стоит писать</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">protected <span style="color: #000088;">$belongs_to</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'author'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'user'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'redactor'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'user'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'categories'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'categories'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Можно смешить псевдонимы с обычными ключами:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">protected <span style="color: #000088;">$belongs_to</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'author'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'user'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'redactor'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'user'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'categories'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

</blockquote>
<h2>Проблемы, с которыми можно столкнуться</h2>
<p><strong>Использование одной таблицы в различных ролях</strong>. Опять же, центральная в моей схеме БД таблица &#8211; <em>users</em>. Мы можем создать одну модель и нафаршировать ее связями со всеми таблицами, использующими ее данные (если вспомнить <a href="http://brotkin.ru/wp-content/uploads/forum_module.png">схему</a>, приведенную мной в статье о модуле &#8220;<em>форум</em>&#8220;, становится понятно, о чем это я. И это только один модуль!). А можем выделить роли этой таблицы и создать для каждой из них свою модель. Для указания имени таблицы, напомню, есть свойство <strong>$table_name</strong>. Например, роль &#8220;<em>Автор</em>&#8221; (<em>Author</em>) просто напрашивается для модуля &#8220;<em>форум</em>&#8220;, т.к. присутствует и в комментариях, и в топиках. Можно поиграться и с наследованием от базового класса, но это не всегда предсказуемо. К примеру, свойства модели при переопределении не дополняются базовыми, т.е. связи предка будут потеряны.</p>
<p><strong>Применение префиксов таблиц</strong>. Если между собой связываются таблицы с различными префиксами (к примеру, <em>users</em> и <em>forum_roles</em> из схемы про <em>много-ко-многим</em>), то могут возникнуть проблемы с автоматическим вычислением системой имен таблиц. В первую очередь это связано  именно со связями <em>много-ко-многим</em>. Имя промежуточной таблицы вычислится в разных моделях по-разному, и в одну из сторон связь работать не будет. В этом случае вместо <em>forum_таблица1_таблица2</em> придется использовать <em>таблица1_forum_таблица2</em>. Это логично с точки зрения <em>ORM</em>, но не очень удобно, если мы хотим, чтобы все таблицы модуля начинались одинаково.</p>
<h2>Что дальше?</h2>
<p>Думаю, с теорией теперь более-менее ясно. В качестве закрепления попробуйте реализовать большую и сложную схему с кучей связанных между собой таблиц. В следующей статье я покажу это на примере описанной мной ранее схемы модуля &#8220;<em>форум</em>&#8220;.</p>
<p>PS. Надеюсь, я ничего не забыл, если что &#8211; традиционно тыкайте меня в ошибки в комментариях.</p>

<div class="bookmarkz"><a href="http://www.google.com/bookmarks/mark?op=add&bkmk=http://brotkin.ru/2009/04/18/orm-svyazi/&title=ORM.+%D0%A1%D0%B2%D1%8F%D0%B7%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/04/18/orm-svyazi/" 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/04/18/orm-svyazi/&title=ORM.+%D0%A1%D0%B2%D1%8F%D0%B7%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/04/18/orm-svyazi/&title=ORM.+%D0%A1%D0%B2%D1%8F%D0%B7%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/04/18/orm-svyazi/&title=ORM.+%D0%A1%D0%B2%D1%8F%D0%B7%D0%B8+-+%D0%98%D0%B7%D1%83%D1%87%D0%B0%D0%B5%D0%BC+Web&description=ORM.+%D0%A1%D0%B2%D1%8F%D0%B7%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/04/18/orm-svyazi/" 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/04/18/orm-svyazi/&title=ORM.+%D0%A1%D0%B2%D1%8F%D0%B7%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/04/18/orm-svyazi/&t=ORM.+%D0%A1%D0%B2%D1%8F%D0%B7%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/04/18/orm-svyazi/" 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/04/18/orm-svyazi/&title=ORM.+%D0%A1%D0%B2%D1%8F%D0%B7%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/04/18/orm-svyazi/&title=ORM.+%D0%A1%D0%B2%D1%8F%D0%B7%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/04/18/orm-svyazi/" 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/04/18/orm-svyazi/&u_data[name]=ORM.+%D0%A1%D0%B2%D1%8F%D0%B7%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/04/18/orm-svyazi/&title=ORM.+%D0%A1%D0%B2%D1%8F%D0%B7%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/04/18/orm-svyazi/&title=ORM.+%D0%A1%D0%B2%D1%8F%D0%B7%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/04/18/orm-svyazi/&bm_description=ORM.+%D0%A1%D0%B2%D1%8F%D0%B7%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/04/18/orm-svyazi/feed/</wfw:commentRss>
		<slash:comments>35</slash:comments>
		</item>
	</channel>
</rss>

