<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>SimpleCoding.org &#187; MySQL</title>
	<atom:link href="http://www.simplecoding.org/category/mysql/feed" rel="self" type="application/rss+xml" />
	<link>http://www.simplecoding.org</link>
	<description>Блог о программировании</description>
	<lastBuildDate>Fri, 27 Jan 2012 18:27:45 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<item>
		<title>WordPress: простой способ отлючить трекбеки для части постов (без плагинов)</title>
		<link>http://www.simplecoding.org/wordpress-prostoj-sposob-otlyuchit-trekbeki-dlya-chasti-postov-bez-plaginov.html</link>
		<comments>http://www.simplecoding.org/wordpress-prostoj-sposob-otlyuchit-trekbeki-dlya-chasti-postov-bez-plaginov.html#comments</comments>
		<pubDate>Sat, 21 Jan 2012 14:46:53 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1259</guid>
		<description><![CDATA[С недавних пор этот блог опять стали одолевать спамеры. Не знаю с чем это связано, больше года всё было относительно спокойно. Проскакивало по несколько спамерских комментариев в неделю, явно написанных людьми, а не ботами, и всё. А тут по 10-20 требкеков в день. Удалить их, конечно, не сложно, но надоедает и раздражает, к тому же [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1260" class="wp-caption alignnone" style="width: 275px"><img src="http://www.simplecoding.org/wp-content/uploads/2012/01/wordpress_block_trackback.png" alt="wordpress block trackback" title="wordpress block trackback" width="265" height="229" class="size-full wp-image-1260" style="float:left" /><p class="wp-caption-text"> </p></div>
<p>С недавних пор этот блог опять стали одолевать спамеры. Не знаю с чем это связано, больше года всё было относительно спокойно. Проскакивало по несколько спамерских комментариев в неделю, явно написанных людьми, а не ботами, и всё. А тут по 10-20 требкеков в день. Удалить их, конечно, не сложно, но надоедает и раздражает, к тому же трекбеки явно ставились автоматически, т.е. спамер своё время на них не тратил.</p>
<p>Вообще я не сторонник отключения каких-либо каналов общения. В теории трекбеки сильно упрощают создание связей между блогами. Но на практике получается, что нормальные требкеки приходят к более-менее новым постам, а спамерские – обычно ко всем подряд.</p>
<p>Поэтому я решил закрыть трекбеки для всех постов старше 2-х месяцев. Ставить специальный плагин для решения этой задачи нет никакой необходимости, всё можно сделать с помощью несложного <strong>SQL запроса и cron&#039;а</strong>.<br />
<span id="more-1259"></span></p>
<h2>Теория</h2>
<p>В WordPress все посты хранятся в таблице <code>wp_posts</code> (префикс <code>wp_</code> может быть другим). В этой таблице есть поле <code>ping_status</code>, которому можно присвоить одно из двух значений: «open» или «closed». Как несложно догадаться по названию, значение «closed» отключает трекбеки к данном посту.</p>
<p>Теперь нужно определиться с датами. MySQL поддерживает довольно много <a href="http://dev.mysql.com/doc/refman/5.6/en/date-and-time-functions.html">функций для работы со временем и датами</a>. Нам потребуются:<br />
1) <code>CURDATE</code> – возвращает текущую дату;<br />
2) <code>DATE_SUB</code> – вычитает даты;<br />
и выражение <code>INTERVAL ... DAY</code> – позволяет указать интервал с заданным количеством дней.</p>
<p>Дата последнего изменения поста хранится в поле <code>post_modified</code> (таблицы <code>wp_posts</code>).</p>
<h2>Формируем запрос</h2>
<pre class="brush: sql; gutter: true; first-line: 1; highlight: []; html-script: false">UPDATE wp_posts SET ping_status=&quot;closed&quot; WHERE post_modified &lt; DATE_SUB(CURDATE(), INTERVAL 60 DAY)</pre>
<p>Как видите, это обычный UPDATE запрос, который установит полю <code>ping_status</code> значение «closed» для всех записей у которые последний раз обновлялись более 60-ти дней назад.</p>
<p>Кстати, аналогичным способом можно закрыть и комментарии. Для этого нужно установить значение «closed» для поля «comment_status».</p>
<h2>Остаётся настроить периодический запуск этого запроса</h2>
<p>Удобнее всего для этого использовать cron. Тут потребуются хотя бы базовые навыки работы с панелью управления хостингом. В большинстве панелей в меню находится ссылка на страницу cron, а для создания задачи нужно заполнить небольшую форму. При этом необходимо указать два обязательных параметра – команду, которую будет выполнять cron, и периодичность её выполнения.</p>
<p>В данном случае команда может выглядеть следующим образом.</p>
<pre class="brush: bash; gutter: true; first-line: 1; highlight: []; html-script: false">mysql --default-character-set=utf8 --user=user_name --password=user_password db_name &lt; path_to/block_trackbacks.sql</pre>
<p>Здесь <code>block_trackbacks.sql</code> – имя файла в котором записан наш запрос.</p>
<p>Периодичность выполнения можно указать – 1 раз в день. Принципиальной роли, в данном случае, она не играет.</p>
<h2>Результаты</h2>
<p>Как и следовало ожидать, работает данный метод очень неплохо. Количество спама в трекбеках снизилось практически до нуля <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  И, обратите внимание, данный способ подходит для любой CMS, главное, найти какое поле отвечает за отключение трекбеков.</p>
<p><strong>Успехов!</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/wordpress-prostoj-sposob-otlyuchit-trekbeki-dlya-chasti-postov-bez-plaginov.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Сортировка в MySQL: несколько редко используемых возможностей</title>
		<link>http://www.simplecoding.org/sortirovka-v-mysql-neskolko-redko-ispolzuemyx-vozmozhnostej.html</link>
		<comments>http://www.simplecoding.org/sortirovka-v-mysql-neskolko-redko-ispolzuemyx-vozmozhnostej.html#comments</comments>
		<pubDate>Mon, 25 Apr 2011 08:17:43 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1204</guid>
		<description><![CDATA[О сортировке данных с помощью SQL запросов, думаю, знают все web разработчики. Достаточно указать в запросе предложение ORDER BY с нужными параметрами и вы получите желаемый результат. Параметры задавать тоже несложно. Просто перечисляете через запятую столбцы по которым нужно выполнить сортировку и указываете её направление (по возрастанию (ASC) или по убыванию (DESC)). Т.е. запрос, выполняющий [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1205" class="wp-caption alignnone" style="width: 272px"><img src="http://www.simplecoding.org/wp-content/uploads/2011/04/mysql_order_by.png" alt="mysql order by" title="mysql order by" width="262" height="177" style="float:left" class="size-full wp-image-1205" /><p class="wp-caption-text"> </p></div>
<p>О <a href="http://dev.mysql.com/doc/refman/5.6/en/sorting-rows.html">сортировке данных с помощью SQL</a> запросов, думаю, знают все web разработчики.</p>
<p>Достаточно указать в запросе предложение <code>ORDER BY</code> с нужными параметрами и вы получите желаемый результат.</p>
<p>Параметры задавать тоже несложно. Просто перечисляете через запятую столбцы по которым нужно выполнить сортировку и указываете её направление (по возрастанию (<code>ASC</code>) или по убыванию (<code>DESC</code>)).</p>
<p>Т.е. запрос, выполняющий сортировку может выглядеть примерно следующим образом.</p>
<pre class="brush: sql">SELECT * FROM articles ORDER BY a_title ASC, a_date DESC</pre>
<p>В этом случае записи из таблицы <code>articles</code> будут отсортированы в возрастающем порядке по полю <code>a_title</code>, а для записей у которых совпадают значения в поле <code>a_title</code> – по полю <code>a_date</code> в убывающем порядке.</p>
<p>Именно в такой форме используются возможности сортировки в большинстве случаев. Но встречаются ситуации, в которых нужно использовать более сложные правила.<br />
<span id="more-1204"></span></p>
<h2>Сортировка с учетом типа данных</h2>
<p>Представьте, что у вас есть две таблицы. Первая содержит какие-нибудь <strong>записи</strong> (статьи, новости, товары и т.п.), а вторая – <strong>метаданные</strong> для этих записей. Метаданные могут содержать какую угодно информацию, например, рейтинг новости или цвет товара.</p>
<p>При этом таблицы будут иметь приблизительно следующую структуру.</p>
<div id="attachment_1206" class="wp-caption alignnone" style="width: 354px"><img src="http://www.simplecoding.org/wp-content/uploads/2011/04/db_structure.png" alt="db_structure" title="db_structure" width="344" height="144" class="size-full wp-image-1206" /><p class="wp-caption-text"> </p></div>
<p>Подобные решения используются во многих <strong>CMS</strong>, т.к. авторы не знают какие именно метаданные будет использовать разработчик сайта и предоставляют ему возможность создавать их в неограниченном количестве.</p>
<p>Но что произойдет если мы попытаемся выполнить сортировку по метаданным?</p>
<p>Такую сортировку можно выполнить с помощью следующего запроса</p>
<pre class="brush: sql">SELECT * FROM articles AS a LEFT JOIN metadata AS m ON a.a_id=m.m_article_id WHERE m.m_name="color"</pre>
<p>Этот запрос выведет все записи из таблицы <code>articles</code> для которых создано мета-поле <code>color</code>.</p>
<p>Очевидно, что тип поля <code>m_value</code> должен быть текстовым, т.к. заранее неизвестно что будет храниться в метаданных.</p>
<p>При этом числовые данные будут отсортированы не правильно. Дело в том, что <code>ORDER BY</code> сравнивает значения с учетом типа поля и, например, при сортировке по возрастанию вы получите следующий ряд значений: «1», «10», «2», «3» и т.д.</p>
<p>Т.е. при выполнении такого запроса нужно указать, что поле <code>m_value</code> необходимо считать числовым. Делается это следующим образом.</p>
<pre class="brush: sql">SELECT * FROM metadata ORDER BY (m_value+0)</pre>
<p>Обратная операция (сортировка числового поля по правилам текстового) записывается немного сложнее.</p>
<pre class="brush: sql">SELECT left(a_id, 20) AS id_str FROM articles ORDER BY id_str</pre>
<p>Функция <code>left</code> возвращает строку, содержащую первые <code>N</code> символов из строки, указанной в первом параметре. Количество символов (N) задается во втором параметре. В данном случае будут выбраны первые 20 символов (достаточно чтобы преобразовать 8-байтное целое число в строку). Т.е. движок <strong>MySQL</strong> выполнит сортировку по строке, полученной из значения числового поля.</p>
<p>Хочу предупредить, что несмотря на то, что данные методы могут быть удобны в ряде ситуаций, их использование приводит к <strong>снижению скорости выполнения SQL запросов</strong>. Поэтому злоупотреблять ими не стоит. С другой стороны, сортировка с помощью PHP (или любого другого языка) также займет какое-то время.</p>
<h2>Сортировка текста с учетом регистра</h2>
<p>Для текстовых полей сортировка выполняется без учета регистра. В большинстве случаев это правильно, т.к. в таблице символов прописная «А» идет после строчной «я». Т.е. отсортированные с учетом регистра строки будут расположены в следующем порядке.</p>
<p>1. «Язык запросов»<br />
2. «Язык программирования»<br />
3. «Язык Запросов»</p>
<p>Но если всё-таки сортировку нужно выполнить с учетом регистра, просто добавьте оператор <code>BINARY</code> перед именем поля.</p>
<pre class="brush: sql">SELECT * FROM articles ORDER BY BINARY a_title</pre>
<h2>Сортировка по фрагменту строки</h2>
<p>Если вам приходится использовать этот прием, то, скорее всего, ваша база данных не соответствует перовой нормальной форме. Поэтому, подумайте, может лучше пересмотреть её структуру?</p>
<p>Но, в любом случае, вы можете использовать функцию <a href="http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_substring-index">SUBSTRING_INDEX</a> для выбора подстроки и последующей сортировки. Например,</p>
<pre class="brush: sql">SELECT SUBSTRING_INDEX(a_title, ' ', -1) AS at FROM wp_5_posts ORDER BY at</pre>
<h2>Сортировка записей по заданному списку значений</h2>
<p>Представьте, что у вас есть записи, которые каким-то образом связаны с временем года. И вы храните эту информацию в одном из столбцов таблицы.</p>
<p>Очевидно, что, используя стандартный вариант сортировки (по алфавиту), расположить сезоны порядке «весна», «лето», «осень», «зима» не получится. Естественно, можно каждому времени года присвоить свой код, но есть и другой вариант решения – использовать функцию <a href="http://dev.mysql.com/doc/refman/5.6/en/string-functions.html#function_field">FIELD</a>.</p>
<pre class="brush: sql">SELECT * FROM articles ORDER BY FIELD(a_season, "весна","лето","осень","зима")</pre>
<p>Эта функция ищет значение, указанное в первом параметре, среди значений, перечисленных в остальных параметрах, и возвращает его порядковый номер. При выполнении запроса в первый параметр функции <code>FIELD</code> будут передаваться значения из поля <code>a_season</code> и, таким образом, записи будут отсортированы в заданном нами порядке.</p>
<h2>Сортировка строк по их длине</h2>
<p>Эта возможность используется довольно редко, т.к. обычно длина строки смысловой нагрузки не несет. Тем не менее, в некоторых случаях может пригодиться.</p>
<pre class="brush: sql">SELECT * FROM articles ORDER BY CHAR_LENGTH(a_title)</pre>
<p>Как видите, «фокус» заключается в использовании функции <code>CHAR_LENGTH</code>, которая определяет количество символов в строке.</p>
<h2>Заключение</h2>
<p>Думаю, глядя на последние несколько рецептов, вы понимаете, что подобным образом можно использовать практически все функции MySQL. Мне будет интересно, если вы поделитесь примерами из своей практики <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><strong>Интересное в Интернете</strong></p>
<p>Заказ <a href="http://imagebook.ru/wedding">свадебных фотоальбомов</a> с доставкой по РФ и СНГ</p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/sortirovka-v-mysql-neskolko-redko-ispolzuemyx-vozmozhnostej.html/feed</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Yii PHP framework: создание запросов с условием IN</title>
		<link>http://www.simplecoding.org/yii-php-framework-sozdanie-zaprosov-s-usloviem-in.html</link>
		<comments>http://www.simplecoding.org/yii-php-framework-sozdanie-zaprosov-s-usloviem-in.html#comments</comments>
		<pubDate>Sat, 03 Jul 2010 10:27:22 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>
		<category><![CDATA[Yii]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1092</guid>
		<description><![CDATA[Последнее время мне довольно часто приходится работать с фреймворком Yii. И иногда возникают вопросы, ответы на которые не очевидны (во всяком случае для меня). Попробую объяснить. Сам фреймворк, на мой взгляд, достаточно удобный и документация подробная. Но классов много, и формат передачи данных их методам часто сильно влияет на результат. Рассмотрим небольшой пример – использование [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1093" class="wp-caption alignnone" style="width: 294px"><img src="http://www.simplecoding.org/wp-content/uploads/2010/07/yii_in_statement.png" alt="yii in condition" title="yii in condition" width="284" height="148" style="float:left" class="size-full wp-image-1093" /><p class="wp-caption-text"> </p></div>
<p>Последнее время мне довольно часто приходится работать с <strong>фреймворком Yii</strong>. И иногда возникают вопросы, ответы на которые не очевидны (во всяком случае для меня).</p>
<p>Попробую объяснить. Сам фреймворк, на мой взгляд, достаточно удобный и документация подробная. Но классов много, и формат передачи данных их методам часто сильно влияет на результат.</p>
<p>Рассмотрим небольшой пример – <strong>использование оператора IN</strong>.</p>
<p>Т.е. нужно сформировать примерно такой запрос.</p>
<pre class="brush: sql">SELECT * FROM tbl_users WHERE id IN (1, 2, 3)</pre>
<p><span id="more-1092"></span><br />
В <a href="http://yiiframework.ru/doc/guide/ru/index">Полном руководстве</a> на эту тему информации я не нашел, а копаться в методах <a href="http://www.yiiframework.com/doc/api/CActiveRecord">CActiveRecord</a> времени не было.</p>
<p>Вообще, я очень не люблю такие ситуации. С одной стороны, понятно как нужно написать запрос, с другой – хочется сделать это красиво, используя встроенную библиотеку. Копаться в документации не хочется, ведь на это уходит время, а запрос можно составить за считанные минуты. Но не все так просто.</p>
<p>Сначала покажу <strong>решение «в лоб»</strong>.</p>
<pre class="brush: php">$ids = array(1, 2, 3);

$dataProvider=new CActiveDataProvider('User',array(
	'criteria'=&gt;array(
		'condition'=&gt;'id IN ('.implode(',', $ids).')',
	)
));

$this-&gt;render('admin',array(
	'model'=&gt;$dataProvider,
));</pre>
<p>Тут мы формируем массив со значениями, которые будут перечислены после <code>IN</code>. А затем, с помощью функции <code>implode</code> преобразуем его в строку и просто вставляем в запрос.</p>
<p><strong>Недостатки</strong> такого подхода очевидны.</p>
<p><em>Во-первых</em>, выглядит код не очень красиво.</p>
<p><em>Во-вторых</em>, в реальном приложении значения для массива <code>$ids</code> будут откуда-то поступать, возможно, из параметров запроса. И если массив <code>$ids</code> окажется пустым, то при выполнении запроса возникнет ошибка. </p>
<p><em>В-третьих</em>, полученные значения нужно проверить. А написать что-то вроде</p>
<pre class="brush: php">'params'=&gt;array(':id'=&gt;implode(', ', $ids)),</pre>
<p>не получится, т.к. результат работы функции <code>implode</code> будет взят в кавычки. Т.е. проверку необходимо сделать предварительно.</p>
<p>Как видите, возникают проблемы практически на пустом месте. Нужно написать код проверок, решить, что делать с пустым массивом, затем протестировать этот код. И все ради решения тривиальной задачи.</p>
<p><strong>Решение с помощью библиотеки Yii.</strong></p>
<p>Оно выглядит гораздо проще.</p>
<pre class="brush: php">$model = User::model()-&gt;findAllByAttributes(array('id'=&gt;array(1, 2, 3)));
$dataProvider=new CActiveDataProvider('User');
$dataProvider-&gt;setData($model);

$this-&gt;render('index',array(
	'dataProvider'=&gt;$dataProvider,
));</pre>
<p>Метод <code>findAllByAttributes</code> класса <code>CActiveRecord</code> позволяет искать записи в БД по названию поля и значению. При этом если значение является массивом, то используется оператор <code>IN</code>.</p>
<p>Этот же самый код можно записать немного иначе.</p>
<pre class="brush: php">$dataProvider=new CActiveDataProvider('User');
$dataProvider-&gt;criteria-&gt;addInCondition('id', array(1,2,3));

$this-&gt;render('index',array(
	'dataProvider'=&gt;$dataProvider,
));</pre>
<p>Тут уже используется метод <code>addInCondition</code> класса <code>CDbCriteria</code>. Если вы работаете с <code>CActiveDataProvider</code>, то получить доступ к объекту <code>CDbCriteria</code> можно с помощью свойства <code>criteria</code>.</p>
<p>Теперь проведем несколько экспериментов.</p>
<p>Попробуем в массиве передать строку.</p>
<pre class="brush: php">$dataProvider-&gt;criteria-&gt;addInCondition('id', array(1,2,'test'));</pre>
<p>В результате будет выполнен следующий запрос.</p>
<pre class="brush: sql">SELECT * FROM 'tbl_user' WHERE &quot;id&quot; IN (1, 2, 0)</pre>
<p>Т.е. текстовое значение было заменено нулем, что вполне логично, т.к. поле <code>id</code> имеет тип <code>INT</code>.</p>
<p>Если запрос будет выполняться к полю текстового типа, то текстовые и числовые значения будут вставлены в кавычках.</p>
<pre class="brush: php">$dataProvider-&gt;criteria-&gt;addInCondition('id', array(1, 'admin','user'));</pre>
<p>сформирует такой запрос</p>
<pre class="brush: sql">SELECT * FROM 'tbl_user' WHERE &quot;id&quot; IN ('1','admin', 'user')</pre>
<p>А если массив окажется пуст, то фреймворк гарантирует, что из таблицы не будет выбрана ни одна запись.</p>
<pre class="brush: php">$dataProvider-&gt;criteria-&gt;addInCondition('id', array());</pre>
<pre class="brush: sql">SELECT * FROM 'tbl_user' WHERE 0=1</pre>
<p>Как видите, использование встроенных библиотек всё-таки оправдывает время, потраченное на их изучение <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Только не забывайте при работе с документацией Yii учитывать один момент. Классы библиотеки тесно связаны между собой, поэтому искать нужно не только в методах класса, с которым вы непосредственно работаете, но и в методах объектов, которые использует этот класс.</p>
<p>Так <code>CActiveDataProvider</code> использует <code>CDbCriteria</code> для формирования условий, <code>CPagination</code> – для разбивки на страницы, CSort – для сортировки и т.д.</p>
<p>Вообще, я заметил, чем больше работаешь с фреймворком, тем логичнее кажутся решения разработчиков и тем проще ориентироваться в документации <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Удачи!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/yii-php-framework-sozdanie-zaprosov-s-usloviem-in.html/feed</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Yii PHP фреймворк: создаем поле с автозаполнением</title>
		<link>http://www.simplecoding.org/yii-php-frejmvork-sozdaem-pole-s-avtozapolneniem.html</link>
		<comments>http://www.simplecoding.org/yii-php-frejmvork-sozdaem-pole-s-avtozapolneniem.html#comments</comments>
		<pubDate>Sun, 16 May 2010 08:51:38 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>
		<category><![CDATA[Yii]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1060</guid>
		<description><![CDATA[Приветствую всех! Сегодня я покажу небольшой пример использования виджета CAutoComplete из фреймворка Yii. Как несложно догадаться, он создаёт текстовое поле, под которым может появляться список с вариантами подстановок. Принцип создания такого поля довольно прост. На странице нужно поместить обычное текстовое поле и назначить событию onKeyUp обработчик, который будет отправлять AJAX запросы серверу. В этих запросах [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1061" class="wp-caption alignnone" style="width: 281px"><img src="http://www.simplecoding.org/wp-content/uploads/2010/05/yii_php_framework_autocomplete.png" alt="yii php framework autocomplete" title="yii php framework autocomplete" width="271" height="166" class="size-full wp-image-1061" style="float:left" /><p class="wp-caption-text"> </p></div>
<p><strong>Приветствую всех!</strong></p>
<p>Сегодня я покажу небольшой пример использования виджета <a href="http://www.yiiframework.com/doc/api/CAutoComplete">CAutoComplete</a> из фреймворка <strong>Yii</strong>. Как несложно догадаться, он создаёт текстовое поле, под которым может появляться список с вариантами подстановок.</p>
<p>Принцип создания такого поля довольно прост. На странице нужно поместить обычное текстовое поле и назначить событию <code>onKeyUp</code> обработчик, который будет отправлять <strong>AJAX</strong> запросы серверу. В этих запросах нужно передавать введённый посетителем текст. Сервер ищет совпадения с этим текстом в БД и возвращает результат браузеру. JavaScript обработчик создаёт список с вариантами, полученными от сервера, и показывает его под полем.</p>
<p>Как видите, алгоритм несложный, но рутинной работы много.</p>
<p>Теперь, давайте разберёмся, что сделает за вас виджет, а что придётся делать вам.<br />
<span id="more-1060"></span><br />
Для работы виджет использует плагин <a href="http://plugins.jquery.com/project/autocompletex">Autocomplete</a> библиотеки <strong>jQuery</strong>, т.е. писать JS код от вас не потребуется (если, конечно, вы не хотите изменить стандартное поведение плагина).</p>
<p>Кроме того, виджет создаст текстовое поле и подключит все необходимые JS и CSS файлы. Вам нужно будет только указать некоторые настройки.</p>
<p>Основная часть вашей работы будет заключаться в написании метода, выполняющего обработку запросов и поиск данных в базе.</p>
<p>Теперь <strong>рассмотрим пример</strong>.</p>
<p>Допустим, у нас есть база данных с названиями стран. Таблица называется <code>countries</code>, а поле, в котором хранятся названия &#8211; <code>c_name</code>.</p>
<p>Создаём для этой таблицы модель.</p>
<p><code>yiic shell<br />
model countries</code></p>
<p><em>Примечание</em>. Тут я предполагаю, что у вас создано веб приложение и настроено подключение к базе данных.</p>
<p>Теперь нужно создать текстовое поле. <code>CAutoComplete</code> – это обычный виджет, поэтому поместить его можно где угодно. Если хотите, чтобы поле выводилось на отдельной странице – добавляйте его в соответствующее представление, хотите показывать на каждой странице – добавляйте в макет (layout).</p>
<p>Код вставки виджета выглядит так.</p>
<pre class="brush: php">$this-&gt;widget('CAutoComplete',
	array(
		'model'=&gt;'countries',
		'name'=&gt;'country',
		'url'=&gt;array('countries/autocomplete'),
		'minChars'=&gt;2,
	)
);</pre>
<p>Во втором параметре необходимо передать массив с параметрами. Обязательными являются первые два.<br />
<code>model</code> – имя модели.<br />
<code>name</code> – атрибут name текстового поля.<br />
<code>url</code> – адрес скрипта, который будет обрабатывать AJAX запросы.<br />
<code>minChars</code> – минимальное количество символов, при котором выполняется отправка запроса.</p>
<p>Естественно, это не все параметры. Подробный их перечень вы найдете на странице <a href="http://www.yiiframework.com/doc/api/CAutoComplete">документации</a>.</p>
<p>По мере ввода текста серверному скрипту будут отправляться AJAX запросы вида:</p>
<p><code>index.php?r=countries/autocomplete&#038;q=%D0%B0%D0%BB&#038;limit=10&#038;timestamp=1273944702297</code></p>
<p>В параметре <code>q</code> передаётся введённый посетителем текст, а в параметре <code>limit</code> – максимальное количество подстановок.</p>
<p>Рассмотрим метод, выполняющий обработку этого запроса.</p>
<pre class="brush: php">public function actionAutoComplete() {

	if (isset($_GET['q'])) {

		$criteria = new CDbCriteria;
		$criteria-&gt;condition = 'c_name LIKE :country';
		$criteria-&gt;params = array(':country'=&gt;$_GET['q'].'%');

		if (isset($_GET['limit']) &#038;&#038; is_numeric($_GET['limit'])) {
			$criteria-&gt;limit = $_GET['limit'];
		}

		$countries = countries::model()-&gt;findAll($criteria);

		$resStr = '';
		foreach ($countries as $country) {
			$resStr .= $country-&gt;c_name."\n";
		}
		echo $resStr;
	}
}</pre>
<p>Здесь мы проверяем, пришли ли параметры и формируем запрос.</p>
<p>Условие записываем с помощью класса <code>CDbCriteria</code>. В атрибуте <code>condition</code> указываем название поля и операцию сравнения (<code>LIKE</code>). В атрибуте <code>params</code> – текст, введенный пользователем. Обратите внимание, мы добавляем к нему знак <code>%</code>, т.е. найдены будут все страны, названия которых начинаются с указанных букв.</p>
<p>Затем добавляем параметр <code>limit</code> и выполняем запрос (<code>findAll</code>).</p>
<p>Из результатов поиска формируем строку с найденными названиями стран. Разделителем служит символ новой строки (это требование плагина). И отправляем результат браузеру.</p>
<p>Как видите, пользоваться виджетом совсем не сложно.</p>
<p>Все вопросы, советы и замечания пишите в комментариях.</p>
<p><strong>Удачи!</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/yii-php-frejmvork-sozdaem-pole-s-avtozapolneniem.html/feed</wfw:commentRss>
		<slash:comments>22</slash:comments>
		</item>
		<item>
		<title>Yii PHP framework: связанные таблицы и limit</title>
		<link>http://www.simplecoding.org/yii-php-framework-svyazannye-tablicy-i-limit.html</link>
		<comments>http://www.simplecoding.org/yii-php-framework-svyazannye-tablicy-i-limit.html#comments</comments>
		<pubDate>Tue, 11 May 2010 09:04:32 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>
		<category><![CDATA[Yii]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1057</guid>
		<description><![CDATA[Давно я собирался написать этот пост, практически сразу после выхода цикла о создании игрового сайта, но как-то всё время откладывал. В новых версиях фреймворка Yii (1.1.х) немного изменился принцип использования встроенной библиотеки для работы с базой данных, точнее она стала по-другому формировать SQL запросы при использовании связанных таблиц. Речь идет об этом изменении. По умолчанию [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1058" class="wp-caption alignnone" style="width: 280px"><img src="http://www.simplecoding.org/wp-content/uploads/2010/05/yii_active_record_limit.png" alt="yii active record limit" title="yii active record limit" width="270" height="136" style="float:left" class="size-full wp-image-1058" /><p class="wp-caption-text"> </p></div>
<p>Давно я собирался написать этот пост, практически сразу после выхода цикла о создании <a href="http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-1-postanovka-zadachi.html">игрового сайта</a>, но как-то всё время откладывал.</p>
<p>В новых версиях <strong>фреймворка Yii</strong> (1.1.х) немного изменился принцип использования встроенной библиотеки для работы с базой данных, точнее она стала по-другому формировать SQL запросы при использовании связанных таблиц.</p>
<p>Речь идет об этом изменении.<br />
<span id="more-1057"></span><br />
<em><br />
<blockquote style="font-size:0.8em">По умолчанию для всех отношений, включенных в &#039;жадную&#039; загрузку, будет сгенерировано и выполнено одно выражение с использованием JOIN. Если в основной таблице есть опции запроса LIMIT или OFFSET, то сначала будет выполнен этот запрос, а затем другой SQL-запрос, который возвращает все связанные объекты. Раньше, в версии 1.0.x, по умолчанию вызывалось N+1 SQL-запросов, если &#039;жадная&#039; загрузка включала N отношений HAS_MANY или MANY_MANY.<br />
(перевод взят <a href="http://yiiframework.ru/doc/guide/ru/upgrade">отсюда</a>)</p></blockquote>
<p></em></p>
<p>В моем примере с игровым сайтом как раз возникла такая ситуация. Есть две таблицы, с играми (<code>ygs_games</code>) и их жанрами (<code>ygs_types</code>). Отношение между таблицами многие-ко-многим.</p>
<p>При этом необходимо выводить <strong>игры определённого жанра с разбивкой на страницы</strong> (пагинацией), т.е. использовать в запросе <code>limit</code> и <code>offset</code>.</p>
<p>Yii позволяет сформировать запросы на получение этих данных двумя способами, которые называются: <strong>&#034;жадная&#034; загрузка</strong> и <strong>&#034;ленивая&#034; загрузка</strong>. Первый предполагает формирование одного запроса, в котором будут получены все необходимые данные. В этом запросе будут использованы объединения (JOINs). Во втором случае используется несколько запросов. Сначала выбираются нужные записи из первой таблицы (первый запрос), затем &#8211; данные из связанной таблицы (для каждой записи из первой таблицы выполняется дополнительный запрос).</p>
<p><strong>Проблема</strong>, с которой я столкнулся.</p>
<p>В старых версиях для этих целей можно было использовать следующий код.</p>
<pre class="brush: php">$criteria=new CDbCriteria;
$criteria-&gt;condition = 't_id=:t_id';
$criteria-&gt;params = array(':t_id'=&gt;$_GET['type_id']);
$criteria-&gt;with = array('ygs_types'=&gt;array('together'=&gt;true));

$pages=new CPagination(Games::model()-&gt;published()-&gt;count($criteria));
$pages-&gt;pageSize=self::PAGE_SIZE;
//этот метод добавляет параметры limit и offset в объект $criteria, т.е. в запрос
$pages-&gt;applyLimit($criteria);

$models=Games::model()-&gt;findAll($criteria);</pre>
<p>здесь <code>t_id</code> &#8211; первичный ключ в таблице жанров.<br />
<code>ygs_types</code> &#8211; название элемента в массиве, который возвращает метод <code>relations()</code> модели (этот элемент просто описывает отношение многие-к-многим).</p>
<p>При этом формировался один запрос по методу &#034;жадной&#034; загрузки, который возвращал все необходимые данные.</p>
<p>Но в новых версиях <strong>Yii</strong> этот код <strong>не работает</strong>.</p>
<p>Дело в том, что как только мы указываем <code>LIMIT</code> или <code>OFFSET</code> в запросе, который включает связанные таблицы, библиотека Yii разбивает запрос на два. Сначала выполняется запрос только к первой таблице и именно к нему применяется LIMIT.</p>
<pre class="brush: sql">SELECT `t`.`g_id` AS `t0_c0`, ... FROM `ygs_games` `t`  WHERE ((g_state=0) AND
(t_id=:t_id)) LIMIT 10. Bind with parameter :t_id='2'</pre>
<p>И сразу же возникает ошибка.</p>
<p><code>Column not found: 1054 Unknown column 't_id' in 'where clause'</code></p>
<p>Причина ошибки в том, что yii пытается вставить параметр для поля <code>t_id</code>, которого нет в таблице <code>ygs_games</code>. Таблица <code>ygs_types</code> будет присоединена в следующем запросе (с помощью JOIN), но LIMIT применяется именно в первом запросе к первой таблице, а нужно, чтобы он применялся к результату объединённого запроса.</p>
<p>Отключить это поведение, судя по всему, нельзя.</p>
<p>Но можно использовать <strong>&#034;ленивую&#034; загрузку</strong>, и при этом будет выполняться также два запроса.</p>
<p>Первым запросом мы находим нужный жанр в таблице <code>ygs_types</code>.</p>
<pre class="brush: php">$type = Types::model()-&gt;findByPk($_GET['type_id']);</pre>
<p>Тут выполняется следующий запрос</p>
<pre class="brush: sql">SELECT * FROM `ygs_types` `t` WHERE `t`.`t_id`=8 LIMIT 1</pre>
<p>Затем, получаем связанные с этим жанром игры.<br />
Здесь есть нюанс. Вызов</p>
<pre class="brush: php">$type-&gt;ygs_games</pre>
<p>нам не подходит, т.к. мы не сможем указать параметры, например тот же limit (если нужно его изменять).</p>
<p><em>Примечание</em>. Можно, конечно, указать параметры в массиве, который возвращает метод relations, но этот метод имеет свои недостатки. Например, чтобы изменить параметры (тот же <code>limit</code>), их придется хранить в отдельном массиве, и его нужно будет объединять с массивом, который возвращает <code>relations()</code>.</p>
<p>Поэтому, на мой взгляд, удобнее использовать метод <a href="http://www.yiiframework.com/doc/api/CActiveRecord#getRelated-detail">getRelated</a>, в его третьем  параметре можно передать массив с настройками.<br />
Код будет выглядеть так.</p>
<pre class="brush: php">$params = array(
        'limit'=&gt;self::PAGE_SIZE,
        'condition'=&gt;'g_state='.Games::PUBLISHED,
        'order'=&gt;'g_added DESC',
);
$games = $type-&gt;getRelated('ygs_games',false, $params);</pre>
<p>При этом Yii формирует следующий запрос (self::PAGE_SIZE = 10)</p>
<pre class="brush: sql">SELECT `ygs_games`.`g_id` AS `t1_c0`, ... FROM `ygs_games` `ygs_games` INNER JOIN
`ygs_games_types` `ygs_games_ygs_games` ON
(`ygs_games_ygs_games`.`gt_type_id`=:ypl0) AND
(`ygs_games`.`g_id`=`ygs_games_ygs_games`.`gt_game_id`) WHERE (g_state=0)
ORDER BY g_added DESC LIMIT 10. Bind with parameter :ypl0='8'</pre>
<p>Т.е. именно то, что нам нужно.</p>
<p>Тут есть один <strong>недостаток</strong> &#8211; усложняется код настройки пагинации. Мы должны вручную установить параметры <code>limit</code> и <code>offset</code>.</p>
<p>Полностью метод, формирующий страницу с играми одного жанра выглядит так.</p>
<pre class="brush: php">public function actionShowGames()
{
	if (isset($_GET['type_id']) &#038;&#038; is_numeric($_GET['type_id'])) {
		$criteria = new CDbCriteria;

		$type = Types::model()-&gt;findByPk($_GET['type_id']);
		//нужно использовать "ленивую" загрузку (не использовать with)
		//иначе не получится указать limit для связанной таблицы
		$params = array(
			'limit'=&gt;self::PAGE_SIZE,
			'condition'=&gt;'g_state='.Games::PUBLISHED,
			'order'=&gt;'g_added DESC',
		);
		//настраиваем пагинацию
		if (isset($_GET['page']) &#038;&#038; is_numeric($_GET['page'])) {
			$params['offset'] = ($_GET['page'] - 1) * self::PAGE_SIZE;
		}
		$pages=new CPagination(count($type-&gt;getRelated('ygs_games')));
		$pages-&gt;pageSize=self::PAGE_SIZE;

		$games = $type-&gt;getRelated('ygs_games',false, $params);

		$this-&gt;render('showGames'
			,array('games'=&gt;$games, 'pages'=&gt;$pages));
	} else {
		$this-&gt;redirect('/games/list');
	}
}</pre>
<p>Обратите внимание на строки 16 и 18. В них мы устанавливаем смещение (<code>offset</code>) и создаём объект <code>CPagination</code>. Последнему передаём количество всех игр данного жанра. Для этого просто используем функцию count.</p>
<p>Если кому-то захочется поэкспериментировать, выкладываю архив с изменённым примером.</p>
<p><a href='http://www.simplecoding.org/wp-content/uploads/2010/05/yii_game_site_new.zip'><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/download_btn_blue.png" alt="архив с исходным кодом" /></a></p>
<p>Чтобы удобнее было сравнивать работу библиотеки, я не удалял старый код создания страниц с жанрами (GamesController.php метод <code>actionList</code>). Новый метод находится в контроллере TypesController.php (метод <code>actionShowGames</code>).</p>
<p>Если есть вопросы или замечания, пишите. Мне будет очень интересно обсудить эту тему <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/yii-php-framework-svyazannye-tablicy-i-limit.html/feed</wfw:commentRss>
		<slash:comments>25</slash:comments>
		</item>
		<item>
		<title>Изменения в Yii 1.1: CActiveDataProvider</title>
		<link>http://www.simplecoding.org/izmeneniya-v-yii-1-1-cactivedataprovider.html</link>
		<comments>http://www.simplecoding.org/izmeneniya-v-yii-1-1-cactivedataprovider.html#comments</comments>
		<pubDate>Sat, 20 Feb 2010 08:55:13 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>
		<category><![CDATA[Yii]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=999</guid>
		<description><![CDATA[Я всё-таки решил продолжить обсуждение фреймворка Yii. Но на этот раз затяжных циклов я не планирую , просто хочу рассказать о некоторых нововведениях в версиии 1.1. Как вы, наверное, знаете, версия 1.1 довольно сильно отличается от 1.0.х. Есть и инструкция по переходу на новую версию. Но есть момент, который может вызвать вопросы у тех, кто [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1000" class="wp-caption alignnone" style="width: 286px"><img src="http://www.simplecoding.org/wp-content/uploads/2010/02/yii_data_provider.png" alt="yii data provider" title="yii data provider" width="276" height="140" style="float:left" class="size-full wp-image-1000" /><p class="wp-caption-text"> </p></div>
<p>Я всё-таки решил продолжить обсуждение фреймворка <strong>Yii</strong>. Но на этот раз затяжных циклов я не планирую <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  , просто хочу рассказать о некоторых нововведениях в версиии 1.1.</p>
<p>Как вы, наверное, знаете, версия 1.1 довольно сильно <a href="http://yiiframework.ru/doc/guide/ru/changes">отличается</a> от 1.0.х. Есть и <a href="http://yiiframework.ru/doc/guide/ru/upgrade">инструкция по переходу</a> на новую версию.</p>
<p>Но есть момент, который может вызвать вопросы у тех, кто начинает знакомство с фреймворком с версии 1.1. Речь о классе <a href="http://www.yiiframework.com/doc/api/CActiveDataProvider">CActiveDataProvider</a>. Как несложно догадаться по названию, он предназначен для работы с базой данных. И если вы создадите сайт с помощью консольной утилиты <strong>yiic</strong>, то этот класс будет использован в методах <code>actionIndex</code> и <code>actionAdmin</code> контроллеров.</p>
<p>Класс очень удобный и позволяет сократить объём кода. Проблема в том, что <a href="http://yiiframework.ru/doc/guide/ru/index">документация</a> немного отстаёт от жизни. В разделе о работе с базой данных подробно рассказывается об использовании классов <code>CActiveRecord</code>, <code>CDbCriteria</code> и других, но информация о <code>CActiveDataProvider</code> есть только в <strong>API</strong>.</p>
<p>Итак, что представляет собой этот класс.<br />
<span id="more-999"></span><br />
По большому счёту это обёртка вокруг четырёх классов <code>CActiveRecord</code>, <code>CDbCriteria</code>, <code>CPagination</code> и <code>CSort</code>. Именно с их помощью выполняется основная работа с базой данных и очень часто все эти классы используются одновременно. Поэтому вполне логично, что разработчики решили создать общую оболочку для работы с ними.</p>
<p>Рассмотрим <strong>небольшой пример</strong>.</p>
<p>В версиях 1.0.х для вывода записей какой-нибудь таблицы с разбивкой на страницы (пагинацией) использовался следующий код.</p>
<pre class="brush: php">$criteria=new CDbCriteria;

$pages=new CPagination(Screenshots::model()->count($criteria));
$pages->pageSize=self::PAGE_SIZE;
$pages->applyLimit($criteria);

$sort=new CSort('Screenshots');
$sort->applyOrder($criteria);

$models=Screenshots::model()->findAll($criteria);

$this->render('admin',array(
	'models'=>$models,
	'pages'=>$pages,
	'sort'=>$sort,
));</pre>
<p>Обратите внимание, что здесь создаются экземпляры <code>CDbCriteria</code>, <code>CPagination</code> и <code>CSort</code>. При этом с помощью <code>CDbCriteria</code> мы можем изменять SQL запросы, которые создаёт модель (Screenshots). <code>CPagination</code> используется для настройки пагинации, а <code>CSort</code> – сортировки записей. Массив с объектами <code>CActiveRecord</code> возвращает метод <code>findAll</code> модели. Обратите внимание, что для настройки, которые хранятся в <code>CDbCriteria</code> используются всеми остальными классами. </p>
<p>Теперь взгляните на то, как решается эта же задача в версии 1.1.</p>
<pre class="brush: php">$dataProvider=new CActiveDataProvider('Screenshots', array(
	'pagination'=>array(
		'pageSize'=>self::PAGE_SIZE,
	),
));

$this->render('admin',array(
	'dataProvider'=>$dataProvider,
));</pre>
<p>Правда, значительно лучше выглядит? <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  Хотя, на самом деле, работает код точно также. Просто все экземпляры объектов <code>CPagination</code>, <code>CSort</code> и <code>CDbCriteria</code> находятся внутри <code>CActiveDataProvider</code>.</p>
<p>Обратите внимание, что в первом параметре конструктора мы передаём название модели, данные которой нужно получить. <code>CActiveDataProvider</code> сам вызовет соответствующие методы <code>find()</code> или <code>findAll()</code>.</p>
<p>Тут возникает вполне резонный вопрос: «Каким образом настраивать поиск, разбивку на страницы и т.п.?» Всё очень просто, нужно передать массив с соответствующими параметрами в конструкторе. Например.</p>
<pre class="brush: php">$dataProvider=new CActiveDataProvider('Post', array(
	'criteria'=>array(
		'condition'=>'status=1 AND tags LIKE :tags',
		'params'=>array(':tags'=>$_GET['tags']),
		'with'=>array('author'),
	),
	'pagination'=>array(
		'pageSize'=>20,
	),
));</pre>
<p>Как видите, настройки указываются точно так же, как и в предыдущих версиях (по большому счёту это они и есть). Т.е. вы можете спокойно использовать документацию по <code>CDbCriteria</code> при настройке <code>CActiveDataProvider</code>.</p>
<p>Кроме того, если возникнет необходимость, можно использовать методы <code>getCriteria()</code>, <code>setCriteria()</code>, <code>getSort()</code>, <code>setSort()</code> для чтения и установки соответствующих объектов.</p>
<p><strong>Передача данных в представление.</strong></p>
<p>Как несложно заметить по листингам, в версиях 1.0.х необходимо было передавать три параметра: с данными, настройками пагинации и сортировки. В новом варианте передаётся только один – сам объект <code>CActiveDataProvider</code>.</p>
<p>При этом если вы будете вручную вытягивать из него данные, код получится довольно объёмным. Но в версию 1.1 входят компоненты <a href="http://code.google.com/p/zii/">zii</a>, один из которых (<code>zii.widgets.grid.CGridView</code>) специально разработан для использования вместе с <code>CActiveDataProvider</code>. Т.е. вы передаёте ему экземпляр <code>CActiveDataProvider</code> и заголовки столбцов, а он на основе этих данных формирует таблицу.</p>
<p>Как видите, <code>CActiveDataProvider</code> принципиально новых возможностей не добавляет, но количество кода, который вы должны написать, <strong>сокращается значительно</strong>. И при этом не нужно привыкать к новой библиотеке.</p>
<p><strong>Интересно почитать</strong></p>
<p><a href="http://bormaley.com/">Раскрутка сайта</a> занятие увлекательное, но ошибки обойдутся недёшево.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/izmeneniya-v-yii-1-1-cactivedataprovider.html/feed</wfw:commentRss>
		<slash:comments>26</slash:comments>
		</item>
		<item>
		<title>Yii PHP framework: создаём игровой сайт. Часть 9. Поиск ошибок.</title>
		<link>http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-8-poisk-oshibok.html</link>
		<comments>http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-8-poisk-oshibok.html#comments</comments>
		<pubDate>Thu, 04 Feb 2010 11:12:15 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>
		<category><![CDATA[Yii]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=992</guid>
		<description><![CDATA[В этой части цикла мы рассмотрим некоторые возможности, которые предоставляет нам Yii фреймворк для отладки приложения. Сразу хочу предупредить, эта статья не претендует на полноту. Я расскажу только от тех инструментах, которые использовал при разработке игрового сайта. Более подробную информацию можно найти в разделе Журналирование и Обработка ошибок. Включаем режим отладки Для этого во входном [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_993" class="wp-caption alignnone" style="width: 247px"><img src="http://www.simplecoding.org/wp-content/uploads/2010/02/yii_game_site_bugs.png" alt="yii game site bugs" title="yii game site bugs" width="237" height="133" class="size-full wp-image-993" style="float:left" /><p class="wp-caption-text"> </p></div>
<p>В этой части цикла мы рассмотрим некоторые возможности, которые предоставляет нам Yii фреймворк для отладки приложения.</p>
<p>Сразу хочу предупредить, эта статья не претендует на полноту. Я расскажу только от тех инструментах, которые использовал при разработке игрового сайта. Более подробную информацию можно найти в разделе <a href="http://www.yiiframework.ru/doc/guide/ru/topics.logging">Журналирование</a> и <a href="http://www.yiiframework.ru/doc/guide/ru/topics.error">Обработка ошибок</a>.</p>
<p><strong>Включаем режим отладки</strong><br />
<span id="more-992"></span><br />
Для этого во входном скрипте (файл <code>index.php</code>, который находится в корневой папки сайта) константе <code>YII_DEBUG</code> должно быть присвоено значение true.</p>
<pre class="brush: php">defined('YII_DEBUG') or define('YII_DEBUG',true);</pre>
<p>Если для создания приложения вы использовали консольную утилиту <strong>yiic</strong>, то эта строка у вас уже есть. Важно удалить её при переносе на рабочий сервер. Иначе при возникновении ошибок, фреймворк будет показывать посетителям подробные их описания.</p>
<p>Кстати, эти описания сделаны очень неплохо. Вы увидите не только номер, название ошибки и содержимое стека, но и фрагмент кода в котором она возникла (нужная строка будет подсвечена).</p>
<p><strong>Включаем журналирование ошибок</strong></p>
<p>Тут все настройки выполняются в конфигурационном файле (<code>protected/config/main.php</code>). Фреймворк предлагает нам несколько вариантов ведения лога. Это запись в файл, вывод на экран, запись в базу данных, отправка по eMail.</p>
<p>За ведения лога отвечает компонент приложения <code>CLogRouter</code>. Подключаем и настраиваем его.</p>
<pre class="brush: php">'components'=&gt;array(
…
	'log'=&gt;array(
		'class'=&gt;'CLogRouter',
		'routes'=&gt;array(
			array(
				//выводим лог внизу страницы
				'class'=&gt;'CWebLogRoute',
				'levels'=&gt;'trace, info, profile',
			),
		),
	),
…
),</pre>
<p>В массиве <code>components</code> мы создали элемент под названием <code>log</code> и присвоили ему массив с настройками. В элементе <code>class</code> указываем название класса, который отвечает за работу компонента. В данном случае это <code>CLogRouter</code>.</p>
<p>Затем настраиваем маршрутизацию (<code>routes</code>). Именно здесь мы определяем куда какие сообщения будут выведены.</p>
<p>В данном случае использован класс <code>CWebLogRoute</code> это означает, что лог будет добавлен внизу страницы сайта.</p>
<p>Параметр <code>levels</code> определяет, что будут выведены сообщения имеющие уровень <code>trace</code>, <code>info</code> или <code>profile</code>. Всего существует пять уровней сообщений: <code>trace</code>, <code>info</code>, <code>profile</code>, <code>warning</code>, <code>error</code>. И с их помощью вы можете отфильтровать ненужную в данный момент информацию.</p>
<p>При переносе на рабочий сервер <strong>эти настройки очень желательно изменить</strong>. Например, можно использовать классы <code>CFileLogRoute</code> и <code>CEmailLogRoute</code> для записи сообщений в файл и одновременной отправки по eMail. Но во время отладки, лично мне удобнее просто прокрутить страницу и посмотреть сообщения, чем лезть в файл.</p>
<p>Для отправки своих сообщений можно использовать методы</p>
<pre class="brush: php">Yii::log($message, $level, $category);
Yii::trace($message, $category);</pre>
<p>Учтите, что метод trace работает только в режиме отладки. В параметре $message нужно указать текст сообщения, <code>$level</code> – уровень, <code>$category</code> – категория к которой относится сообщение (по-умолчанию равна <code>application</code>, но вы можете указать строку в формате <code>xxx.yyy.zzz</code>, например, <code>system.web.CController</code>, в результате сообщение будет добавляться в лог <code>CController</code>).</p>
<p>В нашем примере внизу страницы появится таблица с системными сообщениями. Вы сможете посмотреть какие компоненты и в каком порядке создавались при формировании страницы.</p>
<p><strong>Отладка запросов к БД</strong></p>
<p>В состав Yii фреймворка входит хорошая библиотека для работы с базой данных. Тем не менее, полезно знать какие именно <strong>SQL запросы</strong> она формирует. Особенно, если у вас нет предварительного опыта работы с ней.</p>
<p>Для того, чтобы включить вывод запросов в лог, необходимо указать параметр <code>'enableParamLogging'=&gt;true</code> в настройках базы.</p>
<pre class="brush: php">'db'=&gt;array(
…
	'enableParamLogging'=&gt;true,
	'enableProfiling'=&gt;true,
…
),</pre>
<p>Кроме того, полезно тут же включить профайлинг работы с базой. Это позволит узнать сколько запросов было выполнено при формировании страницы и время их выполнения.</p>
<p>Для того, чтобы вывести результаты профайлинга открываем макет страницы (<code>protected/views/layouts/main.php</code>) и добавляем в хвостовик пару строчек</p>
<pre class="brush: php">$dbStats = Yii::app()-&gt;db-&gt;getStats();
echo 'Выполнено запросов: '.$dbStats[0].' (за '.round($dbStats[1], 5).' сек)';</pre>
<p>Как видите, мы получили массив в первом элементе которого хранится общее количество запросов, а во втором – время их выполнения.</p>
<p><strong>Выводим информацию об использовании ресурсов</strong></p>
<p>Эти данные мы тоже выведем в хвостовике страницы</p>
<pre class="brush: php">$memory = round(Yii::getLogger()-&gt;memoryUsage/1024/1024, 3);
$time = round(Yii::getLogger()-&gt;executionTime, 3);
echo '&lt;br /&gt;Использовано памяти: '.$memory.' МБ&lt;br /&gt;';
echo 'Время выполнения: '.$time.' с&lt;br /&gt;';</pre>
<p>Для получения этой информации мы использовали класс <a href="http://www.yiiframework.com/doc/api/CLogger">CLogger</a>. Он содержит два нужных нам метода: <code>memoryUsage</code> (возвращает объём использованной памяти, в байтах) и <code>executionTime</code> – время создания страницы.</p>
<p>Как видите, ничего сложного. Если возникли вопросы или есть замечания, пишите, постараюсь ответить <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><strong>Все разделы цикла.</strong></p>
<ol style="font-size:80%">
<li><a href="http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-1-postanovka-zadachi.html" rel="bookmark" title="Ссылка на &quot;Yii PHP framework: создаём игровой сайт. Часть 1. Постановка задачи.&quot;">Yii PHP framework: создаём игровой сайт. Часть 1. Постановка задачи.</a></li>
<li><a href="http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-2-baza-dannyx-i-ustanovka-frejmvorka.html" rel="bookmark" title="Ссылка на &quot;Yii PHP framework: создаём игровой сайт. Часть 2. База данных и установка фреймворка.&quot;">Yii PHP framework: создаём игровой сайт. Часть 2. База данных и установка фреймворка.</a></li>
<li><a href="http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-3-autentifikaciya.html" rel="bookmark" title="Ссылка на &quot;Yii PHP framework: создаём игровой сайт. Часть 3. Аутентификация.&quot;">Yii PHP framework: создаём игровой сайт. Часть 3. Аутентификация.</a></li>
<li><a href="http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-4-rabota-s-zhanrami-igr.html" rel="bookmark" title="Ссылка на &quot;Yii PHP framework: создаём игровой сайт. Часть 4. Работа с жанрами игр.&quot;">Yii PHP framework: создаём игровой сайт. Часть 4. Работа с жанрами игр.</a></li>
<li><a href="http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-5-import-igr.html" rel="bookmark" title="Ссылка на &quot;Yii PHP framework: создаём игровой сайт. Часть 5. Импорт игр.&quot;">Yii PHP framework: создаём игровой сайт. Часть 5. Импорт игр.</a></li>
<li><a href="http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-6-formiruem-stranicy-igr-i-zhanrov.html" rel="bookmark" title="Ссылка на &quot;Yii PHP framework: создаём игровой сайт. Часть 6. Формируем страницы игр и жанров.&quot;">Yii PHP framework: создаём игровой сайт. Часть 6. Формируем страницы игр и жанров.</a></li>
<li><a href="http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-7-rabota-s-javascript-i-stranicy-igr.html" rel="bookmark" title="Ссылка на &quot;Yii PHP framework: создаём игровой сайт. Часть 7. Работа с JavaScript и страницы игр.&quot;">Yii PHP framework: создаём игровой сайт. Часть 7. Работа с JavaScript и страницы игр.</a></li>
<li><a href="http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-8-sozdayom-vidzhety.html" rel="bookmark" title="Ссылка на &quot;Yii PHP framework: создаём игровой сайт. Часть 8. Создаём виджеты.&quot;">Yii PHP framework: создаём игровой сайт. Часть 8. Создаём виджеты.</a></li>
<li><a href="http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-8-poisk-oshibok.html" rel="bookmark" title="Ссылка на &quot;Yii PHP framework: создаём игровой сайт. Часть 9. Поиск ошибок.&quot;">Yii PHP framework: создаём игровой сайт. Часть 9. Поиск ошибок.</a></li>
<li><a href="http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-10-panel-upravleniya.html" rel="bookmark" title="Ссылка на &quot;Yii PHP framework: создаём игровой сайт. Часть 10. Панель управления.&quot;">Yii PHP framework: создаём игровой сайт. Часть 10. Панель управления.</a></li>
<li><a href="http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-11-chelovekoponyatnye-url.html" rel="bookmark" title="Ссылка на &quot;Yii PHP framework: создаём игровой сайт. Часть 11. Человекопонятные URL.&quot;">Yii PHP framework: создаём игровой сайт. Часть 11. Человекопонятные URL.</a></li>
<li><a href="http://www.simplecoding.org/wp-content/uploads/2010/01/yii_game_site.zip">Архив с исходниками</a></li>
</ol>
<p><strong>Интересно почитать</strong></p>
<p><a href="http://devicecollection.com/vybiraem-sistemu-oxlazhdeniya-dlya-pk.html">Выбираем систему охлаждения для ПК</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-8-poisk-oshibok.html/feed</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Yii PHP framework: создаём игровой сайт. Часть 8. Создаём виджеты.</title>
		<link>http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-8-sozdayom-vidzhety.html</link>
		<comments>http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-8-sozdayom-vidzhety.html#comments</comments>
		<pubDate>Sat, 30 Jan 2010 13:16:10 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>
		<category><![CDATA[Yii]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=989</guid>
		<description><![CDATA[В этой части мы поговорим о том, какие средства предоставляет Yii для создания виджетов. Если верить википедии, виджет (widget) – это &#034;контент модуль, который встраивается в веб-страницу или браузер&#034; (вообще, это не совсем точно, в википедии есть несколько определений). Правда здесь может возникнуть небольшая путаница в терминологии. Дело в том, что некоторые CMS (WordPress, например) [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_990" class="wp-caption alignnone" style="width: 272px"><img src="http://www.simplecoding.org/wp-content/uploads/2010/01/yii_game_site_widgets.png" alt="yii_game_site_widgets" title="yii_game_site_widgets" width="262" height="134" style="float:left" class="size-full wp-image-990" /><p class="wp-caption-text"> </p></div>
<p>В этой части мы поговорим о том, какие средства предоставляет <strong>Yii</strong> для создания <strong>виджетов</strong>. Если верить википедии, <strong>виджет</strong> (<strong>widget</strong>) – это &#034;контент модуль, который встраивается в веб-страницу или браузер&#034; (вообще, это не совсем точно, в википедии есть несколько определений).</p>
<p>Правда здесь может возникнуть небольшая путаница в терминологии. Дело в том, что некоторые CMS (<strong>WordPress</strong>, например) используют термин виджет для обозначения особых плагинов, которые предназначены для отображения блоков с информацией в сайдбаре. Но сейчас нас интересует <strong>Yii PHP framework</strong>, поэтому мы будем считать виджетами объекты, которые наследуют класс <a href="http://www.yiiframework.com/doc/api/CWidget">CWidget</a>.</p>
<p>Обычно виджеты используют для отображения какого-нибудь контента, который не зависит от основного содержимого страницы. Например, это может быть форма входа, перечень жанров игр, блок со случайными скриншотами, ссылки на страницы архива и т.п.</p>
<p>Для нас важно, что <code>CWidget</code> имеет особенность. Он является потомком класса <code>CComponent</code>, и, следовательно, является компонентом.</p>
<p>Рассмотрим, как создаются компоненты в фреймворке <strong>Yii</strong>.<br />
<span id="more-989"></span><br />
<strong>Шаг 1. </strong>В папке <code>protected/components</code> создаём файл с классом компонента. Этот класс выполняет инициализацию компонента и подготовку данных (например, чтение из БД).</p>
<p><strong>Шаг 2.</strong> В папке <code>protected/components/views</code> создаём файл с представлением компонента. По-сути это шаблон, который используется для отображения содержимого компонента.</p>
<p><strong>Шаг 3.</strong> Добавляем компонент в макет (layout) нужных страниц сайта. Макеты находятся в папке <code>protected/views/layouts</code>.</p>
<p>Теперь рассмотрим конкретный пример. <strong>Создадим виджет, содержащий ссылки на страницы жанров игр.</strong></p>
<p>Назовём класс <code>TypesMenu</code>.</p>
<p>Создаём файл <code>protected/components/TypesMenu.php</code>.</p>
<pre class="brush: php">class TypesMenu extends CWidget {
	public function run() {
		$types = Types::model()-&gt;findAll();

		$this-&gt;render('typesMenu',array('types'=&gt;$types));
	}
}</pre>
<p>Как видите, класс содержит один метод (<code>run</code>), который будет вызван фреймворком при создании виджета.</p>
<p>В этом методе мы получаем список всех жанров игр (строка 3) и результат передаём представлению (строка 5).</p>
<p>Создаём представление (файл <code>protected/components/views/typesMenu.php</code>).</p>
<pre class="brush: php">&lt;h2&gt;Жанры&lt;/h2&gt;
&lt;ul&gt;
&lt;?php
foreach ($types as $type) {
	//каждый пункт списка - ссылка на страницу с играми данного жанра
	//жанр указывается с помощью параметра в get запросе - type_id
	echo '&lt;li&gt;'.CHtml::link($type-&gt;t_name, array('games/list', 'type_id'=&gt;$type-&gt;t_id)).'&lt;/li&gt;';
}
?&gt;
&lt;/ul&gt;</pre>
<p>Обратите внимание, у нас доступна переменная <code>$types</code>. (её название мы указали при загрузке представления, метод <code>render</code>).</p>
<p>Сами ссылки создаём с помощью метода <code>CHtml::link</code>. В первом параметре указываем текст ссылки, а во втором – массив с параметрами. В данном случае будут созданы url вида<br />
<code>http://yiigame.domen/index.php?r=games/list&#038;type_id=1</code><br />
где <code>type_id</code> – id соответствующего жанра.</p>
<p>Вставляем виджет в макет страницы. Для этого в файл <code>protected/views/layouts/main.php</code> добавляем следующий код.</p>
<pre class="brush: php">&lt;div class="menu"&gt;
&lt;?php $this-&gt;widget('application.components.TypesMenu'); ?&gt;
&lt;/div&gt;&lt;!-- menu --&gt;</pre>
<p>Посмотрите, как указано имя виджета. Перед названием файла виджета (без расширения) мы добавляем <code>application.components</code>, проще говоря, указываем путь к виджету.</p>
<p>Всё, <strong>мы получили работающий виджет</strong>, правда, самый примитивный. Давайте рассмотрим вариант немного посложнее.</p>
<p>На некоторых страницах сайта нам нужно выводить <strong>список с самыми популярными записями</strong>.</p>
<p>Популярность игры мы можем определить, используя поле <code>g_rate</code> (таблица <code>ygs_games</code>), т.е. нам нужно будет при поиске игр в базе просто отсортировать их по этому полю.</p>
<p>Показывать виджет нам нужно на страницах с общим перечнем игр и страницах отдельных жанров. И те, и другие страницы формирует метод <code>actionList</code> (класс <code>GamesController</code>). Но на страницах жанров мы будем показывать топ игр, которые относятся к данному жанру, а не все подряд, т.е. в наш запрос нужно будет добавить дополнительное условие.</p>
<p>Если задача ясна, приступаем.</p>
<p>Создаём файл виджета <code>protected/components/TopGames.php</code>.</p>
<pre class="brush: php">class TopGames extends CWidget {

	public $title = 'Популярные игры';
	public $showOn = array();
	public $count = 10;

	public function run() {
		//определяем название контроллера и метода (action)
		$controller = Yii::app()-&gt;controller-&gt;id;
		$action = Yii::app()-&gt;controller-&gt;action-&gt;id;
		//проверяем нужно ли показывать виджет
		if (!in_array($controller.'/'.$action, $this-&gt;showOn)) {
			return;
		}
		//проверяем, нужно ли выводить игры только данного жанра
		if (isset($_GET['type_id'])) {
			$id = $_GET['type_id'];
			$params = array('limit'=&gt;$this-&gt;count,'order'=&gt;'g_rate DESC'
				,'condition'=&gt;'t_id=:id'
				,'params'=&gt;array(':id'=&gt;$id));
			//ищем игры
			$games = Games::model()-&gt;getTopGames($params)-&gt;published()-&gt;with('ygs_types')-&gt;findAll();
		} else {
			$params = array('limit'=&gt;$this-&gt;count,'order'=&gt;'g_rate DESC');
			//ищем игры
			$games = Games::model()-&gt;getTopGames($params)-&gt;published()-&gt;findAll();
		}

		//заполняем массивы с жанрами игр для каждой найденной игры
		//для этого раскодируем поле g_type
		foreach ($games as $key=&gt;$game) {
			$games[$key]-&gt;g_types = Yii::app()-&gt;controller-&gt;_decodeTypes($game-&gt;g_type);
		}
		//показываем виджет
		$this-&gt;render('topGames'
			, array('title'=&gt;$this-&gt;title, 'games'=&gt;$games));
	}
}</pre>
<p>Прежде всего, обратите внимание на три свойства класса <code>$title</code>, <code>$showOn</code> и <code>$count</code>. Фреймворк позволяет указывать значения для всех отрытых (public) свойств виджета при его создании, т.е. в макете (layout) мы можем задать значения для этих свойств. Таким образом, появляется возможность изменять вид виджета, не трогая его код.</p>
<p>В данном случае в свойстве <code>$title</code> мы указываем заголовок виджета, в свойстве <code>$showOn</code> – массив с перечнем страниц, на которых он должен отображаться, а в свойстве <code>$count</code> – количество игр.</p>
<p>Рассмотрим метод <code>run</code>.</p>
<p>Прежде всего, определяем название контроллера и метода (action) (строки 9, 10). И проверяем, нужно ли показывать виджет. Страницы, на которых нужно отображать виджет указываются в формате «название_контроллера/название_метода». Если массив <code>$showOn</code> не содержит подходящего элемента, мы завершаем работу виджета.</p>
<p>В противном случае, мы:</p>
<p>1) Проверяем, является ли эта страница, страницей жанра (получен параметр <code>$_GET['type_id']</code> или нет). Если получен, формируем запрос, при этом в его параметрах мы указываем, что нам нужны игры только текущего жанра.</p>
<p>2) Если мы находимся на странице с общим перечнем игр, то просто получаем игры, отсортированные по полю <code>g_rate</code>.</p>
<p>Обратите внимание на метод <code>getTopGames($params)</code>. Он объявлен в модели (<code>Games</code>) и нужен только для того, чтобы немного сократить запись запроса.</p>
<pre class="brush: php">public function getTopGames($params) {
	$this-&gt;getDbCriteria()-&gt;mergeWith($params);
	return $this;
}</pre>
<p><em>Примечание</em>. Использовать его не обязательно. Можно было просто создать объект <code>CDbCriteria</code>, как мы и делали в предыдущих частях, но я хотел попробовать разные варианты работы.</p>
<p>3) Расшифровываем поле с перечнем жанров (эту операцию мы рассматривали в предыдущих частях).</p>
<p>4) Показываем представление при этом передаём ему заголовок виджета и данные игр.</p>
<p>Само представление выглядит так (файл <code>protected/components/view/topGames.php</code>).</p>
<pre class="brush: php">&lt;h1&gt;&lt;?php echo $title; ?&gt;&lt;/h1&gt;

&lt;?php
$i = 0;
foreach($games as $n=&gt;$model) {
	//шаблон для вывода игры находится в views/games/_short_desc.php
	$this-&gt;controller-&gt;renderPartial('_short_desc', array('game'=&gt;$model));
	if ($i % 2 !== 0) {
		echo '&lt;div class="clear"&gt;&lt;/div&gt;';
	}
	$i++;
}
?&gt;</pre>
<p>Как видите, для вывода игры мы использовали представление, которое относится к контроллеру <code>Games</code> (<code>views/games/_short_desc.php</code>).</p>
<p>Последний шаг – подключение шаблона в макете (файл <code>protected/views/layouts/main.php</code>)</p>
<pre class="brush: php">&lt;div id="top_games" class="grid_9"&gt;
&lt;?php $this-&gt;widget('application.components.TopGames'
	, array('title'=&gt;'Популярные игры'
		,'showOn'=&gt;array('games/list','types/show')
		,'count'=&gt;4)); ?&gt;
&lt;/div&gt;&lt;!-- top_games --&gt;</pre>
<p>Тут стоит отметить <strong>передачу параметров виджету</strong>. Они должны быть записаны в виде массива. При этом, ключ элемента должен совпадать с именем соответствующего свойства класса.</p>
<p>На этом мы остановимся. Думаю, общее представление о виджетах у вас появилось. Но в этой статье рассмотрены далеко не все их возможности, поэтому очень советую почитать соответствующий <a href="http://yiiframework.ru/doc/guide/ru/basics.view">раздел справки</a>.</p>
<p>Продолжение следует <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><strong>Все разделы цикла.</strong></p>
<ol style="font-size:80%">
<li><a href="http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-1-postanovka-zadachi.html" rel="bookmark" title="Ссылка на &quot;Yii PHP framework: создаём игровой сайт. Часть 1. Постановка задачи.&quot;">Yii PHP framework: создаём игровой сайт. Часть 1. Постановка задачи.</a></li>
<li><a href="http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-2-baza-dannyx-i-ustanovka-frejmvorka.html" rel="bookmark" title="Ссылка на &quot;Yii PHP framework: создаём игровой сайт. Часть 2. База данных и установка фреймворка.&quot;">Yii PHP framework: создаём игровой сайт. Часть 2. База данных и установка фреймворка.</a></li>
<li><a href="http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-3-autentifikaciya.html" rel="bookmark" title="Ссылка на &quot;Yii PHP framework: создаём игровой сайт. Часть 3. Аутентификация.&quot;">Yii PHP framework: создаём игровой сайт. Часть 3. Аутентификация.</a></li>
<li><a href="http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-4-rabota-s-zhanrami-igr.html" rel="bookmark" title="Ссылка на &quot;Yii PHP framework: создаём игровой сайт. Часть 4. Работа с жанрами игр.&quot;">Yii PHP framework: создаём игровой сайт. Часть 4. Работа с жанрами игр.</a></li>
<li><a href="http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-5-import-igr.html" rel="bookmark" title="Ссылка на &quot;Yii PHP framework: создаём игровой сайт. Часть 5. Импорт игр.&quot;">Yii PHP framework: создаём игровой сайт. Часть 5. Импорт игр.</a></li>
<li><a href="http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-6-formiruem-stranicy-igr-i-zhanrov.html" rel="bookmark" title="Ссылка на &quot;Yii PHP framework: создаём игровой сайт. Часть 6. Формируем страницы игр и жанров.&quot;">Yii PHP framework: создаём игровой сайт. Часть 6. Формируем страницы игр и жанров.</a></li>
<li><a href="http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-7-rabota-s-javascript-i-stranicy-igr.html" rel="bookmark" title="Ссылка на &quot;Yii PHP framework: создаём игровой сайт. Часть 7. Работа с JavaScript и страницы игр.&quot;">Yii PHP framework: создаём игровой сайт. Часть 7. Работа с JavaScript и страницы игр.</a></li>
<li><a href="http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-8-sozdayom-vidzhety.html" rel="bookmark" title="Ссылка на &quot;Yii PHP framework: создаём игровой сайт. Часть 8. Создаём виджеты.&quot;">Yii PHP framework: создаём игровой сайт. Часть 8. Создаём виджеты.</a></li>
<li><a href="http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-8-poisk-oshibok.html" rel="bookmark" title="Ссылка на &quot;Yii PHP framework: создаём игровой сайт. Часть 9. Поиск ошибок.&quot;">Yii PHP framework: создаём игровой сайт. Часть 9. Поиск ошибок.</a></li>
<li><a href="http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-10-panel-upravleniya.html" rel="bookmark" title="Ссылка на &quot;Yii PHP framework: создаём игровой сайт. Часть 10. Панель управления.&quot;">Yii PHP framework: создаём игровой сайт. Часть 10. Панель управления.</a></li>
<li><a href="http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-11-chelovekoponyatnye-url.html" rel="bookmark" title="Ссылка на &quot;Yii PHP framework: создаём игровой сайт. Часть 11. Человекопонятные URL.&quot;">Yii PHP framework: создаём игровой сайт. Часть 11. Человекопонятные URL.</a></li>
<li><a href="http://www.simplecoding.org/wp-content/uploads/2010/01/yii_game_site.zip">Архив с исходниками</a></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-8-sozdayom-vidzhety.html/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Управление jqGrid с помощью поля с автозавершением</title>
		<link>http://www.simplecoding.org/upravlenie-jqgrid-s-pomoshhyu-polya-s-avtozaversheniem.html</link>
		<comments>http://www.simplecoding.org/upravlenie-jqgrid-s-pomoshhyu-polya-s-avtozaversheniem.html#comments</comments>
		<pubDate>Tue, 17 Nov 2009 14:26:50 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=943</guid>
		<description><![CDATA[Сегодня я продолжу рассказывать о плагине jqGrid и покажу еще один пример его использования. Если не ошибаюсь, это уже 5-ый пост об этом плагине, поэтому я не буду останавливаться на его установке и настройке. Лучше приведу ссылки на предыдущие части: 1) Query Grid Plugin – &#034;продвинутое&#034; решение для создания таблиц 2) jqGrid: редактирование табличных данных [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_944" class="wp-caption alignnone" style="width: 310px"><img src="http://www.simplecoding.org/wp-content/uploads/2009/11/jqGrid_autocomplete.png" alt="jqGrid_autocomplete" title="jqGrid_autocomplete" width="300" height="175" class="size-full wp-image-944" style="float:left" /><p class="wp-caption-text"> </p></div>
<p>Сегодня я продолжу рассказывать о плагине <strong>jqGrid</strong> и покажу еще один пример его использования.</p>
<p>Если не ошибаюсь, это уже 5-ый пост об этом плагине, поэтому я не буду останавливаться на его установке и настройке. Лучше приведу <strong>ссылки на предыдущие части</strong>:</p>
<p>1) <a href="http://www.simplecoding.org/jquery-grid-plugin-prodvinutoe-reshenie-dlya-sozdaniya-tablic.html">Query Grid Plugin – &#034;продвинутое&#034; решение для создания таблиц</a></p>
<p>2) <a href="http://www.simplecoding.org/jqgrid-redaktirovanie-tablichnyx-dannyx-s-pomoshhyu-inline-redaktorov.html">jqGrid: редактирование табличных данных с помощью inline редакторов</a></p>
<p>3) <a href="http://www.simplecoding.org/jqgrid-sozdanie-dopolnitelnyx-knopok.html">jqGrid – создание дополнительных кнопок</a></p>
<p>4) <a href="http://www.simplecoding.org/jqgrid-poisk-dannyx.html">jqGrid – поиск данных</a></p>
<p>Но для тех, кто их не читал, кратко поясню, о чем вообще речь.</p>
<p><strong>jqGrid</strong> – это плагин для библиотеки <strong>jQuery</strong>, предназначенный для работы с табличными данными. Он поддерживает кучу полезных возможностей вроде разбивки данных на страницы, поиска, добавления, удаления, редактирования записей и т.п.</p>
<p>Естественно, у плагина очень много настроек и вариантов использования, но это не означает, что их хватит на все случаи жизни <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Например, раньше я рассказывал об использовании <a href="http://www.simplecoding.org/jqgrid-poisk-dannyx.html">встроенной формы поиска jqGrid</a>. Но иногда удобнее использовать <strong>отдельную форму, содержащую поля с автозавершением</strong>. Под ними по мере набора слова будут появляться варианты, а когда посетитель выберет один из них, то автоматически обновиться таблица с данными.</p>
<p>Как это работает, вы можете посмотреть на демо-страничке</p>
<p><a href="http://demosites.simplecoding.org/jqgridautocomplete/"><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/demo_btn_green.png" alt="демонстрационный пример" /></a></p>
<p>либо скачать архив с примером и установить его на своем сервере</p>
<p><a href='http://www.simplecoding.org/wp-content/uploads/2009/11/jqgrid_autocomplete.zip'><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/download_btn_blue.png" alt="архив с исходным кодом" /></a></p>
<p>Реализовать такую систему не сложно.<br />
<span id="more-943"></span><br />
Потребуются:</p>
<p>1) Библиотека <a href="http://jquery.com/">jQuery</a>.</p>
<p>2) Плагин <a href="http://www.trirand.com/blog/">jqGrid</a>.</p>
<p>3) Плагин для создания поля с автозаполением. Я выбрал <a href="http://www.devbridge.com/projects/autocomplete/jquery/">Ajax AutoComplete for jQuery</a>.</p>
<p>Теперь рассмотрим сам пример.</p>
<p><strong>1) Клиентская часть.</strong> Тут нам нужно создать только страничку с таблицей и формой, которая содержит поле с автозаполнением (index.html).</p>
<blockquote style="white-space: nowrap; overflow:auto; margin: 10px 0 10px 0; border: dotted 1px #aeaeae; background-color: #f0f0f0;"><p><code><font size="2" face="Courier New" color="black">
<ol>
<li><font color="#0000ff">&#60;!</font><font color="#800000">DOCTYPE</font> <font color="#ff0000">html</font> <font color="#ff0000">PUBLIC</font> <font color="#0000ff">"-//W3C//DTD XHTML 1.1//EN"</font> <font color="#0000ff">"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"</font><font color="#0000ff">&#62;</font></li>
<li><font color="#0000ff">&#60;</font><font color="#800000">html</font> <font color="#ff0000">xmlns</font><font color="#0000ff">="http://www.w3.org/1999/xhtml"</font> <font color="#ff0000">xml:lang</font><font color="#0000ff">="en"</font><font color="#0000ff">&#62;</font></li>
<li>&nbsp;</li>
<li><font color="#0000ff">&#60;</font><font color="#800000">head</font><font color="#0000ff">&#62;</font></li>
<li>&nbsp;&nbsp;<font color="#0000ff">&#60;</font><font color="#800000">title</font><font color="#0000ff">&#62;</font>jqGrid + Autocomplete<font color="#0000ff">&#60;/</font><font color="#800000">title</font><font color="#0000ff">&#62;</font></li>
<li>&nbsp;</li>
<li>&nbsp;&nbsp;<font color="#0000ff">&#60;</font><font color="#800000">meta</font> <font color="#ff0000">http-equiv</font><font color="#0000ff">="content-type"</font> <font color="#ff0000">content</font><font color="#0000ff">="text/html;charset=utf-8"</font> <font color="#0000ff">/&#62;</font></li>
<li>&nbsp;&nbsp;<font color="#0000ff">&#60;</font><font color="#800000">meta</font> <font color="#ff0000">http-equiv</font><font color="#0000ff">="Content-Style-Type"</font> <font color="#ff0000">content</font><font color="#0000ff">="text/css"</font> <font color="#0000ff">/&#62;</font></li>
<li>&nbsp;</li>
<li>&nbsp;&nbsp;<font color="#0000ff">&#60;</font><font color="#800000">link</font> <font color="#ff0000">rel</font><font color="#0000ff">="stylesheet"</font> <font color="#ff0000">type</font><font color="#0000ff">="text/css"</font> <font color="#ff0000">media</font><font color="#0000ff">="screen"</font> <font color="#ff0000">href</font><font color="#0000ff">="css/reset.css"</font> <font color="#0000ff">/&#62;</font></li>
<li>&nbsp;&nbsp;<font color="#0000ff">&#60;</font><font color="#800000">link</font> <font color="#ff0000">rel</font><font color="#0000ff">="stylesheet"</font> <font color="#ff0000">type</font><font color="#0000ff">="text/css"</font> <font color="#ff0000">media</font><font color="#0000ff">="screen"</font> <font color="#ff0000">href</font><font color="#0000ff">="css/smoothness/jquery-ui-1.7.2.custom.css"</font> <font color="#0000ff">/&#62;</font></li>
<li>&nbsp;&nbsp;<font color="#0000ff">&#60;</font><font color="#800000">link</font> <font color="#ff0000">rel</font><font color="#0000ff">="stylesheet"</font> <font color="#ff0000">type</font><font color="#0000ff">="text/css"</font> <font color="#ff0000">media</font><font color="#0000ff">="screen"</font> <font color="#ff0000">href</font><font color="#0000ff">="css/ui.jqgrid.css"</font> <font color="#0000ff">/&#62;</font></li>
<li>&nbsp;&nbsp;<font color="#0000ff">&#60;</font><font color="#800000">link</font> <font color="#ff0000">rel</font><font color="#0000ff">="stylesheet"</font> <font color="#ff0000">type</font><font color="#0000ff">="text/css"</font> <font color="#ff0000">media</font><font color="#0000ff">="screen"</font> <font color="#ff0000">href</font><font color="#0000ff">="css/styles.css"</font> <font color="#0000ff">/&#62;</font></li>
<li><font color="#0000ff">&#60;/</font><font color="#800000">head</font><font color="#0000ff">&#62;</font></li>
<li><font color="#0000ff">&#60;</font><font color="#800000">body</font><font color="#0000ff">&#62;</font></li>
<li><font color="#0000ff">&#60;</font><font color="#800000">div</font> <font color="#ff0000">id</font><font color="#0000ff">="container"</font><font color="#0000ff">&#62;</font></li>
<li>&nbsp;&nbsp;<font color="#0000ff">&#60;</font><font color="#800000">h1</font><font color="#0000ff">&#62;</font>jqGrid + Autocomplete<font color="#0000ff">&#60;/</font><font color="#800000">h1</font><font color="#0000ff">&#62;</font></li>
<li>&nbsp;&nbsp;</li>
<li>&nbsp;&nbsp;<font color="#0000ff">&#60;</font><font color="#800000">table</font> <font color="#ff0000">id</font><font color="#0000ff">="list"</font><font color="#0000ff">&#62;&#60;/</font><font color="#800000">table</font><font color="#0000ff">&#62;</font> </li>
<li>&nbsp;&nbsp;<font color="#0000ff">&#60;</font><font color="#800000">div</font> <font color="#ff0000">id</font><font color="#0000ff">="pager"</font><font color="#0000ff">&#62;&#60;/</font><font color="#800000">div</font><font color="#0000ff">&#62;</font></li>
<li>&nbsp;&nbsp;</li>
<li>&nbsp;&nbsp;<font color="#0000ff">&#60;</font><font color="#800000">form</font> <font color="#ff0000">action</font><font color="#0000ff">="#"</font> <font color="#ff0000">method</font><font color="#0000ff">="post"</font> <font color="#ff0000">id</font><font color="#0000ff">="autocomplete_form"</font><font color="#0000ff">&#62;</font></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">&#60;</font><font color="#800000">p</font><font color="#0000ff">&#62;</font></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">&#60;</font><font color="#800000">label</font> <font color="#ff0000">for</font><font color="#0000ff">="city_field"</font><font color="#0000ff">&#62;</font>Название города<font color="#0000ff">&#60;/</font><font color="#800000">label</font><font color="#0000ff">&#62;</font></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">&#60;</font><font color="#800000">input</font> <font color="#ff0000">type</font><font color="#0000ff">="text"</font> <font color="#ff0000">id</font><font color="#0000ff">="city_field"</font> <font color="#ff0000">name</font><font color="#0000ff">="city_field"</font> <font color="#ff0000">size</font><font color="#0000ff">="20"</font> <font color="#0000ff">/&#62;</font></li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">&#60;/</font><font color="#800000">p</font><font color="#0000ff">&#62;</font></li>
<li>&nbsp;&nbsp;<font color="#0000ff">&#60;/</font><font color="#800000">form</font><font color="#0000ff">&#62;</font></li>
<li>&nbsp;&nbsp;...</li>
<li><font color="#0000ff">&#60;/</font><font color="#800000">div</font><font color="#0000ff">&#62;</font></li>
<li><font color="#0000ff">&#60;/</font><font color="#800000">body</font><font color="#0000ff">&#62;</font></li>
<li><font color="#0000ff">&#60;/</font><font color="#800000">html</font><font color="#0000ff">&#62;</font></li>
<p></font></ol>
<p><font size="1" color="gray">* This source code was highlighted with <a href="http://virtser.net/blog/post/source-code-highlighter.aspx"><font size="1" color="gray">Source Code Highlighter</font></a>.</font></code></p></blockquote>
<p><font size="1" color="gray">* This source code was highlighted with <a href="http://virtser.net/blog/post/source-code-highlighter.aspx"><font size="1" color="gray">Source Code Highlighter</font></a>.</font></code></p></blockquote>
<p><strong>2) Подключение и настройка плагинов</strong>. Этот код добавляем в конец файла index.html перед закрывающим тегом body.</p>
<blockquote style="white-space: nowrap; overflow:auto; margin: 10px 0 10px 0; border: dotted 1px #aeaeae; background-color: #f0f0f0;"><p><code><font size="2" face="Courier New" color="black">
<ol>
<li>&#60;script src=<font color="#A31515">"js/jquery-1.3.2.min.js"</font> type=<font color="#A31515">"text/javascript"</font>&#62;&#60;/script&#62;</li>
<li>&#60;script src=<font color="#A31515">"js/jquery-ui-1.7.2.custom.min.js"</font> type=<font color="#A31515">"text/javascript"</font>&#62;&#60;/script&#62;</li>
<li>&#60;script src=<font color="#A31515">"js/i18n/grid.locale-ru.js"</font> type=<font color="#A31515">"text/javascript"</font>&#62;&#60;/script&#62;</li>
<li>&#60;script src=<font color="#A31515">"js/jquery.jqGrid.min.js"</font> type=<font color="#A31515">"text/javascript"</font>&#62;&#60;/script&#62;</li>
<li>&#60;script src=<font color="#A31515">"js/jquery.autocomplete-min.js"</font> type=<font color="#A31515">"text/javascript"</font>&#62;&#60;/script&#62;</li>
<li>&#60;script type=<font color="#A31515">"text/javascript"</font>&#62;</li>
<li>$(<font color="#0000ff">function</font>() {</li>
<li>&nbsp;&nbsp;<font color="#008000">//настройка плагина jqGrid</font></li>
<li>&nbsp;&nbsp;jQuery(<font color="#A31515">"#list"</font>).jqGrid({</li>
<li>&nbsp;&nbsp;&nbsp;url:<font color="#A31515">'getdata.php'</font>,</li>
<li>&nbsp;&nbsp;&nbsp;datatype: <font color="#A31515">'json'</font>,</li>
<li>&nbsp;&nbsp;&nbsp;mtype: <font color="#A31515">'POST'</font>,</li>
<li>&nbsp;&nbsp;&nbsp;colNames:[<font color="#A31515">'Город'</font>,<font color="#A31515">'Страна'</font>],</li>
<li>&nbsp;&nbsp;&nbsp;colModel :[ </li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;{name:<font color="#A31515">'city'</font>, index:<font color="#A31515">'city'</font>, width:350}, </li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;{name:<font color="#A31515">'country'</font>, index:<font color="#A31515">'country'</font>, width:350}</li>
<li>&nbsp;&nbsp;&nbsp;],</li>
<li>&nbsp;&nbsp;&nbsp;pager: <font color="#A31515">'#pager'</font>,</li>
<li>&nbsp;&nbsp;&nbsp;rowNum:10,</li>
<li>&nbsp;&nbsp;&nbsp;rowList:[10,20,30],</li>
<li>&nbsp;&nbsp;&nbsp;sortname: <font color="#A31515">'country'</font>,</li>
<li>&nbsp;&nbsp;&nbsp;sortorder: <font color="#A31515">'desc'</font>,</li>
<li>&nbsp;&nbsp;&nbsp;viewrecords: <font color="#0000ff">true</font>,</li>
<li>&nbsp;&nbsp;&nbsp;caption: <font color="#A31515">'Города Украины и России'</font></li>
<li>&nbsp;&nbsp;}).navGrid(<font color="#A31515">'#pager'</font>, {edit:<font color="#0000ff">false</font>,add:<font color="#0000ff">false</font>,del:<font color="#0000ff">false</font>,refresh:<font color="#0000ff">true</font>,search:<font color="#0000ff">false</font>});</li>
<li>&nbsp;&nbsp;</li>
<li>&nbsp;&nbsp;<font color="#008000">//эта функция добавляет GET параметр в запрос на получение</font></li>
<li>&nbsp;&nbsp;<font color="#008000">//данных для таблицы и обновляет её</font></li>
<li>&nbsp;&nbsp;<font color="#0000ff">function</font> updateTable(value) {</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;jQuery(<font color="#A31515">"#list"</font>)</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.setGridParam({url:<font color="#A31515">"getdata.php?sel_city="</font>+value, page:1})</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.trigger(<font color="#A31515">"reloadGrid"</font>); </li>
<li>&nbsp;&nbsp;}</li>
<li>&nbsp;&nbsp;</li>
<li>&nbsp;&nbsp;<font color="#008000">//настройка плагина Autocomplete</font></li>
<li>&nbsp;&nbsp;<font color="#008000">//при возникновении события onSelect вызываем функцию updateTable</font></li>
<li>&nbsp;&nbsp;$(<font color="#A31515">'#city_field'</font>).autocomplete({</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;serviceUrl:<font color="#A31515">'search.php'</font>,</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;maxHeight:150,</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;onSelect: <font color="#0000ff">function</font>(value) {</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;updateTable(value);</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;}</li>
<li>&nbsp;&nbsp;});</li>
<li>&nbsp;&nbsp;</li>
<li>&nbsp;&nbsp;<font color="#008000">//этот обработчик используется если посетитель ввел название города</font></li>
<li>&nbsp;&nbsp;<font color="#008000">//и нажал Enter</font></li>
<li>&nbsp;&nbsp;$(<font color="#A31515">'#autocomplete_form'</font>).submit(<font color="#0000ff">function</font>() {</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;updateTable($(<font color="#A31515">'#city_field'</font>).val());</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font> <font color="#0000ff">false</font>;</li>
<li>&nbsp;&nbsp;});</li>
<li>});</li>
<li>&#60;/script&#62;</li>
<p></font></ol>
<p><font size="1" color="gray">* This source code was highlighted with <a href="http://virtser.net/blog/post/source-code-highlighter.aspx"><font size="1" color="gray">Source Code Highlighter</font></a>.</font></code></p></blockquote>
<p>Для демонстрационных целей я использовал урезанную базу данных городов России и Украины, поэтому таблица содержит 2 поля: название города и название страны. На настройках отображения полей и таблицы я останавливаться не буду, т.к. уже об этом <a href="http://www.simplecoding.org/jquery-grid-plugin-prodvinutoe-reshenie-dlya-sozdaniya-tablic.html">рассказывал</a>.</p>
<p>Тут гораздо интереснее другой момент – источники данных.</p>
<p>И для поля, и для таблицы данные приходят в <strong>JSON</strong> формате, но для таблицы их формирует скрипт <code>getdata.php</code>, а для поля - <code>search.php</code>. Почему используются разные скрипты? Дело в том, что для плагина автозаполнения нужно меньше данных (только название города), чем для таблицы, и их структура отличается, а вводить какие-нибудь специальные параметры в запрос мне показалось не самым лучшим решением.</p>
<p><strong>3) Связываем плагины между собой.</strong> Тут нам нужно чтобы при выборе посетителем города из списка произошло обновление данных в таблице.</p>
<p>Для этого мы в обработчик события <code>onSelect</code> (строки 40-42) добавили вызов функции <code>updateTable</code> и передали ей название города.</p>
<p>Теперь нам нужно обновить таблицу, но при этом необходимо как-то указать, что мы хотим получить данные только для выбранного города. Т.к. таблица с данными формируется серверным php скриптом, то нам нужно создать дополнительный параметр и добавить его к запросу.</p>
<p>Для этого с помощью метода <code>setGridParam</code> изменяем параметр <code>url</code> на<br />
<code>getdata.php?sel_city="+value</code><br />
т.е. мы добавили GET параметр <code>sel_city</code>.<br />
Затем вызываем метод <code>trigger("reloadGrid")</code>, который запускает обновление таблицы.</p>
<p>Еще я добавил вызов функции <code>updateTable</code> в обработчик отправки формы (строки 47-50). На случай если пользователь введет название города и нажмет Enter.</p>
<p><strong>4) Создаем серверные скрипты.</strong></p>
<p>Для автозаполнения (<code>search.php</code>)</p>
<blockquote style="white-space: nowrap; overflow:auto; margin: 10px 0 10px 0; border: dotted 1px #aeaeae; background-color: #f0f0f0;"><p><code><font size="2" face="Courier New" color="black">
<ol>
<li>&#60;?php</li>
<li>require_once(<font color="#A31515">'dbdata.php'</font>);</li>
<li>&nbsp;</li>
<li><font color="#0000ff">try</font> {</li>
<li>&nbsp;&nbsp;<font color="#008000">//читаем параметры</font></li>
<li>&nbsp;&nbsp;$s_query = $_GET[<font color="#A31515">'query'</font>];</li>
<li>&nbsp;&nbsp;</li>
<li>&nbsp;&nbsp;<font color="#008000">//подключаемся к базе</font></li>
<li>&nbsp;&nbsp;$dbh = <font color="#0000ff">new</font> PDO(<font color="#A31515">'mysql:host='</font>.$dbHost.<font color="#A31515">';dbname='</font>.$dbName, $dbUser, $dbPass);</li>
<li>&nbsp;&nbsp;<font color="#008000">//указываем, что нужно использовать utf8</font></li>
<li>&nbsp;&nbsp;$dbh-&#62;exec(<font color="#A31515">'SET CHARACTER SET utf8'</font>);</li>
<li>&nbsp;</li>
<li>&nbsp;&nbsp;$stmt = $dbh-&#62;prepare(<font color="#A31515">'SELECT city FROM cities WHERE city LIKE :query'</font>);</li>
<li>&nbsp;&nbsp;$search = $s_query.<font color="#A31515">'%'</font>;</li>
<li>&nbsp;&nbsp;$stmt-&#62;bindParam(<font color="#A31515">':query'</font>, $search);</li>
<li>&nbsp;&nbsp;$stmt-&#62;execute();</li>
<li>&nbsp;&nbsp;</li>
<li>&nbsp;&nbsp;$i=0;</li>
<li>&nbsp;&nbsp;$response-&#62;query = $s_query;</li>
<li>&nbsp;&nbsp;$response-&#62;suggestions = array();</li>
<li>&nbsp;&nbsp;<font color="#0000ff">while</font>($row = $stmt-&#62;fetch(PDO::FETCH_ASSOC)) {</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;$response-&#62;suggestions[]=$row[<font color="#A31515">'city'</font>];</li>
<li>&nbsp;&nbsp;}</li>
<li>&nbsp;&nbsp;echo json_encode($response);</li>
<li>}</li>
<li><font color="#0000ff">catch</font> (PDOException $e) {</li>
<li>&nbsp;&nbsp;echo <font color="#A31515">'Database error: '</font>.$e-&#62;getMessage();</li>
<li>}</li>
<li>&nbsp;</li>
<li>// end of search.php</li>
<p></font></ol>
<p><font size="1" color="gray">* This source code was highlighted with <a href="http://virtser.net/blog/post/source-code-highlighter.aspx"><font size="1" color="gray">Source Code Highlighter</font></a>.</font></code></p></blockquote>
<p>Тут, набранные пользователем буквы мы получаем в параметре <code>$_GET['query']</code>.</p>
<p>После этого выполняется один запрос к базе данных (строки 13-16), который находит список всех городов, начинающихся с этих букв.</p>
<p>Затем мы формируем массив с ответом (строки 19-23) и отправляем его браузеру.</p>
<p><em>Примечание</em>. Структура массива описана в документации к плагину, вам нужно только ее соблюдать.</p>
<p>Скрипт для заплнения таблицы (<code>getdata.php</code>).</p>
<blockquote style="white-space: nowrap; overflow:auto; margin: 10px 0 10px 0; border: dotted 1px #aeaeae; background-color: #f0f0f0;"><p><code><font size="2" face="Courier New" color="black">
<ol>
<li>&#60;?php</li>
<li>require_once(<font color="#A31515">'dbdata.php'</font>);</li>
<li>&nbsp;</li>
<li><font color="#0000ff">try</font> {</li>
<li>&nbsp;&nbsp;<font color="#008000">//читаем параметры</font></li>
<li>&nbsp;&nbsp;$curPage = $_POST[<font color="#A31515">'page'</font>];</li>
<li>&nbsp;&nbsp;$rowsPerPage = $_POST[<font color="#A31515">'rows'</font>];</li>
<li>&nbsp;&nbsp;$sortingField = $_POST[<font color="#A31515">'sidx'</font>];</li>
<li>&nbsp;&nbsp;$sortingOrder = $_POST[<font color="#A31515">'sord'</font>];</li>
<li>&nbsp;&nbsp;</li>
<li>&nbsp;&nbsp;$selCity = <font color="#0000ff">null</font>;</li>
<li>&nbsp;&nbsp;<font color="#0000ff">if</font> (isset($_GET[<font color="#A31515">'sel_city'</font>])) {</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;$selCity = $_GET[<font color="#A31515">'sel_city'</font>];</li>
<li>&nbsp;&nbsp;}</li>
<li>&nbsp;&nbsp;</li>
<li>&nbsp;&nbsp;<font color="#008000">//подключаемся к базе</font></li>
<li>&nbsp;&nbsp;$dbh = <font color="#0000ff">new</font> PDO(<font color="#A31515">'mysql:host='</font>.$dbHost.<font color="#A31515">';dbname='</font>.$dbName, $dbUser, $dbPass);</li>
<li>&nbsp;&nbsp;<font color="#008000">//указываем, что нужно использовать utf8</font></li>
<li>&nbsp;&nbsp;$dbh-&#62;exec(<font color="#A31515">'SET CHARACTER SET utf8'</font>);</li>
<li>&nbsp;</li>
<li>&nbsp;&nbsp;<font color="#008000">//определяем количество записей в таблице</font></li>
<li>&nbsp;&nbsp;<font color="#0000ff">if</font> (<font color="#0000ff">null</font> === $selCity) {</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;$rows = $dbh-&#62;query(<font color="#A31515">'SELECT COUNT(id) AS count FROM cities'</font>);</li>
<li>&nbsp;&nbsp;} <font color="#0000ff">else</font> {</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;$rows = $dbh-&#62;query(<font color="#A31515">'SELECT COUNT(id) AS count FROM cities WHERE city='</font>.$dbh-&#62;quote($selCity));</li>
<li>&nbsp;&nbsp;}</li>
<li>&nbsp;&nbsp;$totalRows = $rows-&#62;fetch(PDO::FETCH_ASSOC);</li>
<li>&nbsp;</li>
<li>&nbsp;&nbsp;$firstRowIndex = $curPage * $rowsPerPage - $rowsPerPage;</li>
<li>&nbsp;&nbsp;<font color="#008000">//получаем список городов из базы</font></li>
<li>&nbsp;&nbsp;<font color="#0000ff">if</font> (<font color="#0000ff">null</font> === $selCity) {</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;$res = $dbh-&#62;query(<font color="#A31515">'SELECT * FROM cities ORDER BY '</font>.$sortingField.<font color="#A31515">' '</font>.$sortingOrder.<font color="#A31515">' LIMIT '</font>.$firstRowIndex.<font color="#A31515">', '</font>.$rowsPerPage);</li>
<li>&nbsp;&nbsp;} <font color="#0000ff">else</font> {</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;$res = $dbh-&#62;query(<font color="#A31515">'SELECT * FROM cities WHERE city='</font>.$dbh-&#62;quote($selCity).<font color="#A31515">' ORDER BY '</font>.$sortingField.<font color="#A31515">' '</font>.$sortingOrder.<font color="#A31515">' LIMIT '</font>.$firstRowIndex.<font color="#A31515">', '</font>.$rowsPerPage);</li>
<li>&nbsp;&nbsp;}</li>
<li>&nbsp;&nbsp;</li>
<li>&nbsp;&nbsp;<font color="#008000">//сохраняем номер текущей страницы, общее количество страниц и общее количество записей</font></li>
<li>&nbsp;&nbsp;$response-&#62;page = $curPage;</li>
<li>&nbsp;&nbsp;$response-&#62;total = ceil($totalRows[<font color="#A31515">'count'</font>] / $rowsPerPage);</li>
<li>&nbsp;&nbsp;$response-&#62;records = $totalRows[<font color="#A31515">'count'</font>];</li>
<li>&nbsp;</li>
<li>&nbsp;&nbsp;$i=0;</li>
<li>&nbsp;&nbsp;<font color="#0000ff">while</font>($row = $res-&#62;fetch(PDO::FETCH_ASSOC)) {</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;$response-&#62;rows[$i][<font color="#A31515">'id'</font>]=$row[<font color="#A31515">'id'</font>];</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;$response-&#62;rows[$i][<font color="#A31515">'cell'</font>]=array($row[<font color="#A31515">'city'</font>], $row[<font color="#A31515">'country'</font>]);</li>
<li>&nbsp;&nbsp;&nbsp;&nbsp;$i++;</li>
<li>&nbsp;&nbsp;}</li>
<li>&nbsp;&nbsp;echo json_encode($response);</li>
<li>}</li>
<li><font color="#0000ff">catch</font> (PDOException $e) {</li>
<li>&nbsp;&nbsp;echo <font color="#A31515">'Database error: '</font>.$e-&#62;getMessage();</li>
<li>}</li>
<li>&nbsp;</li>
<li>// end of getdata.php</li>
<p></font></ol>
<p><font size="1" color="gray">* This source code was highlighted with <a href="http://virtser.net/blog/post/source-code-highlighter.aspx"><font size="1" color="gray">Source Code Highlighter</font></a>.</font></code></p></blockquote>
<p>Тут код выглядит немного сложнее, но это только из-за использования пагинации (разбивки на страницы). На самом деле большую его часть я просто скопировал из документации к jqGrid (к тому же, он <a href="http://www.simplecoding.org/jquery-grid-plugin-prodvinutoe-reshenie-dlya-sozdaniya-tablic.html">уже обсуждался</a>).</p>
<p>Обратить внимание нужно на обработку параметра <code>sel_city</code> (строки 12, 22 и 31).</p>
<p>Если этот параметр получен, то в запрос на поиск данных мы добавляем условие <code>WHERE city=…</code>, если нет – берем из базы все города подряд.</p>
<p>Я надеюсь, что у вас не возникнет проблем с этим примером. Идея ведь достаточно простая: добавить параметр с нужными данными к запросу и обработать его в серверном скрипте.</p>
<p>Инструкции по установке и настройке примера есть в архиве.</p>
<p>И, конечно, я буду рад услышать ваше мнение <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><strong>UPD 21.06.2010</strong> В этом примере обнаружилась недоработка. Оказалось, что IE не хочет передавать название города в UTF-8 (название вставляется в URL, т.е. на сервер приходит в GET параметре). Для решения необходимо перед отправкой закодировать название города с помощью encodeURIComponent (в браузере) и раскодировать с помощью rawurldecode (на сервере).</p>
<p><strong>Интересно почитать</strong></p>
<p>Несколько способов о том <a href="http://blog-invest.ru/kak-zarabotat-studentu/" title="заработок для студента">как заработать студенту</a> в наше время.</p>
<p>Руководителям: <a href="http://busins.ru/uslugi_po_vedeniju_buhucheta">оказание услуг бухучета</a> позволяет сэкономить на штатном бухгалтере</p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/upravlenie-jqgrid-s-pomoshhyu-polya-s-avtozaversheniem.html/feed</wfw:commentRss>
		<slash:comments>53</slash:comments>
		</item>
		<item>
		<title>RedBean PHP ORM – за и против</title>
		<link>http://www.simplecoding.org/redbean-php-orm-za-i-protiv.html</link>
		<comments>http://www.simplecoding.org/redbean-php-orm-za-i-protiv.html#comments</comments>
		<pubDate>Thu, 08 Oct 2009 10:36:24 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=923</guid>
		<description><![CDATA[Приветствую всех! Сегодня я хочу рассказать о небольшой ORM библиотеке под названием RedBean с которой я на днях экспериментировал. Прежде всего, пару слов о ORM (англ. Object-relational mapping, русск. Объектно-реляционная проекция) вообще. Основное назначение таких библиотек – преобразование объектов, которые используются в программах, в записи реляционных баз данных и обратно. Дело в том, что все [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_917" class="wp-caption alignnone" style="width: 288px"><img src="http://www.simplecoding.org/wp-content/uploads/2009/10/redbean_logo.png" alt="redbean_logo" title="redbean_logo" width="278" height="143" style="float:left" class="size-full wp-image-917" /><p class="wp-caption-text"> </p></div>
<p><strong>Приветствую всех!</strong></p>
<p>Сегодня я хочу рассказать о небольшой <strong>ORM</strong> библиотеке под названием <a href="http://www.redbeanphp.com">RedBean</a> с которой я на днях экспериментировал.</p>
<p>Прежде всего, пару слов о <strong>ORM</strong> (англ. Object-relational mapping, русск. Объектно-реляционная проекция) вообще.</p>
<p>Основное назначение таких библиотек – преобразование объектов, которые используются в программах, в записи реляционных баз данных и обратно.</p>
<p>Дело в том, что все данные в БД хранятся в таблицах (аналог двумерных массивов), а объекты могут быть организованы в сложные иерархии (например, объект типа «Post» может содержать массив объектов типа «Comment»). И для того, чтобы сохранить такую структуру в БД нужно использовать несколько таблиц с дополнительными полями, которые устанавливают связи между записями.</p>
<p><strong>Все это увеличивает сложность SQL запросов и время разработки.</strong></p>
<p>ORM библиотеки могут в таких ситуациях значительно упрощают жизнь разработчику. Но, естественно, за все нужно платить. В данном случае счет вы получите в виде повышенного потребления ресурсов.</p>
<p><strong>Вернемся к RedBean.</strong><br />
<span id="more-923"></span><br />
Проиллюстрировать работу любой библиотеки проще всего на примере. Поэтому я написал небольшой скрипт.</p>
<pre class="brush: php">&lt;?php
include 'oodb.php';

//подключаемся к БД
RedBean_Setup::kickstartDev('Post,Comment','mysql:host=localhost;dbname=my_database', 'user_name', 'password');

$post = new Post();
$post-&gt;title = 'Новая запись';
$post-&gt;content = 'Просто какой-то текст';
$id = $post-&gt;save();

$comment = new Comment;
$comment-&gt;author = 'admin';
$comment-&gt;text = 'Очень простой комментарий';
$comment-&gt;belongsTo($post);
?&gt;
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
&lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"&gt;
&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8" /&gt;
&lt;meta name="language" content="en" /&gt;
&lt;title&gt;Test RedBean&lt;/title&gt;
&lt;/head&gt;

&lt;body&gt;

&lt;ul&gt;
&lt;?php
$posts = Post::listAll();
foreach ($posts as $post) {
	$curPost = new Post($post['id']);
	echo '&lt;li&gt;&lt;strong&gt;'.$curPost-&gt;getTitle().'&lt;/strong&gt;&lt;br /&gt;';
	echo $curPost-&gt;getContent();
	$comments = $curPost-&gt;getRelatedComment();
	echo '&lt;ol&gt;';
	foreach ($comments as $comment) {
		echo '&lt;li&gt;'.$comment-&gt;text.' ('.$comment-&gt;author.')&lt;/li&gt;';
	}
	echo '&lt;/ol&gt;&lt;/li&gt;';
}
?&gt;
&lt;/ul&gt;

&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Посмотрим, что он делает.</p>
<p>1) <strong>Подключаем библиотеку</strong> (строка 2). Тут объяснять нечего, <strong>RedBean</strong> состоит всего из одного файла.</p>
<p>2) <strong>Подключаемся к базе данных и создаем объекты, которые будем в ней хранить</strong> (строка 5).<br />
Обе операции выполняются с помощью метода <code>kickstartDev</code>. В первом параметре мы указываем перечень нужных объектов (они будут создаваться динамически). В остальных параметрах – данные, необходимые для подключения к базе (dns, имя пользователя и пароль).</p>
<p>Предварительно от нас требуется только создать пустую БД. Созданием таблиц, сохранением и чтением данных будет заниматься RedBean.</p>
<p><em>Примечание</em>. Метод <code>kickstartDev</code> переводит библиотеку в т.н. <strong>fluid</strong> режим. При этом если вы измените, количество или названия свойств объектов, то RedBean автоматически изменит структуру таблиц в БД. Этот режим имеет смысл использовать во время разработки. После переноса приложения на «боевой» сервер <code>kickstartDev</code> лучше заменить на <code>kickstartFrozen</code>. Библиотека перейдет во frozen режим, при этом таблицы автоматически изменяться не будут, но и потребление ресурсов сократится.</p>
<p>3) <strong>Создаем данные и сохраняем их в БД</strong> (строки 7-15).</p>
<p>В данном случае создано два объекта типов <code>Post</code> и <code>Comment</code>, каждый из которых содержит несколько свойств.<br />
Обратите внимание, что свойства создаются автоматически. От нас требуется указать только название свойства и его значение.<br />
Мы просто присваиваем значения нужным свойствам и вызываем метод <code>save()</code>, который записывает объект в БД (строка 10).</p>
<p>Объект <code>Comment</code> принадлежит <code>Post</code>. Эту связь мы устанавливаем с помощью метода <code>belongsTo</code>. При этом использовать save не нужно. Сохранение в БД произойдет автоматически.</p>
<p>4) <strong>Читаем данные из базы</strong> (строки 29-40).<br />
Тут тоже все достаточно прозрачно. С помощью статического метода <code>listAll</code> мы получаем массив со всеми объектами типа <code>Post</code>, находящимися в БД.</p>
<p>Чтобы получить доступ к комментариям мы создаем объект типа <code>Post</code> (строка 31) и при этом в качестве параметра указываем <code>id</code>.</p>
<p>После этого мы можем использовать метод <code>getRelatedComment</code> для получения массива с комментариями.<br />
Примечание. Название метода <code>getRelatedComment</code> формируется следующим образом. К приставке <code>getRelated</code> добавляется имя объекта, который мы хотим получить.</p>
<p>Затем в цикле мы выводим комментарии.</p>
<p>В результате выполнения скрипта вы увидите такую страницу.</p>
<p><img src="http://www.simplecoding.org/wp-content/uploads/2009/10/pic1.png" alt="pic1" title="pic1" width="340" height="82" class="alignnone size-full wp-image-918" /></p>
<p><strong>Теперь посмотрим, что у нас делается с базой данных.</strong></p>
<p>Прежде всего, взгляните на перечень таблиц.</p>
<p><img src="http://www.simplecoding.org/wp-content/uploads/2009/10/pic2.png" alt="pic2" title="pic2" width="466" height="190" class="alignnone size-full wp-image-919" /></p>
<p>Как видите, RedBean создал 6 таблиц. Три из них (post, comment_post и comment) используются для хранения данных приложения, остальные – используются самой RedBean.</p>
<p>Теперь посмотрим, что сохранено в самих таблицах.</p>
<p><strong>post</strong></p>
<p><img src="http://www.simplecoding.org/wp-content/uploads/2009/10/pic3.png" alt="pic3" title="pic3" width="366" height="47" class="alignnone size-full wp-image-920" /></p>
<p><strong>comment_post</strong></p>
<p><img src="http://www.simplecoding.org/wp-content/uploads/2009/10/pic4.png" alt="pic4" title="pic4" width="280" height="48" class="alignnone size-full wp-image-921" /></p>
<p><strong>comment</strong></p>
<p><img src="http://www.simplecoding.org/wp-content/uploads/2009/10/pic5.png" alt="pic5" title="pic5" width="367" height="48" class="alignnone size-full wp-image-922" /></p>
<p>Думаю, вы уже догадались, в чем дело.</p>
<p>Между объектами Post и Comment отношение типа ОДИН-К-МНОГИМ и для его реализации не нужна промежуточная таблица. Т.е. если бы база создавалась вручную, мы бы обошлись всего двумя таблицами. Соответственно, упрощаются и SQL запросы.</p>
<p><strong>Использовать или не использовать?</strong></p>
<p>Это вопрос философский <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  . RedBean не единственная ORM библиотека. Например, существуют более мощные <a href="http://propel.phpdb.org/trac/">Propel</a> и <a href="http://www.doctrine-project.org/">Doctrine</a>.</p>
<p>Ответ будет зависеть от требований к конкретному приложению. В общем случае при использовании ORM увеличивается скорость разработки и упрощается поддержка, но при этом растет потребление ресурсов.</p>
<p>К тому же стоит учесть время, необходимое на изучение библиотеки. В этом RedBean значительно превосходит библиотеки типа Doctrine. Вряд ли у вас уйдет больше пары дней на эксперименты с RedBean.</p>
<p>В общем, думаю, что в ряде случаев использование RedBean будет вполне оправданно.</p>
<p>В заключение хочу сказать, что это статью нельзя рассматривать как руководство по использованию библиотеки. Поэтому я очень рекомендую вам почитать документацию на сайте.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/redbean-php-orm-za-i-protiv.html/feed</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
	</channel>
</rss>

