<?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; CodeIgniter</title>
	<atom:link href="http://www.simplecoding.org/category/code-igniter/feed" rel="self" type="application/rss+xml" />
	<link>http://www.simplecoding.org</link>
	<description>Блог о программировании</description>
	<lastBuildDate>Sun, 07 Mar 2010 19:36:29 +0000</lastBuildDate>
	
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<link rel="http://api.friendfeed.com/2008/03#sup" xmlns="http://www.w3.org/2005/Atom" type="application/json" href="http://friendfeed.com/api/public-sup.json#d217526a2c"/>		<item>
		<title>XML-RPC, CodeIgniter, LiveJournal и куча проблем :)</title>
		<link>http://www.simplecoding.org/xml-rpc-codeigniter-livejournal-i-kucha-problem.html</link>
		<comments>http://www.simplecoding.org/xml-rpc-codeigniter-livejournal-i-kucha-problem.html#comments</comments>
		<pubDate>Fri, 13 Nov 2009 13:42:47 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[CodeIgniter]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=941</guid>
		<description><![CDATA[Недавно ко мне обратился читатель с просьбой помочь отправить сообщение в LiveJournal через XML-RPC протокол. При этом использовать нужно было библиотеку фреймворка CodeIgniter.
Честно говоря, когда я вижу такие вопросы, то сразу пробую найти готовое решение. Этот случай исключением не был и подходящая инструкция быстро нашлась. XML-RPC и кросспостинг в ЖЖ. Константин Лихачев в ней подробно [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_942" class="wp-caption alignnone" style="width: 310px"><img src="http://www.simplecoding.org/wp-content/uploads/2009/11/codeigniter-livejournal-xml-rpc.png" alt="codeigniter-livejournal-xml-rpc" title="codeigniter-livejournal-xml-rpc" width="300" height="178" class="size-full wp-image-942" style="float:left" /><p class="wp-caption-text"> </p></div>
<p>Недавно ко мне обратился читатель с просьбой помочь отправить сообщение в <strong>LiveJournal</strong> через <strong><acronym title="eXtensible Markup Language">XML</acronym>-<acronym title="Remote Procedure Call">RPC</acronym></strong> протокол. При этом использовать нужно было библиотеку фреймворка <a href="http://codeigniter.com/">CodeIgniter</a>.</p>
<p>Честно говоря, когда я вижу такие вопросы, то сразу пробую найти готовое решение. Этот случай исключением не был и подходящая инструкция быстро нашлась. <a href="http://www.likhachev.net/2008/03/01/xml-rpc-crossposting/"><acronym title="eXtensible Markup Language">XML</acronym>-<acronym title="Remote Procedure Call">RPC</acronym> и кросспостинг в ЖЖ</a>. Константин Лихачев в ней подробно рассказывает об отправке сообщений, единственное но – используется <a href="http://scripts.incutio.com/xmlrpc/">Incutio <acronym title="eXtensible Markup Language">XML</acronym>-<acronym title="Remote Procedure Call">RPC</acronym> Library</a>, а не встроенная библиотека CI.</p>
<p>Раз работает код с использованием Incutio <acronym title="eXtensible Markup Language">XML</acronym>-<acronym title="Remote Procedure Call">RPC</acronym>, то сервис 100% рабочий и нужно просто правильно передать параметры в библиотеке CodeIgniter&#039;а.</p>
<p>Думаю: «Почему бы не помочь человеку? Опыт работы с CI у меня есть, с документацией JiveJournal разбираться не нужно, т.к. список всех нужных параметров есть в статье Константина. Минут за 20 сделаю…» <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Мне пора бы привыкнуть, что когда я так думаю, эти 20 минут часто превращаются в 2-3 часа. <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /><br />
<span id="more-941"></span><br />
Проблема была такая. Встроенная библиотека CodeIgniter требует, чтобы все параметры запроса были <strong>заданы в виде массива</strong>. При этом если нужно передавать структуры данных, получается куча вложенных друг в друга массивов.</p>
<p>И пропустить один из них (что я и сделал) или вставить лишний очень легко.</p>
<p>По-идее, именно для таких ситуаций предусмотрен режим отладки. Но в этом режиме библиотека CI выводит <strong>только <acronym title="eXtensible Markup Language">XML</acronym> ответ сервера</strong>, а мне нужно было посмотреть на <acronym title="eXtensible Markup Language">XML</acronym> строку, которая отправляется в запросе.</p>
<p><em>Примечание</em>. Ответ сервера:</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1">Can&#039;t use string (&quot;Array&quot;) as a HASH ref while &quot;strict refs&quot; in use at /home/lj/cgi-bin/Apache/LiveJournal.pm line 1779.</div>
</li>
</ol>
</div>
<p>лично мне ни о чем не говорит (на perl я не программирую). Кстати, тот же <strong>WordPress</strong> в таких случаях возвращает «parse error. not well formed» &#8211; на мой взгляд, более понятный ответ, хоть и не очень информативный.</p>
<p>В документации LiveJournal есть примеры <acronym title="eXtensible Markup Language">XML</acronym> запросов, которые нужно отправить для добавления записи, т.е. достаточно просто сравнить их со своими и все проблемы будут видны.</p>
<p>После нескольких неудачных попыток узнать что все-таки отправляется серверу, пришлось лезть в исходники библиотеки.</p>
<p>Чтобы вывести запрос я добавил строку</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw3">echo</span> <span class="st0">&#039;&lt;pre&gt;&#039;</span>.<span class="kw3">htmlspecialchars</span><span class="br0">&#40;</span><span class="re0">$op</span><span class="br0">&#41;</span>.<span class="st0">&#039;&lt;/pre&gt;&#039;</span>;</div>
</li>
</ol>
</div>
<p>в методе <code>sendPayload</code> перед</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">if</span> <span class="br0">&#40;</span> ! <span class="kw3">fputs</span><span class="br0">&#40;</span><span class="re0">$fp</span>, <span class="re0">$op</span>, <span class="kw3">strlen</span><span class="br0">&#40;</span><span class="re0">$op</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span></div>
</li>
</ol>
</div>
<p>Не очень элегантное решение, но зато сразу стало ясно, в чем проблема.</p>
<p>Привожу рабочий код отправки сообщения в livejournal.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">class</span> LiveJournal <span class="kw2">extends</span> Controller <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw2">private</span> <span class="re0">$LJ_url</span> = <span class="st0">&#039;http://www.livejournal.com/interface/xmlrpc&#039;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw2">private</span> <span class="re0">$LJ_login</span> = <span class="st0">&#039;your login&#039;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="kw2">private</span> <span class="re0">$LJ_pass</span> = <span class="st0">&#039;your pass&#039;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw2">function</span> LiveJournal<span class="br0">&#40;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; parent::<span class="me2">Controller</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//подключаем <acronym title="eXtensible Markup Language">XML</acronym>-<acronym title="Remote Procedure Call">RPC</acronym> библиотеку</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">library</span><span class="br0">&#40;</span><span class="st0">&#039;xmlrpc&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; </div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="kw2">function</span> index<span class="br0">&#40;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">xmlrpc</span>-&gt;<span class="me1">server</span><span class="br0">&#40;</span><span class="re0">$this</span>-&gt;<span class="me1">LJ_url</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//отправляем challange-запрос</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">xmlrpc</span>-&gt;<span class="me1">method</span><span class="br0">&#40;</span><span class="st0">&#039;LJ.XMLRPC.getchallenge&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>!<span class="re0">$this</span>-&gt;<span class="me1">xmlrpc</span>-&gt;<span class="me1">send_request</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">echo</span> <span class="re0">$this</span>-&gt;<span class="me1">xmlrpc</span>-&gt;<span class="me1">display_error</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//если получен ответ с challenge-строкой, читаем его и отправляем запись </span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$challenge_response</span> = <span class="re0">$this</span>-&gt;<span class="me1">xmlrpc</span>-&gt;<span class="me1">display_response</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//формируем массив с данными для создания записи</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$request</span> = <span class="kw3">array</span><span class="br0">&#40;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">array</span><span class="br0">&#40;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">array</span><span class="br0">&#40;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&#039;username&#039;</span>=&gt;array<span class="br0">&#40;</span><span class="re0">$this</span>-&gt;<span class="me1">LJ_login</span>,<span class="st0">&#039;string&#039;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ,<span class="st0">&#039;auth_method&#039;</span>=&gt;array<span class="br0">&#40;</span><span class="st0">&#039;challenge&#039;</span>,<span class="st0">&#039;string&#039;</span><span class="br0">&#41;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ,<span class="st0">&#039;auth_challenge&#039;</span>=&gt;array<span class="br0">&#40;</span><span class="re0">$challenge_response</span><span class="br0">&#91;</span><span class="st0">&#039;challenge&#039;</span><span class="br0">&#93;</span>,<span class="st0">&#039;string&#039;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ,<span class="st0">&#039;auth_response&#039;</span>=&gt;array<span class="br0">&#40;</span><span class="kw3">md5</span><span class="br0">&#40;</span><span class="re0">$challenge_response</span><span class="br0">&#91;</span><span class="st0">&#039;challenge&#039;</span><span class="br0">&#93;</span>.<span class="kw3">md5</span><span class="br0">&#40;</span><span class="re0">$this</span>-&gt;<span class="me1">LJ_pass</span><span class="br0">&#41;</span><span class="br0">&#41;</span>,<span class="st0">&#039;string&#039;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ,<span class="st0">&#039;ver&#039;</span>=&gt;array<span class="br0">&#40;</span><span class="st0">&#039;1&#039;</span>,<span class="st0">&#039;string&#039;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ,<span class="st0">&#039;event&#039;</span>=&gt;array<span class="br0">&#40;</span><span class="st0">&#039;Заголовок записи&#039;</span>,<span class="st0">&#039;string&#039;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ,<span class="st0">&#039;subject&#039;</span>=&gt;array<span class="br0">&#40;</span><span class="st0">&#039;Текст записи &#8230;&#039;</span>,<span class="st0">&#039;string&#039;</span><span class="br0">&#41;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ,<span class="st0">&#039;year&#039;</span>=&gt;array<span class="br0">&#40;</span><span class="nu0">2009</span>,<span class="st0">&#039;int&#039;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ,<span class="st0">&#039;mon&#039;</span>=&gt;array<span class="br0">&#40;</span><span class="nu0">11</span>,<span class="st0">&#039;int&#039;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ,<span class="st0">&#039;day&#039;</span>=&gt;array<span class="br0">&#40;</span><span class="nu0">12</span>,<span class="st0">&#039;int&#039;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ,<span class="st0">&#039;hour&#039;</span>=&gt;array<span class="br0">&#40;</span><span class="nu0">5</span>,<span class="st0">&#039;int&#039;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ,<span class="st0">&#039;min&#039;</span>=&gt;array<span class="br0">&#40;</span><span class="nu0">27</span>,<span class="st0">&#039;int&#039;</span><span class="br0">&#41;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ,<span class="st0">&#039;props&#039;</span>=&gt;array<span class="br0">&#40;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">array</span><span class="br0">&#40;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&#039;opt_backdated&#039;</span>=&gt;array<span class="br0">&#40;</span><span class="kw2">true</span>,<span class="st0">&#039;boolean&#039;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ,<span class="st0">&#039;taglist&#039;</span>=&gt;array<span class="br0">&#40;</span><span class="st0">&#039;tag 1, tag 2, tag 3&#039;</span>,<span class="st0">&#039;string&#039;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ,<span class="st0">&#039;struct&#039;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ,<span class="st0">&#039;security&#039;</span>=&gt;array<span class="br0">&#40;</span><span class="st0">&#039;public&#039;</span>,<span class="st0">&#039;string&#039;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ,<span class="st0">&#039;struct&#039;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//отправляем запрос серверу</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">xmlrpc</span>-&gt;<span class="me1">method</span><span class="br0">&#40;</span><span class="st0">&#039;LJ.XMLRPC.postevent&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">xmlrpc</span>-&gt;<span class="me1">request</span><span class="br0">&#40;</span><span class="re0">$request</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>!<span class="re0">$this</span>-&gt;<span class="me1">xmlrpc</span>-&gt;<span class="me1">send_request</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">echo</span> <span class="re0">$this</span>-&gt;<span class="me1">xmlrpc</span>-&gt;<span class="me1">display_error</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$postData</span> = <span class="re0">$this</span>-&gt;<span class="me1">xmlrpc</span>-&gt;<span class="me1">display_response</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//$postData['url'] &#8211; содержит адрес созданной записи</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Несколько пояснений. Публикация сообщения выполняется в <strong>2</strong> этапа.</p>
<p>1) Нужно получить challenge строку, которая хешируется (строка 36) вместе с вашим паролем и используется вместо него. Это сделано для того, чтобы не передавать пароль в открытом виде.</p>
<p>2) Отправка самого сообщения. Как раз тут и нужно формировать структуру с данными. Как видите, мы везде используем массивы с двумя элементами. Первый элемент содержит передаваемое значение, второй – тип этого значения. Если нужно передать структуру, то первый элемент должен быть массивом.</p>
<p>Выглядит такая конструкция громоздкой и <strong>заполнять ее нужно внимательно</strong>, особенно если вы привыкли к библиотеке вроде Incutio <acronym title="eXtensible Markup Language">XML</acronym>-<acronym title="Remote Procedure Call">RPC</acronym>. Кстати, эту библиотеку не сложно подключить и использовать вместо стандартной CodeIgniter’а.</p>
<p>Вообще в последнее время складывается впечатление, что разработчики забросили фреймворк. Хотя, возможно, я не прав, а Ellislab просто все силы тратит на свою <acronym title="Content Management System">CMS</acronym>, вторую версию ExpressionEngine, которая вроде бы будет работать на основе CodeIgniter.</p>
<p>Очень не хочется, чтобы они забросили CI.</p>
<p><strong>Постовой</strong></p>
<p>Что выгоднее, <a href="http://busins.ru/prihodjawij_buhgalter_v_moskve">услуги приходящего бухгалтера</a> или ведение бухгалтерии у профессионалов? Ответ здесь</p><img src="http://www.simplecoding.org/?ak_action=api_record_view&id=941&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/xml-rpc-codeigniter-livejournal-i-kucha-problem.html/feed</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
		<item>
		<title>PHP скрипт: ToDo с картинками</title>
		<link>http://www.simplecoding.org/php-skript-todo-s-kartinkami.html</link>
		<comments>http://www.simplecoding.org/php-skript-todo-s-kartinkami.html#comments</comments>
		<pubDate>Thu, 13 Aug 2009 19:01:21 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[CodeIgniter]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>
		<category><![CDATA[htaccess]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=885</guid>
		<description><![CDATA[Уделяете ли вы внимание организации своей работы?
Много ли у вас &#034;мелких&#034; дел, о которых вы регулярно забываете?
Вроде бы простые вопросы, но для многих людей (и я не исключение) организация работы – это актуальная проблема.
Хуже всего, когда нужно сделать много «мелких» дел, которые не занимают много времени, но обязательно должны быть выполнены вовремя&#8230; и держать в [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_886" class="wp-caption alignnone" style="width: 320px"><img src="http://www.simplecoding.org/wp-content/uploads/2009/08/simple_tasks.png" alt="simple tasks" title="simple tasks" width="310" height="129" class="size-full wp-image-886" style="float:left" /><p class="wp-caption-text"> </p></div>
<p>Уделяете ли вы внимание организации своей работы?<br />
Много ли у вас &#034;мелких&#034; дел, о которых вы регулярно забываете?</p>
<p>Вроде бы простые вопросы, но для многих людей (и я не исключение) <strong>организация работы</strong> – это актуальная проблема.</p>
<p>Хуже всего, когда нужно сделать много «мелких» дел, которые не занимают много времени, но обязательно должны быть выполнены вовремя&#8230; и держать в голове их все просто невозможно.</p>
<p>Естественно, разработчики реагируют на потребности рынка, и на сегодняшний день создано множество программ-органайзеров, различных напоминалок и т.п.<br />
Примеры создания ToDo списков часто приводят в учебниках по программированию.</p>
<p>Я решил не оставаться в стороне и сделал <strong>собственный вариант такого ToDo списка, естественно, с некоторыми дополнительными возможностями</strong>.</p>
<p>Кстати, скрипт называется <strong>SimpleTasks</strong>.</p>
<p>Главная особенность – <strong>возможность указывать состояние выполнения задач</strong>. При этом используется специальная система обозначений.<br />
<span id="more-885"></span></p>
<div id="attachment_887" class="wp-caption alignnone" style="width: 490px"><img src="http://www.simplecoding.org/wp-content/uploads/2009/08/symbols_for_paper_notebook_with_description.png" alt="symbols for paper notebook with description" title="symbols for paper notebook with description" width="480" height="192" class="size-full wp-image-887" /><p class="wp-caption-text"> </p></div>
<p>Систему обозначений придумал не я. <del datetime="2009-08-14T13:47:28+00:00">Но, к сожалению, не могу найти первоисточник</del> (UPD. Огромное спасибо <a href="http://i-smarty.com">Smarty</a> за ссылку на <a href="http://font.is/?p=790">оригинал</a>). Предназначена она для использования с бумажным блокнотом и довольно удобная. Во всяком случае, читать такой список задач становится намного легче. Взгляд сразу отбрасывает выполненные задачи.</p>
<p>Но <strong>возможности web приложений намного шире</strong>, чем у обычного ежедневника. Например, можно сделать систему фильтров и легко работать с большими списками задач.</p>
<p>В общем, я написал небольшое web приложение, использующее эту систему обозначений.</p>
<p>Если есть желание, можете поиграться с ним (логин admin@todo.loc, пароль password).</p>
<p><a href="http://demosites.org.ua/simpletasks/"><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/08/simpletasks.zip'><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/download_btn_blue.png" alt="архив с исходным кодом" /></a></p>
<p><strong>Принцип работы.</strong></p>
<p><strong>Создание новой записи.</strong><br />
Кликаем по ссылке &#034;Новая запись&#034; (справа в верхней части страницы) и в открывшемся окне вводим данные записи.<br />
При клике по полю &#034;Дата&#034; будет открыт календарь. Т.е. ввести дату в неправильном формате довольно проблематично.</p>
<p><strong>Редактирование.</strong><br />
Клик или двойной клик на соответствующем поле позволяет изменить его. Открываетеся либо диалог, либо inline редактор.</p>
<p><strong>Удаление.</strong><br />
Кликните по картинке с изображением крестика в соответствующей строке и подтвердите удаление.</p>
<p><strong>Фильтры.</strong><br />
Позволяют выбрать задачи с определенным состоянием в указанном диапазоне дат.</p>
<p>Ссылки в верхнем меню дублируют наиболее распространенные (на мой взгляд) фильтры.</p>
<p><strong>Состояние работ.</strong><br />
На данный момент это только бета версия.<br />
Еще не доделана локализация. Доступен только один вариант &#8211; русский.<br />
Возможно, отсутствуют некоторые сообщения об ошибках.</p>
<p>Скорее всего, некоторые функции будут дорабатываться.</p>
<p><strong>И я очень хочу услышать ваше мнение!<br />
</strong><br />
Прежде всего, меня интересуют такие вопросы.</p>
<p>1) Есть ли смысл делать подобное приложение многопользовательским? Т.е. технически это совсем не сложно, вопрос в том будет ли кто-то в рамках небольшой организации использовать такое приложение для хранения заметок сотрудников?</p>
<p>2) Какие еще функии вы бы добавили?</p>
<p>3) Может кто-то видел хороший тьюториал о локализации <acronym title="JavaScript">JS</acronym> приложений? (Сейчас я ориентируюсь на то, как сделана локализация в jQuery UI).</p>
<p><strong>P.S.</strong> На этих выходных я уезжаю догуливать остатки отпуска, поэтому прошу прощения, если не сразу отвечу на ваши комментарии. Я обязательно их прочитаю&#8230; даже спаммерские <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p><img src="http://www.simplecoding.org/?ak_action=api_record_view&id=885&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/php-skript-todo-s-kartinkami.html/feed</wfw:commentRss>
		<slash:comments>59</slash:comments>
		</item>
		<item>
		<title>Bug Tracker: ответы на комментарии (часть десятая)</title>
		<link>http://www.simplecoding.org/bug-tracker-otvety-na-kommentarii-chast-desyataya.html</link>
		<comments>http://www.simplecoding.org/bug-tracker-otvety-na-kommentarii-chast-desyataya.html#comments</comments>
		<pubDate>Sat, 28 Mar 2009 11:25:19 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[CodeIgniter]]></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=797</guid>
		<description><![CDATA[В предыдущих частях (1, 2, 3, 4, 5, 6, 7, 8, 9) мы создали практически работоспособную систему отслеживания ошибок.
«Практически» в данном случае означает, что на данный момент у пользователя отсутствует возможность отвечать на комментарии. Т.е. можно оставить только комментарий 1-ого уровня (комментарий к багу).
Сегодня мы исправим этот недостаток.
Напомню, что на стороне сервера поддержка вложенных комментариев [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_798" class="wp-caption alignnone" style="width: 310px"><img src="http://www.simplecoding.org/wp-content/uploads/2009/03/bug_tracker_logo_part10.png" alt="bug_tracker_logo_part10" title="bug_tracker_logo_part10" width="300" height="154" class="size-full wp-image-798" style="float:left" /><p class="wp-caption-text"> </p></div>
<p>В предыдущих частях (<a href="http://www.simplecoding.org/sozdaem-sobstvennuyu-sistemu-otslezhivaniya-oshibok-na-php.html">1</a>, <a href="http://www.simplecoding.org/bug-tracker-ustanovka-frejmvorka-i-sozdanie-bazy-dannyx-chast-vtoraya.html">2</a>, <a href="http://www.simplecoding.org/bug-tracker-izmeneniya-v-proekte-chast-tretya.html">3</a>, <a href="http://www.simplecoding.org/bug-tracker-preobrazuem-tablicu-v-html-spisok-chast-4.html">4</a>, <a href="http://www.simplecoding.org/bug-tracker-model-i-stranicy-prilozheniya-chast-pyataya.html">5</a>, <a href="http://www.simplecoding.org/bug-tracker-sozdanie-stranic-chast-shestaya.html">6</a>, <a href="http://www.simplecoding.org/bug-tracker-dobavlenie-zapisej-i-kommentariev-chast-sedmaya.html">7</a>, <a href="http://www.simplecoding.org/bugtracker-avtorizaciya-i-autentifikaciya-chast-vosmaya.html">8</a>, <a href="http://www.simplecoding.org/bugtracker-lokalizaciya-chast-devyataya.html">9</a>) мы создали практически работоспособную <strong>систему отслеживания ошибок</strong>.</p>
<p>«Практически» в данном случае означает, что на данный момент у пользователя отсутствует возможность отвечать на комментарии. Т.е. можно оставить только комментарий 1-ого уровня (комментарий к багу).</p>
<p><strong>Сегодня мы исправим этот недостаток.</strong></p>
<p>Напомню, что на стороне сервера поддержка вложенных комментариев уже реализована. В базе данных (таблица <code>comments</code>) есть поле <code>parent_id</code> в котором хранится <code>id</code> родительского комментария.</p>
<p>Кроме того, метод <code>addComment</code> (модели <code>mcomments</code>) принимает массив с данными комментария, одним из полей которого является <code>parent_id</code>.</p>
<p>И, наконец, метод <code>addcomment</code> контроллера читает этот параметр из массива <code>$_POST</code> и передает его модели.</p>
<p>Таким образом, <strong>нам остается обеспечить возможность посетителю указывать на какой комментарий он хочет ответить</strong>.<br />
<span id="more-797"></span><br />
В принципе, реализовать эту возможность можно без <strong>JavaScript</strong>. Но при этом пользоваться ей будет очень <strong>не</strong> удобно. Нам придется сформировать выпадающий список с перечнем <code>id</code> всех комментариев к данному багу, а посетитель вручную будет выбирать на какой он хочет ответить. Не думаю, что кому-то понравиться работать с такой формой.</p>
<p>Ситуация совершенно меняется если использовать <strong>JavaScript</strong>. Под каждым комментарием мы создадим ссылку «Ответить». При клике по ней <strong>форма будет перемещаться под выбранный комментарий</strong>. <code>Id</code> этого комментария мы сохраним в скрытом поле формы.</p>
<p>Таким образом, детали механизма работы со вложенными комментариями будут совершенно незаметны пользователю. Кстати, комментарии в этом блоге работают именно таким образом.</p>
<p><strong>Переходим к реализации</strong>.</p>
<p>Прежде всего, рассмотрим разметку формы.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="sc2"><span class="kw2">&lt;form</span> <span class="kw3">id</span>=<span class="st0">&quot;fAddComment&quot;</span> <span class="kw3">method</span>=<span class="st0">&quot;post&quot;</span> <span class="kw3">action</span>=<span class="st0">&quot;http://www.bugtracker.l/bugtracker/addcomment&quot;</span><span class="kw2">&gt;</span></span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &#8230;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="sc2"><span class="kw2">&lt;div&gt;</span></span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2"><span class="kw2">&lt;input</span> <span class="kw3">type</span>=<span class="st0">&quot;hidden&quot;</span> <span class="kw3">value</span>=<span class="st0">&quot;&quot;</span> <span class="kw3">id</span>=<span class="st0">&quot;parent_id&quot;</span> <span class="kw3">name</span>=<span class="st0">&quot;parent_id&quot;</span>/<span class="kw2">&gt;</span></span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="sc2"><span class="kw2">&lt;/div&gt;</span></span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="sc2"><span class="kw2">&lt;p&gt;</span></span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="sc2"><span class="kw2">&lt;input</span> <span class="kw3">type</span>=<span class="st0">&quot;submit&quot;</span> <span class="kw3">value</span>=<span class="st0">&quot;Отправить&quot;</span> <span class="kw3">class</span>=<span class="st0">&quot;addcomment&quot;</span> <span class="kw3">id</span>=<span class="st0">&quot;addcomment&quot;</span> <span class="kw3">name</span>=<span class="st0">&quot;addcomment&quot;</span>/<span class="kw2">&gt;</span></span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="sc2"><span class="kw2">&lt;/p&gt;</span></span></div>
</li>
<li class="li1">
<div class="de1"><span class="sc2"><span class="kw2">&lt;/form&gt;</span></span></div>
</li>
</ol>
</div>
<p>Чтобы сделать её немного понятнее я опустил поля, которые не имеют отношения ко вложенным комментариями. В данном случае интерес представляет только одно поле &#8211; <code>parent_id</code>. В нём хранится <code>id</code> комментария, на который отвечает посетитель. Пустое значение в этом поле соответствует комментарию к багу (первый уровень).</p>
<p>Теперь подключим два JavaScript файла. Первый – библиотека <code>jQuery</code>, второй – файл с нашими функциями.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1">&lt;script type=<span class="st0">&quot;text/javascript&quot;</span> src=<span class="st0">&quot;&lt;?php echo base_url(); ?&gt;js/jquery-1.3.2.min.js&quot;</span>&gt;&lt;/script&gt;</div>
</li>
<li class="li1">
<div class="de1">&lt;script type=<span class="st0">&quot;text/javascript&quot;</span> src=<span class="st0">&quot;&lt;?php echo base_url(); ?&gt;js/main.js&quot;</span>&gt;&lt;/script&gt;</div>
</li>
</ol>
</div>
<p><em>Примечание</em>. Я разместил этот код в конце страницы (в представлении <code>footer.php</code>).</p>
<p><strong>Добавляем ссылку «Ответить»</strong> внизу каждого комментария. Для этого открываем шаблон комментариев (<code>\application\views\comment_tpl.php</code>)</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1">&lt;div <span class="kw2">class</span>=<span class="st0">&quot;comment depth-{depth}&quot;</span> id=<span class="st0">&quot;comment-{id}&quot;</span>&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;p <span class="kw2">class</span>=<span class="st0">&quot;commentInfo&quot;</span>&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &lt;span <span class="kw2">class</span>=<span class="st0">&quot;commentAuthor&quot;</span>&gt;Автор: <span class="br0">&#123;</span>uname<span class="br0">&#125;</span>.&lt;/span&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &lt;span <span class="kw2">class</span>=<span class="st0">&quot;commentDate&quot;</span>&gt;Дата: <span class="br0">&#123;</span>comment_date<span class="br0">&#125;</span>.&lt;/span&gt;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &lt;/p&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;p <span class="kw2">class</span>=<span class="st0">&quot;commentDescription&quot;</span>&gt;<span class="br0">&#123;</span>description<span class="br0">&#125;</span>&lt;/p&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;p <span class="kw2">class</span>=<span class="st0">&quot;replyComment&quot;</span>&gt;&lt;a href=<span class="st0">&quot;#&quot;</span>&gt;Ответить&lt;/a&gt;&lt;/p&gt;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">&lt;?php</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$this</span>-&gt;<span class="me1">redux_auth</span>-&gt;<span class="me1">logged_in</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&#039;&lt;p class=&quot;deleteComment&quot;&gt;&#039;</span>.anchor<span class="br0">&#40;</span><span class="st0">&#039;bugtracker/deletecomment/{id}&#039;</span>, <span class="st0">&#039;Удалить&#039;</span><span class="br0">&#41;</span>.<span class="st0">&#039;&lt;/p&gt;&#039;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">?&gt;</span></div>
</li>
<li class="li1">
<div class="de1">&lt;/div&gt;</div>
</li>
</ol>
</div>
<p>Ссылка создается в строке 7. Тут может возникнуть вопрос: «Почему в параметрах ссылки мы не указываем <code>id</code> комментария?». Дело в том, что с помощью <a href="http://jquery.com/">jQuery</a> мы можем легко получить родительский <code>div</code> (строка 1) и прочесть его атрибут <code>id</code>, в котором записан <code>id</code> комментария.</p>
<p>Теперь рассмотрим <strong>функцию, которая перемещает форму</strong> (файл <code>main.js</code>).</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1">$<span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="co1">//перемещаем форму</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; $<span class="br0">&#40;</span><span class="st0">&quot;.replyComment a&quot;</span><span class="br0">&#41;</span>.<span class="me1">click</span><span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">var</span> comment = $<span class="br0">&#40;</span><span class="kw1">this</span><span class="br0">&#41;</span>.<span class="me1">parent</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">parent</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">var</span> commentId = comment.<span class="me1">attr</span><span class="br0">&#40;</span><span class="st0">&quot;id&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">var</span> id = Array<span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//в id[1] будет сохранен id комментария на который нужно ответить</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; id = commentId.<span class="me1">split</span><span class="br0">&#40;</span><span class="st0">&#039;-&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; </div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//перемещаем форму</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; $<span class="br0">&#40;</span><span class="st0">&quot;#fAddComment&quot;</span><span class="br0">&#41;</span>.<span class="me1">appendTo</span><span class="br0">&#40;</span>comment<span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//устанавливаем значение в поле parent_id</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; $<span class="br0">&#40;</span><span class="st0">&quot;#parent_id&quot;</span><span class="br0">&#41;</span>.<span class="me1">val</span><span class="br0">&#40;</span>id<span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//добавляем ссылку &quot;Отменить комментарий&quot;, клик по ней возвращает форму вниз страницы</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; cancelComment = $<span class="br0">&#40;</span><span class="st0">&quot;&lt;p class=<span class="es0">\&quot;</span>cancelComment<span class="es0">\&quot;</span>&gt;&lt;a href=<span class="es0">\&quot;</span>#<span class="es0">\&quot;</span>&gt;Отменить комментарий&lt;/a&gt;&lt;/p&gt;&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; cancelComment.<span class="me1">prependTo</span><span class="br0">&#40;</span>$<span class="br0">&#40;</span><span class="st0">&quot;#fAddComment&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">var</span> cancelLink = cancelComment.<span class="me1">children</span><span class="br0">&#40;</span><span class="st0">&quot;a&quot;</span><span class="br0">&#41;</span>.<span class="me1">get</span><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; $<span class="br0">&#40;</span>cancelLink<span class="br0">&#41;</span>.<span class="me1">click</span><span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $<span class="br0">&#40;</span><span class="st0">&quot;#parent_id&quot;</span><span class="br0">&#41;</span>.<span class="me1">val</span><span class="br0">&#40;</span><span class="st0">&quot;&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $<span class="br0">&#40;</span><span class="kw1">this</span><span class="br0">&#41;</span>.<span class="me1">parent</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">remove</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $<span class="br0">&#40;</span><span class="st0">&quot;#fAddComment&quot;</span><span class="br0">&#41;</span>.<span class="me1">insertBefore</span><span class="br0">&#40;</span><span class="st0">&quot;#footer&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">false</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//предотвращает &quot;скачки&quot; страницы</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">false</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="br0">&#125;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="co1">//подтверждение удаления бага</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; $<span class="br0">&#40;</span><span class="st0">&quot;.deleteBug a&quot;</span><span class="br0">&#41;</span>.<span class="me1">click</span><span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw3">confirm</span><span class="br0">&#40;</span><span class="st0">&quot;Точно удалить?&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="br0">&#125;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="co1">//подтверждение удаления комментария</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; $<span class="br0">&#40;</span><span class="st0">&quot;.deleteComment a&quot;</span><span class="br0">&#41;</span>.<span class="me1">click</span><span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw3">confirm</span><span class="br0">&#40;</span><span class="st0">&quot;Будет удалена ветка комментариев начиная с данного. Удалить?&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="br0">&#125;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span><span class="br0">&#41;</span>;</div>
</li>
</ol>
</div>
<p>Рассмотрим как она работает.</p>
<p>Прежде всего, мы находим все ссылки, которые находятся внутри элементов с классом «<code>replyComment</code>» (т.е. наши ссылки «Ответить»), и назначаем им обработчик события <code>onclick</code> (строка 3).</p>
<p>При клике по ссылке начинает выполняться функция (строки 3-30). <strong>Алгоритм</strong> тут следующий.</p>
<p>1) Получаем родительский <code>div</code> и читаем его атрибут <code>id</code> (строки 4, 5).</p>
<p>2) Вырезаем из него номер комментария (с помощью функции <code>split</code>, строка 8).</p>
<p>3) Перемещаем форму. Для этого мы используем функцию <code>appendTo</code> из библиотеки jQuery. Элемент, к которому нужно добавить форму мы получили на 1-ом шаге.</p>
<p>4) Записываем значение в поле <code>parent_id</code> (строка 14).</p>
<p>5) Создаём ссылку «Отменить комментарий» и размещаем её в начале формы. Клик по ней вернет форму в исходное положение.</p>
<p>Без этой ссылки вернуть форму в исходное положение можно будет, только обновив страницу, а сделать это догадаются не все <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  .</p>
<p>6) Находим ссыку «Отменить комментарий» и назначем ей обработчик события onclick (строки 19-26).</p>
<p>7) В этом обработчике мы сбрасываем значение скрытого поля parent_id, удаляем ссылку «Отменить комментарий» и возвращаем форму в исходное положение.</p>
<p>Как видите, принцип работы достаточно простой. А благодаря jQuery вся функция занимает меньше 20 строк (если убрать комментарии и пустые строки).</p>
<p>В завершение мы <strong>выполняем ещё два действия</strong>.</p>
<p>Назначаем обработчик события <code>onclick</code> для всех ссылок «Удалить» (строки 33-40). Теперь при попытке удаления бага или комментария (в администраторском режиме) будет появляться диалог с просьбой подтвердить действие.</p>
<p>На этом я закончу эту часть.</p>
<p><strong>Демо версия баг трекера</strong>.</p>
<p>Если у вас есть желание поэкспериментировать я выложил <a href="http://www.simplecoding.org/bugtracker/">демо версию баг трекера</a>. Логин: <code>vvv@ddd.sss</code>, пароль: <code>111</code>.<br />
Можете не задумываясь вставлять или удалять любые данные, все равно у меня есть бекап базы <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://www.simplecoding.org/wp-content/uploads/2009/03/bugtracker.zip'>архив с исходниками</a>.</p>
<p>И, конечно, вы можете поделиться своими впечатлениями в комментариях <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p><img src="http://www.simplecoding.org/?ak_action=api_record_view&id=797&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/bug-tracker-otvety-na-kommentarii-chast-desyataya.html/feed</wfw:commentRss>
		<slash:comments>34</slash:comments>
		</item>
		<item>
		<title>BugTracker: локализация (часть девятая)</title>
		<link>http://www.simplecoding.org/bugtracker-lokalizaciya-chast-devyataya.html</link>
		<comments>http://www.simplecoding.org/bugtracker-lokalizaciya-chast-devyataya.html#comments</comments>
		<pubDate>Tue, 24 Mar 2009 07:36:44 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[CodeIgniter]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=795</guid>
		<description><![CDATA[Сегодня мы продолжаем разработку собственной системы отслеживания ошибок. В предыдущих частях мы рассмотрели добавление записей о багах и комментариев к ним.
Но при этом не решенным остался вопрос локализации.
По-умолчанию CodeIgniter выводит сообщения об ошибках на английском языке. Прежде всего, это касается описаний ошибок, которые возникают при некорректном заполнении форм.
В этой части я расскажу, как перевести эти [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_796" class="wp-caption alignnone" style="width: 213px"><img src="http://www.simplecoding.org/wp-content/uploads/2009/03/bug_tracker_logo_part9.jpg" alt="bug_tracker_logo_part9" title="bug_tracker_logo_part9" width="203" height="152" class="size-full wp-image-796" style="float:left; padding:0 10px 10px 0" /><p class="wp-caption-text"> </p></div>
<p>Сегодня мы продолжаем разработку собственной системы отслеживания ошибок. В предыдущих частях мы рассмотрели <a href="http://www.simplecoding.org/bug-tracker-dobavlenie-zapisej-i-kommentariev-chast-sedmaya.html">добавление записей о багах и комментариев к ним</a>.</p>
<p>Но при этом не решенным остался вопрос <strong>локализации</strong>.</p>
<p>По-умолчанию <a href="http://codeigniter.com/">CodeIgniter</a> выводит сообщения об ошибках на английском языке. Прежде всего, это касается описаний ошибок, которые возникают при некорректном заполнении форм.</p>
<p>В этой части я расскажу, как <strong>перевести эти сообщения на русский язык</strong>.</p>
<p>Самое интересное, что часть работы мы уже сделали <strong>при создании правил для проверки полей форм</strong>.</p>
<p>Например, правила для проверки <strong>email</strong> выглядят следующим образом.<br />
<span id="more-795"></span></p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re0">$this</span>-&gt;<span class="me1">form_validation</span>-&gt;<span class="me1">set_rules</span><span class="br0">&#40;</span><span class="st0">&#039;email&#039;</span>, <span class="st0">&#039;lang:email&#039;</span>, <span class="st0">&#039;required|valid_email&#039;</span><span class="br0">&#41;</span>;</div>
</li>
</ol>
</div>
<p>Здесь мы вызываем метод <code>set_rules</code> из библиотеки <code>form_validation</code>. В первом параметре указываем имя поля в форме (атрибут <code>name</code>), во втором – его описание, в третьем – правила.</p>
<p>Сейчас нас интересует <strong>второй параметр</strong>. Нам нужно, чтобы <strong>CodeIgniter</strong> подставил вместо него правильное описание поля.</p>
<p>Для этого нужно выполнить 4 шага.</p>
<p>1) Открываем файл <code>\application\config\config.php</code> и устанавливаем язык по-умолчанию.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re0">$config</span><span class="br0">&#91;</span><span class="st0">&#039;language&#039;</span><span class="br0">&#93;</span>&nbsp;= <span class="st0">&quot;russian&quot;</span>;</div>
</li>
</ol>
</div>
<p>Теперь CodeIgniter будет прежде всего искать файлы с описаниями в папке <code>\application\language\russian</code>.</p>
<p>2) Создаем папку <code>\application\language\russian</code> и в ней файл <code>form_fields_lang.php</code>. Обратите внимание: окончание <code>_lang</code> обязательно.</p>
<p>3) В этом файле создаем массив с описаниями полей:</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">&lt;?php</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$lang</span><span class="br0">&#91;</span><span class="st0">&#039;title&#039;</span><span class="br0">&#93;</span> = <span class="st0">&#039;&quot;Заголовок&quot;&#039;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$lang</span><span class="br0">&#91;</span><span class="st0">&#039;uname&#039;</span><span class="br0">&#93;</span> = <span class="st0">&#039;&quot;Ваше имя&quot;&#039;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$lang</span><span class="br0">&#91;</span><span class="st0">&#039;category_id&#039;</span><span class="br0">&#93;</span> = <span class="st0">&#039;&quot;Категория ошибки&quot;&#039;</span>;</div>
</li>
<li class="li2">
<div class="de2"><span class="re0">$lang</span><span class="br0">&#91;</span><span class="st0">&#039;description&#039;</span><span class="br0">&#93;</span> = <span class="st0">&#039;&quot;Описание ошибки&quot;&#039;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$lang</span><span class="br0">&#91;</span><span class="st0">&#039;email&#039;</span><span class="br0">&#93;</span> = <span class="st0">&#039;&quot;eMail&quot;&#039;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$lang</span><span class="br0">&#91;</span><span class="st0">&#039;password&#039;</span><span class="br0">&#93;</span> = <span class="st0">&#039;&quot;Пароль&quot;&#039;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">?&gt;</span></div>
</li>
</ol>
</div>
<p>Ключи элементов этого массива должны совпадать с именами, которые указаны после <code>lang:</code> (во втором параметре метода <code>set_rules</code>).</p>
<p>4) Загружаем файл с описаниями полей. Для этого в конструктор контроллера добавляем строку.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">language</span><span class="br0">&#40;</span><span class="st0">&#039;form_fields&#039;</span><span class="br0">&#41;</span>;</div>
</li>
</ol>
</div>
<p><em>Обратите внимание</em>. Окончание <code>_lang.php</code> не указываем.</p>
<p>После этих манипуляций описания полей будут правильно отображаться. Но сами ошибки будут на английском.</p>
<p>Для их руссификации нужно скачать <a href="http://rmcreative.ru/blog/post/obnovljon-perevod-codeigniter-1.7.0">файлы с переводами</a>.</p>
<p>Архив распаковываем в папку <code>\application\language\russian</code>.</p>
<p>Всё. На этом работа заканчивается. Названия этих файлов совпадают с названиями их английских версий, поэтому <strong>CodeIgniter загрузит их автоматически</strong>.</p>
<p><strong>Заключение</strong>.</p>
<p>В данном случае мы просто русифицировали баг трекер. Ничего сложного, но проблема в том, что выполнить обратную операцию, т.е. перевести приложение на английский, <strong>намного</strong> сложнее.</p>
<p>Для этого нужно найти и исправить весь русский текст в исходниках баг трекера. А их довольно много. Это и файлы шаблонов, и сообщения в контроллере, и текст в представлениях.</p>
<p>Я не ставил задачи сделать мультиязычное приложение, но если этот пункт для вас важен, в CodeIgniter входит <strong>Language Helper</strong> для этих целей. Использовать его не сложно, самый трудоёмкий этап – создание файлов с переводами. И нужно внимательно следить, чтобы в исходниках проекта напрямую не был жестко прописан текст.</p>
<p>До встречи!</p>
<p><strong>P.S.</strong> Думаю, к следующему выпуску будет готова демонстрационная версия баг трекера. И безусловно выложу архив файлами проекта.</p><img src="http://www.simplecoding.org/?ak_action=api_record_view&id=795&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/bugtracker-lokalizaciya-chast-devyataya.html/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>BugTracker: авторизация и аутентификация (часть восьмая)</title>
		<link>http://www.simplecoding.org/bugtracker-avtorizaciya-i-autentifikaciya-chast-vosmaya.html</link>
		<comments>http://www.simplecoding.org/bugtracker-avtorizaciya-i-autentifikaciya-chast-vosmaya.html#comments</comments>
		<pubDate>Sun, 22 Mar 2009 12:46:38 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[CodeIgniter]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=793</guid>
		<description><![CDATA[Приветствую всех читателей!
В этой части мы рассмотрим создание не сложной системы авторизации пользователей нашего баг трекера.
Для начала сформулируем задачу.
Как вы, наверное, помните, оставить сообщение о найденном баге или комментарий к нему может кто угодно. Но удалять записи и комментарии могут только администраторы.
На практике это будет выглядеть следующим образом. Администратор при входе вводит имя и пароль. [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_794" class="wp-caption alignnone" style="width: 273px"><img src="http://www.simplecoding.org/wp-content/uploads/2009/03/bug_tracker_logo_part8.png" alt="bug_tracker_logo_part8" title="bug_tracker_logo_part8" width="263" height="158" class="size-full wp-image-794" style="float:left" /><p class="wp-caption-text"> </p></div>
<p><strong>Приветствую всех читателей!</strong></p>
<p>В этой части мы рассмотрим создание не сложной <strong>системы авторизации пользователей</strong> нашего баг трекера.</p>
<p>Для начала <strong>сформулируем задачу</strong>.</p>
<p>Как вы, наверное, помните, оставить сообщение о найденном баге или комментарий к нему может кто угодно. Но удалять записи и комментарии могут только администраторы.</p>
<p>На практике это будет выглядеть следующим образом. Администратор при входе вводит имя и пароль. Баг трекер их проверяет и, если они совпадают с записанными в базе данных, добавляет к каждому багу и комментарию ссылку «Удалить».</p>
<p>Кроме того, при выполнении каждой операции удаления необходимо проверить является ли текущий пользователь администратором.</p>
<p>Для справки. Эти проверки называются <strong>аутентификация</strong> и <strong>авторизация</strong>.<br />
<span id="more-793"></span></p>
<blockquote><p><strong>Авторизация</strong> (англ. authorization) — процесс предоставления определенному лицу прав на выполнение некоторых действий.</p>
<p><strong>Аутентификация</strong> (англ. Authentication) — процедура проверки соответствия некоего лица и его учетной записи в компьютерной системе.</p></blockquote>
<p>(цитаты из <a href="http://ru.wikipedia.org/">википедии</a>)</p>
<p>Таким образом, при входе в систему нам нужно аутентифицировать администратора, а при выполнении им операции – авторизовать.</p>
<p>Задача, в общем-то, стандартная и для её решения написано множество библиотек разной степени сложности.</p>
<p>Прежде чем переходить к выбору библиотеки, <strong>перечислим функции</strong>, которые нужны для разделения прав в нашем баг трекере.</p>
<p>1) Создание учетной записи в базе данных.</p>
<p>2) Проверка имени и пароля при входе в систему (аутентификация).</p>
<p>3) Проверка прав пользователя на выполнение операции (авторизация).</p>
<p>Требования минимальные и не сложно было бы реализовать такую систему самостоятельно. Но зачем «изобретать велосипед» если есть куча готовых решений?</p>
<p>Для этого проекта я решил использовать библиотеку под названием <a href="http://code.google.com/p/reduxauth/">Redux</a>. Каких-то особых причин, по которым я на ней остановился, нет. Просто видел несколько хороших отзывов, и захотелось поэкспериментировать.</p>
<p>На данный момент есть две версии библиотеки: 1.4а (стабильная) и 2 (бета). Вторая по своим возможностям мне понравилась больше, поэтому и использовал я именно её. Но бета есть бета, и сразу обнаружилось несколько недостатков.</p>
<p>Самое главное, в архиве 2-ой версии нет документации, есть только демонстрационный пример. Полноценная справка написана для версии 1.4, причем очень хорошая, сделана в том же стиле, что и тьюториал <strong>CodeIgniter</strong>.</p>
<p>Используя пример и справку из версии 1.4, разобраться не сложно.</p>
<p>Теперь рассмотрим, что нужно сделать для <strong>подключения этой библиотеки к нашему приложению</strong>.</p>
<p>1) Скачать и распаковать <a href="http://code.google.com/p/reduxauth/">архив</a>.</p>
<p>2) Скопировать 3 файла:<br />
<code>\application\config\redux_auth.php<br />
\application\models\redux_auth_model.php<br />
\application\libraries\redux_auth.php</code></p>
<p>3) Импортировать файл <code>database.sql</code> в базу данных. При этом будут созданы несколько таблиц.</p>
<p>4) Настроить библиотеку. Для этого, открываем файл \application\config\redux_auth.php и изменяем соответствующие значения. Здесь я только отключил активацию по email.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re0">$config</span><span class="br0">&#91;</span><span class="st0">&#039;email_activation&#039;</span><span class="br0">&#93;</span> = <span class="kw2">false</span>;</div>
</li>
</ol>
</div>
<p>5) Создаем группу, которая используется по-умолчанию. В файле <code>\application\config\redux_auth.php</code> есть параметр</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re0">$config</span><span class="br0">&#91;</span><span class="st0">&#039;default_group&#039;</span><span class="br0">&#93;</span> = <span class="st0">&#039;member&#039;</span>;</div>
</li>
</ol>
</div>
<p>Чтобы библиотека нормально заработала нужно создать в таблице groups запись с название этой группы. Т.е. <code>name='member'</code>, <code>description='member group description'</code>.</p>
<p>6) В таблице <code>sessions</code> изменяем сравнение для поля <code>user_data</code> на <code>utf8_general_ci</code>, иначе будут проблемы с кириллицей.</p>
<p>7) Открываем файл <code>\application\config\config.php</code> и находим раздел с настройками сессий. Я изменил</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re0">$config</span><span class="br0">&#91;</span><span class="st0">&#039;sess_encrypt_cookie&#039;</span><span class="br0">&#93;</span>&nbsp; = <span class="kw2">TRUE</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$config</span><span class="br0">&#91;</span><span class="st0">&#039;sess_use_database&#039;</span><span class="br0">&#93;</span>&nbsp; &nbsp; = <span class="kw2">TRUE</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$config</span><span class="br0">&#91;</span><span class="st0">&#039;sess_table_name&#039;</span><span class="br0">&#93;</span>&nbsp; &nbsp; &nbsp; = <span class="st0">&#039;sessions&#039;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$config</span><span class="br0">&#91;</span><span class="st0">&#039;sess_match_ip&#039;</span><span class="br0">&#93;</span>&nbsp; &nbsp; &nbsp; &nbsp; = <span class="kw2">TRUE</span>;</div>
</li>
<li class="li2">
<div class="de2"><span class="re0">$config</span><span class="br0">&#91;</span><span class="st0">&#039;sess_match_useragent&#039;</span><span class="br0">&#93;</span>&nbsp;= <span class="kw2">TRUE</span>;</div>
</li>
</ol>
</div>
<p>8 ) Добавляем библиотеку в автозагрузку (файл <code>\application\config\autoload.php</code>).</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re0">$autoload</span><span class="br0">&#91;</span><span class="st0">&#039;libraries&#039;</span><span class="br0">&#93;</span> = <span class="kw3">array</span><span class="br0">&#40;</span><span class="st0">&#039;database&#039;</span>, <span class="st0">&#039;session&#039;</span>, <span class="st0">&#039;redux_auth&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$autoload</span><span class="br0">&#91;</span><span class="st0">&#039;model&#039;</span><span class="br0">&#93;</span> = <span class="kw3">array</span><span class="br0">&#40;</span><span class="st0">&#039;redux_auth_model&#039;</span><span class="br0">&#41;</span>;</div>
</li>
</ol>
</div>
<p>Теперь нужно <strong>создать учетную запись администратора</strong>.</p>
<p>Т.к. в базе данных храниться не сам пароль, а его хеш, то удобнее всего добавить запись средствами библиотеки, а не вручную.</p>
<p>Для этого, добавим в контроллер (<code>bugtracker</code>) метод <code>register</code>.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">function</span> register<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">redux_auth</span>-&gt;<span class="me1">register</span><span class="br0">&#40;</span><span class="st0">&#039;admin&#039;</span>, <span class="st0">&#039;password&#039;</span>, <span class="st0">&#039;admin@bugtracker.local&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Заходим один раз на страницу <code>bugtracker.local/bugtracker/register</code> и в базе данных появляется новая запись.</p>
<p>После этого метод можно удалить.</p>
<p><em>Обратите внимание!</em> Для аутентификации <strong>Redux</strong> использует не имя (admin), а email.</p>
<p><strong>Создаем страницу с формой входа.</strong></p>
<p>Для этого добавляем в контроллер метод <code>login</code>.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">function</span> login<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$this</span>-&gt;<span class="me1">redux_auth</span>-&gt;<span class="me1">logged_in</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; redirect<span class="br0">&#40;</span><span class="st0">&#039;bugtracker/page&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">$pageData</span><span class="br0">&#91;</span><span class="st0">&#039;title&#039;</span><span class="br0">&#93;</span> = <span class="st0">&#039;Login&#039;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">view</span><span class="br0">&#40;</span><span class="st0">&#039;header&#039;</span>, <span class="re0">$pageData</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">view</span><span class="br0">&#40;</span><span class="st0">&#039;login&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">view</span><span class="br0">&#40;</span><span class="st0">&#039;footer&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Этот метод просто создает страницу с формой. Сама форма находится в представлении <code>\views\login.php</code>.</p>
<p>Перед формированием страницы мы с помощью метода <code>logged_in()</code> проверяем, выполнил ли вход данный пользователь (строки 2-4). И если да, то отправляем его на главную страницу багтрекера.</p>
<p>Теперь рассмотрим <strong>представление</strong> (<code>\views\login.php</code>)</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">&lt;?php</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$mes</span> = <span class="re0">$this</span>-&gt;<span class="me1">session</span>-&gt;<span class="me1">flashdata</span><span class="br0">&#40;</span><span class="st0">&#039;message&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span> <span class="br0">&#40;</span>!<span class="kw3">empty</span><span class="br0">&#40;</span><span class="re0">$mes</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&#039;&lt;div id=&quot;infoMessage&quot;&gt;&#039;</span>.<span class="re0">$mes</span>.<span class="st0">&#039;&lt;/div&gt;&#039;</span>;</div>
</li>
<li class="li2">
<div class="de2"><span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">?&gt;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">&lt;?php</span> <span class="kw3">echo</span> form_open<span class="br0">&#40;</span><span class="st0">&#039;bugtracker/checklogin&#039;</span>, <span class="kw3">array</span><span class="br0">&#40;</span><span class="st0">&#039;id&#039;</span>=&gt;<span class="st0">&#039;fLogin&#039;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>; <span class="kw2">?&gt;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;p&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;label <span class="kw1">for</span>=<span class="st0">&quot;email&quot;</span>&gt;eMail&lt;/label&gt;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &lt;input type=<span class="st0">&quot;text&quot;</span> name=<span class="st0">&quot;email&quot;</span> id=<span class="st0">&quot;email&quot;</span> value=<span class="st0">&quot;&lt;?php echo set_value(&#039;email&#039;); ?&gt;&quot;</span> /&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;/p&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw2">&lt;?php</span> <span class="kw3">echo</span> form_error<span class="br0">&#40;</span><span class="st0">&#039;eMail&#039;</span><span class="br0">&#41;</span>; <span class="kw2">?&gt;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;p <span class="kw2">class</span>=<span class="st0">&quot;even&quot;</span>&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;label <span class="kw1">for</span>=<span class="st0">&quot;password&quot;</span>&gt;Пароль&lt;/label&gt;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &lt;input type=<span class="st0">&quot;password&quot;</span> name=<span class="st0">&quot;password&quot;</span> id=<span class="st0">&quot;password&quot;</span> value=<span class="st0">&quot;&quot;</span> /&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;/p&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw2">&lt;?php</span> <span class="kw3">echo</span> form_error<span class="br0">&#40;</span><span class="st0">&#039;password&#039;</span><span class="br0">&#41;</span>; <span class="kw2">?&gt;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;p&gt;&lt;input type=<span class="st0">&quot;submit&quot;</span> name=<span class="st0">&quot;bLogin&quot;</span> id=<span class="st0">&quot;bLogin&quot;</span> <span class="kw2">class</span>=<span class="st0">&quot;bLogin&quot;</span> value=<span class="st0">&quot;Войти&quot;</span> /&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;/p&gt;</div>
</li>
<li class="li2">
<div class="de2">&lt;/form&gt;</div>
</li>
</ol>
</div>
<p>Тут все просто. Мы создаем обычную форму с двумя полями: «eMail» и «Пароль». После нажатия на кнопку «Войти» данные будут отправлены методу <code>checklogin</code> контроллера (строка 7).</p>
<p>Этот метод выполняет аутентификацию пользователя. Проще говоря проверяет соответствие email&#039;а паролю.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">function</span> checklogin<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">library</span><span class="br0">&#40;</span><span class="st0">&#039;form_validation&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">form_validation</span>-&gt;<span class="me1">set_rules</span><span class="br0">&#40;</span><span class="st0">&#039;email&#039;</span>, <span class="st0">&#039;lang:email&#039;</span>, <span class="st0">&#039;required|valid_email&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">form_validation</span>-&gt;<span class="me1">set_rules</span><span class="br0">&#40;</span><span class="st0">&#039;password&#039;</span>, <span class="st0">&#039;lang:password&#039;</span>, <span class="st0">&#039;required&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">form_validation</span>-&gt;<span class="me1">set_error_delimiters</span><span class="br0">&#40;</span><span class="st0">&#039;&lt;div class=&quot;fErrMessage&quot;&gt;&#039;</span>, <span class="st0">&#039;&lt;/div&gt;&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$this</span>-&gt;<span class="me1">form_validation</span>-&gt;<span class="me1">run</span><span class="br0">&#40;</span><span class="br0">&#41;</span> == <span class="kw2">false</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$pageData</span><span class="br0">&#91;</span><span class="st0">&#039;title&#039;</span><span class="br0">&#93;</span> = <span class="st0">&#039;Login error&#039;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">view</span><span class="br0">&#40;</span><span class="st0">&#039;header&#039;</span>, <span class="re0">$pageData</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">view</span><span class="br0">&#40;</span><span class="st0">&#039;login&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">view</span><span class="br0">&#40;</span><span class="st0">&#039;footer&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">else</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$login</span> &nbsp; &nbsp;= <span class="re0">$this</span>-&gt;<span class="me1">input</span>-&gt;<span class="me1">post</span><span class="br0">&#40;</span><span class="st0">&#039;email&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$password</span> = <span class="re0">$this</span>-&gt;<span class="me1">input</span>-&gt;<span class="me1">post</span><span class="br0">&#40;</span><span class="st0">&#039;password&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$this</span>-&gt;<span class="me1">redux_auth</span>-&gt;<span class="me1">login</span><span class="br0">&#40;</span><span class="re0">$login</span>, <span class="re0">$password</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">session</span>-&gt;<span class="me1">set_flashdata</span><span class="br0">&#40;</span><span class="st0">&#039;message&#039;</span>, <span class="st0">&#039;Привет, &#039;</span>.<span class="re0">$login</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; redirect<span class="br0">&#40;</span><span class="st0">&#039;bugtracker/page&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">session</span>-&gt;<span class="me1">set_flashdata</span><span class="br0">&#40;</span><span class="st0">&#039;message&#039;</span>, <span class="st0">&#039;Неверная пара логин/пароль, попробуйте ещё раз&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; redirect<span class="br0">&#40;</span><span class="st0">&#039;bugtracker/login&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Прежде всего, мы поверяем корректность заполнения формы. Для этого создаем правила (строки 3, 4) и выполняем проверку (сторока 7). Если форма заполнена правильно (данные введены), то с помощью метода <code>login($login, $password)</code> (строка 19) ищем посетителя в базе данных.</p>
<p>Если соответствующая запись в БД будет найдена, отправляем его на главную (строка 21). При этом библиотека сама сохранит данные этого пользователя в сессии. И в дальнейшем мы сможем использовать метод <code>logged_in()</code> для авторизации пользователя.</p>
<p>Если email или пароль введены не правильно, то показываем посетителю форму ещё раз с предложением попробовать ещё раз.</p>
<p>Теперь рассмотрим <strong>метод удаления записи о баге</strong>.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">function</span> deletebug<span class="br0">&#40;</span><span class="re0">$bugId</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$this</span>-&gt;<span class="me1">redux_auth</span>-&gt;<span class="me1">logged_in</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$this</span>-&gt;<span class="me1">mbug</span>-&gt;<span class="me1">delete</span><span class="br0">&#40;</span><span class="re0">$bugId</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">session</span>-&gt;<span class="me1">set_flashdata</span><span class="br0">&#40;</span><span class="st0">&#039;message&#039;</span>, <span class="st0">&#039;Баг удален&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; redirect<span class="br0">&#40;</span><span class="re0">$this</span>-&gt;<span class="me1">session</span>-&gt;<span class="me1">userdata</span><span class="br0">&#40;</span><span class="st0">&#039;prev_page&#039;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">session</span>-&gt;<span class="me1">set_flashdata</span><span class="br0">&#40;</span><span class="st0">&#039;message&#039;</span>, <span class="st0">&#039;При удалении бага возникла ошибка&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; redirect<span class="br0">&#40;</span><span class="re0">$this</span>-&gt;<span class="me1">session</span>-&gt;<span class="me1">userdata</span><span class="br0">&#40;</span><span class="st0">&#039;prev_page&#039;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">session</span>-&gt;<span class="me1">set_flashdata</span><span class="br0">&#40;</span><span class="st0">&#039;message&#039;</span>, <span class="st0">&#039;Вы должны войти для того, чтобы выполнить это действие&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; redirect<span class="br0">&#40;</span><span class="st0">&#039;bugtracker/login&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Во второй строке мы <strong>выполняем авторизацию</strong> пользователя. И в зависимости от её результатов либо удаляем баг (строки 3-10), либо отправляем посетителя на страницу с формой входа (строки 13, 14).</p>
<p>Т.е. если кто-то, не выполнив вход, попробует отправить запрос <code>bugtracker.local/bugtracker/deletebug/1</code>, то он увидит сообщение &#039;Вы должны войти для того, чтобы выполнить это действие&#039; и форму ввода email и пароля.</p>
<p>В шаблонах багов и комментариев (bug_tpl.php и comment_tpl.php) также добавим несколько строк:</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$this</span>-&gt;<span class="me1">redux_auth</span>-&gt;<span class="me1">logged_in</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&#039;&lt;p class=&quot;deleteBug&quot;&gt;&#039;</span>.anchor<span class="br0">&#40;</span><span class="st0">&#039;bugtracker/deletebug/{id}&#039;</span>, <span class="st0">&#039;Удалить&#039;</span><span class="br0">&#41;</span>.<span class="st0">&#039;&lt;/p&gt;&#039;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Таким образом, администраторы увидят ссылку «Удалить» рядом с каждым багом и комментарием.</p>
<p><em>Примечание</em>. Подробнее об этих шаблонах можно почитать в <a href="http://www.simplecoding.org/bug-tracker-preobrazuem-tablicu-v-html-spisok-chast-4.html/2">четвертой части</a>.</p>
<p>И последний момент. Нужно дать возможность администратору <strong>выйти из приложения</strong>.</p>
<p>Для этого создаем метод <code>logout</code>.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">function</span> logout<span class="br0">&#40;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">redux_auth</span>-&gt;<span class="me1">logout</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">session</span>-&gt;<span class="me1">set_flashdata</span><span class="br0">&#40;</span><span class="st0">&#039;message&#039;</span>, <span class="st0">&#039;Вы вышли из администраторского режима&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; redirect<span class="br0">&#40;</span><span class="st0">&#039;bugtracker/page&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>После выхода (строка 2) мы сохраняем в сессии сообщение и отправляем редирект на главную страницу.</p>
<p>Как видите, библиотека довольно удобная и работать с ней не сложно. Кроме того, при необходимости с её помощью можно легко добавить возможность регистрации в баг трекере или разделить пользователей на группы с разными правами.</p>
<p><strong>P.S.</strong> Если возникли вопросы или есть замечания, пишите, постараюсь ответить <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p><img src="http://www.simplecoding.org/?ak_action=api_record_view&id=793&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/bugtracker-avtorizaciya-i-autentifikaciya-chast-vosmaya.html/feed</wfw:commentRss>
		<slash:comments>22</slash:comments>
		</item>
		<item>
		<title>Bug Tracker: добавление записей и комментариев (часть седьмая)</title>
		<link>http://www.simplecoding.org/bug-tracker-dobavlenie-zapisej-i-kommentariev-chast-sedmaya.html</link>
		<comments>http://www.simplecoding.org/bug-tracker-dobavlenie-zapisej-i-kommentariev-chast-sedmaya.html#comments</comments>
		<pubDate>Wed, 18 Mar 2009 17:07:19 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[CodeIgniter]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=789</guid>
		<description><![CDATA[В этой части цикла статей о разработке баг трекера мы рассмотрим добавление записей о багах и комментариев к ним.
Вообще-то обе эти операции сводятся к добавлению записей в таблицы bugs и comments, т.е. их можно выполнить с помощью всего пары строк кода.
Но, как несложно догадаться, основная часть работы будет заключаться в обработке данных.
Кроме того, нужно сразу [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_791" class="wp-caption alignnone" style="width: 275px"><img src="http://www.simplecoding.org/wp-content/uploads/2009/03/bug_tracker_logo_part7.png" alt="bug_tracker_logo_part7" title="bug_tracker_logo_part7" width="265" height="160" class="size-full wp-image-791" style="float:left" /><p class="wp-caption-text"> </p></div>
<p>В этой части цикла статей о разработке баг трекера мы рассмотрим <strong>добавление записей о багах и комментариев к ним</strong>.</p>
<p>Вообще-то обе эти операции сводятся к добавлению записей в <a href="http://www.simplecoding.org/bug-tracker-izmeneniya-v-proekte-chast-tretya.html">таблицы bugs и comments</a>, т.е. их можно выполнить с помощью всего пары строк кода.</p>
<p>Но, как несложно догадаться, <strong>основная часть работы будет заключаться в обработке данных</strong>.</p>
<p>Кроме того, нужно сразу решить вопрос с тегами и <strong>защитой от XSS атак</strong>.</p>
<p>Проблема следующая. Если разрешить пользователям вставлять в текст описания багов любые <acronym title="HyperText Markup Language">HTML</acronym> теги и не выполнять никаких проверок, то кто угодно сможет провести любую XSS атаку. Например, вставить скрипт с редиректом на свой ресурс.</p>
<p>С другой стороны, если фильтровать все теги, то посетители не смогут использовать жирный шрифт, курсив и т.п.</p>
<p>Решить проблему можно с помощью <strong>bbCodes</strong> или <strong>фильтрацией части тегов</strong>. Например, теги <code>script</code> удаляем, а <code>strong</code> – не трогаем.</p>
<p>Я решил выбрать второй вариант. Тем более что его не сложно реализовать с помощью библиотеки <a href="http://htmlpurifier.org/"><acronym title="HyperText Markup Language">HTML</acronym> Purifier</a>. Кроме фильтрации опасных тегов, библиотека исправляет ошибки в разметке. Например, добавляет закрывающие теги.</p>
<p><strong>Подключение <acronym title="HyperText Markup Language">HTML</acronym> Purifier к CodeIgniter</strong>.<br />
<span id="more-789"></span><br />
Я использовал вот <a href="http://blog.ortz.org/2008/12/30/making-html-purifier-work-with-codeigniter/">эту инструкцию</a>. Правда, я создал для библиотеки отдельную папку (\application\libraries\htmlpurifier).</p>
<p>После этого нужно закомментировать строку<br />
<code>require 'HTMLPurifier.php';</code><br />
в файле HTMLPurifier.includes.php.</p>
<p>А в файл HTMLPurifier.php (сразу после <code>&lt;?php</code>) добавить<br />
<code>require_once('HTMLPurifier.includes.php');</code></p>
<p>Подключается библиотека так:</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">library</span><span class="br0">&#40;</span><span class="st0">&#039;htmlpurifier/HTMLPurifier&#039;</span><span class="br0">&#41;</span>;</div>
</li>
</ol>
</div>
<p>Теперь рассмотрим <strong>алгоритм добавления записи о баге</strong>.</p>
<div id="attachment_792" class="wp-caption alignnone" style="width: 422px"><img src="http://www.simplecoding.org/wp-content/uploads/2009/03/addbug.jpg" alt="add bug" title="add bug" width="412" height="504" class="size-full wp-image-792" /><p class="wp-caption-text"> </p></div>
<p>Сначала мы проверяем данные с помощью встроенной библиотеки <code>form_validation</code>. Для её работы нужно <strong>установить правила</strong> для каждого поля формы.</p>
<p>Полей у нас 5: заголовок, имя пользователя, eMail пользователя, категория и описание бага.</p>
<p>Если проверка прошла, мы обрабатываем данные с помощью <strong><acronym title="HyperText Markup Language">HTML</acronym> Purifier</strong> и добавляем их в базу. Читаем из сессии адрес последней страницы, на которой находился посетитель. И отправляем ему редирект с адресом этой страницы. Т.к. у нас есть несколько страниц, на которых находится форма добавления бага (главная, страницы категорий), то пользователь, скорее всего, захочет остаться на той странице, с которой он отправлял сообщение.</p>
<p>Если во время проверки возникли ошибки – формируем страницу с этой же формой и описаниями ошибок и отправляем её посетителю.</p>
<p>Теперь посмотрите на код метода <code>addbug</code>.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">function</span> addbug<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">library</span><span class="br0">&#40;</span><span class="st0">&#039;form_validation&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">form_validation</span>-&gt;<span class="me1">set_error_delimiters</span><span class="br0">&#40;</span><span class="st0">&#039;&lt;div class=&quot;fErrMessage&quot;&gt;&#039;</span>, <span class="st0">&#039;&lt;/div&gt;&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">form_validation</span>-&gt;<span class="me1">set_rules</span><span class="br0">&#40;</span><span class="st0">&#039;title&#039;</span>, <span class="st0">&#039;lang:title&#039;</span>, <span class="st0">&#039;required&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">form_validation</span>-&gt;<span class="me1">set_rules</span><span class="br0">&#40;</span><span class="st0">&#039;uname&#039;</span>, <span class="st0">&#039;lang:uname&#039;</span>, <span class="st0">&#039;required&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">form_validation</span>-&gt;<span class="me1">set_rules</span><span class="br0">&#40;</span><span class="st0">&#039;category_id&#039;</span>, <span class="st0">&#039;lang:category_id&#039;</span>, <span class="st0">&#039;required|integer&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">form_validation</span>-&gt;<span class="me1">set_rules</span><span class="br0">&#40;</span><span class="st0">&#039;description&#039;</span>, <span class="st0">&#039;lang:description&#039;</span>, <span class="st0">&#039;required&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">form_validation</span>-&gt;<span class="me1">set_rules</span><span class="br0">&#40;</span><span class="st0">&#039;email&#039;</span>, <span class="st0">&#039;lang:email&#039;</span>, <span class="st0">&#039;required|valid_email&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$this</span>-&gt;<span class="me1">form_validation</span>-&gt;<span class="me1">run</span><span class="br0">&#40;</span><span class="br0">&#41;</span> === <span class="kw2">FALSE</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//ошибка</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$pageData</span><span class="br0">&#91;</span><span class="st0">&#039;message&#039;</span><span class="br0">&#93;</span> = <span class="st0">&#039;Форма заполнена неправильно&#039;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//показываем форму с описаниями ошибок</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$pageData</span><span class="br0">&#91;</span><span class="st0">&#039;title&#039;</span><span class="br0">&#93;</span> = <span class="st0">&#039;Bug Tracker&#039;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$pageData</span><span class="br0">&#91;</span><span class="st0">&#039;categories&#039;</span><span class="br0">&#93;</span> = <span class="re0">$this</span>-&gt;<span class="me1">mcategory</span>-&gt;<span class="me1">getAllCategories</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">view</span><span class="br0">&#40;</span><span class="st0">&#039;header&#039;</span>, <span class="re0">$pageData</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">view</span><span class="br0">&#40;</span><span class="st0">&#039;categories&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">view</span><span class="br0">&#40;</span><span class="st0">&#039;addbugform&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">view</span><span class="br0">&#40;</span><span class="st0">&#039;footer&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//форма заполнена правильно</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">library</span><span class="br0">&#40;</span><span class="st0">&#039;htmlpurifier/HTMLPurifier&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$config</span> = HTMLPurifier_Config::<span class="me2">createDefault</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugData</span><span class="br0">&#91;</span><span class="st0">&#039;title&#039;</span><span class="br0">&#93;</span> = <span class="re0">$this</span>-&gt;<span class="me1">htmlpurifier</span>-&gt;<span class="me1">purify</span><span class="br0">&#40;</span><span class="re0">$this</span>-&gt;<span class="me1">input</span>-&gt;<span class="me1">post</span><span class="br0">&#40;</span><span class="st0">&#039;title&#039;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugData</span><span class="br0">&#91;</span><span class="st0">&#039;uname&#039;</span><span class="br0">&#93;</span> = <span class="re0">$this</span>-&gt;<span class="me1">htmlpurifier</span>-&gt;<span class="me1">purify</span><span class="br0">&#40;</span><span class="re0">$this</span>-&gt;<span class="me1">input</span>-&gt;<span class="me1">post</span><span class="br0">&#40;</span><span class="st0">&#039;uname&#039;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugData</span><span class="br0">&#91;</span><span class="st0">&#039;category_id&#039;</span><span class="br0">&#93;</span> = <span class="re0">$this</span>-&gt;<span class="me1">input</span>-&gt;<span class="me1">post</span><span class="br0">&#40;</span><span class="st0">&#039;category_id&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugData</span><span class="br0">&#91;</span><span class="st0">&#039;uemail&#039;</span><span class="br0">&#93;</span> = <span class="re0">$this</span>-&gt;<span class="me1">input</span>-&gt;<span class="me1">post</span><span class="br0">&#40;</span><span class="st0">&#039;email&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugData</span><span class="br0">&#91;</span><span class="st0">&#039;description&#039;</span><span class="br0">&#93;</span> = <span class="re0">$this</span>-&gt;<span class="me1">htmlpurifier</span>-&gt;<span class="me1">purify</span><span class="br0">&#40;</span><span class="re0">$this</span>-&gt;<span class="me1">input</span>-&gt;<span class="me1">post</span><span class="br0">&#40;</span><span class="st0">&#039;description&#039;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="br0">&#40;</span><span class="re0">$res</span> = <span class="re0">$this</span>-&gt;<span class="me1">mbug</span>-&gt;<span class="me1">addNewBug</span><span class="br0">&#40;</span><span class="re0">$bugData</span><span class="br0">&#41;</span><span class="br0">&#41;</span> !== <span class="kw2">FALSE</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//данные добавлены</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">session</span>-&gt;<span class="me1">set_flashdata</span><span class="br0">&#40;</span><span class="st0">&#039;message&#039;</span>, <span class="st0">&#039;Сообщение добавлено&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//при добавлении данных возникла ошибка</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">session</span>-&gt;<span class="me1">set_flashdata</span><span class="br0">&#40;</span><span class="st0">&#039;message&#039;</span>, <span class="st0">&#039;При добавлении данных возникла ошибка&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; redirect<span class="br0">&#40;</span><span class="re0">$this</span>-&gt;<span class="me1">session</span>-&gt;<span class="me1">userdata</span><span class="br0">&#40;</span><span class="st0">&#039;prev_page&#039;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Как видите, метод работает точно в соответствии с описанным алгоритмом.</p>
<p>Тут стоит обратить внимание на строки 6 и 8. В них мы установили правила (<code>integer</code>, <code>valid_email</code>), которые обеспечивают проверку номера категории и email адреса.</p>
<p>Кроме того, использовать библиотеку <strong><acronym title="HyperText Markup Language">HTML</acronym> Purifier</strong> имеет смысл только после обычной проверки. Причин тут две. Во-первых, если пользователь не заполнил какое-то поле формы (а в данном случае они все обязательные), то пытаться удалить теги из него бессмысленно. Во-вторых, если вы все-таки попытаетесь это сделать, то <acronym title="HyperText Markup Language">HTML</acronym> Purifier начинает потреблять кучу ресурсов. Например, использование памяти увеличивается с ~2,6 до 7 МБ.</p>
<p>Ещё один интересный момент связан с использованием сессий. Для вставки сообщений о результатах выполнения операции мы используем метод <code>set_flashdata</code>. Особенность flash данных в том, что они автоматически удаляются после считывания.</p>
<p>Таким образом, посетитель увидит сообщение о добавлении бага только один раз. Если он обновит страницу, то сообщение исчезнет.</p>
<p>Рассмотрим представление, которое создает форму (файл application\views\addbugform.php)</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">&lt;?php</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span> <span class="br0">&#40;</span>!<span class="kw3">empty</span><span class="br0">&#40;</span><span class="re0">$errMessage</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&#039;&lt;div id=&quot;errMessage&quot;&gt;&#039;</span>.<span class="re0">$errMessage</span>.<span class="st0">&#039;&lt;/div&gt;&#039;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
<li class="li2">
<div class="de2"><span class="re0">$mes</span> = <span class="re0">$this</span>-&gt;<span class="me1">session</span>-&gt;<span class="me1">flashdata</span><span class="br0">&#40;</span><span class="st0">&#039;message&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span> <span class="br0">&#40;</span>!<span class="kw3">empty</span><span class="br0">&#40;</span><span class="re0">$mes</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&#039;&lt;div id=&quot;infoMessage&quot;&gt;&#039;</span>.<span class="re0">$mes</span>.<span class="st0">&#039;&lt;/div&gt;&#039;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">?&gt;</span></div>
</li>
<li class="li2">
<div class="de2"><span class="kw2">&lt;?php</span> <span class="kw3">echo</span> form_open<span class="br0">&#40;</span><span class="st0">&#039;bugtracker/addbug&#039;</span>, <span class="kw3">array</span><span class="br0">&#40;</span><span class="st0">&#039;id&#039;</span>=&gt;<span class="st0">&#039;fAddBug&#039;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>; <span class="kw2">?&gt;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw2">&lt;?php</span> <span class="kw3">echo</span> form_error<span class="br0">&#40;</span><span class="st0">&#039;title&#039;</span><span class="br0">&#41;</span>; <span class="kw2">?&gt;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;p&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;label <span class="kw1">for</span>=<span class="st0">&quot;title&quot;</span>&gt;Заголовок&lt;/label&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;input type=<span class="st0">&quot;text&quot;</span> name=<span class="st0">&quot;title&quot;</span> id=<span class="st0">&quot;title&quot;</span> value=<span class="st0">&quot;&lt;?php echo set_value(&#039;title&#039;); ?&gt;&quot;</span> /&gt;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &lt;/p&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw2">&lt;?php</span> <span class="kw3">echo</span> form_error<span class="br0">&#40;</span><span class="st0">&#039;uname&#039;</span><span class="br0">&#41;</span>; <span class="kw2">?&gt;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;p&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;label <span class="kw1">for</span>=<span class="st0">&quot;uname&quot;</span>&gt;Ваше имя&lt;/label&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;input type=<span class="st0">&quot;text&quot;</span> name=<span class="st0">&quot;uname&quot;</span> id=<span class="st0">&quot;uname&quot;</span> value=<span class="st0">&quot;&lt;?php echo set_value(&#039;uname&#039;); ?&gt;&quot;</span> /&gt;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &lt;/p&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw2">&lt;?php</span> <span class="kw3">echo</span> form_error<span class="br0">&#40;</span><span class="st0">&#039;category_id&#039;</span><span class="br0">&#41;</span>; <span class="kw2">?&gt;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;p&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;label <span class="kw1">for</span>=<span class="st0">&quot;category_id&quot;</span>&gt;Категория ошибки&lt;/label&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;select name=<span class="st0">&quot;category_id&quot;</span> id=<span class="st0">&quot;category_id&quot;</span> size=<span class="st0">&quot;1&quot;</span>&gt;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="kw2">&lt;?php</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">foreach</span> <span class="br0">&#40;</span><span class="re0">$categories</span> <span class="kw1">as</span> <span class="re0">$category</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&#039;&lt;option value=&quot;&#039;</span>.<span class="re0">$category</span><span class="br0">&#91;</span><span class="st0">&#039;id&#039;</span><span class="br0">&#93;</span>.<span class="st0">&#039;&quot;&#039;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">echo</span> set_select<span class="br0">&#40;</span><span class="st0">&#039;category_id&#039;</span>, <span class="re0">$category</span><span class="br0">&#91;</span><span class="st0">&#039;id&#039;</span><span class="br0">&#93;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&#039;&gt;&#039;</span>.<span class="re0">$category</span><span class="br0">&#91;</span><span class="st0">&#039;name&#039;</span><span class="br0">&#93;</span>.<span class="st0">&#039;&lt;/option&gt;&#039;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw2">?&gt;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;/select&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;/p&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw2">&lt;?php</span> <span class="kw3">echo</span> form_error<span class="br0">&#40;</span><span class="st0">&#039;email&#039;</span><span class="br0">&#41;</span>; <span class="kw2">?&gt;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &lt;p&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;label <span class="kw1">for</span>=<span class="st0">&quot;email&quot;</span>&gt;eMail&lt;/label&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;input type=<span class="st0">&quot;text&quot;</span> name=<span class="st0">&quot;email&quot;</span> id=<span class="st0">&quot;email&quot;</span> value=<span class="st0">&quot;&lt;?php echo set_value(&#039;email&#039;); ?&gt;&quot;</span> /&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;/p&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw2">&lt;?php</span> <span class="kw3">echo</span> form_error<span class="br0">&#40;</span><span class="st0">&#039;description&#039;</span><span class="br0">&#41;</span>; <span class="kw2">?&gt;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &lt;p&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;label <span class="kw1">for</span>=<span class="st0">&quot;description&quot;</span>&gt;Описание ошибки&lt;/label&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;textarea name=<span class="st0">&quot;description&quot;</span> id=<span class="st0">&quot;description&quot;</span> cols=<span class="st0">&quot;30&quot;</span> rows=<span class="st0">&quot;5&quot;</span>&gt;&lt;?php <span class="kw3">echo</span> set_value<span class="br0">&#40;</span><span class="st0">&#039;description&#039;</span><span class="br0">&#41;</span>; ?&gt;&lt;/textarea&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;/p&gt;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &lt;p&gt;&lt;input type=<span class="st0">&quot;submit&quot;</span> name=<span class="st0">&quot;addbug&quot;</span> id=<span class="st0">&quot;addbug&quot;</span> value=<span class="st0">&quot;Отправить&quot;</span> /&gt;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &lt;/p&gt;</div>
</li>
<li class="li1">
<div class="de1">&lt;/form&gt;</div>
</li>
</ol>
</div>
<p>В начале представления мы выводим сообщения, если они есть. После этого создаем форму.</p>
<p>Форма в общем-то обычная. Обратить внимание стоит на функции вывода ошибок <code>form_error</code> и автоматического заполнения формы <code>set_value</code>. Обратите внимание на восстановление предыдущего значения Select Box (строка 28). В первом параметре метода <code>set_select</code> нужно указать значение атрибута <code>name</code> Select Box.</p>
<p>Теперь <strong>переходим к модели</strong> (application\models\ mbug.php).</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">function</span> addNewBug<span class="br0">&#40;</span><span class="re0">$bugData</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$qAddBug</span> = <span class="st0">&#039;INSERT INTO bugs (title, uname, category_id, description, bug_date, uemail)&#039;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; .<span class="st0">&#039; VALUES (?, ?, ?, ?, NOW(), ?)&#039;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$res</span> = <span class="re0">$this</span>-&gt;<span class="me1">db</span>-&gt;<span class="me1">query</span><span class="br0">&#40;</span><span class="re0">$qAddBug</span>, <span class="kw3">array</span><span class="br0">&#40;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugData</span><span class="br0">&#91;</span><span class="st0">&#039;title&#039;</span><span class="br0">&#93;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugData</span><span class="br0">&#91;</span><span class="st0">&#039;uname&#039;</span><span class="br0">&#93;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugData</span><span class="br0">&#91;</span><span class="st0">&#039;category_id&#039;</span><span class="br0">&#93;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugData</span><span class="br0">&#91;</span><span class="st0">&#039;description&#039;</span><span class="br0">&#93;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugData</span><span class="br0">&#91;</span><span class="st0">&#039;uemail&#039;</span><span class="br0">&#93;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="br0">&#41;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$res</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$this</span>-&gt;<span class="me1">db</span>-&gt;<span class="me1">insert_id</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$res</span>;</div>
</li>
<li class="li2">
<div class="de2"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Здесь всё просто. В параметре <code>$bugData</code> передается массив с данными из формы. После этого выполняется вставка этих данных в таблицу <code>bugs</code>.</p>
<p>При выполнении запроса все знаки вопроса заменяются исходными данными. При этом автоматически происходит экранирование спецсимволов, что обеспечивает защиту от <strong><acronym title="Structured Query Language">SQL</acronym> Injection</strong>.</p>
<p><strong>Добавление комментарие</strong>в.</p>
<p>Этот метод практически не отличается от предыдущего. Тот же алгоритм, те же библиотеки.</p>
<p>Поэтому приводить код для этих методов я не буду.</p>
<p>Конечно в форме только 3 поля: имя, email и текст комментария. Правил проверки меньше. И, конечно, данные вставляются в таблицу <code>comments</code>, а не <code>bugs</code>.</p>
<p>Но на один момент хочу обратить ваше внимание. На данный момент (отсутствует поддержка JavaScript) можно оставить комментарий только первого уровня. Т.е. нельзя указать, что ваш комментарий является ответом на предыдущий.</p>
<p>Когда будет добавлена поддержка JavaScript, форма отправки комментария будет работать также как и в этом блоге, т.е. перемещаться под выбранный комментарий. При этом будет добавляться скрытое поле, содержащее <code>id</code> комментария на который вы отвечаете.</p>
<p>Сделать ответы на предыдущие комментарии <strong>без JavaScript</strong> можно, но при этом придется добавлять ещё один select box, содержащий перечень предыдущих комментариев, и пользователь сам должен будет выбрать, на какой комментарий он отвечает. Естественно, это очень неудобно. Поэтому поддержка ответов на предыдущие комментарии будет только при поддержке JavaScript.</p>
<p>До встречи!</p>
<p><strong>P.S.</strong> Если возникли вопросы, пишите, попробую ответить <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p><img src="http://www.simplecoding.org/?ak_action=api_record_view&id=789&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/bug-tracker-dobavlenie-zapisej-i-kommentariev-chast-sedmaya.html/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Bug Tracker: создание страниц (часть шестая)</title>
		<link>http://www.simplecoding.org/bug-tracker-sozdanie-stranic-chast-shestaya.html</link>
		<comments>http://www.simplecoding.org/bug-tracker-sozdanie-stranic-chast-shestaya.html#comments</comments>
		<pubDate>Mon, 16 Mar 2009 06:53:33 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[CodeIgniter]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=787</guid>
		<description><![CDATA[Мы продолжаем разработку собственной системы отслеживания ошибок. И сегодня подробно рассмотрим создание страниц нашего приложения.
В предыдущих частях мы определились с типами страниц. Напомню, их всего два: страницы с общим перечнем багов (главная и страницы категорий) и страницы отдельных багов с комментариями.
Т.к. общее количество записей о багах может быть большим, мы будем использовать библиотеку pagination, входящую [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_788" class="wp-caption alignnone" style="width: 301px"><img src="http://www.simplecoding.org/wp-content/uploads/2009/03/bug_tracker_logo_part6.png" alt="bug_tracker_logo_part6" title="bug_tracker_logo_part6" width="291" height="204" class="size-full wp-image-788" style="float:left" /><p class="wp-caption-text"> </p></div>
<p>Мы продолжаем разработку собственной системы отслеживания ошибок. И сегодня подробно рассмотрим <strong>создание страниц</strong> нашего приложения.</p>
<p>В предыдущих частях мы определились с типами страниц. Напомню, их всего два: страницы с общим перечнем багов (главная и страницы категорий) и страницы отдельных багов с комментариями.</p>
<p>Т.к. общее количество записей о багах может быть большим, мы будем использовать библиотеку <a href="http://codeigniter.com/user_guide/libraries/pagination.html">pagination</a>, входящую в состав фреймворка <strong>CodeIgniter</strong>, для вывода этого списка по частям.</p>
<p>Количество записей на одной странице мы задаем в <strong>файле конфигурации</strong> (application\config\config.php).</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re0">$config</span><span class="br0">&#91;</span><span class="st0">&#039;bugs_per_page&#039;</span><span class="br0">&#93;</span> = <span class="nu0">5</span>;</div>
</li>
</ol>
</div>
<p>Получить значение этого параметра можно так:</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re0">$this</span>-&gt;<span class="me1">config</span>-&gt;<span class="me1">item</span><span class="br0">&#40;</span><span class="st0">&#039;bugs_per_page&#039;</span><span class="br0">&#41;</span>;</div>
</li>
</ol>
</div>
<p>Теперь определимся с <strong>названиями методов контроллера и структурой <acronym title="Uniform Resource Locator">URL</acronym></strong>.</p>
<p>По-умолчанию, <acronym title="Uniform Resource Locator">URL</acronym> в CodeIgniter имеют такой вид:</p>
<p><code>sitename.domen/index.php/имя_контроллера/имя_метода/параметр1/параметр2/…</code></p>
<p>Контроллер у нас будет называться <code>bugtracker</code>, а метод, показывающий страницы с багами – <code>page</code>. В результате получим <acronym title="Uniform Resource Locator">URL</acronym> с такой структурой:</p>
<p><code>…/bugtracker/page/номер_записи</code></p>
<p>В последнем сегменте адреса указываем номер первой записи на текущей странице. Кстати, это не <code>id</code> бага в базе данных, это его индекс в массиве с результатами поиска по БД.</p>
<p><strong>Создаём контроллер</strong> (application\controllers\bugtracker.php)<br />
<span id="more-787"></span></p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">class</span> BugTracker <span class="kw2">extends</span> Controller <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="co1">//настройки отображения списка багов</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw2">private</span> <span class="re0">$listConf</span> = <span class="kw3">array</span><span class="br0">&#40;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&#039;commentOpen&#039;</span>=&gt;<span class="st0">&#039;&lt;li class=&quot;depth-{depth}&quot;&gt;&#039;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw2">function</span> BugTracker<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; parent::<span class="me2">Controller</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">model</span><span class="br0">&#40;</span><span class="st0">&#039;mbug&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">model</span><span class="br0">&#40;</span><span class="st0">&#039;mcategory&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">model</span><span class="br0">&#40;</span><span class="st0">&#039;mcomment&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">library</span><span class="br0">&#40;</span><span class="st0">&#039;Table2Tree&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">library</span><span class="br0">&#40;</span><span class="st0">&#039;session&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">helper</span><span class="br0">&#40;</span><span class="st0">&#039;form&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw2">function</span> index<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">page</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw2">function</span> page<span class="br0">&#40;</span><span class="re0">$firstBug</span> = <span class="nu0">0</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &#8230;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Как видите, на данный момент он содержит конструктор, в котором мы загрузили модели и несколько библиотек, а также два метода.</p>
<p>1) <code>index</code> – вызывается CodeIgniter’ом если имя метода явно не указано в <acronym title="Uniform Resource Locator">URL</acronym>;</p>
<p>2) <code>page($firstBug = 0)</code> – показывает записи о багах начиная с $firstBug.</p>
<p>Т.к. на главной странице у нас будет отображаться список багов начиная с первого, то из метода <code>index</code> мы просто вызываем <code>page</code> без параметров.</p>
<p>Теперь подробно рассмотрим метод <code>page</code>.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">function</span> page<span class="br0">&#40;</span><span class="re0">$firstBug</span> = <span class="nu0">0</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>!<span class="kw3">is_integer</span><span class="br0">&#40;</span><span class="br0">&#40;</span>int<span class="br0">&#41;</span><span class="re0">$firstBug</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$firstBug</span> = <span class="nu0">0</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="co1">//сохраняем адрес этой страницы в сессии</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">session</span>-&gt;<span class="me1">set_userdata</span><span class="br0">&#40;</span><span class="kw3">array</span><span class="br0">&#40;</span><span class="st0">&#039;prev_page&#039;</span>=&gt;current_url<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$pageData</span><span class="br0">&#91;</span><span class="st0">&#039;title&#039;</span><span class="br0">&#93;</span> = <span class="st0">&#039;Bug Tracker&#039;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="co1">//настраиваем разбивку на страницы</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">library</span><span class="br0">&#40;</span><span class="st0">&#039;pagination&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$pconf</span><span class="br0">&#91;</span><span class="st0">&#039;base_url&#039;</span><span class="br0">&#93;</span> = <span class="re0">$this</span>-&gt;<span class="me1">config</span>-&gt;<span class="me1">item</span><span class="br0">&#40;</span><span class="st0">&#039;base_url&#039;</span><span class="br0">&#41;</span>.<span class="st0">&#039;bugtracker/page&#039;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$pconf</span><span class="br0">&#91;</span><span class="st0">&#039;total_rows&#039;</span><span class="br0">&#93;</span> = <span class="re0">$this</span>-&gt;<span class="me1">mbug</span>-&gt;<span class="me1">getBugsCount</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">$pconf</span><span class="br0">&#91;</span><span class="st0">&#039;per_page&#039;</span><span class="br0">&#93;</span> = <span class="re0">$this</span>-&gt;<span class="me1">config</span>-&gt;<span class="me1">item</span><span class="br0">&#40;</span><span class="st0">&#039;bugs_per_page&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">pagination</span>-&gt;<span class="me1">initialize</span><span class="br0">&#40;</span><span class="re0">$pconf</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$pageData</span><span class="br0">&#91;</span><span class="st0">&#039;paginationLinks&#039;</span><span class="br0">&#93;</span> = <span class="re0">$this</span>-&gt;<span class="me1">pagination</span>-&gt;<span class="me1">create_links</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="co1">//загружаем общий список ошибок и комментариев к ним</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$bugs</span> = <span class="re0">$this</span>-&gt;<span class="me1">mbug</span>-&gt;<span class="me1">getAllBugs</span><span class="br0">&#40;</span><span class="re0">$firstBug</span>, <span class="re0">$this</span>-&gt;<span class="me1">config</span>-&gt;<span class="me1">item</span><span class="br0">&#40;</span><span class="st0">&#039;bugs_per_page&#039;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$bugs</span> !== <span class="kw2">false</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugsTree</span> = <span class="re0">$this</span>-&gt;<span class="me1">table2tree</span>-&gt;<span class="me1">getTree</span><span class="br0">&#40;</span><span class="re0">$bugs</span>, <span class="re0">$firstBug</span>, <span class="re0">$this</span>-&gt;<span class="me1">config</span>-&gt;<span class="me1">item</span><span class="br0">&#40;</span><span class="st0">&#039;bugs_per_page&#039;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$pageData</span><span class="br0">&#91;</span><span class="st0">&#039;bugsList&#039;</span><span class="br0">&#93;</span> = <span class="re0">$this</span>-&gt;<span class="me1">table2tree</span>-&gt;<span class="me1">getHTMLList</span><span class="br0">&#40;</span><span class="re0">$bugsTree</span>, <span class="re0">$this</span>-&gt;<span class="me1">listConf</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">$pageData</span><span class="br0">&#91;</span><span class="st0">&#039;categories&#039;</span><span class="br0">&#93;</span> = <span class="re0">$this</span>-&gt;<span class="me1">mcategory</span>-&gt;<span class="me1">getAllCategories</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">view</span><span class="br0">&#40;</span><span class="st0">&#039;header&#039;</span>, <span class="re0">$pageData</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">view</span><span class="br0">&#40;</span><span class="st0">&#039;categories&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="co1">//размещаем форму отправки сообщений о багах</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">view</span><span class="br0">&#40;</span><span class="st0">&#039;addbugform&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">view</span><span class="br0">&#40;</span><span class="st0">&#039;allbugs&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">view</span><span class="br0">&#40;</span><span class="st0">&#039;footer&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Его работу можно разделить на следующие <strong>этапы</strong>.</p>
<p>1) Проверяем параметр и сохраняем адрес текущей страницы в сессии (зачем это нужно я расскажу немного позже).</p>
<p>2) Настраиваем разбивку на страницы (строки 11-18). Для этого загружаем библиотеку <code>pagination</code>, передаём ей массив с параметрами и создаем ссылки. В качестве параметров мы указываем: общее количество записей (получаем с помощью метода <code>getBugsCount()</code>), количество записей, которые нужно показать на странице (читаем из конфига) и первую часть <acronym title="Uniform Resource Locator">URL</acronym> ссылок (к нему последним параметром библиотека будет добавлять номер первой записи на очередной странице).</p>
<p>Т.е. если мы показываем по 5 записей на странице, библиотека создаст такие URL:<br />
<code>.../bugtracker/page/<br />
.../bugtracker/page/5<br />
.../bugtracker/page/10<br />
…</code></p>
<p>После этого мы загружаем список багов для данной страницы (строка 21). Запрос, который формирует этот список мы рассматривали в <a href="http://www.simplecoding.org/bug-tracker-model-i-stranicy-prilozheniya-chast-pyataya.html">прошлый раз</a>.</p>
<p>3) С помощью библиотеки <code>table2tree</code> мы преобразуем таблицу с данными о багах в <strong><acronym title="HyperText Markup Language">HTML</acronym> список</strong> (строки 23-28).</p>
<p>4) Загружаем список категорий (строка 30). Он используется для создания навигации по баг трекеру.</p>
<p>5) Показываем страницы (строки 32-37). Для этого загружаем представления и передаем им параметры.</p>
<p>Подробно рассматривать все представления смысла я не вижу. В любом случае оформлением я не занимался, поэтому, скорее всего, их придется немного изменить. Например, добавить <acronym title="Cascading Style Sheets">CSS</acronym> классы. Но на принцип работы и передаваемые данные это влиять не будет.</p>
<p>Поэтому сейчас я просто приведу краткое описание всех представлений. Все они находятся в папке (application\views):</p>
<p><code>header.php</code> – формирует заголовок страницы, загружает JavaScript и <acronym title="Cascading Style Sheets">CSS</acronym> файлы;<br />
<code>categories.php</code> – формирует список с перечнем категорий (используется для навигации);<br />
<code>addbugform.php</code> – форма добавления записи о найденном баге;<br />
<code>allbugs.php</code> – показывает список багов и строку со ссылками на другие страницы;<br />
<code>footer.php</code> – «хвостовик» страницы.</p>
<p><strong>Создание страницы выбранной категории.</strong></p>
<p>Приводить код этого метода я не буду, т.к. он практически полностью повторяет метод <code>page</code>. Тем не менее, есть несколько нюансов на которых стоит остановиться.</p>
<p>Во-первых, метод контроллера, создающий страницу отдельной категории, называется category и принимает 2 параметра: название категории и номер первой записи на странице.</p>
<p>Т.е. <acronym title="Uniform Resource Locator">URL</acronym> имеет такой вид:</p>
<p><code>…/bugtracker/category/имя_категоии/номер_записи</code></p>
<p>Во-вторых, при настройке библиотеки pagination необходимо явно указать в каком сегменте <acronym title="Uniform Resource Locator">URL</acronym> находится номер первой записи (по-умолчанию, это значение равно 3).</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re0">$pconf</span><span class="br0">&#91;</span><span class="st0">&#039;uri_segment&#039;</span><span class="br0">&#93;</span> = <span class="nu0">4</span>;</div>
</li>
</ol>
</div>
<p>В третьих, список багов получаем с помощью метода <code>getBugsByCategory</code> (модель <code>mbugs</code>). В <a href="http://www.simplecoding.org/bug-tracker-model-i-stranicy-prilozheniya-chast-pyataya.html">прошлый раз</a> мы рассматривали <strong><acronym title="Structured Query Language">SQL</acronym> запрос</strong>, который возвращает список багов для указанной категории.</p>
<p>Остальной код полностью повторяет метод page.</p>
<p><strong>Создание страницы отдельного бага</strong> (метод <code>bug</code>).</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">function</span> bug<span class="br0">&#40;</span><span class="re0">$id</span> = <span class="nu0">1</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>!<span class="kw3">is_integer</span><span class="br0">&#40;</span><span class="br0">&#40;</span>int<span class="br0">&#41;</span><span class="re0">$id</span><span class="br0">&#41;</span> || <span class="br0">&#40;</span>int<span class="br0">&#41;</span><span class="re0">$id</span> &lt;= <span class="nu0">0</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; redirect<span class="br0">&#40;</span><span class="st0">&#039;bugtracker/index&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="co1">//сохраняем адрес этой страницы в сессии</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">session</span>-&gt;<span class="me1">set_userdata</span><span class="br0">&#40;</span><span class="kw3">array</span><span class="br0">&#40;</span><span class="st0">&#039;prev_page&#039;</span>=&gt;current_url<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; </div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="co1">//ищем указанный баг</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$bug</span> = <span class="re0">$this</span>-&gt;<span class="me1">mbug</span>-&gt;<span class="me1">getBug</span><span class="br0">&#40;</span><span class="re0">$id</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$bug</span> !== <span class="kw2">false</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugTree</span> = <span class="re0">$this</span>-&gt;<span class="me1">table2tree</span>-&gt;<span class="me1">getTree</span><span class="br0">&#40;</span><span class="re0">$bug</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; </div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$pageData</span><span class="br0">&#91;</span><span class="st0">&#039;bugList&#039;</span><span class="br0">&#93;</span> = <span class="re0">$this</span>-&gt;<span class="me1">table2tree</span>-&gt;<span class="me1">getHTMLList</span><span class="br0">&#40;</span><span class="re0">$bugTree</span>, <span class="re0">$this</span>-&gt;<span class="me1">listConf</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$pageData</span><span class="br0">&#91;</span><span class="st0">&#039;bug_id&#039;</span><span class="br0">&#93;</span> = <span class="re0">$bugTree</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;id&#039;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$pageData</span><span class="br0">&#91;</span><span class="st0">&#039;categories&#039;</span><span class="br0">&#93;</span> = <span class="re0">$this</span>-&gt;<span class="me1">mcategory</span>-&gt;<span class="me1">getAllCategories</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">view</span><span class="br0">&#40;</span><span class="st0">&#039;header&#039;</span>, <span class="re0">$pageData</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">view</span><span class="br0">&#40;</span><span class="st0">&#039;categories&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">view</span><span class="br0">&#40;</span><span class="st0">&#039;onebug&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">view</span><span class="br0">&#40;</span><span class="st0">&#039;addcommentform&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">view</span><span class="br0">&#40;</span><span class="st0">&#039;footer&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Этот метод очень похож на предыдущие. Но есть несколько существенных различий.</p>
<p>1) Здесь мы не используем библиотеку <code>pagination</code>. В ней просто нет смысла. На странице отображается запись только об одном баге и все комментарии к нему.</p>
<p>2) Данные бага загружаем с помощью метода <code>getHTMLList</code> (строка 15). Кстати, для создания дерева комментариев мы используем собственную библиотеку <code>table2tree</code>. Её методы <code>getTree</code> и <code>getHTMLList</code> автоматически определяют есть ли в исходных данных комментарии и глубину их вложенности.</p>
<p>3) Вместо формы добавления бага вставляем форму добавления комментария (строка 24).</p>
<p>На этом мы закончим эту часть.<br />
В следующий раз рассмотрим добавление записей и комментариев.</p>
<p>До встречи!</p><img src="http://www.simplecoding.org/?ak_action=api_record_view&id=787&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/bug-tracker-sozdanie-stranic-chast-shestaya.html/feed</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Bug Tracker: модель и страницы приложения (часть пятая)</title>
		<link>http://www.simplecoding.org/bug-tracker-model-i-stranicy-prilozheniya-chast-pyataya.html</link>
		<comments>http://www.simplecoding.org/bug-tracker-model-i-stranicy-prilozheniya-chast-pyataya.html#comments</comments>
		<pubDate>Fri, 13 Mar 2009 21:13:39 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[CodeIgniter]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=784</guid>
		<description><![CDATA[В комментариях к прошлой части я получил много советов о том, в каком виде лучше получать данные из базы. Я очень признателен всем за эти замечания, т.к. они действительно помогли найти недостатки в прошлой части.
Основная проблема была в том, что я не продумал до конца, что именно будет отображаться на страницах баг трекера, но взялся [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_785" class="wp-caption alignnone" style="width: 265px"><img src="http://www.simplecoding.org/wp-content/uploads/2009/03/bug_tracker_logo_part5.png" alt="bug_tracker_logo_part5" title="bug_tracker_logo_part5" width="255" height="153" class="size-full wp-image-785" style="float:left" /><p class="wp-caption-text"> </p></div>
<p>В комментариях к прошлой части я получил много советов о том, в каком виде лучше получать данные из базы. Я очень признателен всем за эти замечания, т.к. они действительно помогли найти недостатки в <a href="http://www.simplecoding.org/bug-tracker-preobrazuem-tablicu-v-html-spisok-chast-4.html">прошлой части</a>.</p>
<p>Основная проблема была в том, что я не продумал до конца, <strong>что именно будет отображаться на страницах баг трекера</strong>, но взялся за работу с базой.</p>
<p>В общем-то, страниц у баг трекера не много. Первоначально я вообще хотел сделать одностраничное приложение, но передумал из-за <strong>проблем с индексацией поисковиками</strong>.</p>
<p>Поэтому сегодня постараюсь максимально подробно осветить этот вопрос.</p>
<p>Т.к. индексация страниц баг трекера поисковиками очень желательна, то при разработке имеет смысл придерживаться <a href="http://googlewebmastercentral.blogspot.com/2007/11/spiders-view-of-web-20.html">рекомендаций от Google</a>, а именно методики <strong>Progressive Enhancement</strong> (постепенного улучшения).</p>
<p><strong>Идея следующая</strong>. Нужно сделать приложения так, чтобы <strong>без</strong> поддержки <strong>JavaScript</strong> (только с помощью обычных ссылок) можно было получить доступ к любой информации (багам и комментариям).</p>
<p>После этого, с помощью <strong>JavaScript</strong> вносятся различные улучшения. Например, без JavaScript при клике на заголовке бага посетитель попадет на страницу с его описанием и комментариями.</p>
<p>Если JavaScript включен, то после загрузки страницы обычные ссылки будут преобразованы в <strong>ajax-ссылки</strong> и вместо перехода на другую страницу будет подгужен список комментариев.</p>
<p>Кроме того, не правильно показывать на одной странице одновременно несколько багов вместе с комментариями (как я планировал раньше). Во-первых, если комментарии содержат рисунки, то такая страница будет долго грузиться. Во-вторых, получится, что отдельные страницы багов будут дублировать главную, а, насколько я знаю, поисковики это не любят (дублирование контента).</p>
<p>В результате получается, что для работы баг трекера нужны <strong>страницы двух типов</strong>.<br />
<span id="more-784"></span><br />
1) <strong>Страницы с общим перечнем багов</strong>. Они будут содержать заголовок и описание бага (без комментариев). Сюда относятся: главная и страницы категорий. Тут же будет форма для добавления сообщения о новом баге.</p>
<p>2) <strong>Страницы отдельных багов</strong>. Тут будет полная информация о баге и дерево комментариев. Плюс форма добавления комментария.</p>
<p>Кстати, из страниц первого типа можно будет сформировать <acronym title="Really Simple Syndication">RSS</acronym> ленты (как предлагал <a href="http://www.kachayev.ru/">Алексей Качаев</a>).</p>
<p>Теперь посмотрим, что нам нужно сделать для того, чтобы сформировать содержимое этих страниц.</p>
<p>Как ни странно, но <strong>практически вся работа сделана в прошлой части</strong> <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  .</p>
<p>У нас есть библиотека, которая позволяет преобразовывать таблицу с багами и комментариями в <strong>html</strong> списки. При этом совершенно не важно, сколько багов и комментариев находится в этой таблице.</p>
<p>Например, если мы получим из базы таблицу только с информацией о багах (без комментариев), то сможем точно также сформировать html список.</p>
<p>Кроме того, у нас есть шаблоны для отображения багов и комментариев. И совершенно неважно как их использовать, для создания списка багов с комментариями или без них.</p>
<p>Тем не менее, в библиотеку нужно внести несколько мелких исправлений, чтобы сделать её более универсальной.</p>
<p>1) Убрать <code>array_slice</code>. Дело в том, что я сразу не разобрался как ограничить количество результатов, которые возвращает <strong><acronym title="Structured Query Language">SQL</acronym></strong> запрос при использовании объединений (JOINS), но потом исправил эту ошибку.</p>
<p>2) Добавить метод <code>getHTMLCommentsList</code>, который будет использоваться для преобразования массива с комментариями (без данных о баге) в <acronym title="HyperText Markup Language">HTML</acronym> список. Этот метод потребуется при загрузке списка комментариев с помощью <acronym title="Asynchronous JavaScript and XML">AJAX</acronym>.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">function</span> getHTMLCommentsList<span class="br0">&#40;</span><span class="re0">$comments</span>, <span class="re0">$config</span> = <span class="kw2">null</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>!<span class="kw3">empty</span><span class="br0">&#40;</span><span class="re0">$config</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">foreach</span> <span class="br0">&#40;</span><span class="re0">$config</span> <span class="kw1">as</span> <span class="re0">$key</span> =&gt; <span class="re0">$value</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">config</span><span class="br0">&#91;</span><span class="re0">$key</span><span class="br0">&#93;</span> = <span class="re0">$value</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">CI</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">library</span><span class="br0">&#40;</span><span class="st0">&#039;parser&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$html</span> = <span class="re0">$this</span>-&gt;_convert2HTMLList<span class="br0">&#40;</span><span class="re0">$comments</span>, <span class="nu0">0</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$html</span>;</div>
</li>
<li class="li2">
<div class="de2"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Этот метод по сути представляет собой оболочку, для <code>_convert2HTMLList</code>, описанного в <a href="http://www.simplecoding.org/bug-tracker-preobrazuem-tablicu-v-html-spisok-chast-4.html">прошлой части</a>.</p>
<p>3) Добавить проверку наличия полей с данными о комментариях (в методе <code>_convert2SimpleTree</code>). Т.к. теперь этот метод может получить данные багов как с комментариями так и без них.</p>
<p>Исходники библиотеки можно скачать в виде архива. Ссылка в конце страницы.</p>
<p>Кроме того, я думаю, не стоит отказываться от возможности получения полного списка багов с комментариями. По крайней мере, есть один случай, в котором это может быть полезно. Речь о том, что кроме <acronym title="Really Simple Syndication">RSS</acronym> можно организовать отправку сообщений о новых багах на eMail, например, раз в день. И в таких письмах имеет смысл отправить не только описания багов, но и комментарии к ним. Ведь если между добавлением бага и отправкой письма может пройти несколько часов, то, скорее всего и комментарии появятся.</p>
<p>Также, думаю, стоит рассмотреть основные <acronym title="Structured Query Language">SQL</acronym> запросы, с помощью которых можно будет получить информацию для перечисленных выше страниц. Диаграмма со структурой таблиц приведена в <a href="http://www.simplecoding.org/bug-tracker-izmeneniya-v-proekte-chast-tretya.html">третьей части</a>.</p>
<p>1) Получение списка багов (используется для создания главной страницы и страниц категорий).</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span> b.* , c.link, c.name <span class="kw1">AS</span> category</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">FROM</span> bugs <span class="kw1">AS</span> b</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">LEFT</span> <span class="kw1">JOIN</span> categories <span class="kw1">AS</span> c <span class="kw1">ON</span> b.category_id = c.id</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">ORDER</span> <span class="kw1">BY</span> b.bug_date <span class="kw1">DESC</span> <span class="kw1">LIMIT</span> ?, ?</div>
</li>
</ol>
</div>
<p>Обратите внимание на LIMIT в конце запроса. С его помощью мы ограничиваем число багов на странице. Естественно, при этом будет использоваться библиотека пагинации из <strong>CodeIgniter</strong>.</p>
<p>2) Получение списка багов для выбранной категории.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span> COUNT<span class="br0">&#40;</span>b.id<span class="br0">&#41;</span> <span class="kw1">AS</span> catsnum <span class="kw1">FROM</span> bugs <span class="kw1">AS</span> b</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">LEFT</span> <span class="kw1">JOIN</span> categories <span class="kw1">AS</span> c <span class="kw1">ON</span> b.category_id = c.id</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">WHERE</span> c.link=?</div>
</li>
</ol>
</div>
<p>3) Получение подробной информации о баге и всех его комментариев.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span> b.*, c.link, c.name <span class="kw1">AS</span> category,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; cm.id <span class="kw1">AS</span> c_id, cm.uname <span class="kw1">AS</span> c_uname, cm.description <span class="kw1">AS</span> c_description,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; cm.comment_date, cm.parent_id, cm.bug_id, cm.uemail <span class="kw1">AS</span> c_uemail</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">FROM</span> bugs <span class="kw1">AS</span> b</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="kw1">LEFT</span> <span class="kw1">JOIN</span> categories <span class="kw1">AS</span> c <span class="kw1">ON</span> b.category_id=c.id</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">LEFT</span> <span class="kw1">JOIN</span> comments <span class="kw1">AS</span> cm <span class="kw1">ON</span> b.id=cm.bug_id <span class="kw1">WHERE</span> b.id=?</div>
</li>
</ol>
</div>
<p>4) Получение отдельно списка комментариев выбранного бага (для работы в ajax-режиме). По-моему, не имеет смысла использовать отдельный запрос для решения этой задачи. Ведь все необходимые данные можно получить предыдущим запросом.</p>
<p>5) Получение списка багов и комментариев (я приводил этот запрос в прошлый раз, но сейчас немного изменил его и ввел ограничение на количество полей).</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span> b.* , c.link, c.name <span class="kw1">AS</span> category, cm.id <span class="kw1">AS</span> c_id,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; cm.uname <span class="kw1">AS</span> c_uname, cm.description <span class="kw1">AS</span> c_description,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; cm.comment_date, cm.parent_id, cm.bug_id, cm.uemail <span class="kw1">AS</span> c_uemail</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">FROM</span> comments <span class="kw1">AS</span> cm</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="kw1">RIGHT</span> <span class="kw1">JOIN</span> <span class="br0">&#40;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">SELECT</span> * <span class="kw1">FROM</span> bugs <span class="kw1">ORDER</span> <span class="kw1">BY</span> bugs.bug_date <span class="kw1">DESC</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">LIMIT</span> ?, ?</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#41;</span> b <span class="kw1">ON</span> b.id = cm.bug_id</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">LEFT</span> <span class="kw1">JOIN</span> categories <span class="kw1">AS</span> c <span class="kw1">ON</span> b.category_id = c.id</div>
</li>
</ol>
</div>
<p>Тут стоит обратить внимание на строку 7.</p>
<p>6) Получение общего количества багов (используется для пагинации)</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">function</span> getBugsCount<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$this</span>-&gt;<span class="me1">db</span>-&gt;<span class="me1">count_all</span><span class="br0">&#40;</span><span class="st0">&#039;bugs&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Это не <acronym title="Structured Query Language">SQL</acronym> запрос <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  Здесь я использовал встроенную функцию CodeIgniter. На самом деле выполняется </p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span> COUNT<span class="br0">&#40;</span>*<span class="br0">&#41;</span> <span class="kw1">AS</span> <span class="st0">&#039;numrows&#039;</span> <span class="kw1">FROM</span> <span class="st0">&#039;bugs&#039;</span></div>
</li>
</ol>
</div>
<p>7) Получение общего количества багов в выбранной категории</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span> COUNT<span class="br0">&#40;</span>b.id<span class="br0">&#41;</span> <span class="kw1">AS</span> catsnum <span class="kw1">FROM</span> bugs <span class="kw1">AS</span> b</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">LEFT</span> <span class="kw1">JOIN</span> categories <span class="kw1">AS</span> c <span class="kw1">ON</span> b.category_id = c.id</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">WHERE</span> c.link=?</div>
</li>
</ol>
</div>
<p>Я не буду подробно описывать принцип работы каждого запроса. В <a href="http://www.simplecoding.org/bug-tracker-preobrazuem-tablicu-v-html-spisok-chast-4.html">прошлой части</a> я довольно подробно останавливался на одном из самых сложных (пятый запрос в этом списке). Самое главное четко представлять как работают объединения таблиц (JOINS).</p>
<p>Вместо вопросительно знака в запросы будут подставлены конкретные данные.</p>
<p>В завершение приведу ссылку на <strong>ахив с исходниками библиотеки</strong> <a href='http://www.simplecoding.org/wp-content/uploads/2009/03/table2tree.zip'>table2tree</a>.</p>
<p>Как видите, изменений минимум. На этом примере очень хорошо видно одно из основных преимуществ архитектуры MVC. За счет того, что вся работа с базой данных вынесена в модель можно расширять возможности приложения практически без изменений в остальной части кода.</p>
<p>До встречи!</p>
<p><strong>P.S.</strong> Как всегда я рад выслушать любые замечания и предложения.</p><img src="http://www.simplecoding.org/?ak_action=api_record_view&id=784&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/bug-tracker-model-i-stranicy-prilozheniya-chast-pyataya.html/feed</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
		<item>
		<title>Bug tracker. Преобразуем таблицу в html список (часть 4).</title>
		<link>http://www.simplecoding.org/bug-tracker-preobrazuem-tablicu-v-html-spisok-chast-4.html</link>
		<comments>http://www.simplecoding.org/bug-tracker-preobrazuem-tablicu-v-html-spisok-chast-4.html#comments</comments>
		<pubDate>Mon, 09 Mar 2009 20:23:50 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[CodeIgniter]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=781</guid>
		<description><![CDATA[Сегодня я продолжаю рассказывать о разработке системы отслеживания ошибок. В этой части речь пойдет о создании списка багов и комментариев.
Напомню, в прошлый раз мы решили, что все для хранения записей о багах и комментариях к ним будем использовать две таблицы: bugs и comments.
Там же мы обсудили список полей и их назначение, и создали несколько внешних [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_782" class="wp-caption alignnone" style="width: 263px"><img src="http://www.simplecoding.org/wp-content/uploads/2009/03/bug_tracker_logo_part4.png" alt="bug_tracker_logo_part4" title="bug_tracker_logo_part4" width="253" height="192" class="size-full wp-image-782" style="float:left" /><p class="wp-caption-text"> </p></div>
<p>Сегодня я продолжаю рассказывать о разработке <strong>системы отслеживания ошибок</strong>. В этой части речь пойдет о <strong>создании списка багов и комментариев</strong>.</p>
<p>Напомню, в <a href="http://www.simplecoding.org/bug-tracker-izmeneniya-v-proekte-chast-tretya.html">прошлый раз</a> мы решили, что все для хранения записей о багах и комментариях к ним будем использовать две таблицы: <code>bugs</code> и <code>comments</code>.</p>
<p>Там же мы обсудили список полей и их назначение, и создали несколько внешних ключей для связи между таблицами.</p>
<p>Теперь <strong>переходим к созданию списка</strong>.</p>
<p>Чтобы лучше понять задачу рассмотрим html разметку, которую нам нужно получить.<br />
<span id="more-781"></span></p>
<pre>&lt;ul&gt;
	&lt;li&gt;
		Описание бага №1
		&lt;ul&gt;
			&lt;li&gt;Комментарий 1&lt;/li&gt;
			&lt;li&gt;
				Комментарий 2
				&lt;ul&gt;
					&lt;li&gt;Ответ на комментарий 2&lt;/li&gt;
				&lt;/ul&gt;
			&lt;/li&gt;
		&lt;/ul&gt;
	&lt;/li&gt;
	&lt;li&gt;
		Описание бага №2
		&lt;ul&gt;
			&lt;li&gt;Комментарий 1 к багу 2&lt;/li&gt;
			...
		&lt;/ul&gt;
	&lt;/li&gt;
&lt;/ul&gt;</pre>
<p>Как видите, разметка достаточно простая. Мы создаем список, каждый элемент которого соответствует записи о баге. Если к этому багу оставлены комментарии, то они размещаются во вложенном списке. Вкладывая такие списки друг в друга, мы формируем дерево комментариев.</p>
<p>Таким образом, нам нужно <strong>преобразовать данные из таблиц в дерево</strong>.</p>
<p>Примечание. Если вы интересуетесь хранением древовидных структур в базе данных, то советую почитать статью «<a href="http://leopard.in.ua/2009/02/07/postroenie-derevev/">Построение деревьев</a>».</p>
<p>Теперь посмотрим, каким образом можно сформировать такой список. Есть несколько вариантов.</p>
<p>Можно решать задачу «в лоб». Т.е. первым запросом найти все записи о багах (напомню, у всех таких записей поле <code>parent_id = NULL</code>). А после этого в цикле отправлять запросы поиска комментариев к каждому из найденных багов. Недостаток такого подхода – большое количество запросов к БД.</p>
<p>Второй вариант. Мы можем получить всю необходимую информацию с помощью  <strong>одного</strong> запроса. Но при этом усложняется алгоритм получения дерева с багами и комментариями.</p>
<p>Остановимся мы, конечно, на втором варианте.</p>
<p>И, прежде всего, <strong>нам нужно получить данные</strong>. Для этого создаем модель, назовем её <code>mbug</code> (application\models\mbugs.php), и метод <code>getAllBugsWithComments</code>.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">class</span> MBug <span class="kw2">extends</span> Model <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw2">function</span> MBug<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; parent::<span class="me2">Model</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="coMULTI">/**</span></div>
</li>
<li class="li1">
<div class="de1"><span class="coMULTI">&nbsp; &nbsp; &nbsp;* Ищет все баги и комментарии к ним. Баги возвращаются начиная с последнего добавленного.</span></div>
</li>
<li class="li1">
<div class="de1"><span class="coMULTI">&nbsp; &nbsp; &nbsp;* </span></div>
</li>
<li class="li2">
<div class="de2"><span class="coMULTI">&nbsp; &nbsp; &nbsp;* @return массив со всеми багами и комментариями к ним, FALSE &#8211; если ничего не найдено</span></div>
</li>
<li class="li1">
<div class="de1"><span class="coMULTI">&nbsp; &nbsp; &nbsp;*/</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw2">function</span> getAllBugsWithComments<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$qGetAll</span> = <span class="st0">&#039;SELECT b.*, c.link, c.name AS category,&#039;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span class="st0">&#039; cm.id AS c_id, cm.uname AS c_uname, cm.description AS c_description,&#039;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span class="st0">&#039; cm.comment_date, cm.parent_id, cm.bug_id, cm.uemail AS c_uemail&#039;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span class="st0">&#039; FROM bugs AS b&#039;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span class="st0">&#039; LEFT JOIN categories AS c ON b.category_id=c.id&#039;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span class="st0">&#039; LEFT JOIN comments AS cm ON b.id=cm.bug_id&#039;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span class="st0">&#039; ORDER BY b.bug_date DESC&#039;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$res</span> = <span class="re0">$this</span>-&gt;<span class="me1">db</span>-&gt;<span class="me1">query</span><span class="br0">&#40;</span><span class="re0">$qGetAll</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$res</span>-&gt;<span class="me1">num_rows</span><span class="br0">&#40;</span><span class="br0">&#41;</span> &lt;= <span class="nu0">0</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">false</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$res</span>-&gt;<span class="me1">result_array</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Работает метод <code>getAllBugsWithComments</code> предельно просто. Он выполняет запрос к БД и возвращает результат его выполнения в виде массива.</p>
<p>Самая интересная часть – это, конечно, сам <strong>запрос</strong>. Для того, чтобы сформировать дерево, нам нужны данные о багах, сведения о категориях к которым они относятся и комментарии к ним.</p>
<p>Поэтому в запросе мы выполняем объединение трех таблиц (<code>bugs</code>, <code>categories</code>, <code>comments</code>). Рассмотрим, <strong>как выполняется это объединение</strong>.</p>
<p>Прежде всего, обратите внимание на то, что таблицы объединяются слева направо (<code>LEFT JOIN</code>). На первом этапе объединяются таблицы <code>bugs</code> и <code>categories</code>. Т.к. каждому багу соответствует только одна категория, то в результате мы получим исходную таблицу <code>bugs</code> с двумя новыми столбцами <code>link</code> и <code>name</code> из таблицы <code>categories</code>.</p>
<p>Обратите внимание, что т.к. таблица <code>bugs</code> расположена слева, то в результат войдут только те записи из таблицы <code>categories</code>, для которых есть соответствующая запись в таблице <code>bugs</code>. Другими словами, если у нас есть категория, в которой нет ни одного бага, то сведений о ней в результирующей таблице не будет.</p>
<p>На следующем этапе происходит <strong>объединение с таблицей comments</strong>. Тут возможны два варианта.</p>
<p>Первый – очередной баг не имеет комментариев. В этом случае в результирующей таблице будет одна строка со сведениями из таблиц <code>bugs</code> и <code>categories</code>, а все поля, соответствующие таблице <code>comments</code> будут иметь значения <code>NULL</code>.</p>
<p>Второй – очередной баг имеет один или более комментариев. Тогда в результирующей таблице будет одна или более строк с данными из таблиц <code>bugs</code>, <code>categories</code> и <code>comments</code>. Причем количество таких строк определяется количеством комментариев.</p>
<p>Посмотрите на пример такой таблицы (я опустил часть полей).</p>
<table style="border-collapse:collapse; font-size:80%">
<tr>
<td style="border:1px solid #000000">id</td>
<td style="border:1px solid #000000">title</td>
<td style="border:1px solid #000000">&#8230;</td>
<td style="border:1px solid #000000">name</td>
<td style="border:1px solid #000000">&#8230;</td>
<td style="border:1px solid #000000">c_description</td>
</tr>
<tr>
<td style="border:1px solid #000000">1</td>
<td style="border:1px solid #000000">Баг 1</td>
<td style="border:1px solid #000000">&#8230;</td>
<td style="border:1px solid #000000">Критические ошибки</td>
<td style="border:1px solid #000000">&#8230;</td>
<td style="border:1px solid #000000">Комментарий к багу 1</td>
</tr>
<tr>
<td style="border:1px solid #000000">2</td>
<td style="border:1px solid #000000">Баг 2</td>
<td style="border:1px solid #000000">&#8230;</td>
<td style="border:1px solid #000000">Пожелания</td>
<td style="border:1px solid #000000">&#8230;</td>
<td style="border:1px solid #000000">NULL</td>
</tr>
<tr>
<td style="border:1px solid #000000">3</td>
<td style="border:1px solid #000000">Баг 3</td>
<td style="border:1px solid #000000">&#8230;</td>
<td style="border:1px solid #000000">Критические ошибки</td>
<td style="border:1px solid #000000">&#8230;</td>
<td style="border:1px solid #000000">Первый комментарий к багу 3</td>
</tr>
<tr>
<td style="border:1px solid #000000">3</td>
<td style="border:1px solid #000000">Баг 3</td>
<td style="border:1px solid #000000">&#8230;</td>
<td style="border:1px solid #000000">Критические ошибки</td>
<td style="border:1px solid #000000">&#8230;</td>
<td style="border:1px solid #000000">Второй комментарий к багу 3</td>
</tr>
</table>
<p><strong>Переходим к преобразованию этой таблицы в <acronym title="HyperText Markup Language">HTML</acronym> список.</strong></p>
<p>Т.к. операция довольно сложная, то будет удобно написать для неё небольшую <strong>библиотеку </strong>– <code>Table2Tree</code>.</p>
<p>Для этого создаём файл <code>application\libraries\table2tree.php</code> (название файла совпадает с названием библиотеки).</p>
<p>Но, прежде чем переходить к описанию библиотеки, рассмотрим пример её использования. Допустим, у нас есть контроллер (<code>bugtracker</code>) с методом <code>page</code> (формирует страницу со списком багов и комментариев).</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">class</span> BugTracker <span class="kw2">extends</span> Controller <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="co1">//настройки отображения списка багов</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw2">private</span> <span class="re0">$listConf</span> = <span class="kw3">array</span><span class="br0">&#40;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&#039;commentOpen&#039;</span>=&gt;<span class="st0">&#039;&lt;li class=&quot;depth-{depth}&quot;&gt;&#039;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw2">function</span> BugTracker<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; parent::<span class="me2">Controller</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">model</span><span class="br0">&#40;</span><span class="st0">&#039;mbug&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">load</span>-&gt;<span class="me1">library</span><span class="br0">&#40;</span><span class="st0">&#039;Table2Tree&#039;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="kw2">function</span> page<span class="br0">&#40;</span><span class="re0">$firstBug</span> = <span class="nu0">0</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &#8230;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//загружаем общий список ошибок и комментариев к ним</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugs</span> = <span class="re0">$this</span>-&gt;<span class="me1">mbug</span>-&gt;<span class="me1">getAllBugsWithComments</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; </div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$bugs</span> !== <span class="kw2">false</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugsTree</span> = <span class="re0">$this</span>-&gt;<span class="me1">table2tree</span>-&gt;<span class="me1">getTree</span><span class="br0">&#40;</span><span class="re0">$bugs</span>, <span class="re0">$firstBug</span>, <span class="re0">$this</span>-&gt;<span class="me1">config</span>-&gt;<span class="me1">item</span><span class="br0">&#40;</span><span class="st0">&#039;bugs_per_page&#039;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$pageData</span><span class="br0">&#91;</span><span class="st0">&#039;bugsList&#039;</span><span class="br0">&#93;</span> = <span class="re0">$this</span>-&gt;<span class="me1">table2tree</span>-&gt;<span class="me1">getHTMLList</span><span class="br0">&#40;</span><span class="re0">$bugsTree</span>, <span class="re0">$this</span>-&gt;<span class="me1">listConf</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//формируем страницу</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Как видите, в конструкторе мы загрузили нашу библиотеку (<code>Table2Tree</code>) и модель (<code>mbug</code>).</p>
<p>Метод <code>page()</code> работает следующим образом.</p>
<p>1) Получаем список багов с комментариями (с помощью метода <code>getAllBugsWithComments</code> модели).</p>
<p>2) Преобразовываем полученную таблицу в многомерный массив (метод <code>getTree</code> нашей библиотеки).</p>
<p>3) Преобразовываем многомерный массив в <acronym title="HyperText Markup Language">HTML</acronym> список (метод <code>getHTMLList</code>).</p>
<p>На втором и третьем этапе я хочу остановиться подробнее. Основной вопрос тут: что представляет собой многомерный массив и зачем он вообще нужен.</p>
<p>Дело в том, что мы формируем этот массив таким образом, что <strong>его структура полностью совпадает со структурой <acronym title="HyperText Markup Language">HTML</acronym> списка который мы хотим получить</strong>.</p>
<p>Например, для списка, показанного в начале статьи, этот массив будет выглядеть примерно так.</p>
<pre>[0]=&gt;
	‘title’=&gt;’Описание бага №1’
	...
	‘comments’=&gt;
		[0]=&gt;
			‘description’=&gt;’Комментарий 1’
		[1]=&gt;
			‘description’=&gt;’Комментарий 2’
			‘comments’=&gt;
				[0]=&gt;
					‘description’=&gt;’Ответ на комментарий 2’
