<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2russianfull.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" version="2.0">

<channel>
	<title>WEB рукоделие</title>
	
	<link>http://www.handmadesite.net</link>
	<description>Какой механизм?! Все вручную!</description>
	<lastBuildDate>Thu, 03 Dec 2009 23:29:31 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/handmadesite" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="handmadesite" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><geo:lat>55.778552</geo:lat><geo:long>37.548244</geo:long><creativeCommons:license>http://creativecommons.org/licenses/by/3.0/</creativeCommons:license><image><link>http://creativecommons.org/licenses/by/3.0/</link><url>http://creativecommons.org/images/public/somerights20.gif</url><title>Some Rights Reserved</title></image><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Ffeeds.feedburner.com%2Fhandmadesite" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fhandmadesite" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Fhandmadesite" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2Fhandmadesite" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fhandmadesite" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://www.live.com/?add=http%3A%2F%2Ffeeds.feedburner.com%2Fhandmadesite" src="http://tkfiles.storage.msn.com/x1piYkpqHC_35nIp1gLE68-wvzLZO8iXl_JMledmJQXP-XTBOLfmQv4zhj4MhcWEJh_GtoBIiAl1Mjh-ndp9k47If7hTaFno0mxW9_i3p_5qQw">Subscribe with Live.com</feedburner:feedFlare><feedburner:feedFlare xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" href="http://lenta.yandex.ru/settings.xml?name=feed&amp;url=http%3A%2F%2Ffeeds.feedburner.com%2Fhandmadesite" src="http://lenta.yandex.ru/i/addfeed.gif">?????? ? ??????.?????</feedburner:feedFlare><item>
		<title>Список всех-всех контроллеров</title>
		<link>http://www.handmadesite.net/2009/11/all-controllers-of-app/</link>
		<comments>http://www.handmadesite.net/2009/11/all-controllers-of-app/#comments</comments>
		<pubDate>Mon, 30 Nov 2009 10:58:38 +0000</pubDate>
		<dc:creator>Сергей</dc:creator>
				<category><![CDATA[CakePHP]]></category>

		<guid isPermaLink="false">http://www.handmadesite.net/?p=344</guid>
		<description><![CDATA[Понадобилось мне получить список всех контроллеров приложения, включая контроллеры плагинов. Configure::listObjects, увы, такого не умеет. Этот метод выдает только все контроллеры приложения, но без контроллеров плагинов. Пришлось немного адаптировать метод, предложенный Rob Weaver в гуглогруппе CakePHP. На выходе у моего метода получается объединенный список контроллеров. Основные &#8212; как отдает метод listObjects, а принадлежащие плагинам в [...]]]></description>
			<content:encoded><![CDATA[<p>Понадобилось мне получить список всех контроллеров приложения, включая контроллеры плагинов. Configure::listObjects, увы, такого не умеет. Этот метод выдает только все контроллеры приложения, но без контроллеров плагинов. Пришлось немного адаптировать метод, <a href="http://groups.google.com/group/cake-php/browse_thread/thread/ba66cb8ff0d60957/0f7a7d48ac988c32?lnk=gst&amp;q=listobjects+plugin+controller#0f7a7d48ac988c32" target="_blank">предложенный</a> <a href="http://groups.google.com/groups/profile?enc_user=aYwLfxIAAAAlIZ7IWf4E4HkoLpEPQXFa8rhlH0Pnl47z4AZhN98BFg" target="_blank">Rob Weaver</a> в <a href="http://groups.google.com/group/cake-php" target="_blank">гуглогруппе CakePHP</a>. На выходе у моего метода получается объединенный список контроллеров. Основные &#8212; как отдает метод listObjects, а принадлежащие плагинам в виде &laquo;Plugin.Controller&raquo;. Можно их поочередно скармливать сразу в App::import. Разве что выбрость те, названия которых на &laquo;App&raquo; заканчивается, если они не нужны. Будете загружать, помните, что <a href="http://www.handmadesite.net/2009/11/loding-controllers/">класс &laquo;Controller&raquo; уже должен быть загружен</a>.</p>
<p><span id="more-344"></span>
<p><strong>Update.</strong> Метод Folder::findRecursive возвращал слишком много файлов, в том числе и ненужных. Переписал немного, теперь опрашиваем только директорию с плагином и его контроллерами.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #009933; font-style: italic;">/**
 * Lists the names of controllers including plugin controllers
 * 
 * @return array
 */</span>
static <span style="color: #000000; font-weight: bold;">function</span> listControllers<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    App<span style="color: #339933;">::</span><span style="color: #004000;">import</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Core'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'File'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'Folder'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$controllers</span> <span style="color: #339933;">=</span> Configure<span style="color: #339933;">::</span><span style="color: #004000;">listObjects</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'controller'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$config</span> <span style="color: #339933;">=</span> Configure<span style="color: #339933;">::</span><span style="color: #004000;">getInstance</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$config</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">pluginPaths</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$pluginPath</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$folder</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Folder<span style="color: #009900;">&#40;</span><span style="color: #000088;">$pluginPath</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #990000;">list</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$plugin_dirs</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$folder</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">read</span><span style="color: #009900;">&#40;</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;">$plugin_dirs</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$plugin_dir</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #000088;">$pluginName</span> <span style="color: #339933;">=</span> Inflector<span style="color: #339933;">::</span><span style="color: #004000;">camelize</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$plugin_dir</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$folder</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">cd</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$pluginPath</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$plugin_dir</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$controllerFiles</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$folder</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">find</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'.*_controller\.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$folder</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">cd</span><span style="color: #009900;">&#40;</span>Folder<span style="color: #339933;">::</span><span style="color: #004000;">addPathElement</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$folder</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">path</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'controllers'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$controllerFiles</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array_merge</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$controllerFiles</span><span style="color: #339933;">,</span><span style="color: #000088;">$folder</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">find</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'.*_controller\.php'</span><span style="color: #009900;">&#41;</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;">$controllerFiles</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$file</span><span style="color: #009900;">&#41;</span>
            <span style="color: #009900;">&#123;</span>
                <span style="color: #000088;">$file</span> <span style="color: #339933;">=</span> <span style="color: #990000;">basename</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$file</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #000088;">$controllers</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$pluginName</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'.'</span> <span style="color: #339933;">.</span>
                    Inflector<span style="color: #339933;">::</span><span style="color: #004000;">camelize</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">substr</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$file</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #990000;">strlen</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$file</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-</span>
                    <span style="color: #990000;">strlen</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'_controller.php'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$controllers</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>


<p><a href="http://feedads.g.doubleclick.net/~a/m99QDOWN9nXf_ESSaYjMj7RHMiA/0/da"><img src="http://feedads.g.doubleclick.net/~a/m99QDOWN9nXf_ESSaYjMj7RHMiA/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/m99QDOWN9nXf_ESSaYjMj7RHMiA/1/da"><img src="http://feedads.g.doubleclick.net/~a/m99QDOWN9nXf_ESSaYjMj7RHMiA/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/handmadesite?a=hS65vaP9ZLU:YfavyuIKskU:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/handmadesite?i=hS65vaP9ZLU:YfavyuIKskU:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=hS65vaP9ZLU:YfavyuIKskU:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/handmadesite?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=hS65vaP9ZLU:YfavyuIKskU:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/handmadesite?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=hS65vaP9ZLU:YfavyuIKskU:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/handmadesite?i=hS65vaP9ZLU:YfavyuIKskU:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/handmadesite/~4/hS65vaP9ZLU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.handmadesite.net/2009/11/all-controllers-of-app/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Попробуем почитать между строк</title>
		<link>http://www.handmadesite.net/2009/11/lets-try-to-read-between-lines/</link>
		<comments>http://www.handmadesite.net/2009/11/lets-try-to-read-between-lines/#comments</comments>
		<pubDate>Wed, 25 Nov 2009 17:22:03 +0000</pubDate>
		<dc:creator>Сергей</dc:creator>
				<category><![CDATA[Поисковики]]></category>
		<category><![CDATA[yandex]]></category>

		<guid isPermaLink="false">http://www.handmadesite.net/?p=337</guid>
		<description><![CDATA[Очередное интервью с представителями Яндекса, на этот раз на Roem.Ru. Никаких особенных откровений, конечно, нет. Что же вы хотели, чтоб яндексоиды всем бесплатно раздали рекомендации, как выбраться на первое место в выдаче по любому запросу? Но все-таки что-то надо говорить и из обтекаемых формулировок можно выстраивать разные забавные предположения. Лично я не завсегдатай SEO-форумов, возможно, [...]]]></description>
			<content:encoded><![CDATA[<p>Очередное <a href="http://roem.ru/2009/11/23/shestnadtsat_voprosov_yandexu/" target="_blank">интервью с представителями Яндекса</a>, на этот раз на Roem.Ru. Никаких особенных откровений, конечно, нет. Что же вы хотели, чтоб яндексоиды всем бесплатно раздали рекомендации, как выбраться на первое место в выдаче по любому запросу? Но все-таки что-то надо говорить и из обтекаемых формулировок можно выстраивать разные забавные предположения. Лично я не завсегдатай SEO-форумов, возможно, все это уже где-то обсуждалось &#8212; если баян, извините.<span id="more-337"></span></p>
<p><strong>Сегалович</strong>:</p>
<blockquote><p>Ровно в этих рамках (борьба с «глупостью») мы относительно недавно реализовали алгоритм определения запросов и ответов, которые можно трактовать двояко: и как поиск эротического и порнографического содержания, и как невинный информационный запрос. Например, запрос [девочки] может быть поиском повести Людмилы Улицкой, а вовсе не «девочек по вызову». Для человека, ищущего Улицкую, ответ с порнографией не просто нерелевантен, он «явная глупость».</p>
<p>Опираясь на классификаторы запросов и сайтов по порнографическому и непорнографическому содержанию, и построив соответствующие метрики, отражающие долю резко нерелевантного поведения нашей системы по «двояким» запросам, мы смогли реализовать механизм понижения в выдаче сайтов порнографического содержания.</p></blockquote>
<p>Было бы логично, если бы Яндекс подсовывал разным посетителям разные варианты выдачи, основываясь на данных предыдущих запросов, статистики из Метрики и т.д. Не специально для каждого пользователя, а для каких-то условных групп, типа &laquo;любитель клубнички&raquo;, &laquo;книжный червь&raquo; или каких-то таких. А что? Статистика по запросам есть, статистика посещенных сайтов и проведенного на них времени &#8212; то же (Метрика, различные кнопки ТИЦ, блогов и т.д.) &#8212; нарисовать схему интересов пользователя можно. И потом соотнести с какой-то своей внутренней классификацией. А вот слова о том, что ответ не подвергается модификации &#8212; это, возможно, и временно. На паре &laquo;порно/непорно&raquo; алгоритм просто обкатывается.</p>
<p>Если Яндекс все-таки реализует модификацию выдачи в зависимости от вычесленных предпочтений пользователя &#8212; вот будет головная боль оптимизаторам! Почистил куки, походил по сайтам с пластиковыми окнами &#8211; получи выдачи про строительство и остекление балконов, почистил куки, походил по сайтам с программным обеспечением &#8212; получи выдачу про Windows. И все в ответ на один и тот же запрос &laquo;окошки&raquo;.</p>
<p><strong>Сегалович</strong>:</p>
<blockquote><p>по ряду запросов мы мониторим выдачу других поисковых машин, всех, кто хоть как-то ищет по-русски, включая все версии самого Яндекса &#8211; рабочую версию и внутренние, экспериментальные (у Яндекса много версий). И складываем все результаты в один котел. Если какой-то сайт присутствует в этом «котле», если он там имеет достаточно хорошие оценки, и при этом отсутствует в Яндексе, мы начинаем разбираться – почему</p></blockquote>
<p><strong>Садовский</strong>:</p>
<blockquote><p>Чтобы было понятно, «котел» какого объема оценивается, подчеркну, что это речь идет о десятках тысяч запросов, которые мы проверяем таким образом. Мы проверяем первые 30 позиций по каждому запросу. Считайте: десятки тысяч запросов, умножить на 30 первых позиций, умножить на количество версий, &#8211; это десятки миллионов URL.</p></blockquote>
<p>Мониторят конкурентов. Очевидно, Google, Bing и Рамблер. Наверное и Yahoo. Об остальных можно только догадываться. Составляют множество сайтов, попадающих в выдачу всех или бОльшей части конкурентов. Потом сравнивают со своими результатами. Конкретная позиция, наверное, не очень важна &#8212; главное присутствие в первых 30-ти результатах. Смотрят, какие сайты попали к ним &#8212; если различие сильное, это повод задуматься. Т.е. если после получения результатов от конкурентов оказывается, например, что 22 сайта присутствуют у всех, а у Яндекса только 5 из этих сайтов &#8212; это повод побеспокоиться.</p>
<p>Сразу возникает интересная идея &#8212; путь к первой странице выдачи Яндекса может лежать и через результаты выдачи его конкурентов.</p>
<p><strong>Сегалович</strong>:</p>
<blockquote><p>Так вот, практически все обращения в службу техподдержки &#8211; я думаю, в цифрах это будет более 90% &#8211; касаются именно таких сайтов из «серой зоны». Пишут грамотные аргументированные письма: «А вот смотрите, почему вы этот сайт выбросили, он качественный, контент уникальный, ссылки по теме. Объясните почему.» Цель таких писем – методом перебора уточнить безопасные границы в этой «серой зоне». Предприняли какое-то действие – смотрят результат. Если результат отрицательный, сайт попал под санкции, они пытаются получить от нас обратную связь, проанализировать причины.</p></blockquote>
<p><strong>Певцов</strong>:</p>
<blockquote><p>&#8230;как показывает практика, большинство сайтов, по поводу отсутствия которых в выдаче к нам обращаюся вебмастера, создавались специально с целью обмана поисковой системы и манипуляции результатами поиска&#8230;</p></blockquote>
<p><strong>Садовский</strong>:</p>
<blockquote><p>Я хочу заметить, что если мы видим, что имела место ошибка с нашей стороны, то в алгоритмы вносятся изменения, улучшающие работу системы в целом, и это касается других сайтов, которые тоже могли бы пострадать в аналогичной ситуации.</p></blockquote>
<p>Ну все уже догадались? Жаловаться на то, что сайт выпал из индекса, хотя соответствует &laquo;техническим параметрам&raquo; &#8211; ссылки, качество контента и т.д. &#8211; не надо. Ищите другую аргументацию. Вам же не робот отвечает, человек. И он понимает, что вебмастер беспокоящийся о технической стороне вопроса &#8212; не их союзник. И еще. Удалось убедить, что &laquo;сателлит&raquo; белый и пушистый? Будьте готовы к тому, что из под санкций могут выползти и &laquo;сателлиты&raquo; конкурентов. Любите жаловаться на &laquo;сателлиты&raquo; конкурентов, присутствующие в выдаче? Будьте готовы к тому, что вместе с ними пойдут ко дну и ваши такие-же.</p>
<p><strong>Певцов</strong>:</p>
<blockquote><p>уникальность контента совсем не определяющая вещь. О ней много говорят, но более важная характеристика &#8211; не уникальность, а полезность контента <em>[и далее по тексту]</em></p></blockquote>
<p>&laquo;У вас на сайте неуникальный текст! Ужас-ужас-ужас!&raquo; &#8211; страшилка. То есть, если скопировать все подряд, санкции будут. Но умеренное разбавление своих статей статьями, взятыми из других источников, может не повлечь никаких санкций. Таким образом, если где-то в интернетах нашлась удачная статья, подходящая сайту и автор не против ее распространения, можно спокойно скопировать ее к себе или процитировать. Ссылка на оригинал, как мне кажется, в данном случае будет лишним подтверждением &laquo;добрых намерений&raquo;.</p>
<p>Четвертая часть о воровстве контента. Авторам стОит отдавать свои статьи в RSS. Не жмотитесь, отдавайте всю статью. Роботы, сканирующие блогосферу быстрее и чаще забирают контент. Если статья у кого-то скопирована, не надо расстраиваться, страница с этим текстом не первая в выдаче. Еще не факт, что посетителя заинтересует первый сайт. 2-5 место тоже хороши. И до конца первой страницы &#8211; нормально. Кроме того, скопированная страница может придать общий тематический вес сайту, подняв его по другим, похожим, низкочастотным запросам.</p>
<p>Торговля и обмен ссылками яндексоидов раздражают. Но, если уж они научились находить &laquo;продажные ссылки&raquo;, то зачем банить всю страницу, она может оказаться вполне нормальной, а ссылки &#8211; результатом баловства наемного вебмастера. Ну неучитывали-бы тихонько эти самые ссылки молча. Дятлы бы продолжали бы заниматься бесполезным трудом и не искали бы каких-то иных методов воздействия на поисковик.</p>
<p>Ну вот как-то вот так. Спасибо, что дочитали до конца. :)</p>

<p><a href="http://feedads.g.doubleclick.net/~a/_gW2c63IMDz4JdqsYFLn9DvOYlU/0/da"><img src="http://feedads.g.doubleclick.net/~a/_gW2c63IMDz4JdqsYFLn9DvOYlU/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/_gW2c63IMDz4JdqsYFLn9DvOYlU/1/da"><img src="http://feedads.g.doubleclick.net/~a/_gW2c63IMDz4JdqsYFLn9DvOYlU/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/handmadesite?a=qYOr9YbFdyM:Jd4zxGrtZ_I:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/handmadesite?i=qYOr9YbFdyM:Jd4zxGrtZ_I:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=qYOr9YbFdyM:Jd4zxGrtZ_I:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/handmadesite?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=qYOr9YbFdyM:Jd4zxGrtZ_I:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/handmadesite?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=qYOr9YbFdyM:Jd4zxGrtZ_I:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/handmadesite?i=qYOr9YbFdyM:Jd4zxGrtZ_I:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/handmadesite/~4/qYOr9YbFdyM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.handmadesite.net/2009/11/lets-try-to-read-between-lines/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Контроллеры: загрузка</title>
		<link>http://www.handmadesite.net/2009/11/loding-controllers/</link>
		<comments>http://www.handmadesite.net/2009/11/loding-controllers/#comments</comments>
		<pubDate>Mon, 23 Nov 2009 17:50:02 +0000</pubDate>
		<dc:creator>Сергей</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[Console]]></category>
		<category><![CDATA[Controller]]></category>

		<guid isPermaLink="false">http://www.handmadesite.net/?p=332</guid>
		<description><![CDATA[Удивительно но факт. Если из консольного, например, приложения нужно попользоваться моделью, то, само собой, надо загрузить класс модели.

App::import&#40;'Model', 'MyModel'&#41;;

Но загрузить контроллер так не получится. Получим сообщение об ошибке из-за невозможности найти базовый класс Controller. Вот найти класс Model кейк может, а Controller &#8211; нет. Во всяком случае 1.2.5. В версии 1.3 не пробовал.
Поэтому приходится загружать [...]]]></description>
			<content:encoded><![CDATA[<p>Удивительно но факт. Если из консольного, например, приложения нужно попользоваться моделью, то, само собой, надо загрузить класс модели.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">App<span style="color: #339933;">::</span><span style="color: #004000;">import</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Model'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'MyModel'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Но загрузить контроллер так не получится. Получим сообщение об ошибке из-за невозможности найти базовый класс Controller. Вот найти класс Model кейк может, а Controller &#8211; нет. Во всяком случае 1.2.5. В версии 1.3 не пробовал.</p>
<p>Поэтому приходится загружать его явно и напрямую:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">App<span style="color: #339933;">::</span><span style="color: #004000;">import</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Core'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'Controller'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
App<span style="color: #339933;">::</span><span style="color: #004000;">import</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Controller'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'MyController'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>


<p><a href="http://feedads.g.doubleclick.net/~a/rzCahmhwzkCxJR3e5-b_7QYTHeY/0/da"><img src="http://feedads.g.doubleclick.net/~a/rzCahmhwzkCxJR3e5-b_7QYTHeY/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/rzCahmhwzkCxJR3e5-b_7QYTHeY/1/da"><img src="http://feedads.g.doubleclick.net/~a/rzCahmhwzkCxJR3e5-b_7QYTHeY/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/handmadesite?a=oP7xPiDsP8M:04qu1B2EA-U:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/handmadesite?i=oP7xPiDsP8M:04qu1B2EA-U:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=oP7xPiDsP8M:04qu1B2EA-U:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/handmadesite?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=oP7xPiDsP8M:04qu1B2EA-U:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/handmadesite?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=oP7xPiDsP8M:04qu1B2EA-U:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/handmadesite?i=oP7xPiDsP8M:04qu1B2EA-U:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/handmadesite/~4/oP7xPiDsP8M" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.handmadesite.net/2009/11/loding-controllers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Компоненты: перезагрузка</title>
		<link>http://www.handmadesite.net/2009/10/reload-components/</link>
		<comments>http://www.handmadesite.net/2009/10/reload-components/#comments</comments>
		<pubDate>Tue, 13 Oct 2009 22:02:40 +0000</pubDate>
		<dc:creator>Сергей</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[Component]]></category>

		<guid isPermaLink="false">http://www.handmadesite.net/?p=324</guid>
		<description><![CDATA[Не знаю, такую-ли ситуацию имел в виду BorisPlus в своем комментарии. Ну, чем богаты. Вообще не хотел это все описывать, потому как код довольно халтурно написан.
Этот код приложения, изначально крутившийся по Cake 1.1, был переписан для какой-то беты Cake 1.2. С текущей версией, 1.2.5, он работает без проблем, но, возможно, нуждается в чистке.
Эта часть программы [...]]]></description>
			<content:encoded><![CDATA[<p>Не знаю, такую-ли ситуацию имел в виду <a href="/2008/12/m-for-model/comment-page-1/#comment-794">BorisPlus в своем комментарии</a>. Ну, чем богаты. Вообще не хотел это все описывать, потому как код довольно халтурно написан.</p>
<p>Этот код приложения, изначально крутившийся по Cake 1.1, был переписан для какой-то беты Cake 1.2. С текущей версией, 1.2.5, он работает без проблем, но, возможно, нуждается в чистке.</p>
<p>Эта часть программы выполняющий импорт данных от поставщиков. Поставщики предоставляют данные в CSV формате, но порядок колонок, некоторые значения и т.д., конечно разные. Для осмысленной обработки эти полученные данные надо привести к единообразному виду.</p>
<p>Данные поступают из написанного куцего <em>Datasource</em>, скармливанются компоненту, который и выполняет разбор и приведение к общему виду, потом записываются в нашу таблицу.</p>
<p><span id="more-324"></span></p>
<p>Компонент подгружается динамически, в зависимости от поставщика. Все компоненты являются наследниками базового и реализуют метод <strong>parse</strong>. Этот метод базового компонента, если не перегружен, возвращает <em>NULL</em> &#8212; в этом случае в нашу таблицу ничего не записываем, переходим к следующей порции данных. Соответственно методы наследников тоже могут возвращать <em>NULL</em> при ошибке разбора, например, при отсутствии какого-либо ключевого поля.</p>
<p>Еще базовый компонент содержит некоторое количество служебных методов, общих для всех, с целью унифицировать данные.</p>
<p>Увы, все файлы с компонентами находятся в каталоге <em>components</em>. Зато после перегрузки можно к загруженному компоненту обращаться по имени базового:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">SupplierCsv</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">parse</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$data</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;"><span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>App<span style="color: #339933;">::</span><span style="color: #004000;">import</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Component'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'SupplierCsv'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #990000;">die</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Cannot load SupplierCsv component'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Еще у базового компонента есть метод <strong>factory</strong>. Я не помню, почему я его статическим объявил, честно. :-) Он получает в качестве параметра ссылку на контроллер и название компонента для обработки данных от конкретного поставщика:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">SupplierCsvComponent<span style="color: #339933;">::</span><span style="color: #004000;">factory</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'CsvComponentName'</span><span style="color: #339933;">=&gt;</span><span style="color: #000088;">$component_name</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Теперь методы базового компонента, <em>SupplierCsvComponent</em>:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> startup<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span><span style="color: #000088;">$controller</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">controller</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$controller</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$controller</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">SupplierCsv</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
static <span style="color: #000000; font-weight: bold;">function</span> factory<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span><span style="color: #000088;">$controller</span><span style="color: #339933;">,</span> <span style="color: #000088;">$supplier</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    App<span style="color: #339933;">::</span><span style="color: #004000;">import</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Component'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$supplier</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'CsvComponentName'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$componentclass</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$supplier</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'CsvComponentName'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'Component'</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$controller</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">SupplierCsv</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #000088;">$componentclass</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$controller</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">SupplierCsv</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">startup</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$controller</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>ну и код метода <strong>startup</strong> дочерних классов:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> startup<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span><span style="color: #000088;">$controller</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    parent<span style="color: #339933;">::</span><span style="color: #004000;">startup</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$controller</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">init</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">name</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Решение неидельное, наверняка можно соптимизировать. Мне, честно говоря, заниматься этим не хочется. Просто потому, что я в итоге начну вообще все с нуля переделывать и менять логику. :)</p>
<p>Откровенно говоря, огород можно было бы и не городить. Можно через App::import() загрузить класс компонента, а потом какой-нибудь переменной контроллера присвоить экземпляр этого класса.</p>
<p>Наверное, я раньше грузил компонент, указывая его в массиве $components, потому и сделал такую навернутую схему.</p>
<p>А может мне не хотелось require_once использовать&#8230; Ну не помню. :)</p>
<p><em>Update:</em> Если соберусь переписывать, надо будет рефлексию попробовать использовать. :)</p>

<p><a href="http://feedads.g.doubleclick.net/~a/t84WUblTmkl1bflcemVvkE6T5iM/0/da"><img src="http://feedads.g.doubleclick.net/~a/t84WUblTmkl1bflcemVvkE6T5iM/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/t84WUblTmkl1bflcemVvkE6T5iM/1/da"><img src="http://feedads.g.doubleclick.net/~a/t84WUblTmkl1bflcemVvkE6T5iM/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/handmadesite?a=uQ4y5AoxfNE:ZWZTZC0OYJw:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/handmadesite?i=uQ4y5AoxfNE:ZWZTZC0OYJw:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=uQ4y5AoxfNE:ZWZTZC0OYJw:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/handmadesite?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=uQ4y5AoxfNE:ZWZTZC0OYJw:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/handmadesite?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=uQ4y5AoxfNE:ZWZTZC0OYJw:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/handmadesite?i=uQ4y5AoxfNE:ZWZTZC0OYJw:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/handmadesite/~4/uQ4y5AoxfNE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.handmadesite.net/2009/10/reload-components/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Кэш и консоль</title>
		<link>http://www.handmadesite.net/2009/09/cache-and-console/</link>
		<comments>http://www.handmadesite.net/2009/09/cache-and-console/#comments</comments>
		<pubDate>Mon, 21 Sep 2009 16:41:48 +0000</pubDate>
		<dc:creator>Сергей</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[config]]></category>
		<category><![CDATA[XCache]]></category>

		<guid isPermaLink="false">http://www.handmadesite.net/?p=321</guid>
		<description><![CDATA[За полноценный пост не считается. Так, узелок на память.
В качестве кэша байткода и переменных я использую XCache. Но при запуске консольных приложений, он у меня не работает. Должен или нет, не знаю, не разбирался. Наверное, не должен, если подумать. :-) Просто отметил, что консольные приложения Cake, включая &#8216;cake bake&#8216; высыпают кучу ошибок, если XCache используется, [...]]]></description>
			<content:encoded><![CDATA[<p>За полноценный пост не считается. Так, узелок на память.</p>
<p>В качестве кэша байткода и переменных я использую <a href="http://xcache.lighttpd.net/">XCache</a>. Но при запуске консольных приложений, он у меня не работает. Должен или нет, не знаю, не разбирался. Наверное, не должен, если подумать. :-) Просто отметил, что консольные приложения Cake, включая &#8216;<em>cake bake</em>&#8216; высыпают кучу ошибок, если XCache используется, как кэш по умолчанию. Поэтому в конфигурации кэша приложения (APP/config/core.php) на CakePHP добавляю маленькую проверку на тип API.</p>
<p>Вот как-то так:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>PHP_SAPI <span style="color: #339933;">==</span> <span style="color: #0000ff;">'cli'</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  Cache<span style="color: #339933;">::</span><span style="color: #004000;">config</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'default'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'engine'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'File'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
  Cache<span style="color: #339933;">::</span><span style="color: #004000;">config</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'default'</span><span style="color: #339933;">,</span>
    <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #0000ff;">'engine'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'Xcache'</span><span style="color: #339933;">,</span>
          <span style="color: #0000ff;">'prefix'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'mypfx_'</span><span style="color: #339933;">,</span>
          <span style="color: #0000ff;">'user'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'IamAdmin'</span><span style="color: #339933;">,</span>
          <span style="color: #0000ff;">'password'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'c00leztPass'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Можно пользоваться константой <a href="http://php.net/manual/en/reserved.constants.php#reserved.constants.core">PHP_SAPI</a> или функцией <a href="http://php.net/php_sapi_name">php_sapi_name()</a>, не важно.</p>

<p><a href="http://feedads.g.doubleclick.net/~a/lhRVDZTLNfaKsclhmxskUPfXLKk/0/da"><img src="http://feedads.g.doubleclick.net/~a/lhRVDZTLNfaKsclhmxskUPfXLKk/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/lhRVDZTLNfaKsclhmxskUPfXLKk/1/da"><img src="http://feedads.g.doubleclick.net/~a/lhRVDZTLNfaKsclhmxskUPfXLKk/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/handmadesite?a=r326Qf4BvAU:mZX8aJ8Y-mc:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/handmadesite?i=r326Qf4BvAU:mZX8aJ8Y-mc:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=r326Qf4BvAU:mZX8aJ8Y-mc:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/handmadesite?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=r326Qf4BvAU:mZX8aJ8Y-mc:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/handmadesite?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=r326Qf4BvAU:mZX8aJ8Y-mc:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/handmadesite?i=r326Qf4BvAU:mZX8aJ8Y-mc:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/handmadesite/~4/r326Qf4BvAU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.handmadesite.net/2009/09/cache-and-console/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>CakePHP 1.2, Content-type, debug, RequestHandler и все-все-все</title>
		<link>http://www.handmadesite.net/2009/09/cakephp-1-2-content-type-debug-requesthandler-ftd-so-on/</link>
		<comments>http://www.handmadesite.net/2009/09/cakephp-1-2-content-type-debug-requesthandler-ftd-so-on/#comments</comments>
		<pubDate>Sat, 12 Sep 2009 12:46:16 +0000</pubDate>
		<dc:creator>Сергей</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[parseExtensions]]></category>
		<category><![CDATA[RequestHandler]]></category>

		<guid isPermaLink="false">http://www.handmadesite.net/?p=305</guid>
		<description><![CDATA[Как правильно, с точки зрения CakePHP, отвечать на запросы, если ответ требуется не html, а, например, json? Я считаю, что для получения ответа в нужном формате надо воспользоваться компонентом RequestHandler и указать в запросе расширение, в нашем случае &#8216;.json&#8217;. URL для запроса получится какой-то такой:
http://www.oursite.com/controller/action.json
Чтобы Cake не пугался этого расширения и вызывал правильное действие (action), [...]]]></description>
			<content:encoded><![CDATA[<p>Как правильно, с точки зрения CakePHP, отвечать на запросы, если ответ требуется не html, а, например, json? Я считаю, что для получения ответа в нужном формате надо воспользоваться компонентом <em>RequestHandler</em> и указать в запросе расширение, в нашем случае &#8216;.json&#8217;. URL для запроса получится какой-то такой:</p>
<pre>http://www.oursite.com/controller/action.json</pre>
<p>Чтобы Cake не пугался этого расширения и вызывал правильное действие (action), в файл APP/config/routes.php добавим строку:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">Router<span style="color: #339933;">::</span><span style="color: #004000;">parseExtensions</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'json'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p><span id="more-305"></span>Теперь надо разобраться с разными представлениями наших данных, чтобы по запросам к /action и /action.json возвращались разные виды. Для этого нужен компонент <em>RequestHandler</em>. Подключим его либо в самом контроллере, либо в родительском AppController:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">var</span> <span style="color: #000088;">$components</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'RequestHandler'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Теперь шаблоны для view и layout Cake будет искать в поддиректориях /json. Т.е для layout надо будет создать файл /views/layout/json/default.ctp:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$content_for_layout</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span></pre></div></div>

<p>и файл для действия /views/controller/json/action.ctp. Какой-то такой:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$javascript</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">object</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span></pre></div></div>

<p>Это все и без меня все знают, ничего нового тут нет. Разве что <a href="http://cakebaker.42dh.com/2009/07/02/default-views-for-extensions/">cakebaker советует воспользоваться Zend::Json вместо стандартного помощника Javascript</a>, дескать Zend&#8217;овская библиотека автоматом кодирует некоторые спецсимволы.</p>
<p>Но есть одна тонкость, недостаточно отраженная в документации &#8212; заголовок ответа Content-type. По всем ожиданиям он должен быть &#8216;application/json&#8217;, как это определено в коде компонента <em>RequestHandler</em>.</p>
<p>Однако, если включен режим отладки, т.е. <em>Configure.debug &gt; 0</em>, то <em>RequestHandler</em> устанавливает Сontent-Type в text/html без вариантов. Это, в общем-то описано в документации и докопаться до этого можно.</p>
<p>Но совершенно неочевидно, что если режим отладки выключить в коде самого action, написав</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">Configure<span style="color: #339933;">::</span><span style="color: #004000;">write</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'debug'</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>то это ничего уже не изменит! <em>RequestHandler</em> устанавливает заголовок во время загрузки компонента. Его метод <em>startup()</em> вызывает метод <em>renderAs()</em>, который вызывает метод <em>respondAs()</em>. Таким образом шаблоны подключаются нужные, те, которые из директорий /json, а Content-Type неправильный.</p>
<p>Лично я, пока, в acton, который должен отдавать данные в json, явно вызывываю <em>RequestHandler-&gt;respondAs()</em> повторно:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>Configure<span style="color: #339933;">::</span><span style="color: #004000;">read</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    Configure<span style="color: #339933;">::</span><span style="color: #004000;">write</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'debug'</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">RequestHandler</span><span style="color: #339933;">-&gt;</span>__responseTypeSet <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">RequestHandler</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">renderAs</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'json'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Это заставляет <em>RequestHandler</em> изменить заголовок Content-type еще раз. Можно похожий код, с проверкой типа запроса и установкой режима отладки и заголовков попробовать запихнуть, скажем, в <em>beforeRender</em>. Обратите внимание на грязный хак с установкой свойства __responseTypeSet в NULL. Метод respondAs сохраняет в эту переменную тип ответа и повторно не будет срабатывать, если он уже был вызван.</p>

<p><a href="http://feedads.g.doubleclick.net/~a/ue9ZDTvvly5PvVlFFKRc8gvWfX8/0/da"><img src="http://feedads.g.doubleclick.net/~a/ue9ZDTvvly5PvVlFFKRc8gvWfX8/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/ue9ZDTvvly5PvVlFFKRc8gvWfX8/1/da"><img src="http://feedads.g.doubleclick.net/~a/ue9ZDTvvly5PvVlFFKRc8gvWfX8/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/handmadesite?a=zIYWOAye2G0:bJo8Mds-ZR0:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/handmadesite?i=zIYWOAye2G0:bJo8Mds-ZR0:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=zIYWOAye2G0:bJo8Mds-ZR0:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/handmadesite?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=zIYWOAye2G0:bJo8Mds-ZR0:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/handmadesite?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=zIYWOAye2G0:bJo8Mds-ZR0:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/handmadesite?i=zIYWOAye2G0:bJo8Mds-ZR0:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/handmadesite/~4/zIYWOAye2G0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.handmadesite.net/2009/09/cakephp-1-2-content-type-debug-requesthandler-ftd-so-on/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Метрическая аналитика</title>
		<link>http://www.handmadesite.net/2009/05/metricheskaya-analitika/</link>
		<comments>http://www.handmadesite.net/2009/05/metricheskaya-analitika/#comments</comments>
		<pubDate>Fri, 01 May 2009 21:01:29 +0000</pubDate>
		<dc:creator>Сергей</dc:creator>
				<category><![CDATA[Поисковики]]></category>
		<category><![CDATA[Аналитика]]></category>
		<category><![CDATA[Статистика]]></category>
		<category><![CDATA[Яндекс]]></category>

		<guid isPermaLink="false">http://www.handmadesite.net/?p=301</guid>
		<description><![CDATA[У Яндекса есть полезная система статистики, похожая частью на Google Analytics, частью -- на счетчик Liveinternet]]></description>
			<content:encoded><![CDATA[<p>У Яндекса есть полезная система статистики, похожая частью на Google Analytics, частью &#8212; на счетчик Liveinternet. Называется <a href="http://metrika.yandex.ru/" target="_blank">Яндекс.Метрика</a>.</p>
<div id="attachment_300" class="wp-caption alignnone" style="width: 455px"><img class="size-full wp-image-300" title="Яндекс.Метрика" src="http://www.handmadesite.net/wp-content/uploads/2009/05/ya-metrics.jpg" alt="Яндекс.Метрика" width="445" height="102" /><p class="wp-caption-text">Яндекс.Метрика</p></div>
<p>Все как обычно &#8212; устанавливаете код на страницы своего сайта и наблюдаете статистику по посетителям. В отличие от GA, которая обновляется раз в сутки, <strong>Метрика</strong> показывает результаты практически в реальном времени, как Liveinternet &#8212; это гораздо удобнее.</p>
<p>Если сайт рекламируется с помощью <strong>Яндекс.Директ</strong> и на рекламируемом сайте установлен код для сбора статистики для Директа &#8212; это и есть код Метрики!  В этом случае можно уже не напрягаться, а смотреть отчеты.</p>

<p><a href="http://feedads.g.doubleclick.net/~a/_K_4VmUXk1RUtvLNpGEu0kF3-s8/0/da"><img src="http://feedads.g.doubleclick.net/~a/_K_4VmUXk1RUtvLNpGEu0kF3-s8/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/_K_4VmUXk1RUtvLNpGEu0kF3-s8/1/da"><img src="http://feedads.g.doubleclick.net/~a/_K_4VmUXk1RUtvLNpGEu0kF3-s8/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/handmadesite?a=Kqe18IsLWTI:sPVb_SbbgG0:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/handmadesite?i=Kqe18IsLWTI:sPVb_SbbgG0:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=Kqe18IsLWTI:sPVb_SbbgG0:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/handmadesite?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=Kqe18IsLWTI:sPVb_SbbgG0:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/handmadesite?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=Kqe18IsLWTI:sPVb_SbbgG0:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/handmadesite?i=Kqe18IsLWTI:sPVb_SbbgG0:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/handmadesite/~4/Kqe18IsLWTI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.handmadesite.net/2009/05/metricheskaya-analitika/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>UPDATE нельзя INSERT</title>
		<link>http://www.handmadesite.net/2009/04/update-insert/</link>
		<comments>http://www.handmadesite.net/2009/04/update-insert/#comments</comments>
		<pubDate>Sat, 11 Apr 2009 22:13:55 +0000</pubDate>
		<dc:creator>Сергей</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[таблицы]]></category>

		<guid isPermaLink="false">http://www.handmadesite.net/?p=293</guid>
		<description><![CDATA[Задача очень простая: обновить запись в таблице, а если подходящей записи нет, добавить новую. Кажется вполне тривиальной задачей. Особенно, если условия, по которым выбирается запись для обновления сделать первичным или уникальным ключом.
Эта тема пару месяцев назад обсуждалась в ЖЖ сообществе ru_php, но как-то вяло. Попробую этим небольшим постом обобщить разные методики.
Самый простой метод: сначала SELECT [...]]]></description>
			<content:encoded><![CDATA[<p>Задача очень простая: обновить запись в таблице, а если подходящей записи нет, добавить новую. Кажется вполне тривиальной задачей. Особенно, если условия, по которым выбирается запись для обновления сделать первичным или уникальным ключом.</p>
<p>Эта тема пару месяцев назад обсуждалась в <a href="http://community.livejournal.com/ru_php/1321540.html" target="_blank">ЖЖ сообществе ru_php</a>, но как-то вяло. Попробую этим небольшим постом обобщить разные методики.</p>
<p>Самый простой метод: сначала SELECT COUNT(*), а потом, по результатам, либо INSERT, либо UPDATE. Если речь идет об обновлении одной записи на этом методе можно остановиться.</p>
<p>Увы, если надо вставить много записей, этот метод начинает изрядно тормозить. Для такого случая у MySQL есть несколько разных методов.</p>
<p><a href="http://dev.mysql.com/doc/refman/5.1/en/replace.html" target="_blank">REPLACE</a> &#8212; наиболее очевидный и самый неудобный. Сервер пытается вставить новую строку, если возникает ошибка с повторяющимся уникальным ключом, запись удаляется и потом снова добавляется новая. Увы, при этом значения тех полей, которые обновлять не надо сбрасываются в дефолтные. Использовать эту команду можно, если обновляется полностью вся запись, что случается редко. Например, если в таблице есть колонка `created`, содержащая дату <em>создания</em> записи, то REPLACE уже не подходит. Кроме того, в случае, если большинство записей заменяется, а не добавляется, получается конструкция INSERT-(ошибка)-DELETE-INSERT &#8212; три запроса!</p>
<p><a href="http://dev.mysql.com/doc/refman/5.1/en/insert-on-duplicate.html" target="_blank">INSERT &#8230; ON DUPLICATE KEY UPDATE &#8230;</a> &#8212; этот вариант сильно интереснее. Сервер пытается вставить запись, если получает ошибку c дублирующимся ключом, обновляет поля, указанные в после UPDATE. Работает отлично, в документации сказано, что эта конструкция специально задумана для вставки множества записей. Но пара неприятных моментов есть.</p>
<ol>
<li>Первый, как мне казалось, довольно экзотичный, но я с ним все-таки столкнулся. В конструкции INSERT можно в качестве источника данных использовать <a href="http://dev.mysql.com/doc/refman/5.1/en/insert-select.html" target="_blank">подзапрос SELECT</a>. Но, в случае с INSERT &#8230; ON DUPLICATE KEY UPDATE, в подзапросе <em>не должно</em> быть группировки GROUP BY.</li>
<li>Второй момент для многих неважен. Если записей для обновления сильно больше чем новых, то получается все равно много лишних обращений к БД &#8212; ведь вся конструкция это сочетание INSERT-(ошибка)-UPDATE. Лучше, чем с REPLACE, но все же&#8230;</li>
</ol>
<p>Долгое время я пользовался UPDATE, а потом проверял mysql_affected_rows() (в CakePHP это $DataSource-&gt;lastAffected(). То есть проверял количество обновленных записей и, если получал 0, добавлял запись. У этого метода есть очень существенный недостаток: если среди данных для обновления встречаются две одинаковых строки, то при повторном UPDATE сервер, как самый умный, не обновляет запись. Соответственно число обновленных записей, affected rows, при построчном переборе, будет равно 0 несмотря на то, что такая строка в таблице есть. Соответственно решение о вставки новой строки будет ошибочным.</p>
<p>Устав мириться с ожидаемым, но неприятным поведением mysql_affected_rows() я порылся в документации на MySQL и нашел еще одну функцию: <a href="http://dev.mysql.com/doc/refman/5.1/en/mysql-info.html" target="_blank">mysql_info()</a>. Она выдает обычную строчку со статистикой последнего запроса к БД, причем для разных типов запросов строчки разные. Для UPDATE выглядит так:</p>
<p><code class="literal">Rows matched: 40 Changed: 40             Warnings: 0</code></p>
<p>Зато содержит чрезвычайно ценную информацию: количество записей, которые попадают под условие для обновления. Это те цифры, что после слова &#8216;<em>matched:</em>&#8216;. Ну, регулярное выражение для получения циферок из строки сами напишите? ;-)</p>
<p>P.S. У меня ощущение deja vu &#8212; мне кажется, что я уже писал похожий пост. Перерыл дневники &#8212; нет такого. Или это черновик был&#8230;</p>

<p><a href="http://feedads.g.doubleclick.net/~a/doB8CRgAW-FEczx9-pQhbiByXvs/0/da"><img src="http://feedads.g.doubleclick.net/~a/doB8CRgAW-FEczx9-pQhbiByXvs/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/doB8CRgAW-FEczx9-pQhbiByXvs/1/da"><img src="http://feedads.g.doubleclick.net/~a/doB8CRgAW-FEczx9-pQhbiByXvs/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/handmadesite?a=eoT_CJnm7Vg:HR-sTyDzKeg:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/handmadesite?i=eoT_CJnm7Vg:HR-sTyDzKeg:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=eoT_CJnm7Vg:HR-sTyDzKeg:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/handmadesite?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=eoT_CJnm7Vg:HR-sTyDzKeg:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/handmadesite?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=eoT_CJnm7Vg:HR-sTyDzKeg:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/handmadesite?i=eoT_CJnm7Vg:HR-sTyDzKeg:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/handmadesite/~4/eoT_CJnm7Vg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.handmadesite.net/2009/04/update-insert/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Поиск по дате</title>
		<link>http://www.handmadesite.net/2009/03/mysql-datetime/</link>
		<comments>http://www.handmadesite.net/2009/03/mysql-datetime/#comments</comments>
		<pubDate>Thu, 12 Mar 2009 23:52:25 +0000</pubDate>
		<dc:creator>Сергей</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[datetime]]></category>
		<category><![CDATA[Детские грабли]]></category>

		<guid isPermaLink="false">http://www.handmadesite.net/?p=281</guid>
		<description><![CDATA[Вот уж не подумал бы, что на совершенно тривиальных запросах к MySQL можно наступить на детские грабли.
Я не люблю обновлять MySQL ни на своей машине, ни на сервере. Каждый раз гадаешь: &#171;понадобится бэкап или или нет?&#187; Поэтому имеет место некоторая несогласованность версий, на которую я не слишком сильно обращал внимание. До сегодняшнего вечера. Итак у [...]]]></description>
			<content:encoded><![CDATA[<p><img class="size-full wp-image-280 alignright" title="Детские грабли" src="http://www.handmadesite.net/wp-content/uploads/2009/03/detskie-grabli.png" alt="Детские грабли" width="200" height="156" />Вот уж не подумал бы, что на совершенно тривиальных запросах к MySQL можно наступить на детские грабли.</p>
<p>Я не люблю обновлять MySQL ни на своей машине, ни на сервере. Каждый раз гадаешь: &laquo;понадобится бэкап или или нет?&raquo; Поэтому имеет место некоторая несогласованность версий, на которую я не слишком сильно обращал внимание. До сегодняшнего вечера. Итак у меня в наличии на домашней машине MySQL 5.1.22-rc-community, win32. На сервере соответственно MySQL 5.0.45 из бокса CentOS 5.</p>
<p>Самая обычная таблица в БД, с самым обычным полем created типа DATETIME.</p>
<p>Однако запрос</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span>
    COUNT<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">*</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`count`</span>
<span style="color: #993333; font-weight: bold;">FROM</span>
    <span style="color: #ff0000;">`offers`</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`Offer`</span>
<span style="color: #993333; font-weight: bold;">WHERE</span>
    <span style="color: #ff0000;">`Offer`</span><span style="color: #66cc66;">.</span><span style="color: #ff0000;">`supplier_id`</span> <span style="color: #66cc66;">=</span> <span style="color: #cc66cc;">3</span> <span style="color: #993333; font-weight: bold;">AND</span>
    DATE<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`Offer`</span><span style="color: #66cc66;">.</span><span style="color: #ff0000;">`created`</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'2009-03-12'</span></pre></div></div>

<p>работает на них совершенно по-разному!</p>
<p>На домашней машине все, как ожидается, возвращается количество записей за 12-е число. На сервере &#8212; 0 записей. <span id="more-281"></span>После некоторого яндексения в гугле, выяснилось, что на эти грабли, конечно же, наступал не я один и, в зависимости от версии, вернее, от релиза, обработка такого условия работает по-разному.</p>
<p>На домашней машине у поля DATETIME обрезается часть, содержащая время. На сервере наоборот, к выражению для сравнения добавляется &#8216; 00:00:00&#8242;. :-/ Но отчего тогда не срабатывает функция DATE() все равно непонятно, это встроенный оптимизатор MySQL ее оптимизирует нафиг?</p>
<p>Много английских букв на близкую тему: <a href="http://bugs.mysql.com/bug.php?id=28929">http://bugs.mysql.com/bug.php?id=28929</a>.</p>
<p>В соответствии с <a href="http://dev.mysql.com/doc/refman/5.0/en/date-and-time-types.html">советами из мануала MySQL</a> переделал запрос так:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span>
    COUNT<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">*</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`count`</span>
<span style="color: #993333; font-weight: bold;">FROM</span>
    <span style="color: #ff0000;">`offers`</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`Offer`</span>
<span style="color: #993333; font-weight: bold;">WHERE</span>
    <span style="color: #ff0000;">`Offer`</span><span style="color: #66cc66;">.</span><span style="color: #ff0000;">`supplier_id`</span> <span style="color: #66cc66;">=</span> <span style="color: #cc66cc;">3</span> <span style="color: #993333; font-weight: bold;">AND</span>
    CAST<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`Offer`</span><span style="color: #66cc66;">.</span><span style="color: #ff0000;">`created`</span> <span style="color: #993333; font-weight: bold;">AS</span> DATE<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'2009-03-12'</span></pre></div></div>

<p>все равно не работает! Единственный заработавший вариант выглядит так:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span>
    COUNT<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">*</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`count`</span>
<span style="color: #993333; font-weight: bold;">FROM</span>
    <span style="color: #ff0000;">`offers`</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`Offer`</span>
<span style="color: #993333; font-weight: bold;">WHERE</span>
    <span style="color: #ff0000;">`Offer`</span><span style="color: #66cc66;">.</span><span style="color: #ff0000;">`supplier_id`</span> <span style="color: #66cc66;">=</span> <span style="color: #cc66cc;">3</span> <span style="color: #993333; font-weight: bold;">AND</span>
    SUBSTR<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`Offer`</span><span style="color: #66cc66;">.</span><span style="color: #ff0000;">`created`</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">10</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'2009-03-12'</span></pre></div></div>

<p>некрасиво, но других идей нет. Использовать BETWEEN совсем не хочется.</p>
<p>Самое неприятное в том, что заранее точно сказать будет-ли работать нормальное условие с DATE() на каком-то сервере нельзя. Можно только предположить.</p>
<p>Оставить SUBSTR навечно или наваять какой-нибудь переключатель в зависимости от настроек? Написать тест и по его результатам указыватьчто-то типа</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">Configure<span style="color: #339933;">::</span><span style="color: #004000;">write</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'App.Database.MySQLDateTimeExtractor'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'SUBSTR'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// or 'DATE'</span></pre></div></div>

<p>В общем, надо повнимательнее к выборке дат.</p>

<p><a href="http://feedads.g.doubleclick.net/~a/bFadZUgSHAmMIQik-8bg-X8-50w/0/da"><img src="http://feedads.g.doubleclick.net/~a/bFadZUgSHAmMIQik-8bg-X8-50w/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/bFadZUgSHAmMIQik-8bg-X8-50w/1/da"><img src="http://feedads.g.doubleclick.net/~a/bFadZUgSHAmMIQik-8bg-X8-50w/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/handmadesite?a=SJxZmXt8KnQ:h5_zwkSRR_0:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/handmadesite?i=SJxZmXt8KnQ:h5_zwkSRR_0:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=SJxZmXt8KnQ:h5_zwkSRR_0:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/handmadesite?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=SJxZmXt8KnQ:h5_zwkSRR_0:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/handmadesite?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/handmadesite?a=SJxZmXt8KnQ:h5_zwkSRR_0:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/handmadesite?i=SJxZmXt8KnQ:h5_zwkSRR_0:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/handmadesite/~4/SJxZmXt8KnQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.handmadesite.net/2009/03/mysql-datetime/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Производительность pagination в CakePHP 1.2</title>
		<link>http://www.handmadesite.net/2009/02/improving-pagination-performance-in-cakephp-12/</link>
		<comments>http://www.handmadesite.net/2009/02/improving-pagination-performance-in-cakephp-12/#comments</comments>
		<pubDate>Sun, 15 Feb 2009 17:50:46 +0000</pubDate>
		<dc:creator>Сергей</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[Models]]></category>
		<category><![CDATA[optimization]]></category>
		<category><![CDATA[pagination]]></category>
		<category><![CDATA[tips and tricks]]></category>
		<category><![CDATA[Модели]]></category>
		<category><![CDATA[Модель]]></category>

		<guid isPermaLink="false">http://www.handmadesite.net/?p=253</guid>
		<description><![CDATA[Как влиять на метод контроллера paginate? Можно-ли сделать выборку более оптимальной и как? Много букв о тюнинге постраничных запросов могут быть любопытны более-менее продвинутым программистам на CakePHP]]></description>
			<content:encoded><![CDATA[<p>Хотя использование разбивки на страницы (pagination) вполне заслуживает отдельного, обстоятельного поста, хочу остановиться лишь на паре не слишком очевидных моментов. Я предполагаю, что у читающих этот пост есть определенный навык использования CakePHP, моделей вообще и pagination в частности. Этот пост и так получается длинным.</p>
<p>Известно, что метод контроллера <em>paginate()</em> вызывает последовательно два метода модели &#8212; первый для подсчета общего числа записей, удовлетворяющих заданным условиям, и второй на выборку указанного числа записей начиная с заданной. Т.е. первый это фактически функция SQL COUNT(*), второй &#8212; SELECT &#8230; LIMIT n,m.</p>
<p>Именно из-за того, что вызовов методов больше одного, не срабаывает временная привязка/отвязка подчиненных моделей с помощью <em>bindModel()</em>/<em>unbindModel()</em>. Этим методам, для корректной работы с <em>paginate()</em> приходится передавать второй параметр, равный <em>false</em>. К счастью, еть ContainableBehavior, решающий эту проблему.</p>
<p>Эти запросы не всегда оптимальны и есть возможность улучшить производительность метода <em>paginate()</em> именно за счет оптимизации собственно самих запросов.<span id="more-253"></span></p>
<p>Для того, чтобы влиять на работу метода paginate(), в контроллере CakePHP предусмотрены вызовы двух специальных методов модели: <em>Model::paginateCount()</em> и <em>Model::paginate()</em>. Метод <em>paginate()</em> <strong>контроллера</strong> ищет у модели указанные методы и, если они определены, вызывает их. Если у модели методы не определены, вызываются стандартные <em>Model::find(&#8216;count&#8217; &#8230;)</em> и <em>Model::find(&#8216;all&#8217;,..)</em>, которым в качестве параметров передаются условия выборки, условия для Containable и все прочее.</p>
<p>Понятно, что определив эти методы в модели, все вместе или любой на выбор, можно творить все, что захочется. А сам метод <em>Controller::paginate()</em> (не путайте с нашим <em>Model::paginate()</em>!) тогда будет заниматься исключительно вспомогательной работой &#8212; опредять параметры для LIMIT и настраивать переменные вида (View). Самое главное, чтобы наш метод Model::paginateCount() возвращал (int) количество записей, а Model::paginate() &#8212; массив записей.</p>
<p>Все это предоставляет большое пространство для творчества и гибкость при каких-нибудь навернутых запросах. Но не только. Этими методами можно воспользоваться для оптимизации запросов, которые CakePHP мог бы и самостоятельно составлять.</p>
<p><strong>Model::paginateCount</strong></p>
<p>Первым займемся методом для подсчета количества записей. Этот метод <a href="http://kossak.blogspot.com/2007/11/pagination-cakephp-12.html" target="_blank">я уже описывал чуть более года назад</a>, но то описание во-первых устарело, потому, что в итоге в CakePHP сменился синтаксис вызова COUNT(*), а во-вторых здесь я постараюсь дать более развернутое описание.</p>
<p>При вызове метода Model::paginateCount(), контроллер передает ему три параметра: $conditions, $recursive и $extra.</p>
<ul>
<li>(array) <strong>conditions</strong> &#8212; ассоциативный массив условий, такой же, как массивы условий для любых других методов модели. В нашем случае в него копируются условия из массива Controller::paginate['conditions'].</li>
<li>(int) <strong>recursive</strong> &#8212; значение параметра $recursive. Если это значение установлено в переменной Controller::raginate['recursive'], то оно. Если нет, то берется из значения свойства Model::recursive</li>
<li>(array) <strong>extra</strong> &#8212; ассоциативный массив всех остальных переменных, передаваемых в Controller::paginate, &#8216;contain&#8217; (для ContainableBehavior), &#8216;fields&#8217; и т.д. В общем, содержимое переменной Controller::paginate без первых двух параметров.</li>
</ul>
<p>Хочу отметить, что никто не запрещает указывать в массиве Controller::paginate какие-то свои собственные ключи. Так что, если в методе нашего контроллера определить что-то типа:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">paginate</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'my-cool-param'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #0000ff;">'YES!'</span><span style="color: #339933;">;</span></pre></div></div>

<p>то эта пара ключ-значение тоже попадет в параметр <strong>extra</strong>.</p>
<p>Чаще всего для разбивки на страницы используется модель, связанная с другими. Классический пример с моделью Article, которая принадлежит (belongsTo) модели Author. Для окончательного вывода нам нужны данные из обоих моделей, но для подсчета записей достаточно посчитать только записи в Article. Т.е. для подсчета строк достаточно выполнить COUNT(*) только для таблицы articles, без лишних JOIN&#8217;ов. MySQL работает гораздо веселее, когда удается обойтись без связанных таблиц. Для этого простого случая вполне можно вызывать $this-&gt;Article-&gt;unbindModel(array(&#8216;belongsTo&#8217;=&gt;array(&#8216;Author&#8217;)))) и связанная модель Author не будет участвовать в подсчете, но будет в выборке результатов. Помните, что метод <em>unbindModel()</em> по умолчанию «отвязывает» модель только на один, следующий, запрос?</p>
<p>Но если связанных моделей много, что, надо помнить их все? Да и дергать unbindModel() перед Controller::paginate() что-то не улыбается. Особенно с точки зрения парадигмы «тонкий контроллер, толстая модель».</p>
<p>Иными словами, я считаю, что надо написать такой метод paginateCount, который будет подсчитывать записи в таблице без присоединения зависимых моделей. Сделать это можно жестко задавая параметр $recursive при вызове <em>Model::find(&#8216;count&#8217;&#8230;)</em>. Получится примерно такой код:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> paginateCount<span style="color: #009900;">&#40;</span><span style="color: #000088;">$conditions</span><span style="color: #339933;">,</span> <span style="color: #000088;">$recursive</span><span style="color: #339933;">,</span> <span style="color: #000088;">$extra</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">find</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'count'</span><span style="color: #339933;">,</span>
        <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
            <span style="color: #0000ff;">'conditions'</span><span style="color: #339933;">=&gt;</span><span style="color: #000088;">$conditions</span><span style="color: #339933;">,</span>
            <span style="color: #0000ff;">'recursive'</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: #009900;">&#125;</span></pre></div></div>

<p>Теперь при вызове COUNT(*) не будет совсем никаких JOIN&#8217;ов, несмотря ни на какие отношения.</p>
<p>Я довольно долго пользовался этим вариантом метода и быль вполне им доволен. Но совсем недавно возникла необходимость все-таки в полном подсчете записей &#8212; из-за условия отбора по полю присоединенной модели. Совсем убирать этот метод мне не хотелось и я решил просто добавить возможность указания &#8212; надо ли использовать для подсчета запрос с присоединенными моделями или можно обойтись подсчетом записей только в одной. Если конкретнее, то для frontend метода index использую «быстрый» метод подсчета, а в админской части есть более сложные фильтры, требующие использования «медленного» метода. Чтобы указать необходимость использования «медленного» метода, с использованием присоединенных моделей, используется дополнительный ключ в массиве <em>Controller::paginate</em>. Что я, зря, чтоль столько букв про $extra написал? :-) Теперь если задан сложный фильтр по записям, кроме условий в Controller::paginate['conditions'], добавляю ключ Controller::paginate['count_recursive']=1. А метод стал выглядить так:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> paginateCount<span style="color: #009900;">&#40;</span><span style="color: #000088;">$conditions</span><span style="color: #339933;">,</span> <span style="color: #000088;">$recursive</span><span style="color: #339933;">,</span> <span style="color: #000088;">$extra</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">@</span><span style="color: #000088;">$extra</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'count_recursive'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$extra</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'count_recursive'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$recursive</span><span style="color: #339933;">=-</span><span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">find</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'count'</span><span style="color: #339933;">,</span> 
        <span style="color: #990000;">array_merge</span><span style="color: #009900;">&#40;</span>
            <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
                <span style="color: #0000ff;">'conditions'</span><span style="color: #339933;">=&gt;</span><span style="color: #000088;">$conditions</span><span style="color: #339933;">,</span>
                <span style="color: #0000ff;">'recursive'</span><span style="color: #339933;">=&gt;</span><span style="color: #000088;">$recursive</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
                <span style="color: #000088;">$extra</span>
            <span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Получилось, на мой взгляд вполне неплохо.</p>
<p><strong>Model::paginate</strong></p>
<p>После доработки подсчета я решил посмотреть, что можно сделать с самим запросом на выборку. По сути, find(&#8216;all&#8217;, &#8230;) он и есть find(&#8216;all&#8217;, &#8230;) чего там еще с ним сделаешь? Тем не менее, из метода контроллера <em>Controller::paginate()</em>, одноименный метод модели <em>Model::paginate()</em> вызывается с множеством параметров.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> paginate<span style="color: #009900;">&#40;</span><span style="color: #000088;">$conditions</span><span style="color: #339933;">,</span> <span style="color: #000088;">$fields</span><span style="color: #339933;">,</span> <span style="color: #000088;">$order</span><span style="color: #339933;">,</span> <span style="color: #000088;">$limit</span><span style="color: #339933;">,</span> <span style="color: #000088;">$page</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span> <span style="color: #000088;">$recursive</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">,</span> <span style="color: #000088;">$extra</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span></pre></div></div>

<p>Для простых запросов тут не стоило бы и напрягаться. Зато для сложных запросов, которые CakePHP не может выполнить сам, или выполняет неоптимально, вызов этого метода &#8212; золотое дно. Ведь здесь можно манипулировать результирующими данными.</p>
<p>В качестве примера, простая ситуация с цепочкой из трех моделей. Таблица с продуктами, у которых есть много цен (розничная, опт1, и т.д.) в разных валютах (их всего три, так получилось). Для работы только с розничными ценами мы перепривязали с помощью <em>unbindModel()</em> и <em>bindModel()</em> модель с ценами как hasOne с условием Price.price_type=&#8217;retail&#8217;. Но цепочка из трех моделей осталась:</p>
<ul>
<li> модель Product владеет ценой (hasOne) Price;</li>
<li>Price принадлежит валюте (belongsTo) Currency</li>
</ul>
<p>Обычный <em>Model::find(&#8216;all&#8217;&#8230;)</em> поступит просто. Выберет все записи Product-JOIN-Price, а потом для каждого элемента массива выберет Currency. С учетом того, что в самом худшем варианте, на странице будут цены в трех валютах, двадцать запросов &#8216;SELECT Price &#8230; &#8216; все равно выглядят удручающе. В похожей ситуации я поступил так:</p>
<ul>
<li>С помощью recursive при вызове Model::find(&#8216;all&#8217;,&#8230;) ограничил выборку только связью Product-Price</li>
<li>Используя Set::classicExtract получил массив id нужных валют. Можно было и с помощью SQL запроса SELECT DISTINCT это сделать, но Set::classicExtract мне ближе ;-)</li>
<li>Выбрал нужные вылюты из модели Currency</li>
<li>Добавил в массив, полученный в первом пункте выбранные валюты в соответствии с Price.currency_id</li>
</ul>
<p>Получилось всего три запроса, включая запрос на подсчет!</p>
<p>Возможность оптимизации менее сложных запросов при вызове <em>Controller::paginate()</em> тоже есть.</p>
<p>Когда я сделал свой метод <em>Model::paginateCount()</em> для общей и админской части, обратил внимание, что возможен вариант, когда в админской части заданы такие условия выборки, под которые не попадает ни одной записи. Например, в указанном разделе автор не опубликовал ни одной записи. В этом случае возвращается, как нетрудно догадаться, пустой массив. Поскольку меня уже было не остановить :-) , я задался вопросом &#8212; а если нет ни одной записи, и <em>paginateCount()</em> это уже определил, то зачем вообще выполнять запрос к БД на выборку? Можно же просто вернуть пустой массив! Так и поступил.</p>
<p>В модель добавил переменную, в которую <em>Model::paginateCount()</em> записывал полученное количество записей.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000088;">$_lastPaginationCountResult</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">function</span> paginateCount<span style="color: #009900;">&#40;</span><span style="color: #000088;">$conditions</span><span style="color: #339933;">,</span> <span style="color: #000088;">$recursive</span><span style="color: #339933;">,</span> <span style="color: #000088;">$extra</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">@</span><span style="color: #000088;">$extra</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'count_recursive'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$extra</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'count_recursive'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$recursive</span><span style="color: #339933;">=-</span><span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_lastPaginationCountResult <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">find</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'count'</span><span style="color: #339933;">,</span> 
        <span style="color: #990000;">array_merge</span><span style="color: #009900;">&#40;</span>
            <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
                <span style="color: #0000ff;">'conditions'</span><span style="color: #339933;">=&gt;</span><span style="color: #000088;">$conditions</span><span style="color: #339933;">,</span>
                <span style="color: #0000ff;">'recursive'</span><span style="color: #339933;">=&gt;</span><span style="color: #000088;">$recursive</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
                <span style="color: #000088;">$extra</span>
            <span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_lastPaginationCountResult<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>И написал маленький метод <em>Model::paginate()</em>. Мною собственноручно написана только одна строка, проверка переменной с результатами <em>paginateCount()</em>, которая была вызвана до того. Весь остальной код просто скопировал из соответствующего метода <em>Controller::paginate()</em>.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> paginate<span style="color: #009900;">&#40;</span><span style="color: #000088;">$conditions</span><span style="color: #339933;">,</span> <span style="color: #000088;">$fields</span><span style="color: #339933;">,</span> <span style="color: #000088;">$order</span><span style="color: #339933;">,</span> <span style="color: #000088;">$limit</span><span style="color: #339933;">,</span> <span style="color: #000088;">$page</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span> <span style="color: #000088;">$recursive</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">,</span> <span style="color: #000088;">$extra</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_lastPaginationCountResult <span style="color: #339933;">===</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$parameters</span> <span style="color: #339933;">=</span> <span style="color: #990000;">compact</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'conditions'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'fields'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'order'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'limit'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'page'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$recursive</span> <span style="color: #339933;">!=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">recursive</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$parameters</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'recursive'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$recursive</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">array_key_exists</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'type'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$extra</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$type</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$extra</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'type'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        <span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$extra</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'type'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">else</span> <span style="color: #000088;">$type</span><span style="color: #339933;">=</span><span style="color: #0000ff;">'all'</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">find</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$type</span><span style="color: #339933;">,</span> <span style="color: #990000;">array_merge</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$parameters</span><span style="color: #339933;">,</span> <span style="color: #000088;">$extra</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Кстати, обратите внимание, на параметр type, это не я придумал, это в оригинале так было. Он позволяет вместо find(&#8216;all&#8217;,&#8230;) использовать для выборки любой другой тип запроса. Даже самостоятельно определенный, например, find(&#8216;recent&#8217;,&#8230;), если, конечно, поддержку этого метода кто-нибудь заранее напишет ;-)</p>

<p><a href="http://feedads.g.doubleclick.net/~a/SbIMUR-lcQLdyHGIi_P81VD1Xtw/0/da"><img src="http://feedads.g.doubleclick.net/~a/SbIMUR-lcQLdyHGIi_P81VD1Xtw/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/SbIMUR-lcQLdyHGIi_P81VD1Xtw/1/da"><img src="http://feedads.g.doubleclick.net/~a/SbIMUR-lcQLdyHGIi_P81VD1Xtw/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/handmadesite?a=c4RfpXXS"><img src="http://feeds.feedburner.com/~f/handmadesite?i=c4RfpXXS" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/handmadesite?a=3vAFxBFq"><img src="http://feeds.feedburner.com/~f/handmadesite?d=52" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/handmadesite?a=KWYSOrSV"><img src="http://feeds.feedburner.com/~f/handmadesite?i=KWYSOrSV" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/handmadesite/~4/2ydmUwTyWAI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.handmadesite.net/2009/02/improving-pagination-performance-in-cakephp-12/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
