<?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>Ars Longa, Vita Brevis &#187; Kohana</title>
	<atom:link href="http://blog.sjinks.pro/kohana/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.sjinks.pro</link>
	<description>Quod scripsi, scripsi</description>
	<lastBuildDate>Thu, 19 Jan 2012 12:18:51 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Исправление ошибки в INSERT INTO … SELECT в Kohana 3 при использовании конфигурации базы данных, отличной от default</title>
		<link>http://blog.sjinks.pro/php/kohana/806-fix-insert-select-bug-with-non-default-db-config-in-kohana-3/</link>
		<comments>http://blog.sjinks.pro/php/kohana/806-fix-insert-select-bug-with-non-default-db-config-in-kohana-3/#comments</comments>
		<pubDate>Thu, 12 Aug 2010 07:40:55 +0000</pubDate>
		<dc:creator>Wandering Soul</dc:creator>
				<category><![CDATA[Kohana]]></category>
		<category><![CDATA[Kohana 3]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[база данных]]></category>
		<category><![CDATA[ошибка]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=806</guid>
		<description><![CDATA[Исправление короче описания Ситуация: нужно выполнить запрос вида INSERT INTO `table` (`col1`, `col2`) SELECT * FROM `table` WHERE `col1` &#60;&#62; 0; Если использовать конфигурацию default, то всё отлично работает. Если же использовать другую конфигурацию, то можем получить ошибку соединения с базой данных и исключение. Например: &#60;?php // application/config/database.php // Важно, чтобы в конфигурации default нельзя [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/kohana/806-fix-insert-select-bug-with-non-default-db-config-in-kohana-3/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Исправление короче описания</em></h2>
<p><strong>Ситуация:</strong> нужно выполнить запрос вида</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p8067">
        <div class="code sql" id="p806code7">
<span class="kw1">INSERT</span> <span class="kw1">INTO</span> <span class="st0">`table`</span> <span class="br0">&#40;</span><span class="st0">`col1`</span><span class="sy0">,</span> <span class="st0">`col2`</span><span class="br0">&#41;</span> <span class="kw1">SELECT</span> <span class="sy0">*</span> <span class="kw1">FROM</span> <span class="st0">`table`</span> <span class="kw1">WHERE</span> <span class="st0">`col1`</span> <span class="sy0">&lt;&gt;</span> <span class="nu0">0</span>;
        </div>
    </div>
</div>

<p>Если использовать конфигурацию <code>default</code>, то всё отлично работает. Если же использовать другую конфигурацию, то можем получить ошибку соединения с базой данных и исключение.<span id="more-806"></span></p>
<p>Например:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p8068">
        <div class="code php" id="p806code8">
<span class="kw2">&lt;?php</span><br />
<span class="co1">// application/config/database.php</span><br />
<span class="co1">// Важно, чтобы в конфигурации default нельзя было подключиться к серверу</span><br />
<span class="kw1">return</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st_h">'test'</span> <span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'type'</span> &nbsp; &nbsp; &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'mysql'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'connection'</span> <span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'hostname'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'localhost'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'database'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'test'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'username'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'username'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'password'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'password'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'persistent'</span> <span class="sy0">=&gt;</span> <span class="kw4">FALSE</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'table_prefix'</span> <span class="sy0">=&gt;</span> <span class="st_h">''</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'charset'</span> &nbsp; &nbsp; &nbsp;<span class="sy0">=&gt;</span> <span class="st_h">'utf8'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'caching'</span> &nbsp; &nbsp; &nbsp;<span class="sy0">=&gt;</span> <span class="kw4">FALSE</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'profiling'</span> &nbsp; &nbsp;<span class="sy0">=&gt;</span> <span class="kw4">TRUE</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
<span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="sy1">?&gt;</span><br />
<br />
<span class="kw2">&lt;?php</span><br />
<span class="co1">// application/classes/controller/welcome.php</span><br />
<br />
<span class="kw2">class</span> Controller_Welcome <span class="kw2">extends</span> Controller<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> action_index<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">request</span><span class="sy0">-&gt;</span><span class="me1">response</span> <span class="sy0">=</span> DB<span class="sy0">::</span><span class="me2">insert</span><span class="br0">&#40;</span><span class="st_h">'test'</span><span class="sy0">,</span> <span class="kw1">array</span><span class="br0">&#40;</span><span class="st_h">'col1'</span><span class="sy0">,</span> <span class="st_h">'col2'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">-&gt;</span><span class="me1">select</span><span class="br0">&#40;</span>DB<span class="sy0">::</span><span class="me2">select</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">from</span><span class="br0">&#40;</span><span class="st_h">'test'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">where</span><span class="br0">&#40;</span><span class="st_h">'column1'</span><span class="sy0">,</span> <span class="st_h">'&lt;&gt;'</span><span class="sy0">,</span> <span class="st_h">'0'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">-&gt;</span><span class="me1">compile</span><span class="br0">&#40;</span>Database<span class="sy0">::</span><span class="me2">instance</span><span class="br0">&#40;</span><span class="st_h">'test'</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy0">.</span> <span class="st0">&quot;<span class="es1">\n</span>&quot;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

<p>Важно, чтобы правая часть условия в <code>where()</code> была строкой.</p>
<p>В результате если мы запустим проект, то получим что-то вида:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p8069">
        <div class="code text" id="p806code9">
INSERT INTO `test` (`column1`, `column2`) ErrorException [ 2 ]: mysql_connect(): Access denied for user 'www-data'@'localhost' (using password: NO) ~ MODPATH/database/classes/kohana/database/mysql.php [ 56 ]
        </div>
    </div>
</div>

<p>Связано это с особенностью реализации метода <code><a href="http://blog.sjinks.pro/tag/kohana/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Kohana">Kohana</a>_Database_Query_Builder_Insert::compile()</code>:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p80610">
        <div class="code php" id="p806code10">
&nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> compile<span class="br0">&#40;</span>Database <span class="re0">$db</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// Start an insertion query</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$query</span> <span class="sy0">=</span> <span class="st_h">'INSERT INTO '</span><span class="sy0">.</span><span class="re0">$db</span><span class="sy0">-&gt;</span><span class="me1">quote_table</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span>_table<span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// Не интересно</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// …</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw3">is_array</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span>_values<span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// Не интересно</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// …</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$query</span> <span class="sy0">.=</span> <span class="st_h">'VALUES '</span><span class="sy0">.</span><span class="kw3">implode</span><span class="br0">&#40;</span><span class="st_h">', '</span><span class="sy0">,</span> <span class="re0">$groups</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// Add the sub-query</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$query</span> <span class="sy0">.=</span> <span class="br0">&#40;</span>string<span class="br0">&#41;</span> <span class="re0">$this</span><span class="sy0">-&gt;</span>_values<span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$query</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>Строка <span class="codebox"><code class="php"><span class="re0">$query</span> <span class="sy0">.=</span> <span class="br0">&#40;</span>string<span class="br0">&#41;</span> <span class="re0">$this</span><span class="sy0">-&gt;</span>_values<span class="sy0">;</span></code></span> вызывает метод <code>compile()</code> для <code>SELECT</code>, но так как конфигурация базы данных не передаётся, используется конфигурация <code>default</code>.</p>
<p>Самое простое исправление очевидно: заменить строку</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p80611">
        <div class="code php" id="p806code11">
<span class="re0">$query</span> <span class="sy0">.=</span> <span class="br0">&#40;</span>string<span class="br0">&#41;</span> <span class="re0">$this</span><span class="sy0">-&gt;</span>_values<span class="sy0">;</span>
        </div>
    </div>
</div>

<p>на </p>
          
<div class="codebox">
    <div class="the_code" style="" id="p80612">
        <div class="code php" id="p806code12">
<span class="re0">$query</span> <span class="sy0">.=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span>_values<span class="sy0">-&gt;</span><span class="me1">compile</span><span class="br0">&#40;</span><span class="re0">$db</span><span class="br0">&#41;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p>Тем не менее, если <code>SELECT</code> использует одну базу данных, а <code>INSERT</code> — другую, и при этом используются разные charset&#8217;ы (да, это не самое большое извращение — бывают и хуже), этого будет недостаточно. В этом случае нужно добавить дополнительный параметр в метод <code>select()</code>, указывающий, какую конфигурацию использовать. Требуемые изменения кода тривиальны, посему остаются упражнением интересующемуся читателю.</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/kohana/806-fix-insert-select-bug-with-non-default-db-config-in-kohana-3/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/php/kohana/806-fix-insert-select-bug-with-non-default-db-config-in-kohana-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Поддержка JOIN в запросах DELETE для Kohana 3</title>
		<link>http://blog.sjinks.pro/php/kohana/805-join-support-for-delete-in-kohana-3/</link>
		<comments>http://blog.sjinks.pro/php/kohana/805-join-support-for-delete-in-kohana-3/#comments</comments>
		<pubDate>Wed, 11 Aug 2010 10:48:13 +0000</pubDate>
		<dc:creator>Wandering Soul</dc:creator>
				<category><![CDATA[Kohana]]></category>
		<category><![CDATA[Kohana 3]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[база данных]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=805</guid>
		<description><![CDATA[Добавление поддержки multiple-table DELETE в Query Builder Kohana 3 Иногда бывает полезно выполнить удаление записей в нескольких связанных таблицах, благо синтаксис позволяет. Разумеется, есть такая вещь как каскадное удаление записей, но в случае с MySQL (а именно — таблицами MyISAM) на неё надеяться не приходится. Модуль Database из Kohana 3 не умеет использовать JOIN с операцией DELETE. Нужно [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/kohana/805-join-support-for-delete-in-kohana-3/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Добавление поддержки multiple-table DELETE в Query Builder <a href="http://blog.sjinks.pro/tag/kohana/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Kohana">Kohana</a> 3</em></h2>
<p>Иногда бывает полезно выполнить удаление записей в нескольких связанных таблицах, благо <a href="http://dev.mysql.com/doc/refman/5.0/en/delete.html">синтаксис позволяет</a>. Разумеется, есть такая вещь как каскадное удаление записей, но в случае с <a href="http://blog.sjinks.pro/tag/mysql/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  MySQL">MySQL</a> (а именно — таблицами MyISAM) на неё надеяться не приходится.</p>
<p>Модуль Database из <a href="http://blog.sjinks.pro/tag/kohana-3/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Kohana 3">Kohana 3</a> не умеет использовать JOIN с операцией DELETE. Нужно ему помочь.<span id="more-805"></span></p>
          
<div class="codebox">
    <div class="the_code" style="" id="p80518">
        <div class="code php" id="p805code18">
<span class="kw2">&lt;?php</span><br />
<br />
&nbsp; &nbsp; <span class="kw2">class</span> Database_Query_Builder_Delete <span class="kw2">extends</span> Kohana_Database_Query_Builder_Delete<br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">protected</span> <span class="re0">$_to_delete</span> <span class="sy0">=</span> <span class="kw1">array</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">protected</span> <span class="re0">$_join</span> <span class="sy0">=</span> <span class="kw1">array</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">protected</span> <span class="re0">$_last_join</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co4">/**<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;* Adds addition tables to &quot;JOIN ...&quot;.<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;* @param mixed &nbsp; column name or array($column, $alias) or object<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;* @param string &nbsp;join type (LEFT, RIGHT, INNER, etc)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;* @return Database_Query_Builder_Delete<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> <span class="kw3">join</span><span class="br0">&#40;</span><span class="re0">$table</span><span class="sy0">,</span> <span class="re0">$type</span> <span class="sy0">=</span> <span class="kw4">NULL</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span>_join<span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span>_last_join <span class="sy0">=</span> <span class="kw2">new</span> Database_Query_Builder_Join<span class="br0">&#40;</span><span class="re0">$table</span><span class="sy0">,</span> <span class="re0">$type</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$this</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> delete_table<span class="br0">&#40;</span><span class="re0">$table</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span>_to_delete<span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="re0">$table</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co4">/**<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;* Adds &quot;ON ...&quot; conditions for the last created JOIN statement.<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;* @param &nbsp; mixed &nbsp; column name or array($column, $alias) or object<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;* @param &nbsp; string &nbsp;logic operator<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;* @param &nbsp; mixed &nbsp; column name or array($column, $alias) or object<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;* @return &nbsp;$this<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> on<span class="br0">&#40;</span><span class="re0">$c1</span><span class="sy0">,</span> <span class="re0">$op</span><span class="sy0">,</span> <span class="re0">$c2</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span>_last_join<span class="sy0">-&gt;</span><span class="me1">on</span><span class="br0">&#40;</span><span class="re0">$c1</span><span class="sy0">,</span> <span class="re0">$op</span><span class="sy0">,</span> <span class="re0">$c2</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$this</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co4">/**<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;* Compile the SQL query and return it.<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;*<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;* @param Database &nbsp;Database instance<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;* @return string<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;*/</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> compile<span class="br0">&#40;</span>Database <span class="re0">$db</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$query</span> <span class="sy0">=</span> <span class="st_h">'DELETE'</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span>_to_delete<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$query</span> <span class="sy0">.=</span> <span class="st_h">' '</span> <span class="sy0">.</span> <span class="kw3">join</span><span class="br0">&#40;</span><span class="st_h">', '</span><span class="sy0">,</span> <span class="kw3">array_map</span><span class="br0">&#40;</span><span class="kw1">array</span><span class="br0">&#40;</span><span class="re0">$db</span><span class="sy0">,</span> <span class="st_h">'quote_identifier'</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="re0">$this</span><span class="sy0">-&gt;</span>_to_delete<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$query</span> <span class="sy0">.=</span> <span class="st_h">' FROM '</span> <span class="sy0">.</span> <span class="re0">$db</span><span class="sy0">-&gt;</span><span class="me1">quote_table</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span>_table<span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span>_join<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$query</span> <span class="sy0">.=</span> <span class="st_h">' '</span> <span class="sy0">.</span> <span class="re0">$this</span><span class="sy0">-&gt;</span>_compile_join<span class="br0">&#40;</span><span class="re0">$db</span><span class="sy0">,</span> <span class="re0">$this</span><span class="sy0">-&gt;</span>_join<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span>_where<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$query</span> <span class="sy0">.=</span> <span class="st_h">' WHERE '</span> <span class="sy0">.</span> <span class="re0">$this</span><span class="sy0">-&gt;</span>_compile_conditions<span class="br0">&#40;</span><span class="re0">$db</span><span class="sy0">,</span> <span class="re0">$this</span><span class="sy0">-&gt;</span>_where<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span><span class="re0">$this</span><span class="sy0">-&gt;</span>_join<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span>_order_by<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$query</span> <span class="sy0">.=</span> <span class="st_h">' '</span> <span class="sy0">.</span> <span class="re0">$this</span><span class="sy0">-&gt;</span>_compile_order_by<span class="br0">&#40;</span><span class="re0">$db</span><span class="sy0">,</span> <span class="re0">$this</span><span class="sy0">-&gt;</span>_order_by<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span>_limit <span class="sy0">!==</span> <span class="kw4">null</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$query</span> <span class="sy0">.=</span> <span class="st_h">' LIMIT '</span> <span class="sy0">.</span> <span class="re0">$this</span><span class="sy0">-&gt;</span>_limit<span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw <span class="kw2">new</span> Kohana_Exception<span class="br0">&#40;</span><span class="st_h">'Cannot use ORDER BY or LIMIT in a multiple-table DELETE'</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$query</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> <span class="kw3">reset</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">parent</span><span class="sy0">::</span><span class="kw3">reset</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span>_to_delete <span class="sy0">=</span> <span class="kw1">array</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span>_join &nbsp; &nbsp; &nbsp;<span class="sy0">=</span> <span class="kw1">array</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span>_last_join <span class="sy0">=</span> <span class="kw4">null</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
<span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

<p>Данный класс добавляет функциональность, связанную с удалением данных из нескольких таблиц, в Query Builder. Использование покажу на примерах:</p>
<p>Запросу</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p80519">
        <div class="code mysql" id="p805code19">
<span class="kw1">DELETE</span> t1<span class="sy2">,</span> t2 <span class="kw1">FROM</span> t1 <span class="kw1">INNER</span> <span class="kw1">JOIN</span> t2 <span class="kw1">INNER</span> <span class="kw1">JOIN</span> t3<br />
<span class="kw1">WHERE</span> t1.id<span class="sy1">=</span>t2.id <span class="kw10">AND</span> t2.id<span class="sy1">=</span>t3.id<span class="sy2">;</span>
        </div>
    </div>
</div>

<p>соответствует код</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p80520">
        <div class="code php" id="p805code20">
DB<span class="sy0">::</span><span class="me2">delete</span><span class="br0">&#40;</span><span class="st_h">'t1'</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="sy0">-&gt;</span><span class="me1">join</span><span class="br0">&#40;</span><span class="st_h">'t2'</span><span class="sy0">,</span> <span class="st_h">'INNER'</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="sy0">-&gt;</span><span class="me1">on</span><span class="br0">&#40;</span><span class="st_h">'t1.id'</span><span class="sy0">,</span> <span class="st_h">'='</span><span class="sy0">,</span> <span class="st_h">'t2.id'</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="sy0">-&gt;</span><span class="me1">join</span><span class="br0">&#40;</span><span class="st_h">'t3'</span><span class="sy0">,</span> <span class="st_h">'INNER'</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="sy0">-&gt;</span><span class="me1">on</span><span class="br0">&#40;</span><span class="st_h">'t2.id'</span><span class="sy0">,</span> <span class="st_h">'='</span><span class="sy0">,</span> <span class="st_h">'t3.id'</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="sy0">-&gt;</span><span class="me1">delete_table</span><span class="br0">&#40;</span><span class="st_h">'t1'</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="sy0">-&gt;</span><span class="me1">delete_table</span><span class="br0">&#40;</span><span class="st_h">'t2'</span><span class="br0">&#41;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p>Запросу </p>
          
<div class="codebox">
    <div class="the_code" style="" id="p80521">
        <div class="code mysql" id="p805code21">
<span class="kw1">DELETE</span> <span class="kw1">FROM</span> t1 <span class="kw1">INNER</span> <span class="kw1">JOIN</span> t2 <span class="kw1">INNER</span> <span class="kw1">JOIN</span> t3<br />
<span class="kw1">WHERE</span> t1.id<span class="sy1">=</span>t2.id <span class="kw10">AND</span> t2.id<span class="sy1">=</span>t3.id<span class="sy2">;</span>
        </div>
    </div>
</div>

<p>соответствует код</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p80522">
        <div class="code php" id="p805code22">
DB<span class="sy0">::</span><span class="me2">delete</span><span class="br0">&#40;</span><span class="st_h">'t1'</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="sy0">-&gt;</span><span class="me1">join</span><span class="br0">&#40;</span><span class="st_h">'t2'</span><span class="sy0">,</span> <span class="st_h">'INNER'</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="sy0">-&gt;</span><span class="me1">on</span><span class="br0">&#40;</span><span class="st_h">'t1.id'</span><span class="sy0">,</span> <span class="st_h">'='</span><span class="sy0">,</span> <span class="st_h">'t2.id'</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="sy0">-&gt;</span><span class="me1">join</span><span class="br0">&#40;</span><span class="st_h">'t3'</span><span class="sy0">,</span> <span class="st_h">'INNER'</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="sy0">-&gt;</span><span class="me1">on</span><span class="br0">&#40;</span><span class="st_h">'t2.id'</span><span class="sy0">,</span> <span class="st_h">'='</span><span class="sy0">,</span> <span class="st_h">'t3.id'</span><span class="br0">&#41;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p>Как видим, метод <code>Database_Query_Builder_Delete::delete_table()</code> задаёт имена таблиц, которые нужно удалить; если данный метод не вызывать, будут удалены <strong>все</strong> таблицы, перечисленные в запросе.</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/kohana/805-join-support-for-delete-in-kohana-3/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/php/kohana/805-join-support-for-delete-in-kohana-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Патч для кэширования пустых результатов запросов в Kohana</title>
		<link>http://blog.sjinks.pro/php/kohana/804-patch-cache-empty-query-results-in-kohana/</link>
		<comments>http://blog.sjinks.pro/php/kohana/804-patch-cache-empty-query-results-in-kohana/#comments</comments>
		<pubDate>Wed, 11 Aug 2010 08:25:23 +0000</pubDate>
		<dc:creator>Wandering Soul</dc:creator>
				<category><![CDATA[Kohana]]></category>
		<category><![CDATA[Kohana 3]]></category>
		<category><![CDATA[база данных]]></category>
		<category><![CDATA[кэш]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=804</guid>
		<description><![CDATA[Простое исправление досадного недоразумения Проблема: Kohana 3 (3.0.7, возможно, ранние версии) не может брать результаты запросов из кэша, если запрос вернул пустой результат. Решение проблемы. Разгадка кроется в файле modules/database/classes/kohana/database/query.php. Дело в том, что в PHP проверки вида if ($condition) возвращают false, если вычисленное значение $condition — 0, null, false, &#34;&#34;, array(), …. Поэтому в такой проверке: if [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/kohana/804-patch-cache-empty-query-results-in-kohana/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Простое исправление досадного недоразумения</em></h2>
<p><strong>Проблема:</strong> <a href="http://blog.sjinks.pro/tag/kohana/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Kohana">Kohana</a> 3 (3.0.7, возможно, ранние версии) не может брать результаты запросов из кэша, если запрос вернул пустой результат.</p>
<p><strong>Решение проблемы.</strong><span id="more-804"></span></p>
<p>Разгадка кроется в файле <code>modules/database/classes/kohana/database/query.php</code>.  Дело в том, что в PHP проверки вида <span class="codebox"><code class="php"><span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$condition</span><span class="br0">&#41;</span></code></span> возвращают <code>false</code>, если вычисленное значение <code>$condition</code> — <a href="http://php.net/manual/en/language.types.boolean.php#language.types.boolean.casting">0, null, false, <span class="codebox"><code class="php"><span class="st0">&quot;&quot;</span></code></span>, array(), …</a>.</p>
<p>Поэтому в такой проверке:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p80425">
        <div class="code php" id="p804code25">
<span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$result</span> <span class="sy0">=</span> Kohana<span class="sy0">::</span><span class="me2">cache</span><span class="br0">&#40;</span><span class="re0">$cache_key</span><span class="sy0">,</span> <span class="kw4">NULL</span><span class="sy0">,</span> <span class="re0">$this</span><span class="sy0">-&gt;</span>_lifetime<span class="br0">&#41;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="co1">// Return a cached result</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">new</span> Database_Result_Cached<span class="br0">&#40;</span><span class="re0">$result</span><span class="sy0">,</span> <span class="re0">$sql</span><span class="sy0">,</span> <span class="re0">$this</span><span class="sy0">-&gt;</span>_as_object<span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>условие всегда будет ложно для пустых результатов.</p>
<p>Исправляется просто: из исходного кода <code>Kohana::cache()</code> видно, что <code>Kohana::cache()</code> возвращает <code>null</code>, если объект в кэше не найден либо произошла <a href="http://blog.sjinks.pro/tag/bug/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  ошибка">ошибка</a>. Следовательно,</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p80426">
        <div class="code php" id="p804code26">
<span class="kw1">if</span> <span class="br0">&#40;</span><span class="br0">&#40;</span><span class="re0">$result</span> <span class="sy0">=</span> Kohana<span class="sy0">::</span><span class="me2">cache</span><span class="br0">&#40;</span><span class="re0">$cache_key</span><span class="sy0">,</span> <span class="kw4">NULL</span><span class="sy0">,</span> <span class="re0">$this</span><span class="sy0">-&gt;</span>_lifetime<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy0">!==</span> <span class="kw4">null</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="co1">// Return a cached result</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">new</span> Database_Result_Cached<span class="br0">&#40;</span><span class="re0">$result</span><span class="sy0">,</span> <span class="re0">$sql</span><span class="sy0">,</span> <span class="re0">$this</span><span class="sy0">-&gt;</span>_as_object<span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>даст корректный результат.</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/kohana/804-patch-cache-empty-query-results-in-kohana/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/php/kohana/804-patch-cache-empty-query-results-in-kohana/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Ошибка в ORM Kohana 3 при использовании префиксов таблиц</title>
		<link>http://blog.sjinks.pro/php/kohana/772-bug-in-kohana-3-orm-when-using-table-prefixes/</link>
		<comments>http://blog.sjinks.pro/php/kohana/772-bug-in-kohana-3-orm-when-using-table-prefixes/#comments</comments>
		<pubDate>Fri, 19 Feb 2010 11:00:51 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[Kohana]]></category>
		<category><![CDATA[Kohana 3]]></category>
		<category><![CDATA[ORM]]></category>
		<category><![CDATA[ошибка]]></category>
		<category><![CDATA[патч]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=772</guid>
		<description><![CDATA[Патч для решения проблемы прилагается Ситуация: имеем две таблицы: пользователи и подписки: CREATE TABLE prefix_users ( id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(255) NOT NULL ); CREATE TABLE prefix_subscriptions ( id INTEGER NOT NULL PRIMARY KEY, user_id INTEGER UNSIGNED NOT NULL, some_data TEXT NOT NULL ); Один пользователь может иметь несколько подписок, одна подписка [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/kohana/772-bug-in-kohana-3-orm-when-using-table-prefixes/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em><a href="http://blog.sjinks.pro/tag/patch/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  патч">Патч</a> для решения проблемы прилагается</em></h2>
<p>Ситуация: имеем две таблицы: пользователи и подписки:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p77234">
        <div class="code mysql" id="p772code34">
<span class="kw1">CREATE</span> <span class="kw1">TABLE</span> prefix_users <span class="br0">&#40;</span><br />
&nbsp; &nbsp; id <span class="kw4">INTEGER</span> <span class="kw10">NOT</span> <span class="kw3">NULL</span> <span class="kw1">PRIMARY KEY</span><span class="sy2">,</span><br />
&nbsp; &nbsp; name <span class="kw4">VARCHAR</span><span class="br0">&#40;</span>255<span class="br0">&#41;</span> <span class="kw10">NOT</span> <span class="kw3">NULL</span><br />
<span class="br0">&#41;</span><span class="sy2">;</span><br />
<br />
<span class="kw1">CREATE</span> <span class="kw1">TABLE</span> prefix_subscriptions <span class="br0">&#40;</span><br />
&nbsp; &nbsp; id <span class="kw4">INTEGER</span> <span class="kw10">NOT</span> <span class="kw3">NULL</span> <span class="kw1">PRIMARY KEY</span><span class="sy2">,</span><br />
&nbsp; &nbsp; user_id <span class="kw4">INTEGER</span> <span class="kw6">UNSIGNED</span> <span class="kw10">NOT</span> <span class="kw3">NULL</span><span class="sy2">,</span><br />
&nbsp; &nbsp; some_data <span class="kw4">TEXT</span> <span class="kw10">NOT</span> <span class="kw3">NULL</span><br />
<span class="br0">&#41;</span><span class="sy2">;</span>
        </div>
    </div>
</div>

<p>Один пользователь может иметь несколько подписок, одна подписка может принадлежать только одному пользователю.<span id="more-772"></span></p>
<p>Настройки соединения с базой данных (<code>application/config/database.php</code>) имеют следующий вид:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p77235">
        <div class="code php" id="p772code35">
<span class="kw1">return</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st_h">'default'</span> <span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'type'</span> &nbsp; &nbsp; &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'mysql'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'connection'</span> <span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'hostname'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'localhost'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'username'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'user'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'password'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'pass'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'persistent'</span> <span class="sy0">=&gt;</span> <span class="kw4">FALSE</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'database'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'database'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'table_prefix'</span> <span class="sy0">=&gt;</span> <span class="st_h">'prefix_'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'charset'</span> &nbsp; &nbsp; &nbsp;<span class="sy0">=&gt;</span> <span class="st_h">'utf8'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'caching'</span> &nbsp; &nbsp; &nbsp;<span class="sy0">=&gt;</span> <span class="kw4">FALSE</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'profiling'</span> &nbsp; &nbsp;<span class="sy0">=&gt;</span> <span class="kw4">TRUE</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
<span class="br0">&#41;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p>Модели в <a href="http://blog.sjinks.pro/tag/kohana/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Kohana">Kohana</a> 3 будут иметь следующий вид:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p77236">
        <div class="code php" id="p772code36">
<span class="co1">// application/classes/model/user.php</span><br />
&nbsp; &nbsp; <span class="kw2">class</span> Model_User <span class="kw2">extends</span> ORM<br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">protected</span> <span class="re0">$_has_many</span> <span class="sy0">=</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'subscriptions'</span> <span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'foreign_key'</span> <span class="sy0">=&gt;</span> <span class="st_h">'user_id'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'model'</span> &nbsp; &nbsp; &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'Subscription'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
<span class="co1">// application/classes/model/subscription.php</span><br />
&nbsp; &nbsp; <span class="kw2">class</span> Model_Subscription <span class="kw2">extends</span> ORM<br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">protected</span> <span class="re0">$_belongs_to</span> <span class="sy0">=</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'user'</span> <span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'foreign_key'</span> <span class="sy0">=&gt;</span> <span class="st_h">'user_id'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'model'</span> &nbsp; &nbsp; &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'User'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>Допустим, что в контроллере у нас есть вызов наподобие</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p77237">
        <div class="code php" id="p772code37">
ORM<span class="sy0">::</span><span class="me2">factory</span><span class="br0">&#40;</span><span class="st_h">'Subscription'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">with</span><span class="br0">&#40;</span><span class="st_h">'user'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">find_all</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p>Что произойдёт? А ничего хорошего:</p>
<pre>
Database_Exception [ 1054 ]: Unknown column 'prefix_user.id' in 'field list' [ SELECT `prefix_user`.`id` AS `user:id`, `prefix_user`.`name` AS `user:name`, `prefix_subscriptions`.* FROM `prefix_subscriptions` LEFT JOIN `prefix_users` AS `user` ON (`prefix_user`.`id` = `prefix_subscriptions`.`user_id`) ORDER BY `prefix_subscriptions`.`id` ASC ] ~ MODPATH/database/classes/kohana/database/<a href="http://blog.sjinks.pro/tag/mysql/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  MySQL">mysql</a>.php [ 183 ]
</pre>
<p>Почему? Модуль <a href="http://blog.sjinks.pro/tag/orm/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  ORM">ORM</a> предполагал, что запрос будет выглядеть так:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p77238">
        <div class="code mysql" id="p772code38">
<span class="kw1">SELECT</span> <span class="st0">`user`</span>.<span class="st0">`id`</span> <span class="kw1">AS</span> <span class="st0">`user:id`</span><span class="sy2">,</span> <span class="st0">`user`</span>.<span class="st0">`name`</span> <span class="kw1">AS</span> <span class="st0">`user:name`</span><span class="sy2">,</span> <span class="st0">`subscriptions`</span>.<span class="sy1">*</span><br />
<span class="kw1">FROM</span> <span class="st0">`subscriptions`</span><br />
<span class="kw13">LEFT</span> <span class="kw1">JOIN</span> <span class="st0">`users`</span> <span class="kw1">AS</span> <span class="st0">`user`</span> <span class="kw1">ON</span> <span class="br0">&#40;</span><span class="st0">`user`</span>.<span class="st0">`id`</span> <span class="sy1">=</span> <span class="st0">`subscriptions`</span>.<span class="st0">`user<span class="es1">_</span>id`</span><span class="br0">&#41;</span><br />
<span class="kw1">ORDER BY</span> <span class="st0">`subscriptions`</span>.<span class="st0">`id`</span> <span class="kw1">ASC</span>
        </div>
    </div>
</div>

<p>Так бы и было, если бы таблицы не имели префикса. <code>ORM</code> передаёт <code>Database</code> поля в виде <code>user.id</code>, <code>Database</code> их экранирует в <code>`user`.`id`</code>. Проблема в том, что <code>Database</code> ничего не знает о псевдонимах таблиц (<code>users AS user</code> в <span class="codebox"><code class="mysql"><span class="kw1">JOIN</span></code></span>), а ORM ничего не знает о префиксах таблиц. Поэтому Database с чистой совестью добавляет префикс ко всему, что находится в именах слева от точки. В результате вместо <code>SELECT `user`.`id` AS `user:id`</code> получаем <code>SELECT `prefix_user`.`id` AS `user:id`</code>.</p>
<p>Есть два решения:</p>
<ol>
<li>Унаследовать свой класс ORM от Kohana_ORM и исправить в нём метод <code>with()</code>;</li>
<li>Исправить метод <span class="codebox"><code class="php">Kohana_ORM<span class="sy0">::</span><span class="me2">with</span><span class="br0">&#40;</span><span class="br0">&#41;</span></code></span>.</li>
</ol>
<p>Результат получится примерно одинаковым — код будет выглядеть так:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p77239">
        <div class="code php" id="p772code39">
&nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> with<span class="br0">&#40;</span><span class="re0">$target_path</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">isset</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span>_with_applied<span class="br0">&#91;</span><span class="re0">$target_path</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// Don't join anything already joined</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$this</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// Split object parts</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$aliases</span> <span class="sy0">=</span> <span class="kw3">explode</span><span class="br0">&#40;</span><span class="st_h">':'</span><span class="sy0">,</span> <span class="re0">$target_path</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$target</span> &nbsp;<span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">foreach</span> <span class="br0">&#40;</span><span class="re0">$aliases</span> <span class="kw1">as</span> <span class="re0">$alias</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// Go down the line of objects to find the given target</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$parent</span> <span class="sy0">=</span> <span class="re0">$target</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$target</span> <span class="sy0">=</span> <span class="re0">$parent</span><span class="sy0">-&gt;</span>_related<span class="br0">&#40;</span><span class="re0">$alias</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="sy0">!</span> <span class="re0">$target</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// Can't find related object</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$this</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// Target alias is at the end</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$target_alias</span> <span class="sy0">=</span> <span class="re0">$alias</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// Pop-off top alias to get the parent path (user:photo:tag becomes user:photo - the parent table prefix)</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">array_pop</span><span class="br0">&#40;</span><span class="re0">$aliases</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$parent_path</span> <span class="sy0">=</span> <span class="kw3">implode</span><span class="br0">&#40;</span><span class="st_h">':'</span><span class="sy0">,</span> <span class="re0">$aliases</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">empty</span><span class="br0">&#40;</span><span class="re0">$parent_path</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// Use this table name itself for the parent path</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$parent_path</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span>_table_name<span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span> <span class="sy0">!</span> <span class="kw1">isset</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span>_with_applied<span class="br0">&#91;</span><span class="re0">$parent_path</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// If the parent path hasn't been joined yet, do it first (otherwise LEFT JOINs fail)</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">with</span><span class="br0">&#40;</span><span class="re0">$parent_path</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// Add to with_applied to prevent duplicate joins</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span>_with_applied<span class="br0">&#91;</span><span class="re0">$target_path</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="kw4">TRUE</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// Use the keys of the empty object to determine the columns</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">foreach</span> <span class="br0">&#40;</span><span class="kw3">array_keys</span><span class="br0">&#40;</span><span class="re0">$target</span><span class="sy0">-&gt;</span>_object<span class="br0">&#41;</span> <span class="kw1">as</span> <span class="re0">$column</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$name</span> &nbsp; <span class="sy0">=</span> <span class="st_h">'&quot;'</span><span class="sy0">.</span><span class="re0">$target_path</span><span class="sy0">.</span><span class="st_h">'&quot;.&quot;'</span><span class="sy0">.</span><span class="re0">$column</span> <span class="sy0">.</span> <span class="st_h">'&quot;'</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$alias</span> &nbsp;<span class="sy0">=</span> <span class="re0">$target_path</span><span class="sy0">.</span><span class="st_h">':'</span><span class="sy0">.</span><span class="re0">$column</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// Add the prefix so that load_result can determine the relationship</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">select</span><span class="br0">&#40;</span><span class="kw1">array</span><span class="br0">&#40;</span><span class="re0">$name</span><span class="sy0">,</span> <span class="re0">$alias</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">isset</span><span class="br0">&#40;</span><span class="re0">$parent</span><span class="sy0">-&gt;</span>_belongs_to<span class="br0">&#91;</span><span class="re0">$target_alias</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// Parent belongs_to target, use target's primary key and parent's foreign key</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$join_col1</span> <span class="sy0">=</span> <span class="st_h">'&quot;'</span><span class="sy0">.</span><span class="re0">$target_path</span><span class="sy0">.</span><span class="st_h">'&quot;.&quot;'</span><span class="sy0">.</span><span class="re0">$target</span><span class="sy0">-&gt;</span>_primary_key<span class="sy0">.</span><span class="st_h">'&quot;'</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$join_col2</span> <span class="sy0">=</span> <span class="re0">$parent_path</span><span class="sy0">.</span><span class="st_h">'.'</span><span class="sy0">.</span><span class="re0">$parent</span><span class="sy0">-&gt;</span>_belongs_to<span class="br0">&#91;</span><span class="re0">$target_alias</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st_h">'foreign_key'</span><span class="br0">&#93;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// Parent has_one target, use parent's primary key as target's foreign key</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$join_col1</span> <span class="sy0">=</span> <span class="re0">$parent_path</span><span class="sy0">.</span><span class="st_h">'.'</span><span class="sy0">.</span><span class="re0">$parent</span><span class="sy0">-&gt;</span>_primary_key<span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$join_col2</span> <span class="sy0">=</span> <span class="st_h">'&quot;'</span><span class="sy0">.</span><span class="re0">$target_path</span><span class="sy0">.</span><span class="st_h">'&quot;.&quot;'</span><span class="sy0">.</span><span class="re0">$parent</span><span class="sy0">-&gt;</span>_has_one<span class="br0">&#91;</span><span class="re0">$target_alias</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st_h">'foreign_key'</span><span class="br0">&#93;</span> <span class="sy0">.</span><span class="st_h">'&quot;'</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// Join the related object into the result</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">join</span><span class="br0">&#40;</span><span class="kw1">array</span><span class="br0">&#40;</span><span class="re0">$target</span><span class="sy0">-&gt;</span>_table_name<span class="sy0">,</span> <span class="re0">$target_path</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="st_h">'LEFT'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">on</span><span class="br0">&#40;</span><span class="re0">$join_col1</span><span class="sy0">,</span> <span class="st_h">'='</span><span class="sy0">,</span> <span class="re0">$join_col2</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$this</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>Патч по объёму гораздо меньше:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p77240">
        <div class="code diff" id="p772code40">
--- kohana/modules/orm/classes/kohana/orm.php<br />
<span class="re4">+++ kohana/modules/orm/classes/kohana/orm.php</span><br />
<span class="re6">@@ -<span class="nu0">637</span>,<span class="nu0">7</span> +<span class="nu0">637</span>,<span class="nu0">7</span> @@</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; // Use the keys of the empty object to determine the columns<br />
&nbsp; &nbsp; &nbsp; &nbsp; foreach <span class="br0">&#40;</span>array_keys<span class="br0">&#40;</span>$target-&gt;_object<span class="br0">&#41;</span> as $column<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
<span class="re7">- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $name &nbsp; = $target_path.'.'.$column;</span><br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $name &nbsp; = '&quot;'.$target_path.'&quot;.&quot;'.$column . '&quot;';</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $alias &nbsp;= $target_path.':'.$column;<br />
&nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Add the prefix so that load_result can determine the relationship<br />
<span class="re6">@@ -<span class="nu0">647</span>,<span class="nu0">14</span> +<span class="nu0">647</span>,<span class="nu0">14</span> @@</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; if <span class="br0">&#40;</span>isset<span class="br0">&#40;</span>$parent-&gt;_belongs_to<span class="br0">&#91;</span>$target_alias<span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Parent belongs_to target, use target's primary key and parent's foreign key<br />
<span class="re7">- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $join_col1 = $target_path.'.'.$target-&gt;_primary_key;</span><br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $join_col1 = '&quot;'.$target_path.'&quot;.&quot;'.$target-&gt;_primary_key.'&quot;';</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $join_col2 = $parent_path.'.'.$parent-&gt;_belongs_to<span class="br0">&#91;</span>$target_alias<span class="br0">&#93;</span><span class="br0">&#91;</span>'foreign_key'<span class="br0">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; else<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Parent has_one target, use parent's primary key as target's foreign key<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $join_col1 = $parent_path.'.'.$parent-&gt;_primary_key;<br />
<span class="re7">- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $join_col2 = $target_path.'.'.$parent-&gt;_has_one<span class="br0">&#91;</span>$target_alias<span class="br0">&#93;</span><span class="br0">&#91;</span>'foreign_key'<span class="br0">&#93;</span>;</span><br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $join_col2 = '&quot;'.$target_path.'&quot;.&quot;'.$parent-&gt;_has_one<span class="br0">&#91;</span>$target_alias<span class="br0">&#93;</span><span class="br0">&#91;</span>'foreign_key'<span class="br0">&#93;</span> .'&quot;';</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; // Join the related object into the result
        </div>
    </div>
</div>

<p><strong><a href='http://static.sjinks.info/wp-content/uploads/2010/02/orm.php.diff'>Скачать патч (unified diff)</a>.</strong></p>
<p>Идея в том, что имена псевдонимов заключаются в двойные кавычки — в этом случае <code>Database</code> не занимается «самодеятельностью» в виде добавления префиксов куда надо и не надо.</p>
<p><strong>Проверялось на Kohana 3.0.3</strong></p>
<p><strong><a href="http://dev.kohanaframework.org/issues/2634">Отчёт об ошибке в трекере Kohana</a></strong></p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/kohana/772-bug-in-kohana-3-orm-when-using-table-prefixes/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/php/kohana/772-bug-in-kohana-3-orm-when-using-table-prefixes/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>SQLMon для Kohana 3</title>
		<link>http://blog.sjinks.pro/php/kohana/762-sqlmon-for-kohana-3/</link>
		<comments>http://blog.sjinks.pro/php/kohana/762-sqlmon-for-kohana-3/#comments</comments>
		<pubDate>Tue, 09 Feb 2010 19:16:01 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[Kohana]]></category>
		<category><![CDATA[Kohana 3]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[SQLMon]]></category>
		<category><![CDATA[оптимизация]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=762</guid>
		<description><![CDATA[Мониторинг SQL-запросов в Kohana 3 Продолжая славную традицию реализации SQLMon под различные CMS/фреймворки, написал одному заказчику модуль для Kohana 3. SQLMon для Kohana 3 интегрируется в иерархию классов Database (встраивается между классами Database_MySQL и Kohana_Database_MySQL) и реализует обёртку над методом Kohana_Database_MySQL::query(), измеряя время выполнения запроса, объём потребляемой памяти, записывая код ошибки запроса, трассу вызовов и [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/kohana/762-sqlmon-for-kohana-3/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Мониторинг SQL-запросов в <a href="http://blog.sjinks.pro/tag/kohana/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Kohana">Kohana</a> 3</em></h2>
<p>Продолжая славную традицию реализации <a href="http://blog.sjinks.pro/tag/sqlmon/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  SQLMon">SQLMon</a> под различные CMS/фреймворки, написал одному заказчику модуль для <a href="http://blog.sjinks.pro/tag/kohana-3/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Kohana 3">Kohana 3</a>.</p>
<p>SQLMon для Kohana 3 интегрируется в иерархию классов Database (встраивается между классами <code>Database_<a href="http://blog.sjinks.pro/tag/mysql/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  MySQL">MySQL</a></code> и <code>Kohana_Database_MySQL</code>) и реализует обёртку над методом <span class="codebox"><code class="php">Kohana_Database_MySQL<span class="sy0">::</span><span class="me2">query</span><span class="br0">&#40;</span><span class="br0">&#41;</span></code></span>, измеряя время выполнения запроса, объём потребляемой памяти, записывая код ошибки запроса, трассу вызовов и <span class="codebox"><code class="mysql"><span class="kw1">EXPLAIN</span></code></span> запроса (причём не только для <span class="codebox"><code class="mysql"><span class="kw1">SELECT</span></code></span>, но и <span class="codebox"><code class="mysql"><span class="kw1">UPDATE</span></code></span>/<span class="codebox"><code class="mysql"><span class="kw1">DELETE</span></code></span> и <span class="codebox"><code class="mysql"><span class="kw2">INSERT</span></code></span>/<span class="codebox"><code class="mysql"><span class="kw2">REPLACE</span> <span class="kw1">INTO</span> … <span class="kw1">AS</span></code></span> или <span class="codebox"><code class="mysql"><span class="kw1">CREATE</span> &nbsp;<span class="kw1">TABLE</span> … <span class="kw1">AS</span></code></span>) — всё то же самое, что и <a href="http://blog.sjinks.pro/wordpress-plugins/sqlmon/">SQLMon для WordPress</a>.<span id="more-762"></span></p>
<p>Данный модуль будет полезен разработчикам для анализа производительности запросов MySQL и поиска решений для их оптимизации. Перед использованием модуля рекомендуется прочитать статью «<a href="http://dev.mysql.com/doc/refman/5.0/en/using-explain.html">Optimizing Queries with EXPLAIN</a>».</p>
<p><strong>Использование модуля.</strong> Модуль должен быть распакован в каталог <code>modules</code> проекта (после распаковки появится каталог <code>sqlmon</code>). Затем модуль должен быть активирован в файле <code>application/bootstrap.php</code>. Очень важно, чтобы модуль подключался <strong>перед модулем <code>database</code></strong> — это связано с <a href="http://v3.kohanaphp.com/guide/about.filesystem">особенностями поиска классов в Kohana 3</a>.</p>
<p>Например:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p76244">
        <div class="code php" id="p762code44">
Kohana<span class="sy0">::</span><span class="me2">modules</span><span class="br0">&#40;</span><span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st_h">'sqlmon'</span> &nbsp; &nbsp; <span class="sy0">=&gt;</span> MODPATH<span class="sy0">.</span><span class="st_h">'sqlmon'</span><span class="sy0">,</span> &nbsp; &nbsp; <span class="co1">// SQL Monitor — обязательно перед Database</span><br />
&nbsp; &nbsp; <span class="st_h">'database'</span> &nbsp; <span class="sy0">=&gt;</span> MODPATH<span class="sy0">.</span><span class="st_h">'database'</span><span class="sy0">,</span> &nbsp; <span class="co1">// Database access</span><br />
&nbsp; &nbsp; <span class="st_h">'orm'</span> &nbsp; &nbsp; &nbsp; &nbsp;<span class="sy0">=&gt;</span> MODPATH<span class="sy0">.</span><span class="st_h">'orm'</span><span class="sy0">,</span> &nbsp; &nbsp; &nbsp; &nbsp;<span class="co1">// Object Relationship Mapping</span><br />
&nbsp; &nbsp; <span class="st_h">'pagination'</span> <span class="sy0">=&gt;</span> MODPATH<span class="sy0">.</span><span class="st_h">'pagination'</span><span class="sy0">,</span> <span class="co1">// Paging of results</span><br />
<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p>Для отображения статистики нужно выполнить</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p76245">
        <div class="code php" id="p762code45">
<span class="kw2">&lt;?php</span> <span class="kw1">echo</span> View<span class="sy0">::</span><span class="me2">factory</span><span class="br0">&#40;</span><span class="st_h">'sqlmon/sqlmon'</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

<p>Результатом будет нечто вида (скриншот можно кликнуть):</p>
<p><a href="http://static.sjinks.info/wp-content/uploads/2010/02/kohana-sqlmon.png" rel="lightbox" title="SQLMon для Kohana — пример работы"><img src="http://static.sjinks.info/wp-content/uploads/2010/02/kohana-sqlmon-300x136.png" alt="SQLMon для Kohana — пример работы" title="SQLMon для Kohana — пример работы" width="300" height="136" class="size-medium wp-image-763" /></a></p>
<p><strong>Настройка.</strong> SQLMon использует файлы конфигурации модуля Database — <code>config/database.php</code>. Для контроля поведения SQLMon нужно использовать параметры:</p>
<ul>
<li><code>backtrace</code> — <code>boolean</code> (по умолчанию true) — должен ли SQLMon отображать трассу вызовов (то, что отображается синим цветом на скриншоте выше);</li>
<li><code>explain</code> — <code>boolean</code> (по умолчанию true) — должен ли SQLMon отображать план выполнения запросов (<span class="codebox"><code class="mysql"><span class="kw1">EXPLAIN</span></code></span>).</li>
</ul>
<p>Пример файла конфигурации:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p76246">
        <div class="code php" id="p762code46">
<span class="kw2">&lt;?php</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'default'</span> <span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'type'</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="sy0">=&gt;</span> <span class="st_h">'mysql'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'profiling'</span> &nbsp; &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'charset'</span> &nbsp; &nbsp; &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'utf8'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'table_prefix'</span> &nbsp;<span class="sy0">=&gt;</span> <span class="st_h">''</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// Настройки SQLMon</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'backtrace'</span> &nbsp; &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'explain'</span> &nbsp; &nbsp; &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// ---</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'connection'</span> &nbsp; &nbsp;<span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'username'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'root'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'password'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'M1dn19ht'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'hostname'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'localhost'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'persistent'</span> <span class="sy0">=&gt;</span> <span class="kw4">false</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'database'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'feedfetcher'</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

<p><strong><a href="http://d.sjinks.pro/kohana/sqlmon.zip">Скачать SQLMon для Kohana 3</a>.</strong></p>
<p></p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/kohana/762-sqlmon-for-kohana-3/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/php/kohana/762-sqlmon-for-kohana-3/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