[1]=&gt;
	‘title’=&gt;’Описание бага №2’
	...
	‘comments’=&gt;
		[0]=&gt;
			‘description’=&gt;’Комментарий 1 к багу 2’</pre>
<p>Используя такой массив, получить <acronym title="HyperText Markup Language">HTML</acronym> список будет значительно проще.</p>
<p>Теперь рассмотрим, каким образом можно <strong>преобразовать результаты поиска по БД в такой массив</strong>.</p>
<p>Я решил разбить задачу на 2 этапа.</p>
<p>На первом – <strong>формируем массив с багами</strong>. В нем каждый элемент будет содержать описание бага и одномерный массив со всеми комментариями к нему.</p>
<p>На втором – <strong>преобразуем массивы с комментариями в многомерные</strong> (на основании значения в поле <code>parent_id</code>), т.е. формируем дерево комментариев.</p>
<p>Рассмотрим метод <code>getTree</code></p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">function</span> getTree<span class="br0">&#40;</span><span class="re0">$data</span>, <span class="re0">$firstBug</span> = <span class="nu0">0</span>, <span class="re0">$count</span> = <span class="nu0">1</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$sTree</span> = <span class="re0">$this</span>-&gt;_convert2SimpleTree<span class="br0">&#40;</span><span class="re0">$data</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="co1">//запоминаем общее количество багов</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$this</span>-&gt;<span class="me1">bugsCount</span> = <span class="kw3">count</span><span class="br0">&#40;</span><span class="re0">$sTree</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="co1">//оставляем в массиве только те элементы, которые будут отображаться на странице</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$sTree</span> = <span class="kw3">array_slice</span><span class="br0">&#40;</span><span class="re0">$sTree</span>, <span class="re0">$firstBug</span>, <span class="re0">$count</span>, <span class="kw2">TRUE</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">foreach</span> <span class="br0">&#40;</span><span class="re0">$sTree</span> <span class="kw1">as</span> <span class="re0">$i</span> =&gt; <span class="re0">$row</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>!<span class="kw3">empty</span><span class="br0">&#40;</span><span class="re0">$row</span><span class="br0">&#91;</span><span class="st0">&#039;comments&#039;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$sTree</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;comments&#039;</span><span class="br0">&#93;</span> = <span class="re0">$this</span>-&gt;_nestedComments<span class="br0">&#40;</span><span class="re0">$row</span><span class="br0">&#91;</span><span class="st0">&#039;comments&#039;</span><span class="br0">&#93;</span>, <span class="kw2">null</span>, <span class="nu0">0</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$sTree</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Он имеет 3 входных параметра:<br />
<code>data</code> – массив с результатами поиска в БД;<br />
<code>firstBug</code> – номер первого бага на странице (используется для пагинации, нет никакого смысла строить дерево комментариев для багов, которые не будут отображаться на странице);<br />
<code>count</code> – количество багов на странице.</p>
<p>Первый этап работы (формирование массива с багами) осуществляется с помощью метода <code>_convert2SimpleTree</code> (по соглашению, принятому в CodeIgniter, имена приватных методов должны начинаться с подчеркивания).</p>
<p>После этого мы оставляем в массиве только те записи о багах, которые будут отображаться на странице (строка 6).</p>
<p>И <strong>формируем дерево комментариев</strong>. Для этого мы проходим в цикле по всем элементам массива и с помощью метода <code>_nestedComments</code> преобразовываем массив <code>comments</code> в многомерный.</p>
<p>Рассмотрим метод <code>_convert2SimpleTree</code></p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">function</span> _convert2SimpleTree<span class="br0">&#40;</span><span class="re0">$bugs</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$bugRes</span> = <span class="kw3">array</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$currentBugId</span> = <span class="nu0">0</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$i</span> = <span class="nu0">-1</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">$j</span> = <span class="nu0">0</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">foreach</span> <span class="br0">&#40;</span><span class="re0">$bugs</span> <span class="kw1">as</span> <span class="re0">$bug</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;id&#039;</span><span class="br0">&#93;</span> != <span class="re0">$currentBugId</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$currentBugId</span> = <span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;id&#039;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$i</span>++;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//заполняем массив данными о баге</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugRes</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;id&#039;</span><span class="br0">&#93;</span> = <span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;id&#039;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugRes</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;title&#039;</span><span class="br0">&#93;</span> = <span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;title&#039;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugRes</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;uname&#039;</span><span class="br0">&#93;</span> = <span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;uname&#039;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugRes</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;category_id&#039;</span><span class="br0">&#93;</span> = <span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;category_id&#039;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugRes</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;description&#039;</span><span class="br0">&#93;</span> = <span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;description&#039;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugRes</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;status&#039;</span><span class="br0">&#93;</span> = <span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;status&#039;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugRes</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;bug_date&#039;</span><span class="br0">&#93;</span> = <span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;bug_date&#039;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugRes</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;uemail&#039;</span><span class="br0">&#93;</span> = <span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;uemail&#039;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//данные о категории</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugRes</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;link&#039;</span><span class="br0">&#93;</span> = <span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;link&#039;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugRes</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;category&#039;</span><span class="br0">&#93;</span> = <span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;category&#039;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//создаем массив с комментариями</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;c_id&#039;</span><span class="br0">&#93;</span> != <span class="kw2">NULL</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugRes</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;comments&#039;</span><span class="br0">&#93;</span> = <span class="kw3">array</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$j</span> = <span class="nu0">0</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugRes</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;comments&#039;</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="re0">$j</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;id&#039;</span><span class="br0">&#93;</span> = <span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;c_id&#039;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugRes</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;comments&#039;</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="re0">$j</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;uname&#039;</span><span class="br0">&#93;</span> = <span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;c_uname&#039;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugRes</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;comments&#039;</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="re0">$j</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;description&#039;</span><span class="br0">&#93;</span> = <span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;c_description&#039;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugRes</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;comments&#039;</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="re0">$j</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;comment_date&#039;</span><span class="br0">&#93;</span> = <span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;comment_date&#039;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugRes</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;comments&#039;</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="re0">$j</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;parent_id&#039;</span><span class="br0">&#93;</span> = <span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;parent_id&#039;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugRes</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;comments&#039;</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="re0">$j</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;bug_id&#039;</span><span class="br0">&#93;</span> = <span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;bug_id&#039;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugRes</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;comments&#039;</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="re0">$j</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;uemail&#039;</span><span class="br0">&#93;</span> = <span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;c_uemail&#039;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$j</span>++;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//добавляем новую запись в массив с комментариями</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugRes</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;comments&#039;</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="re0">$j</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;id&#039;</span><span class="br0">&#93;</span> = <span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;c_id&#039;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugRes</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;comments&#039;</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="re0">$j</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;uname&#039;</span><span class="br0">&#93;</span> = <span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;c_uname&#039;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugRes</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;comments&#039;</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="re0">$j</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;description&#039;</span><span class="br0">&#93;</span> = <span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;c_description&#039;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugRes</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;comments&#039;</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="re0">$j</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;comment_date&#039;</span><span class="br0">&#93;</span> = <span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;comment_date&#039;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugRes</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;comments&#039;</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="re0">$j</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;parent_id&#039;</span><span class="br0">&#93;</span> = <span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;parent_id&#039;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugRes</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;comments&#039;</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="re0">$j</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;bug_id&#039;</span><span class="br0">&#93;</span> = <span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;bug_id&#039;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$bugRes</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;comments&#039;</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="re0">$j</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&#039;uemail&#039;</span><span class="br0">&#93;</span> = <span class="re0">$bug</span><span class="br0">&#91;</span><span class="st0">&#039;c_uemail&#039;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$j</span>++;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$bugRes</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Выглядит он довольно объемным, но большую часть его составляют операторы присвоения. А <strong>принцип работы</strong> достаточно простой.</p>
<p>В исходной таблице (с результатами из БД) каждому багу может соответствовать несколько строк (в зависимости от количества комментариев).</p>
<p>Поэтому мы перебираем в цикле все строки этой таблицы и если встречаем новый баг (его <code>id</code> отличается от предыдущего), то создаём новый элемент в результирующем массиве и копируем в него данные бага, категории и комментария (если он есть).</p>
<p>Если очередная строка относится к той же записи о баге, что и предыдущая, то мы копируем только данные комментария.</p>
<p>Продолжение на <a href="http://www.simplecoding.org/bug-tracker-preobrazuem-tablicu-v-html-spisok-chast-4.html/2">следующей странице &gt;&gt;</a></p><img src="http://www.simplecoding.org/?ak_action=api_record_view&id=781&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/bug-tracker-preobrazuem-tablicu-v-html-spisok-chast-4.html/feed</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>Bug Tracker: изменения в проекте (часть третья)</title>
		<link>http://www.simplecoding.org/bug-tracker-izmeneniya-v-proekte-chast-tretya.html</link>
		<comments>http://www.simplecoding.org/bug-tracker-izmeneniya-v-proekte-chast-tretya.html#comments</comments>
		<pubDate>Thu, 05 Mar 2009 20:55:09 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[CodeIgniter]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=778</guid>
		<description><![CDATA[Приветствую всех!
В этой статье продолжения рассказа о разработке собственной системы отслеживания ошибок. Предыдущие части вы найдете здесь и здесь.
В прошлый раз я обещал рассказать о формировании страницы со списком багов и комментариев. Но обсуждения предыдущих частей ясно показали, что в проект необходимо внести некоторые изменения. О них и пойдет речь сегодня.
База данных.
Первоначально я хотел максимально [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_779" class="wp-caption alignnone" style="width: 276px"><img src="http://www.simplecoding.org/wp-content/uploads/2009/03/bug_tracker_logo_part3.png" alt="bug_tracker_logo_part3" title="bug_tracker_logo_part3" width="266" height="140" class="size-full wp-image-779" style="float:left" /><p class="wp-caption-text"> </p></div>
<p><strong>Приветствую всех!</strong></p>
<p>В этой статье продолжения рассказа о разработке собственной системы отслеживания ошибок. Предыдущие части вы найдете <a href="http://www.simplecoding.org/sozdaem-sobstvennuyu-sistemu-otslezhivaniya-oshibok-na-php.html">здесь</a> и <a href="http://www.simplecoding.org/bug-tracker-ustanovka-frejmvorka-i-sozdanie-bazy-dannyx-chast-vtoraya.html">здесь</a>.</p>
<p>В прошлый раз я обещал рассказать о формировании страницы со списком багов и комментариев. Но обсуждения предыдущих частей ясно показали, что в проект необходимо внести некоторые изменения. О них и пойдет речь сегодня.</p>
<p><strong>База данных.</strong></p>
<p>Первоначально я хотел максимально упростить структуру БД и перестарался. А именно: я решил хранить описания багов и комментарии к ним в одной таблице. В принципе, это возможно. Баги и комментарии имеют много одинаковых полей, и работать с такой таблицей было бы вполне реально.</p>
<p>Но я не учел, что при этом <strong>значительно усложняется код формирования страницы</strong>. Например, для создания списка багов с комментариями нужна рекурсивная функция с множеством проверок.</p>
<p>В общем, я решил, что лучше изменить базу данных сейчас, чем морочить себе голову потом <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Новая <strong>структура базы данных</strong> выглядит следующим образом.<br />
<span id="more-778"></span><br />
<div id="attachment_780" class="wp-caption alignnone" style="width: 377px"><img src="http://www.simplecoding.org/wp-content/uploads/2009/03/database_structure.png" alt="database_structure" title="database_structure" width="367" height="354" class="size-full wp-image-780" /><p class="wp-caption-text"> </p></div></p>
<p>Как видите, баги и комментарии к ним находятся в разных таблицах, которые связаны с помощью поля <code>bug_id</code> в таблице <code>comments</code>.</p>
<p>Это поле (bug_id) является внешним ключом и для него установлена опция <code>ON DELETE CASCADE</code>. Это гарантирует, что удаление записи в таблице <code>bugs</code> повлечет за собой автоматическое удаление (движком MySQL) всех записей из таблицы <code>comments</code>, у которых значение поля <code>bug_id</code> совпадает со значением поля <code>id</code> удаляемой записи.</p>
<p>Кроме того, таблица <code>comments</code> имеет ещё один внешний ключ – поле <code>parent_id</code>.</p>
<p>С его помощью можно создавать <strong>связанные списки комментариев</strong>. Т.е. значение этого поля должно совпадать со значением поля <code>id</code> родительского комментария. Если комментарий является первым в цепочке, то <code>parent_id</code> должно быть равно <code>NULL</code>.</p>
<p>Для этого поля также установлена опция <code>ON DELETE CASCADE</code>. Таким образом, удалив родительский комментарий, мы удалим всю цепочку. И, точно также, удаляя запись о баге, мы будем удалять все связанные комментарии, не зависимо от глубины их вложенности.</p>
<p>О таблице <code>categories</code> я рассказывал в прошлый раз. В ней ничего не изменилось.</p>
<p>Четвертая таблица (<code>users</code>) предназначена для хранения данных об администраторах баг трекера. Они могут удалять чужие записи. Добавить сообщение о баге или комментарий к нему может кто угодно без авторизации.</p>
<p><strong>Структура приложения</strong>.</p>
<p>Тут я тоже решил внести некоторые изменения. Первоначально я планировал сделать одностраничное приложение, а весь функционал реализовать с помощью <strong><acronym title="Asynchronous JavaScript and XML">AJAX</acronym></strong> запросов.</p>
<p>Дело в том, что мне очень нравятся такие приложения. Они удобные, быстро работают и вообще это Web 2.0 <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Но есть одна проблемка – <strong>поисковики</strong>.</p>
<p>Если доступ к вашему приложению возможен только после авторизации, то и говорить не о чем. Поисковик всё равно до него не доберется. Но баг трекеры практически всегда открыты, и было бы очень не плохо добавить возможность поиска с помощью того же Google.</p>
<p>Я начал искать возможные пути решения проблемы и практически сразу наткнулся на <a href="http://googlewebmastercentral.blogspot.com/2007/11/spiders-view-of-web-20.html">пост в официальном блоге Google</a>.</p>
<p>Подробно пересказывать его нет смысла. Если отбросить фразы в духе «мы понимаем роль <acronym title="Asynchronous JavaScript and XML">AJAX</acronym> и Flash в развитии интернета&#8230;», то суть сводится к следующему:</p>
<p>1) индексируется только текст;</p>
<p>2) для перемещения по сайту поисковому боту нужны обычные ссылки (ajax-ссылки, т.е. <code>sitename.domen#...</code> игнорируются).</p>
<p>Т.е. делать сайт можно как угодно, но Google проиндексирует только то, что найдет. И, насколько я знаю, с Яндексом ситуация такая же.</p>
<p>Попасть в индекс и при этом использовать <acronym title="Asynchronous JavaScript and XML">AJAX</acronym> можно с помощью методики <strong>Progressive Enhancement</strong> (постепенного улучшения).</p>
<p>Это означает, что разрабатывать сайт нужно так, чтобы с ним можно было нормально работать при отключенном <strong>JavaScript</strong> и <strong><acronym title="Cascading Style Sheets">CSS</acronym></strong> стилях (т.е. посетитель должен видеть весь необходимый ему контент, иметь возможность перемещаться по страницам и отправлять данные с помощью форм). Включение JavaScript должно увеличивать удобство работы с сайтом, например, добавлять поддержку асинхронной загрузки данных (<acronym title="Asynchronous JavaScript and XML">AJAX</acronym>), создавать различные визуальные эффекты вроде слайдеров, выпадающих меню и т.п.</p>
<p>Кстати, есть хорошее <a href="http://domscripting.com/presentations/xtech2006/">слайд-шоу о Progressive Enhancement</a>.</p>
<p>У этой методики есть ещё одно преимущество (кроме индексации поисковиками), с сайтом можно будет работать, используя устройства чтения с экрана.</p>
<p>Поэтому на первом этапе мы напишем баг трекер <strong>без использования ajax</strong>. Т.е. все ссылки будут обычными, например,</p>
<p><code>bugtracker.local/bugtracker/addbug</code></p>
<p>После этого, мы с помощью JavaScript будем изменять эти ссылки для использования в <acronym title="Asynchronous JavaScript and XML">AJAX</acronym> запросах. Например, предыдущая ссылка будет выглядеть так:</p>
<p><code>bugtracker.local/bugtracker#addbug</code></p>
<p>Поисковый бот JavaScript не выполняет, поэтому он будет работать с первым вариантом ссылки, а посетители – со вторым.</p>
<p>Теперь рассмотрим <strong>перечень страниц баг трекера</strong>.</p>
<p><code>index</code> &#8211; главная, отображается форма добавления сообщения о баге, список багов с комментариями и навигация;</p>
<p><code>page/id</code> – показываем выбранную страницу (<code>id</code> – номер страницы), тоже самое, что и index, т.е. index соответствует <code>page/1</code>;</p>
<p><code>category/id</code> &#8211; тоже самое, что и <code>page/id</code>, только показываем баги, относящиеся к указанной категории;</p>
<p><code>bug/id</code> &#8211; страница с выбранным багом, внизу будет форма для добавления комментария;</p>
<p><code>bug/add</code> &#8211; добавляет новое сообщение о баге (передача данных методом POST);</p>
<p><code>bug/addcomment</code> &#8211; добавляет комментарий к выбранному багу (данные передаём методом POST);</p>
<p><code>bug/remove</code> &#8211; удаляет выбранный баг (id бага передается методом POST).</p>
<p><code>comment/remove</code> &#8211; удаляет выбранный комментарий.</p>
<p>Это ориентировочный список. При необходимости можно будет добавить ту или иную функцию.</p>
<p>В следующих выпусках мы подробно рассмотрим добавление нового сообщения о баге и формирование страниц приложения.</p>
<p>До встречи!</p>
<p><strong>P.S.</strong> Если есть вопросы или предложения, пишите в комментариях, обсудим <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p><img src="http://www.simplecoding.org/?ak_action=api_record_view&id=778&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/bug-tracker-izmeneniya-v-proekte-chast-tretya.html/feed</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
	</channel>
</rss>
