<?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/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>garotosopa &#187; PHP</title>
	<atom:link href="http://garotosopa.wordpress.com/category/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://garotosopa.wordpress.com</link>
	<description>juntando as letrinhas desde 1986</description>
	<lastBuildDate>Mon, 05 Oct 2009 12:00:34 +0000</lastBuildDate>
	<generator>http://wordpress.com/</generator>
	<language>pt-br</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<cloud domain='garotosopa.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://www.gravatar.com/blavatar/1aa997062c21c77622f350c2011b4705?s=96&#038;d=http://s.wordpress.com/i/buttonw-com.png</url>
		<title>garotosopa &#187; PHP</title>
		<link>http://garotosopa.wordpress.com</link>
	</image>
			<item>
		<title>Pequena utilidade para variáveis estáticas</title>
		<link>http://garotosopa.wordpress.com/2009/09/09/pequena-utilidade-para-variaveis-estaticas/</link>
		<comments>http://garotosopa.wordpress.com/2009/09/09/pequena-utilidade-para-variaveis-estaticas/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 12:50:10 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=664</guid>
		<description><![CDATA[Finalmente, depois de muitos anos, achei que tivesse encontrado uma situação em que variáveis estáticas seriam úteis para mim no PHP.
A diferença da variável estática em uma função é que ela não perde o seu valor quando a execução deixa o seu escopo. Isto é, na próxima vez que a função for executada, a variável [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=664&subd=garotosopa&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Finalmente, depois de muitos anos, achei que tivesse encontrado uma situação em que variáveis estáticas seriam úteis para mim no PHP.</p>
<p>A diferença da variável estática em uma função é que ela não perde o seu valor quando a execução deixa o seu escopo. Isto é, na próxima vez que a função for executada, a variável terá o mesmo valor que tinha na execução anterior.</p>
<p>Nunca tinha achado muita utilidade pra isso, até porque geralmente as variáveis locais de um método realmente tinham o tempo de vida de cada execução. Quando não, fazia mais sentido utilizar uma propriedade da classe.</p>
<p>Até que recentemente surgiu a necessidade de executar um método que consultava o banco de dados dezenas de vezes em uma única requisição, alterando apenas o parâmetro da query.<br />
<span id="more-664"></span><br />
Como consultar o banco uma única vez não era viável neste caso, um raciocínio que segui para tentar poupar um pouco o servidor foi efetuar o <em>prepare</em> somente 1 vez para cada query. E aí entrou a variável estática, guardando o resultado do <em>prepare</em> para execuções futuras, na mesma requisição.</p>
<div style="font-size:12px;font-family:Monaco,monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#bdb76b;">&lt;?php</span><br />
<span style="color:#00ff00;">class</span>&nbsp;TrechoDaMinhaClasse <span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">public</span>&nbsp;<span style="color:#ffd700;">function</span>&nbsp;consultarAlgo<span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">id</span><span style="color:#bdb76b;">)</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">static</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">prepare</span>;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">if</span>&nbsp;<span style="color:#bdb76b;">(</span>&nbsp;<span style="color:#ff0000;">!</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">prepare</span>&nbsp;<span style="color:#bdb76b;">)</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">prepare</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">this</span><span style="color:#00ff00;">-&gt;</span>db<span style="color:#00ff00;">-&gt;</span>prepare<span style="color:#bdb76b;">(</span>&#39;<br />
<span style="color:#87ceeb;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SELECT id, descricao, peso</span><br />
<span style="color:#87ceeb;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FROM minhatabela</span><br />
<span style="color:#87ceeb;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WHERE id = :0</span><br />
<span style="color:#87ceeb;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>&#39;<span style="color:#bdb76b;">)</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#bdb76b;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">rs</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">this</span><span style="color:#00ff00;">-&gt;</span>db<span style="color:#00ff00;">-&gt;</span>execute<span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">prepare</span>, <span style="color:#6495ed;">array</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">id</span><span style="color:#bdb76b;">))</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">return</span>&nbsp;<span style="color:#ffd700;">new</span>&nbsp;GradeCurricular<span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">rs</span><span style="color:#00ff00;">-&gt;</span>fetchRow<span style="color:#bdb76b;">())</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#bdb76b;">}</span><br />
<span style="color:#bdb76b;">}</span></div>
<p>Dessa forma, a partir da segunda vez que o método for chamado, ele executa direto o <em>prepared statement</em> com o id que deve ser consultado, sem ter que fazer o <em>prepare</em> de novo.</p>
<p>Para minha surpresa, fazendo um benchmark simples hoje (meses depois de implementar com static, assumindo que seria mais rápido), percebi que poupar o <em>prepare</em> no Oracle não fez muita diferença. Pelo visto o Oracle percebe que é a mesma query e não prepara novamente, ou simplesmente fazer o prepare é tão simples que não faz diferença economizar.</p>
<p>Sendo assim, parece que a pequena utilidade que eu tinha dado a variáveis estáticas não me serviu de nada. Estou apresentando o resultado aqui porque, bem&#8230; &#8220;Negative results are still results. Even 20 thousand of them&#8221;.</p>
<p>Pelo visto vou ficar sem ter utilidade para variáveis estáticas. A não ser que você tenha outros relatos positivos :)</p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/664/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/664/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/664/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/664/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/664/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/664/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/664/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/664/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/664/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/664/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=664&subd=garotosopa&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2009/09/09/pequena-utilidade-para-variaveis-estaticas/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>
	</item>
		<item>
		<title>7 coisas simples em PHP que alguns ainda complicam</title>
		<link>http://garotosopa.wordpress.com/2009/05/30/7-coisas-simples-em-php-que-alguns-ainda-complicam/</link>
		<comments>http://garotosopa.wordpress.com/2009/05/30/7-coisas-simples-em-php-que-alguns-ainda-complicam/#comments</comments>
		<pubDate>Sat, 30 May 2009 18:54:17 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=608</guid>
		<description><![CDATA[É comum ver scripts com dezenas de linhas de código pra fazer algo extremamente simples. Fica aqui meu apelo desesperado com algumas dicas rápidas.

1 &#8211; Listar arquivos de um diretório
Se não houver um motivo muito claro pra usar opendir, readdir e closedir (não consigo pensar em nenhum), a forma mais prática de listar o conteúdo [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=608&subd=garotosopa&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>É comum ver scripts com dezenas de linhas de código pra fazer algo extremamente simples. Fica aqui meu apelo desesperado com algumas dicas rápidas.</p>
<p><span id="more-608"></span></p>
<h3><a href="#listar-arquivos" name="listar-arquivos">1 &#8211; Listar arquivos de um diretório</a></h3>
<p>Se não houver um motivo muito claro pra usar <a href="http://php.net/opendir">opendir</a>, <a href="http://php.net/readdir">readdir</a> e <a href="http://php.net/closedir">closedir</a> (não consigo pensar em nenhum), a forma mais prática de listar o conteúdo de um diretório é com <a href="http://php.net/DirectoryIterator">DirectoryIterator</a>:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#ff0000;">$</span><span style="color:#fa8072;">iterator</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffd700;">new</span>&nbsp;<span style="color:#ffdead;">DirectoryIterator</span><span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">/var/www</span>&#39;<span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
<span style="color:#6495ed;">foreach</span>&nbsp;<span style="color:#bdb76b;">(</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">iterator</span>&nbsp;<span style="color:#6495ed;">as</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">entry</span>&nbsp;<span style="color:#bdb76b;">)</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ffd700;">echo</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">entry</span><span style="color:#00ff00;">-&gt;</span>getFilename<span style="color:#bdb76b;">()</span>, &quot;<span style="color:#bdb76b;">\n</span>&quot;;<br />
<span style="color:#bdb76b;">}</span></div>
<p>Se for necessário listar os arquivos recursivamente, percorrendo todos os subdiretórios, é só usar o <a href="http://php.net/RecursiveDirectoryIterator">RecursiveDirectoryIterator</a> junto com o <a href="http://php.net/RecursiveIteratorIterator">RecursiveIteratorIterator</a>:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#ff0000;">$</span><span style="color:#fa8072;">iterator</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffd700;">new</span>&nbsp;<span style="color:#ffdead;">RecursiveDirectoryIterator</span><span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">/var/www</span>&#39;<span style="color:#bdb76b;">)</span>;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">recursiveIterator</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffd700;">new</span>&nbsp;<span style="color:#ffdead;">RecursiveIteratorIterator</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">iterator</span><span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
<span style="color:#6495ed;">foreach</span>&nbsp;<span style="color:#bdb76b;">(</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">recursiveIterator</span>&nbsp;<span style="color:#6495ed;">as</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">entry</span>&nbsp;<span style="color:#bdb76b;">)</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ffd700;">echo</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">entry</span><span style="color:#00ff00;">-&gt;</span>getFilename<span style="color:#bdb76b;">()</span>, &quot;<span style="color:#bdb76b;">\n</span>&quot;;<br />
<span style="color:#bdb76b;">}</span></div>
<p>Com um pouco de criatividade, é possível estender essas classes com qualquer lógica facilmente, como por exemplo, para montar uma árvore com a estrutura dos diretórios.</p>
<h3><a href="#query-string" name="query-string">2 &#8211; montar e desmontar query strings</a></h3>
<p>Mesmo que menos comum (e menos útil), colocar uma <em>query string</em> numa URL é um trabalho trivial demais pra ser feito com <a href="http://php.net/implode">implode</a>, concatenando tudo ou qualquer outro método engenhoso. Desde o lançamento do PHP 5 é possível contar com a <a href="http://php.net/http_build_query">http_build_query</a>:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#ff0000;">$</span><span style="color:#fa8072;">dados</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#6495ed;">array</span><span style="color:#bdb76b;">(</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#87ceeb;">hl</span>&#39;&nbsp;<span style="color:#ff0000;">=</span><span style="color:#ff0000;">&gt;</span>&nbsp;&#39;<span style="color:#87ceeb;">pt-BR</span>&#39;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#87ceeb;">q</span>&#39;&nbsp;&nbsp;<span style="color:#ff0000;">=</span><span style="color:#ff0000;">&gt;</span>&nbsp;&#39;<span style="color:#87ceeb;">Forgetting Sarah Marshall</span>&#39;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#87ceeb;">testa-escape</span>&#39;&nbsp;<span style="color:#ff0000;">=</span><span style="color:#ff0000;">&gt;</span>&nbsp;&#39;<span style="color:#87ceeb;">acentuação</span>&#39;,<br />
<span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
<span style="color:#ffd700;">echo</span>&nbsp;<span style="color:#ffdead;">http_build_query</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">dados</span><span style="color:#bdb76b;">)</span>;<br />
<span style="color:#666666;">// hl=pt-BR&amp;q=Forgetting+Sarah+Marshall&amp;testa-escape=acentua%C3%A7%C3%A3o </span></div>
<p>E o inverso também é possível com as funções <a href="http://php.net/parse_url">parse_url</a> e <a href="http://php.net/parse_str">parse_str</a>:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#ff0000;">$</span><span style="color:#fa8072;">url</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffdead;">parse_url</span><span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">http://www.google.com/search?q=anneke+van+giersbergen&amp;num=50</span>&#39;<span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
<span style="color:#ffdead;">parse_str</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">url</span><span style="color:#bdb76b;">[</span>&#39;<span style="color:#87ceeb;">query</span>&#39;<span style="color:#bdb76b;">]</span>, <span style="color:#ff0000;">$</span><span style="color:#fa8072;">query</span><span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
<span style="color:#ffd700;">echo</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">query</span><span style="color:#bdb76b;">[</span>&#39;<span style="color:#87ceeb;">q</span>&#39;<span style="color:#bdb76b;">]</span>;<br />
<span style="color:#666666;">// anneke van giersbergen</span></div>
<p>Só fique atento que, por motivos alheios ao bom senso, <a href="http://php.net/parse_str">parse_str</a> por padrão extrai as variáveis no escopo onde foi chamada. É necessário passar um segundo argumento para ter um array gerado por referência, como no exemplo acima com a variável <em>$query</em>.</p>
<h3><a href="#ler-paginas-remotas" name="ler-paginas-remotas">3 &#8211; ler páginas remotas</a></h3>
<p>Dentre todas as implementações, a mais desnecessária costuma ser <a href="http://php.net/fsockopen">fsockopen</a>, <a href="http://php.net/fwrite">fwrite</a>, <a href="http://php.net/feof">feof</a>, <a href="http://php.net/fgets">fgets</a> e <a href="http://php.net/fclose">fclose</a> para ler arquivos remotos por HTTP.</p>
<p>Uma função já resolve:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#ff0000;">$</span><span style="color:#fa8072;">contents</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffdead;">file_get_contents</span><span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">http://php.net/file_get_contents</span>&#39;<span style="color:#bdb76b;">)</span>;</div>
<p>Isso é possível graças aos <a href="http://php.net/wrappers">protocol wrappers</a> que encapsulam a lógica de acesso aos respectivos protocolos, tal como HTTP. Esta forma de acesso, no entanto, depende da configuração <a href="http://php.net/filesystem.configuration#ini.allow-url-fopen">allow_url_fopen</a> estar habilitada no php.ini (que é o padrão).</p>
<p>Para ler os <em>response headers</em> da requisição, utilize <a href="http://php.net/fopen">fopen</a> com <a href="http://php.net/stream_get_meta_data">stream_get_meta_data</a>.</p>
<p>E se um dia você quiser impressionar a mulherada, veja a função <a href="http://php.net/stream_wrapper_register">stream_wrapper_register</a> para criar o seu próprio <em>protocol wrapper</em>.</p>
<h3><a href="#submeter-post-remoto" name="submeter-post-remoto">4 &#8211; submeter dados por post para uma página remota</a></h3>
<p>A coisa fica mais complicada quando o desenvolvedor pensa em usar <a href="http://php.net/curl">cURL</a> pra submeter dados por POST para outro servidor. A extensão até tem seu mérito, mas usá-la <strong>apenas</strong> pra este propósito é um grande equívoco.</p>
<p>As funções que fazem uso dos <a href="http://php.net/wrappers">protocol wrappers</a> aceitam um objeto de <em>stream context</em>, criado pela função <a href="http://php.net/stream_context_create">stream_context_create</a>, para configurar alguns aspectos do protocolo. As <a href="http://php.net/context.http">opções de contexto do protocolo HTTP</a> permitem definir, entre outras coisas, o método de acesso (GET, POST, etc) e o conteúdo a ser postado:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#ff0000;">$</span><span style="color:#fa8072;">content</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffdead;">http_build_query</span><span style="color:#bdb76b;">(</span><span style="color:#6495ed;">array</span><span style="color:#bdb76b;">(</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#87ceeb;">cidade</span>&#39;&nbsp;<span style="color:#ff0000;">=</span><span style="color:#ff0000;">&gt;</span>&nbsp;&#39;<span style="color:#87ceeb;">Rio de Janeiro</span>&#39;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#87ceeb;">tipo</span>&#39;&nbsp;&nbsp; <span style="color:#ff0000;">=</span><span style="color:#ff0000;">&gt;</span>&nbsp;&#39;<span style="color:#87ceeb;">Apartamento</span>&#39;,<br />
<span style="color:#bdb76b;">))</span>;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">context</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffdead;">stream_context_create</span><span style="color:#bdb76b;">(</span><span style="color:#6495ed;">array</span><span style="color:#bdb76b;">(</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#87ceeb;">http</span>&#39;&nbsp;<span style="color:#ff0000;">=</span><span style="color:#ff0000;">&gt;</span>&nbsp;<span style="color:#6495ed;">array</span><span style="color:#bdb76b;">(</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#87ceeb;">method</span>&#39;&nbsp;&nbsp;<span style="color:#ff0000;">=</span><span style="color:#ff0000;">&gt;</span>&nbsp;&#39;<span style="color:#87ceeb;">POST</span>&#39;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#87ceeb;">content</span>&#39;&nbsp;<span style="color:#ff0000;">=</span><span style="color:#ff0000;">&gt;</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">content</span>,<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#bdb76b;">)</span><br />
<span style="color:#bdb76b;">))</span>;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">contents</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffdead;">file_get_contents</span><span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">http://exemplo/teste.php</span>&#39;, <span style="color:#6495ed;">null</span>, <span style="color:#ff0000;">$</span><span style="color:#fa8072;">context</span><span style="color:#bdb76b;">)</span>;</div>
<p>Quando não for necessário ler o retorno da requisição, basta chamar a url com <a href="http://php.net/fopen">fopen</a> passando o contexto como quarto argumento.</p>
<h3><a href="#download-remoto" name="download-remoto">5 &#8211; fazer download de um arquivo remoto</a></h3>
<p>Vale lembrar que a maioria das funções de stream e filesystem aceitam URLs completas e fazem uso da abstração do protocolo. O que eu vejo muita gente esquecer é que isso inclui a função <a href="http://php.net/copy">copy</a>:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#ff0000;">$</span><span style="color:#fa8072;">url</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;&quot;<span style="color:#87ceeb;">http://userserve-ak.last.fm/serve/500/4349551/Terri+Clark.jpg</span>&quot;;<br />
&nbsp;<br />
<span style="color:#ffdead;">copy</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">url</span>, &#39;<span style="color:#87ceeb;">/tmp/</span>&#39;&nbsp;<span style="color:#ff0000;">.</span>&nbsp;<span style="color:#ffdead;">urldecode</span><span style="color:#bdb76b;">(</span><span style="color:#ffdead;">basename</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">url</span><span style="color:#bdb76b;">)))</span>;</div>
<p>O trecho acima vai baixar a imagem remota e salvar no arquivo local <em>/tmp/Terri Clark.jpg</em>. E caso não seja óbvio, &#8220;local&#8221; se refere a quem está executando o script PHP, que no caso será o seu servidor caso seja um script web, e não o cliente que está acessando pelo browser.</p>
<p>Se o objetivo for realmente repassar o conteúdo remoto para o cliente que estiver acessando pelo browser, o script é igualmente simples:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#ff0000;">$</span><span style="color:#fa8072;">url</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;&#39;<span style="color:#87ceeb;">http://userserve-ak.last.fm/serve/500/4349551/Terri+Clark.jpg</span>&#39;;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">handle</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffdead;">fopen</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">url</span>, &#39;<span style="color:#87ceeb;">r</span>&#39;<span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">meta_data</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffdead;">stream_get_meta_data</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">handle</span><span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
<span style="color:#666666;">// Repassa todos os headers do servidor remoto para o nosso cliente</span><br />
<span style="color:#6495ed;">foreach</span>&nbsp;<span style="color:#bdb76b;">(</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">meta_data</span><span style="color:#bdb76b;">[</span>&#39;<span style="color:#87ceeb;">wrapper_data</span>&#39;<span style="color:#bdb76b;">]</span>&nbsp;<span style="color:#6495ed;">as</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">header</span>&nbsp;<span style="color:#bdb76b;">)</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ffdead;">header</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">header</span><span style="color:#bdb76b;">)</span>;<br />
<span style="color:#bdb76b;">}</span><br />
&nbsp;<br />
<span style="color:#666666;">// Repassa o conteúdo para o nosso cliente</span><br />
<span style="color:#ffdead;">fpassthru</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">handle</span><span style="color:#bdb76b;">)</span>;</div>
<p>Considerando que estamos apenas testando a funcionalidade. Ter um script de proxy totalmente funcional é bem mais complexo, e certamente já tem algo pronto por aí.</p>
<h3><a href="#calculo-data" name="calculo-data">6 &#8211; fazer cálculo com data</a></h3>
<p>Dentre todas as simplificações possíveis, a que mais costuma comover é a função <a href="http://php.net/strtotime">strtotime</a>. Pra quem já está acostumado, parece que não faz mais do que sua obrigação. Mas pra quem ainda faz cálculos com data multiplicando por 86400, chega a parecer mágico:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#ffd700;">echo</span>&nbsp;&#39;<span style="color:#87ceeb;">Amanhã: </span>&#39;, <span style="color:#ffdead;">strftime</span><span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">%A</span>&#39;, <span style="color:#ffdead;">strtotime</span><span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">tomorrow</span>&#39;<span style="color:#bdb76b;">))</span>;<br />
<span style="color:#666666;">// Amanhã: domingo</span><br />
&nbsp;<br />
<span style="color:#ffd700;">echo</span>&nbsp;&#39;<span style="color:#87ceeb;">Próxima segunda: </span>&#39;, <span style="color:#ffdead;">strftime</span><span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">%d de %B de %Y</span>&#39;, <span style="color:#ffdead;">strtotime</span><span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">next monday</span>&#39;<span style="color:#bdb76b;">))</span>;<br />
<span style="color:#666666;">// Próxima segunda: 01 de junho de 2009</span><br />
&nbsp;<br />
<span style="color:#ffd700;">echo</span>&nbsp;&#39;<span style="color:#87ceeb;">Vencimento: </span>&#39;, <span style="color:#ffdead;">strftime</span><span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">%d/%m/%Y</span>&#39;, <span style="color:#ffdead;">strtotime</span><span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">+3 months</span>&#39;<span style="color:#bdb76b;">))</span>;<br />
<span style="color:#666666;">// Vencimento: 30/08/2009</span></div>
<p>Mais exemplos você mesmo pode ver no manual do PHP ou na página de <a href="http://www.gnu.org/software/tar/manual/html_node/Date-input-formats.html">Date Input Formats do projeto GNU</a>. Para o nome dos meses e dias da semana ficarem em português, utilize <em>setlocale(LC_TIME, &#8216;pt_BR&#8217;);</em> antes de chamar a função <a href="http://php.net/strftime">strftime</a>.</p>
<h3><a href="#escapar-sql-html" name="escapar-sql-html">7 &#8211; escapar sql e html</a></h3>
<p>Felizmente nunca mais vi nenhum script com aberrações anti-sql-injection, mas há algum tempo era possível encontrar pessoas removendo palavras-chave de SQL de todas as strings que íam para o banco de dados. Se o usuário digitasse palavras como select, delete ou drop, elas eram simplesmente removidas da frase. Isso quando o programador não interrompia o script e acusava o usuário de estar tentando explorar alguma falha de segurança. Eu juro, isso existia.</p>
<p>Ao trabalhar com <a href="http://php.net/pdo">PDO</a>, a melhor opção (pra não dizer a única!) é utilizar <a href="http://php.net/pdo.prepare">prepare</a> e <a href="http://php.net/pdostatement.execute">execute</a> pra separar a query em si dos seus parâmetros:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#ff0000;">$</span><span style="color:#fa8072;">conexao</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffd700;">new</span>&nbsp;<span style="color:#ffdead;">PDO</span><span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">mysql:dbname=banco;host=localhost</span>&#39;, &#39;<span style="color:#87ceeb;">login</span>&#39;, &#39;<span style="color:#87ceeb;">senha</span>&#39;<span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">uf</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;&#39;<span style="color:#87ceeb;">RJ</span>&#39;;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">idade</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffa0a0;">18</span>;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">sth</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">conexao</span><span style="color:#00ff00;">-&gt;</span>prepare<span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">SELECT nome FROM pessoa WHERE uf = ? AND idade &gt; ?</span>&#39;<span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">sth</span><span style="color:#00ff00;">-&gt;</span>execute<span style="color:#bdb76b;">(</span><span style="color:#6495ed;">array</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">uf</span>, <span style="color:#ff0000;">$</span><span style="color:#fa8072;">idade</span><span style="color:#bdb76b;">))</span>;<br />
&nbsp;<br />
<span style="color:#6495ed;">while</span>&nbsp;<span style="color:#bdb76b;">(</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">row</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">sth</span><span style="color:#00ff00;">-&gt;</span>fetch<span style="color:#bdb76b;">()</span>&nbsp;<span style="color:#bdb76b;">)</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ffd700;">echo</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">row</span><span style="color:#bdb76b;">[</span>&#39;<span style="color:#87ceeb;">nome</span>&#39;<span style="color:#bdb76b;">]</span>;<br />
<span style="color:#bdb76b;">}</span></div>
<p>Se estiver utilizando drivers nativos, veja as funções <a href="http://php.net/mysql_real_escape_string">mysql_real_escape_string</a> ou <a href="http://php.net/mysqli.prepare">mysqli_prepare</a> e <a href="http://php.net/mysqli-stmt.bind-param">mysqli_stmt_bind_param</a>, dependendo da extensão. Certamente outros bancos de dados têm a mesma funcionalidade.</p>
<p>A única preocupação é garantir que os parâmetros não se misturem com a query; não precisa inventar moda e remover o que o usuário digitou.</p>
<p>Outra confusão comum é ao escapar HTML. O objetivo é evitar que o texto digitado por um usuário seja interpretado pelo browser de todos os usuários do site.</p>
<p>Conceitualmente, esta é uma responsabilidade da camada de exibição. O template é que deve utilizar <a href="http://php.net/htmlspecialchars">htmlspecialchars</a> antes de gerar a saída na tela, e não antes de salvar no banco. Isso garante que o conteúdo que está no banco é fiel ao que foi digitado pelo usuário e pode ser reaproveitado em outras mídias além do HTML.</p>
<p>O que pode e deve ser feito é filtrar conteúdo realmente indevido, como caracteres inválidos ou espaços extras, dependendo da aplicação.</p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/608/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/608/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/608/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/608/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/608/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/608/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/608/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/608/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/608/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/608/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=608&subd=garotosopa&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2009/05/30/7-coisas-simples-em-php-que-alguns-ainda-complicam/feed/</wfw:commentRss>
		<slash:comments>22</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>
	</item>
		<item>
		<title>Organizando classes de acesso ao banco de dados</title>
		<link>http://garotosopa.wordpress.com/2009/01/17/organizando-classes-de-acesso-ao-banco-de-dados/</link>
		<comments>http://garotosopa.wordpress.com/2009/01/17/organizando-classes-de-acesso-ao-banco-de-dados/#comments</comments>
		<pubDate>Sun, 18 Jan 2009 01:21:28 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[OOP]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=485</guid>
		<description><![CDATA[E então o camarada decide programar orientado a objetos. Coloca todas as funções procedurais dentro de uma classe e acha o máximo. Comete o erro que eu chamo de Programação Orientada a Classes.
Assunto batido demais na altura do campeonato, mas com a quantidade de vezes que tenho visto isso acontecer, melhor tentar esclarecer algumas coisas.

Ultimamente, [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=485&subd=garotosopa&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>E então o camarada decide programar orientado a objetos. Coloca todas as funções procedurais dentro de uma classe e acha o máximo. <strong>Comete o erro que eu chamo de Programação Orientada a Classes</strong>.</p>
<p>Assunto batido demais na altura do campeonato, mas com a quantidade de vezes que tenho visto isso acontecer, melhor tentar esclarecer algumas coisas.<br />
<span id="more-485"></span></p>
<p>Ultimamente, o erro mais comum tem sido ao criar classes de acesso ao banco. Não entrarei no mérito de usar ou não um framework já existente ou da vantagem de ORM. Se o cara quer criar as classes, que crie. Mas crie corretamente.</p>
<p>A dificuldade está em <strong>perceber os objetos</strong> e criar métodos orientados a cada um deles. Ao lidar com banco de dados, o primeiro passo é identificar os três sujeitos principais:</p>
<ul>
<li>a conexão com o banco</li>
<li>o resultado de uma consulta, ou <em>rowset</em></li>
<li>e cada item desse resultado, ou <em>row</em></li>
</ul>
<p>Como assumem três papéis distintos, <strong>devem ser representados por três classes diferentes</strong>.</p>
<p>Surge então a dúvida se o <em>rowset</em> deve estender a conexão ou vice-versa. Esse pensamento é fruto direto do que o desenvolvedor acha que entendeu ao ver tantos <em>extends</em> por aí. Se não houvesse influência de achar que orientação a objeto significa objetos estendendo objetos, ficaria mais claro que <strong>as classes trabalham independentemente</strong>.</p>
<p><strong>Estende-se uma classe para criar um subtipo dela</strong>. É perfeitamente válido que a classe Carro estenda a classe Automóvel, porque carro é um tipo de automóvel. Mas fisicamente não faz sentido que Carro estenda Motor; ele simplesmente usa um motor. Até porque, se fosse seguir essa linha de raciocínio, um carro teria que estender motor, porta, roda, volante&#8230;</p>
<p>A dúvida seguinte é de como interligar essas classes. A solução vem conforme identificamos o papel de cada uma delas.</p>
<p>A classe que representa a conexão precisa de um método para <strong>conectar no banco</strong> e outro para <strong>executar queries</strong>. Podemos assumir também que cada query tem um resultado. Sendo assim, a execução de queries deve <strong>retornar um objeto <em>rowset</em></strong>.</p>
<p>O <em>rowset</em> por sua vez <strong>precisa de um <em>resource</em></strong> no qual trabalhar. Logo, a conexão, que é quem vai criar este objeto, deve passar o <em>resource</em> no <em>constructor</em>, que nada mais é do que o retorno de <em>mysql_query()</em>, por exemplo. Uma vez construído, o <em>rowset</em> precisa minimamente de um método para contar a quantidade de <em>rows</em> retornados e outro para retornar cada <em>row</em>.</p>
<p>Seguindo este modelo, uma classe para conexão com o MySQL pode começar assim:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#00ff00;">class</span>&nbsp;Conexao_Mysql <span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">private</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">dbh</span>;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">public</span>&nbsp;<span style="color:#ffd700;">function</span>&nbsp;connect<span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">host</span>, <span style="color:#ff0000;">$</span><span style="color:#fa8072;">user</span>, <span style="color:#ff0000;">$</span><span style="color:#fa8072;">password</span><span style="color:#bdb76b;">)</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">this</span><span style="color:#00ff00;">-&gt;</span>dbh&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffdead;">mysql_connect</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">host</span>, <span style="color:#ff0000;">$</span><span style="color:#fa8072;">user</span>, <span style="color:#ff0000;">$</span><span style="color:#fa8072;">password</span><span style="color:#bdb76b;">)</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#bdb76b;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">public</span>&nbsp;<span style="color:#ffd700;">function</span>&nbsp;useDatabase<span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">database</span><span style="color:#bdb76b;">)</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ffdead;">mysql_select_db</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">database</span>, <span style="color:#ff0000;">$</span><span style="color:#fa8072;">this</span><span style="color:#00ff00;">-&gt;</span>dbh<span style="color:#bdb76b;">)</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#bdb76b;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">public</span>&nbsp;<span style="color:#ffd700;">function</span>&nbsp;query<span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">sql</span><span style="color:#bdb76b;">)</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">res</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffdead;">mysql_query</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">sql</span>, <span style="color:#ff0000;">$</span><span style="color:#fa8072;">this</span><span style="color:#00ff00;">-&gt;</span>dbh<span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">return</span>&nbsp;<span style="color:#ffd700;">new</span>&nbsp;Rowset_Mysql<span style="color:#bdb76b;">(</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">res</span>&nbsp;<span style="color:#bdb76b;">)</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#bdb76b;">}</span><br />
<span style="color:#bdb76b;">}</span></div>
<p>Um ponto importante a observar é que o resultado de <em>mysql_connect()</em> é associado a uma propriedade do objeto para ser referenciado mais tarde. Isso garante que, caso existam outras conexões, as funções <em>mysql_select_db</em> e <em>mysql_query</em> sejam utilizadas na <strong>conexão correspondente ao objeto</strong> no qual foram chamadas.</p>
<p>O método <em>query</em> executa a SQL passada como argumento e monta um objeto para representar o <em>rowset</em>, passando o <em>resource</em> retornado pela <em>mysql_query()</em> para o <em>constructor</em>.</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#00ff00;">class</span>&nbsp;Rowset_Mysql <span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">private</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">res</span>;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">public</span>&nbsp;<span style="color:#ffd700;">function</span>&nbsp;<span style="color:#ff0000;">__construct</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">res</span><span style="color:#bdb76b;">)</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">this</span><span style="color:#00ff00;">-&gt;</span>res&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">res</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#bdb76b;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">public</span>&nbsp;<span style="color:#ffd700;">function</span>&nbsp;<span style="color:#ffdead;">count</span><span style="color:#bdb76b;">()</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">return</span>&nbsp;<span style="color:#ffdead;">mysql_num_rows</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">this</span><span style="color:#00ff00;">-&gt;</span>res<span style="color:#bdb76b;">)</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#bdb76b;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">public</span>&nbsp;<span style="color:#ffd700;">function</span>&nbsp;fetchAssoc<span style="color:#bdb76b;">()</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6495ed;">return</span>&nbsp;<span style="color:#ffdead;">mysql_fetch_assoc</span><span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">this</span><span style="color:#00ff00;">-&gt;</span>res<span style="color:#bdb76b;">)</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#bdb76b;">}</span><br />
<span style="color:#bdb76b;">}</span></div>
<p>No <em>constructor</em>, colocamos o <em>resource</em> em uma propriedade do objeto porque precisaremos dele nos métodos <em>count()</em> e <em>fetchAssoc()</em>.</p>
<p>No <em>fetchAssoc()</em>, seria legal retornar um objeto próprio do tipo <em>Row</em> ao invés de retornar simplesmente um array. Isso ajuda principalmente se for necessário <strong>encapsular alguma lógica</strong> nos <em>rows</em>. Mas isso fica como dever de casa.</p>
<p>As consultas ficariam assim:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#ff0000;">$</span><span style="color:#fa8072;">conexao</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffd700;">new</span>&nbsp;Conexao_Mysql<span style="color:#bdb76b;">()</span>;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">conexao</span><span style="color:#00ff00;">-&gt;</span>connect<span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">localhost</span>&#39;, &#39;<span style="color:#87ceeb;">nobody</span>&#39;, &#39;<span style="color:#87ceeb;">nobody</span>&#39;<span style="color:#bdb76b;">)</span>;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">conexao</span><span style="color:#00ff00;">-&gt;</span>useDatabase<span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">lyriken</span>&#39;<span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">artistas</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">conexao</span><span style="color:#00ff00;">-&gt;</span>query<span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">SELECT * FROM artists</span>&#39;<span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
<span style="color:#6495ed;">while</span>&nbsp;<span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">artista</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">artistas</span><span style="color:#00ff00;">-&gt;</span>fetchAssoc<span style="color:#bdb76b;">())</span>&nbsp;<span style="color:#bdb76b;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#ffd700;">echo</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">artista</span><span style="color:#bdb76b;">[</span>&#39;<span style="color:#87ceeb;">name</span>&#39;<span style="color:#bdb76b;">]</span>, &quot;<span style="color:#87ceeb;">&nbsp;&lt;br /&gt;</span><span style="color:#bdb76b;">\n</span>&quot;;<br />
<span style="color:#bdb76b;">}</span></div>
<p>A principal diferença desta implementação com o que alguns desenvolvedores têm implementado é que os métodos estão realmente <strong>orientados aos respectivos objetos</strong>, e não amontuados em uma única classe.</p>
<p>Agora, pra impressionar mais as gatinhas:</p>
<ol>
<li>Controle erros utilizando <a href="http://php.net/exceptions">Exceptions</a></li>
<li>Leia sobre <a href="http://php.net/interface">interfaces</a> e <a href="http://www.php.net/manual/en/language.oop5.patterns.php#language.oop5.patterns.factory">factory pattern</a> para saber como abstrair o driver do código final</li>
<li>Implemente a interface<a href="http://www.php.net/manual/en/class.iterator.php"> Iterator da SPL</a> e utilize o <em>rowset</em> em um foreach</li>
<li>Crie classes de acesso para não ter SQL espalhado nos scripts</li>
<li><strong>Finalmente, jogue tudo fora e use um framework com ORM <span style="color:#f00;">:)</span></strong></li>
</ol>
<p>Espero que essa tentativa ajude a esclarecer também aqueles que estejam com dificuldade de desenhar seus objetos, mesmo que não sejam de acesso a banco.</p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/485/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/485/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/485/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/485/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/485/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/485/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/485/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/485/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/485/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/485/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=485&subd=garotosopa&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2009/01/17/organizando-classes-de-acesso-ao-banco-de-dados/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>
	</item>
		<item>
		<title>Domain Specific Language externa com PHP</title>
		<link>http://garotosopa.wordpress.com/2008/11/19/domain-specific-language-externa-com-php/</link>
		<comments>http://garotosopa.wordpress.com/2008/11/19/domain-specific-language-externa-com-php/#comments</comments>
		<pubDate>Wed, 19 Nov 2008 10:30:04 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[OOP]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[domain specific language]]></category>
		<category><![CDATA[dsl]]></category>
		<category><![CDATA[fluent interface]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=265</guid>
		<description><![CDATA[No post sobre Fluent Interface, testei seu uso para nomear métodos de forma clara e reutilizável nas consultas ao banco de dados.
Durante o desenvolvimento, percebi que o Eclipse completava o código conforme eu digitava, tornando o uso das classes extremamente simples:

No final, a linha de código soava como uma frase em português, exceto pelos caracteres [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=265&subd=garotosopa&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>No post sobre <a href="/fluent-interface-php">Fluent Interface</a>, testei seu uso para nomear métodos de forma clara e reutilizável nas consultas ao banco de dados.</p>
<p>Durante o desenvolvimento, percebi que o <strong>Eclipse completava o código</strong> conforme eu digitava, tornando o uso das classes extremamente simples:
<div style="border:1px solid #ccc;width:422px;margin:auto;padding:5px;"><img src="http://garotosopa.files.wordpress.com/2008/11/dslcatalog-autocomplete-eclipse1.png?w=422&#038;h=136" alt="Eclipse autocompletando métodos do catálogo de alunos" title="DSLCatalog - Eclipse autocomplete" width="422" height="136" /></div>
<p>No final, a linha de código soava como uma <strong>frase em português</strong>, exceto pelos caracteres adicionais para a sintaxe do PHP.</p>
<p>A idéia então foi exportar a lista de classes e métodos parar criar uma linguagem própria do sistema, de forma que o usuário final pudesse usar o <strong>autocomplete pela web</strong> para formar uma frase sem as distrações da sintaxe.</p>
<p>A interface ficou assim:</p>
<div style="width:425px;margin:auto;"><span style="text-align:center; display: block;"><a href="http://garotosopa.wordpress.com/2008/11/19/domain-specific-language-externa-com-php/"><img src="http://img.youtube.com/vi/i4fGnmkW0WY/2.jpg" alt="" /></a></span></div>
<p>Se o player não abrir, <a href="http://br.youtube.com/watch?v=i4fGnmkW0WY">clique aqui para ver o vídeo de demonstração da interface no Youtube</a>.</p>
<p>O autocomplete ainda não acompanha o que o usuário digita sem escolher uma opção, mas já é possível selecionar as opções com o teclado ou mouse, preencher cada parâmetro pelo <em>prompt</em> do Javascript e ter os métodos listados de acordo com o contexto.</p>
<p>A biblioteca e uma aplicação de exemplo estão <strong>no projeto <a href="http://code.google.com/p/dslcatalog/">DslCatalog</a></strong> que criei no Google Code.</p>
<p>Abaixo seguem os detalhes de como implementar os catálogos em um banco de dados já existente em <strong>3 passos rápidos</strong>. Rápidos mesmo, eu juro :)</p>
<p><span id="more-265"></span></p>
<h3>Passo 1 de 3: Criando as classes do modelo</h3>
<p>A aplicação de exemplo segue com um banco de dados SQLite neste modelo:</p>
<div style="width:407px;margin:auto;padding:5px;"><img src="http://garotosopa.files.wordpress.com/2008/11/dscatalogdemoappnc.png?w=407&#038;h=241" alt="Tabelas cidade (id, nome), aluno (id, nome, nascimento, id_cidade), matricula (id_aluno, id_curso), curso (id, nome), matricula_status (id_aluno, id_curso, data_inicio, data_fim, status)" title="DSL Catalog Banco de dados da Aplicação de exemplo" width="407" height="241" /></div>
<p>Atualmente o único adapter de banco de dados para uso no DSL Catalog é a <strong><a href="http://framework.zend.com/manual/en/zend.db.table.html">Zend Db Table</a></strong>. Mesmo que o projeto já utilize algum outro ORM ou qualquer abstração, as tabelas deverão ser mapeadas com a <em>Zend_Db_Table_Abstract</em>. O que não significa mudar de biblioteca. Apenas o mapeamento das tabelas deve ser feito.</p>
<p>Utilizando a Zend Db Table, que já está inclusa no pacote para download, a <strong>classe da tabela de cidades</strong> do modelo acima fica assim:</p>
<p><code style="display:block;background-color:#fff;border-left:3px solid #ccc;line-height:1em;padding:.5em;"><span style="color:#2e8b57;">class</span>&nbsp;Model_Cidade_Table <span style="color:#2e8b57;">extends</span>&nbsp;Zend_Db_Table_Abstract<br />
<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">protected</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">_name</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;&#39;<span style="color:#ff00ff;">cidade</span>&#39;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">protected</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">_rowClass</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;&#39;<span style="color:#ff00ff;">Model_Cidade_Row</span>&#39;;<br />
<span style="color:#6a5acd;">}</span></span></code></p>
<p>Para as tabelas que têm <strong>chave estrangeira</strong>, é preciso mapear as colunas e a classe que cada chave referencia:</p>
<p><code style="display:block;background-color:#fff;border-left:3px solid #ccc;line-height:1em;padding:.5em;"><span style="color:#2e8b57;">class</span>&nbsp;Model_Matricula_Table <span style="color:#2e8b57;">extends</span>&nbsp;Zend_Db_Table_Abstract<br />
<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">protected</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">_primary</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#2e8b57;">array</span><span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">id_aluno</span>&#39;, &#39;<span style="color:#ff00ff;">id_matricula</span>&#39;<span style="color:#6a5acd;">)</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">protected</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">_name</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;&#39;<span style="color:#ff00ff;">matricula</span>&#39;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">protected</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">_rowClass</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;&#39;<span style="color:#ff00ff;">Model_Matricula_Row</span>&#39;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">protected</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">_referenceMap</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#2e8b57;">array</span><span style="color:#6a5acd;">(</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#ff00ff;">aluno</span>&#39;&nbsp;<span style="color:#a52a2a;">=</span><span style="color:#a52a2a;">&gt;</span>&nbsp;<span style="color:#2e8b57;">array</span><span style="color:#6a5acd;">(</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#ff00ff;">columns</span>&#39;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#a52a2a;">=</span><span style="color:#a52a2a;">&gt;</span>&nbsp;&#39;<span style="color:#ff00ff;">id_aluno</span>&#39;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#ff00ff;">refTableClass</span>&#39;&nbsp;<span style="color:#a52a2a;">=</span><span style="color:#a52a2a;">&gt;</span>&nbsp;&#39;<span style="color:#ff00ff;">Model_Aluno_Table</span>&#39;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#ff00ff;">refColumns</span>&#39;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">=</span><span style="color:#a52a2a;">&gt;</span>&nbsp;&#39;<span style="color:#ff00ff;">id</span>&#39;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">)</span>,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#ff00ff;">curso</span>&#39;&nbsp;<span style="color:#a52a2a;">=</span><span style="color:#a52a2a;">&gt;</span>&nbsp;<span style="color:#2e8b57;">array</span><span style="color:#6a5acd;">(</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#ff00ff;">columns</span>&#39;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#a52a2a;">=</span><span style="color:#a52a2a;">&gt;</span>&nbsp;&#39;<span style="color:#ff00ff;">id_curso</span>&#39;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#ff00ff;">refTableClass</span>&#39;&nbsp;<span style="color:#a52a2a;">=</span><span style="color:#a52a2a;">&gt;</span>&nbsp;&#39;<span style="color:#ff00ff;">Model_Curso_Table</span>&#39;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#ff00ff;">refColumns</span>&#39;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">=</span><span style="color:#a52a2a;">&gt;</span>&nbsp;&#39;<span style="color:#ff00ff;">id</span>&#39;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">)</span>,<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">)</span>;<br />
<span style="color:#6a5acd;">}</span></span></code></p>
<p>A propriedade <strong><em>$_rowClass</em></strong> descreve qual classe representará cada linha da tabela e é onde os métodos que atuam individualmente nos objetos devem ser implementados.</p>
<p>Para nós isso é importante porque precisamos de uma forma genérica de representar na tela cada objeto do catálogo. Nos exemplos, a representação é feita apenas como string com o método mágico <strong><em>__toString</em></strong> que o PHP utiliza, mas com um pouco de criatividade pode-se evoluir facilmente para widgets mais elaborados.</p>
<p>Cada cidade será objeto dessa classe, e sua representação como string é o próprio <strong>nome da cidade</strong>:</p>
<p><code style="display:block;background-color:#fff;border-left:3px solid #ccc;line-height:1em;padding:.5em;"><span style="color:#2e8b57;">class</span>&nbsp;Model_Cidade_Row <span style="color:#2e8b57;">extends</span>&nbsp;Zend_Db_Table_Row_Abstract<br />
<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">public</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;<span style="color:#a52a2a;">__toString</span><span style="color:#6a5acd;">()</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>nome;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
<span style="color:#6a5acd;">}</span></span></code></p>
<p>O mapeamento das classes deve ocorrer <strong>para cada tabela</strong> que estará disponível através dos catálogos.</p>
<h3>Passo 2 de 3: Criando os catálogos</h3>
<p>Nas imagens anteriores a consulta era <em>alunos matriculados no curso letras atualmente com status cursando</em>. Quando esta frase é interpretada pelo parser, os tokens são separados e a árvore de execução fica dessa forma:</p>
<ol>
<li>catálogo de alunos</li>
<li>critério <em>matriculados</em></li>
<li>catálogo de matrículas</li>
<li>critério <em>noCurso</em> com argumento <em>letras</em></li>
<li>critério <em>atualmenteComStatus</em> com argumento <em>cursando</em></li>
</ol>
<p>Para permitir esta gramática, o catálogo de alunos fica assim:</p>
<p><code style="display:block;background-color:#fff;border-left:3px solid #ccc;line-height:1em;padding:.5em;"><span style="color:#2e8b57;">class</span>&nbsp;Catalogo_Alunos <span style="color:#2e8b57;">extends</span>&nbsp;DslCatalog_Abstract<br />
<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#0000ff;">/**</span><br />
<span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp; * Instancia e retorna tabela de alunos</span><br />
<span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp; *</span><br />
<span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp; * @return DslCatalog_Database_Adapter_Zend</span><br />
<span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp; */</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">protected</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;_factoryAdapter<span style="color:#6a5acd;">()</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a020f0;">new</span>&nbsp;DslCatalog_Database_Adapter_Zend<span style="color:#6a5acd;">(</span><span style="color:#a020f0;">new</span>&nbsp;Model_Aluno_Table<span style="color:#6a5acd;">())</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#0000ff;">/**</span><br />
<span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp; * Retorna ligação destes alunos com suas matrículas</span><br />
<span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp; *</span><br />
<span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp; * @return Catalogo_Matriculas</span><br />
<span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp; */</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">public</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;matriculados<span style="color:#6a5acd;">()</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>_reference<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">Catalogo_Matriculas</span>&#39;<span style="color:#6a5acd;">)</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
<span style="color:#6a5acd;">}</span></span></code></p>
<p>O método <strong><em>_factoryTable</em></strong> deve ser sempre implementado e retornar o adaptador para a tabela que o catálogo representa.</p>
<p>Já o método <em>matriculados</em> faz parte da <strong>gramática do usuário</strong>. Ele utiliza o <em>_reference</em> para instanciar e retornar o catálogo relacionado, passando o nome do catálogo como argumento. Para realizar o JOIN, é importante que a relação entre as tabelas esteja mapeada (no Zend Db, através da array <em>_referenceMap</em>).</p>
<p>Como no PHP não existe type hint de retorno, é fundamental que <strong>a tag <em>@return</em> do phpDoc</strong> seja sempre incluída corretamente, pois é através dela que a interface determina o contexto dos critérios.</p>
<p>E então o catálogo de matrículas:</p>
<p><code style="display:block;background-color:#fff;border-left:3px solid #ccc;line-height:1em;padding:.5em;"><span style="color:#2e8b57;">class</span>&nbsp;Catalogo_Matriculas <span style="color:#2e8b57;">extends</span>&nbsp;DslCatalog_Abstract<br />
<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#0000ff;">/**</span><br />
<span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp; * Instancia e retorna tabela de matrículas</span><br />
<span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp; *</span><br />
<span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp; * @return DslCatalog_Database_Adapter_Zend</span><br />
<span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp; */</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">protected</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;_factoryAdapter<span style="color:#6a5acd;">()</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a020f0;">new</span>&nbsp;DslCatalog_Database_Adapter_Zend<span style="color:#6a5acd;">(</span><span style="color:#a020f0;">new</span>&nbsp;Model_Matricula_Table<span style="color:#6a5acd;">())</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#0000ff;">/**</span><br />
<span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp; * Filtra matrículas pelo nome do curso</span><br />
<span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp; *</span><br />
<span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp; * @param string $curso</span><br />
<span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp; * @return Catalogo_Matriculas</span><br />
<span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp; */</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">public</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;noCurso<span style="color:#6a5acd;">(</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">curso</span><span style="color:#6a5acd;">)</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">cursos</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>_reference<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">Catalogo_Cursos</span>&#39;<span style="color:#6a5acd;">)</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">cursos</span><span style="color:#2e8b57;">-&gt;</span>chamados<span style="color:#6a5acd;">(</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">curso</span><span style="color:#6a5acd;">)</span>;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#0000ff;">/**</span><br />
<span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp; * Filtra matrículas pelo status atual</span><br />
<span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp; *</span><br />
<span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp; * @param string $status</span><br />
<span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp; * @return Catalogo_Matriculas</span><br />
<span style="color:#0000ff;">&nbsp;&nbsp;&nbsp;&nbsp; */</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">public</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;atualmenteComStatus<span style="color:#6a5acd;">(</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">status</span><span style="color:#6a5acd;">)</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">criterio</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;&#39;<span style="color:#ff00ff;">matricula.id_aluno = matricula_status.id_aluno</span>&#39;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">.</span>&nbsp;&#39;<span style="color:#ff00ff;">&nbsp;AND matricula.id_curso = matricula_status.id_curso</span>&#39;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">.</span>&nbsp;&#39;<span style="color:#ff00ff;">&nbsp;AND CURRENT_TIMESTAMP BETWEEN matricula_status.data_inicio</span>&#39;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">.</span>&nbsp;&#39;<span style="color:#ff00ff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AND matricula_status.data_fim</span>&#39;;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>criteria<span style="color:#6a5acd;">()</span><span style="color:#2e8b57;">-&gt;</span>join<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">matricula_status</span>&#39;, <span style="color:#a52a2a;">$</span><span style="color:#008b8b;">criterio</span>, <span style="color:#2e8b57;">array</span><span style="color:#6a5acd;">())</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#2e8b57;">-&gt;</span>where<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">matricula_status.status LIKE ?</span>&#39;, <span style="color:#a52a2a;">$</span><span style="color:#008b8b;">status</span><span style="color:#6a5acd;">)</span>;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span>;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
<span style="color:#6a5acd;">}</span></span></code></p>
<p>O interessante neste caso é que o método <em>noCurso</em> referencia e utiliza um critério do catálogo de cursos, mas retorna o próprio catálogo de matrículas. Isso foi necessário por conveniência na gramática <strong>para manter o fluxo no mesmo contexto</strong>. Mais detalhes podem ser vistos no antigo post sobre <a href="/contexto-fluent-interface/">problema do contexto nas Fluent Interfaces</a>.</p>
<p>E finalmente o método <em>atualmenteComStatus</em> adiciona um <strong>critério à query</strong>. Esse ponto tem mais a ver com a Zend Db do que com a lógica da DSL em si.</p>
<p>Os demais catálogos estão disponíveis na demonstração.</p>
<p>Uma vez com os catálogos criados, é preciso reuní-los para <strong>montar a gramática</strong>. Como o conjunto de catálogos tende a ser o mesmo em todo o sistema, parece interessante estender a classe dessa forma:</p>
<p><code style="display:block;background-color:#fff;border-left:3px solid #ccc;line-height:1em;padding:.5em;"><span style="color:#2e8b57;">class</span>&nbsp;Catalogo_Grammar <span style="color:#2e8b57;">extends</span>&nbsp;DslCatalog_Parser_Grammar<br />
<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">public</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;<span style="color:#a52a2a;">__construct</span><span style="color:#6a5acd;">()</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>addCatalog<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">Catalogo_Alunos</span>&#39;<span style="color:#6a5acd;">)</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>addCatalog<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">Catalogo_Cidades</span>&#39;<span style="color:#6a5acd;">)</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>addCatalog<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">Catalogo_Cursos</span>&#39;<span style="color:#6a5acd;">)</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>addCatalog<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">Catalogo_Matriculas</span>&#39;<span style="color:#6a5acd;">)</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
<span style="color:#6a5acd;">}</span></span></code></p>
<h3>Passo 3 de 3: Criando a interface do usuário</h3>
<p>Considerando a consulta do usuário em uma string qualquer (por exemplo vinda de um formulário), basta instanciar o <em>parser</em> e adicionar a ele a gramática que criamos logo acima.</p>
<p>A partir daí é possível interpretar a consulta e receber um catálogo que pode ser iterado e ter seus objetos mostrados na tela:</p>
<p><code style="display:block;background-color:#fff;border-left:3px solid #ccc;line-height:1em;padding:.5em;"><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">consulta</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;&#39;<span style="color:#ff00ff;">alunos matriculados no curso letras</span>&#39;;<br />
&nbsp;<br />
<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">gramatica</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#a020f0;">new</span>&nbsp;Catalogo_Grammar<span style="color:#6a5acd;">()</span>;<br />
&nbsp;<br />
<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">parser</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#a020f0;">new</span>&nbsp;DslCatalog_Parser<span style="color:#6a5acd;">()</span>;<br />
<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">parser</span><span style="color:#2e8b57;">-&gt;</span>setGrammar<span style="color:#6a5acd;">(</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">gramatica</span><span style="color:#6a5acd;">)</span>;<br />
&nbsp;<br />
<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">catalogo</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">parser</span><span style="color:#2e8b57;">-&gt;</span>parse<span style="color:#6a5acd;">(</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">consulta</span><span style="color:#6a5acd;">)</span>;<br />
&nbsp;<br />
<span style="color:#a52a2a;">foreach</span>&nbsp;<span style="color:#6a5acd;">(</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">catalogo</span>&nbsp;<span style="color:#a52a2a;">as</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">item</span><span style="color:#6a5acd;">)</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a020f0;">echo</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">item</span>, &#39;<span style="color:#ff00ff;">&lt;br /&gt;</span>&#39;;<br />
<span style="color:#6a5acd;">}</span></span></code></p>
<p>Para deixar a <strong>caixa de texto da consulta com autocomplete</strong>, o script <em>dslcatalog.js</em> deve ser incluído junto com a estrutura da gramática:</p>
<p><code style="display:block;background-color:#fff;border-left:3px solid #ccc;line-height:1em;padding:.5em;"><span style="color:#008b8b;">&lt;</span><span style="color:#a52a2a;">form</span><span style="color:#008b8b;">&nbsp;</span><span style="color:#2e8b57;">method</span><span style="color:#008b8b;">=</span><span style="color:#ff00ff;">&quot;get&quot;</span><span style="color:#008b8b;">&nbsp;</span><span style="color:#2e8b57;">action</span><span style="color:#008b8b;">=</span><span style="color:#ff00ff;">&quot;index.php&quot;</span><span style="color:#008b8b;">&gt;</span><br />
<span style="color:#008b8b;">&lt;</span><span style="color:#a52a2a;">p</span><span style="color:#008b8b;">&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#008b8b;">&lt;</span><span style="color:#a52a2a;">input</span><span style="color:#008b8b;">&nbsp;</span><span style="color:#2e8b57;">type</span><span style="color:#008b8b;">=</span><span style="color:#ff00ff;">&quot;text&quot;</span><span style="color:#008b8b;">&nbsp;</span><span style="color:#2e8b57;">id</span><span style="color:#008b8b;">=</span><span style="color:#ff00ff;">&quot;q&quot;</span><span style="color:#008b8b;">&nbsp;</span><span style="color:#2e8b57;">name</span><span style="color:#008b8b;">=</span><span style="color:#ff00ff;">&quot;q&quot;</span><span style="color:#008b8b;">&nbsp;</span><span style="color:#2e8b57;">value</span><span style="color:#008b8b;">=</span><span style="color:#ff00ff;">&quot;&quot;</span><span style="color:#008b8b;">&nbsp;/&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#008b8b;">&lt;</span><span style="color:#a52a2a;">input</span><span style="color:#008b8b;">&nbsp;</span><span style="color:#2e8b57;">type</span><span style="color:#008b8b;">=</span><span style="color:#ff00ff;">&quot;submit&quot;</span><span style="color:#008b8b;">&nbsp;/&gt;</span><br />
<span style="color:#008b8b;">&lt;/</span><span style="color:#a52a2a;">p</span><span style="color:#008b8b;">&gt;</span><br />
<span style="color:#008b8b;">&lt;/</span><span style="color:#a52a2a;">form</span><span style="color:#008b8b;">&gt;</span><br />
&nbsp;<br />
<span style="color:#008b8b;">&lt;</span><span style="color:#a52a2a;">script</span><span style="color:#008b8b;">&nbsp;</span><span style="color:#2e8b57;">type</span><span style="color:#008b8b;">=</span><span style="color:#ff00ff;">&quot;text/javascript&quot;</span><span style="color:#008b8b;">&nbsp;</span><span style="color:#2e8b57;">src</span><span style="color:#008b8b;">=</span><span style="color:#ff00ff;">&quot;dslcatalog.js&quot;</span><span style="color:#008b8b;">&gt;</span><span style="color:#008b8b;">&lt;/</span><span style="color:#a52a2a;">script</span><span style="color:#008b8b;">&gt;</span><br />
<span style="color:#008b8b;">&lt;</span><span style="color:#a52a2a;">script</span><span style="color:#008b8b;">&nbsp;</span><span style="color:#2e8b57;">type</span><span style="color:#008b8b;">=</span><span style="color:#ff00ff;">&quot;text/javascript&quot;</span><span style="color:#008b8b;">&gt;</span><br />
<span style="color:#6a5acd;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#008b8b;">var</span><span style="color:#6a5acd;">&nbsp;gramatica = </span><span style="color:#6a5acd;">&lt;?php</span>&nbsp;<span style="color:#a020f0;">echo</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">gramatica</span><span style="color:#2e8b57;">-&gt;</span>getJson<span style="color:#6a5acd;">()</span>&nbsp;<span style="color:#6a5acd;">?&gt;</span><span style="color:#6a5acd;">;</span><br />
&nbsp;<br />
<span style="color:#6a5acd;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#a52a2a;">new</span><span style="color:#6a5acd;">&nbsp;DslCatalog.AutoComplete</span>(<span style="color:#a52a2a;">document</span><span style="color:#6a5acd;">.getElementById</span>(<span style="color:#ff00ff;">&#39;q&#39;</span>)<span style="color:#6a5acd;">, gramatica</span>)<span style="color:#6a5acd;">;</span><br />
<span style="color:#008b8b;">&lt;/</span><span style="color:#a52a2a;">script</span><span style="color:#008b8b;">&gt;</span></span></code></p>
<p>Na aplicação de exemplo, a gramática foi deixada em um script separado com o objetivo de ficar no cache do navegador. Falando em cache, atualmente nenhuma camada da biblioteca tem essa preocupação, mas com o tempo isso tende a melhorar.</p>
<h3>Download</h3>
<p>A biblioteca com a aplicação de exemplo na revisão 39 está disponível no link abaixo, já incluindo as classes necessárias do Zend Framework. É só baixar e acessar o caminho <em>demo/public/index.php</em>.</p>
<p><span style="font-size:125%;"><a href="http://dslcatalog.googlecode.com/files/dslcatalog-r39.zip">http://dslcatalog.googlecode.com/files/dslcatalog-r39.zip</a></span><br />
ou<br />
<span style="font-size:125%;"><a href="http://dslcatalog.googlecode.com/files/dslcatalog-r39.tar.gz">http://dslcatalog.googlecode.com/files/dslcatalog-r39.tar.gz</a></span></p>
<p>Para a demonstração, o único requisito é que o PDO esteja habilitado com o driver SQLite. Caso receba a mensagem <em>The sqlite driver is not currently installed</em>, basta instalar a extensão pelo pecl:</p>
<div style="background-color:#666;color:#fff;padding:.25em;"><span style="color:#f00;">#</span> pecl install pdo_sqlite</div>
<p>Uma vez instalada, algum dos arquivos do php.ini deve conter <strong>extension=pdo_sqlite.so</strong>. Depois é só reiniciar o Apache.</p>
<h3>Testes</h3>
<p>Se alguém puder testar para tentar levantar possíveis sugestões seria legal. E se der algum problema é só falar.</p>
<p>Alguns dos recursos já planejados incluem:</p>
<ul>
<li>outra camada de acesso ao banco quando a Zend Db se mostrar limitada;</li>
<li>catálogos de agregação com possibilidade de agrupamento para consultas como <em>total de alunos matriculados por curso e cidade</em>;</li>
<li>parâmetros por widgets configuráveis (consulta de datas em um calendário, consulta de cursos em um combo pré-definido, etc);</li>
<li>item dos catálogos mostrados em seus respectivos widgets;</li>
<li>melhorar o autocomplete;</li>
<li>e por aí vai&#8230;</li>
</ul>
<p>E por enquanto eu fico devendo os testes de unidade, foi pura falta de habilidade mesmo. Mas já serão providenciados.</p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/265/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/265/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/265/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/265/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/265/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/265/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/265/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/265/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/265/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/265/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=265&subd=garotosopa&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2008/11/19/domain-specific-language-externa-com-php/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>

		<media:content url="http://garotosopa.files.wordpress.com/2008/11/dslcatalog-autocomplete-eclipse1.png" medium="image">
			<media:title type="html">DSLCatalog - Eclipse autocomplete</media:title>
		</media:content>

		<media:content url="http://img.youtube.com/vi/i4fGnmkW0WY/2.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/11/dscatalogdemoappnc.png" medium="image">
			<media:title type="html">DSL Catalog Banco de dados da Aplicação de exemplo</media:title>
		</media:content>
	</item>
		<item>
		<title>O problema do contexto nas Fluent Interfaces</title>
		<link>http://garotosopa.wordpress.com/2008/10/29/contexto-fluent-interface/</link>
		<comments>http://garotosopa.wordpress.com/2008/10/29/contexto-fluent-interface/#comments</comments>
		<pubDate>Wed, 29 Oct 2008 23:50:05 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[OOP]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[domain specific language]]></category>
		<category><![CDATA[fluent interface]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=188</guid>
		<description><![CDATA[No post sobre Fluent Interface no PHP foi apresentada uma API que terminou assim:
$alunos&#160;=&#160;new&#160;Catalogo_Aluno();
&#160;
$alunos-&#62;emOrdem()
&#160;&#160;&#160;&#160;&#160;&#160; -&#62;daCidade(&#39;Rio de Janeiro&#39;)
&#160;&#160;&#160;&#160;&#160;&#160; -&#62;matriculados()
&#160;&#160;&#160;&#160;&#160;&#160; -&#62;noCurso(&#39;Enfermagem&#39;);
&#160;
foreach&#160;($alunos&#160;as&#160;$aluno)&#160;{
&#160;&#160;&#160;&#160;echo&#160;$aluno-&#62;nome, &#39;&#60;br /&#62;&#39;;
}
O banco de dados estava estruturado com as tabelas de aluno, cidade, matrícula e curso. Como a relação do aluno com o curso é através da tabela de matrícula, foi necessário um catálogo extra para [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=188&subd=garotosopa&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>No <a href="/fluent-interface-php">post sobre Fluent Interface no PHP</a> foi apresentada uma API que terminou assim:</p>
<div style="font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#fff;color:#000;border-left:3px solid #ccc;font-size:12px;margin:1em 0;padding:.5em;"><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">alunos</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#a020f0;">new</span>&nbsp;Catalogo_Aluno<span style="color:#6a5acd;">()</span>;<br />
&nbsp;<br />
<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">alunos</span><span style="color:#2e8b57;">-&gt;</span>emOrdem<span style="color:#6a5acd;">()</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#2e8b57;">-&gt;</span>daCidade<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">Rio de Janeiro</span>&#39;<span style="color:#6a5acd;">)</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#2e8b57;">-&gt;</span>matriculados<span style="color:#6a5acd;">()</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#2e8b57;">-&gt;</span>noCurso<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">Enfermagem</span>&#39;<span style="color:#6a5acd;">)</span>;<br />
&nbsp;<br />
<span style="color:#a52a2a;">foreach</span>&nbsp;<span style="color:#6a5acd;">(</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">alunos</span>&nbsp;<span style="color:#a52a2a;">as</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">aluno</span><span style="color:#6a5acd;">)</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a020f0;">echo</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">aluno</span><span style="color:#2e8b57;">-&gt;</span>nome, &#39;<span style="color:#ff00ff;">&lt;br /&gt;</span>&#39;;<br />
<span style="color:#6a5acd;">}</span></div>
<p>O banco de dados estava estruturado com as tabelas de aluno, cidade, matrícula e curso. Como a relação do aluno com o curso é através da tabela de matrícula, foi necessário um catálogo extra para adicionar o critério sem quebrar o significado dos métodos.<br />
<span id="more-188"></span><br />
Para o critério do nome da cidade do aluno como chave estrangeira, bastou realizar um JOIN a partir do próprio método e continuar o fluxo no catálogo de alunos.</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#fff;color:#000;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#2e8b57;">public</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;daCidade<span style="color:#6a5acd;">(</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">cidade</span><span style="color:#6a5acd;">)</span>&nbsp;<span style="color:#6a5acd;">{</span>&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>select<span style="color:#6a5acd;">()</span><span style="color:#2e8b57;">-&gt;</span>join<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">cidade</span>&#39;, &#39;<span style="color:#ff00ff;">aluno.id_cidade = cidade.id</span>&#39;, <span style="color:#2e8b57;">array</span><span style="color:#6a5acd;">())</span>&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#2e8b57;">-&gt;</span>where<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">cidade.nome = ?</span>&#39;, <span style="color:#a52a2a;">$</span><span style="color:#008b8b;">cidade</span><span style="color:#6a5acd;">)</span>;&nbsp;&nbsp;<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span>;&nbsp;&nbsp;<br />
<span style="color:#6a5acd;">}</span></div>
<p>Neste caso é um critério simples, mas é comum acontecer o contrário, como no caso em que o aluno tem vínculo com a tabela de matrículas e esta tem vínculo com a tabela de cursos.</p>
<p>Poderia ser criado um método <em>matriculadosNoCurso($curso)</em> que fizesse JOIN nas duas tabelas, mas não seria uma prática adequada, já que o catálogo de alunos estaria assumindo uma responsabilidade do contexto de matrículas, o que em breve levaria à repetição de código.</p>
<p>O ideal é permitir que catálogos tenham referências entre si. O critério do nome do curso passa para o catálogo de matrículas que poderá ser associado com o catálogo de alunos.</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#fff;color:#000;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#2e8b57;">class</span>&nbsp;Model_Matricula_Table <span style="color:#2e8b57;">extends</span>&nbsp;Zend_Db_Table_Abstract <span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">protected</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">_name</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;&#39;<span style="color:#ff00ff;">matricula</span>&#39;;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">protected</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">_referenceMap</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#2e8b57;">array</span><span style="color:#6a5acd;">(</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#ff00ff;">aluno</span>&#39;&nbsp;<span style="color:#a52a2a;">=</span><span style="color:#a52a2a;">&gt;</span>&nbsp;<span style="color:#2e8b57;">array</span><span style="color:#6a5acd;">(</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#ff00ff;">columns</span>&#39;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#a52a2a;">=</span><span style="color:#a52a2a;">&gt;</span>&nbsp;&#39;<span style="color:#ff00ff;">id_aluno</span>&#39;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#ff00ff;">refTableClass</span>&#39;&nbsp;<span style="color:#a52a2a;">=</span><span style="color:#a52a2a;">&gt;</span>&nbsp;&#39;<span style="color:#ff00ff;">Model_Aluno_Table</span>&#39;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;<span style="color:#ff00ff;">refColumns</span>&#39;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">=</span><span style="color:#a52a2a;">&gt;</span>&nbsp;&#39;<span style="color:#ff00ff;">id</span>&#39;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">)</span>,<br />
<span style="color:#6a5acd;">}</span><br />
&nbsp;<br />
<span style="color:#2e8b57;">class</span>&nbsp;Catalogo_Matricula <span style="color:#2e8b57;">extends</span>&nbsp;Catalogo_Abstract <span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">protected</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;_factoryTable<span style="color:#6a5acd;">()</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a020f0;">new</span>&nbsp;Model_Matricula_Table<span style="color:#6a5acd;">()</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">public</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;noCurso<span style="color:#6a5acd;">(</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">curso</span><span style="color:#6a5acd;">)</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>select<span style="color:#6a5acd;">()</span><span style="color:#2e8b57;">-&gt;</span>join<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">curso</span>&#39;, &#39;<span style="color:#ff00ff;">matricula.id_curso = curso.id</span>&#39;, <span style="color:#2e8b57;">array</span><span style="color:#6a5acd;">())</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#2e8b57;">-&gt;</span>where<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">curso.nome = ?</span>&#39;, <span style="color:#a52a2a;">$</span><span style="color:#008b8b;">curso</span><span style="color:#6a5acd;">)</span>;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
<span style="color:#6a5acd;">}</span></div>
<p>Agora falta relacionar o catálogo de matrículas com o catálogo de alunos.</p>
<h3>Passando o contexto para outro objeto</h3>
<p>Começando de fora pra dentro, o catálogo de alunos precisa passar o contexto para o catálogo de matrículas para que a interface possa utilizar os seus métodos.</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#fff;color:#000;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#2e8b57;">class</span>&nbsp;Catalogo_Aluno <span style="color:#2e8b57;">extends</span>&nbsp;Catalogo_Abstract <span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#888;">/* complementando o código do post anterior */</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">public</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;matriculados<span style="color:#6a5acd;">()</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>_reference<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">Catalogo_Matricula</span>&#39;<span style="color:#6a5acd;">)</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
<span style="color:#6a5acd;">}</span></div>
<p>O método <em>_reference</em> é herdado da classe <em>Catalogo_Abstract</em> e é responsável por instanciar e retornar o catálogo desejado.</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#fff;color:#000;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#2e8b57;">abstract</span>&nbsp;<span style="color:#2e8b57;">class</span>&nbsp;Catalogo_Abstract <span style="color:#6a5acd;">{</span>&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#888;">/* complementando o código do post anterior */</span>&nbsp;&nbsp;<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">private</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">_references</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#2e8b57;">array</span><span style="color:#6a5acd;">()</span>;&nbsp;&nbsp;<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">protected</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;_reference<span style="color:#6a5acd;">(</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">catalogo</span><span style="color:#6a5acd;">)</span>&nbsp;<span style="color:#6a5acd;">{</span>&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">if</span>&nbsp;<span style="color:#6a5acd;">(</span><span style="color:#a52a2a;">!</span><span style="color:#a52a2a;">isset</span><span style="color:#6a5acd;">(</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>_references<span style="color:#6a5acd;">[</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">catalogo</span><span style="color:#6a5acd;">]))</span>&nbsp;<span style="color:#6a5acd;">{</span>&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>_references<span style="color:#6a5acd;">[</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">catalogo</span><span style="color:#6a5acd;">]</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#a020f0;">new</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">catalogo</span><span style="color:#6a5acd;">(</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#6a5acd;">)</span>;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span>&nbsp;&nbsp;<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>_references<span style="color:#6a5acd;">[</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">catalogo</span><span style="color:#6a5acd;">]</span>;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span>&nbsp;&nbsp;<br />
<span style="color:#6a5acd;">}</span></div>
<p>Os catálogos são mapeados em um array para que a referência não seja feita mais de uma vez a partir do mesmo objeto.</p>
<p>Ao instanciar o objeto, o próprio catálogo é passado como argumento para o construtor, e é nessa etapa que o relacionamento será realizado.</p>
<h3>Aceitando a referência</h3>
<p>Ao receber uma referência no construtor, três procedimentos precisam ser feitos:</p>
<ol>
<li>guardar no array de referências o objeto passado;</li>
<li>utilizar o mesmo <em>select</em>, já que a query é só uma;</li>
<li>fazer JOIN entre as tabelas.</li>
</ol>
<p>Para associar os catálogos é necessário saber o critério que os relaciona. Apesar de no Zend Framework essa informação estar disponível no <em>reference map</em>, parece que ainda não há uma forma automática de relacionar duas classes Zend_Db_Table. Como o uso do framework não é o foco, os detalhes serão dispensados.</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#fff;color:#000;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#2e8b57;">abstract</span>&nbsp;<span style="color:#2e8b57;">class</span>&nbsp;Catalogo_Abstract <span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#888;">/* complementando o código */</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">public</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;<span style="color:#a52a2a;">__construct</span><span style="color:#6a5acd;">(</span>Catalogo_Abstract <span style="color:#a52a2a;">$</span><span style="color:#008b8b;">reference</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#2e8b57;">null</span><span style="color:#6a5acd;">)</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">if</span>&nbsp;<span style="color:#6a5acd;">(</span><span style="color:#2e8b57;">null</span>&nbsp;<span style="color:#a52a2a;">!==</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">reference</span><span style="color:#6a5acd;">)</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#888;">// 1 &#8211; guarda a referência do catálogo</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>_references<span style="color:#6a5acd;">[</span><span style="color:#008b8b;">get_class</span><span style="color:#6a5acd;">(</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">reference</span><span style="color:#6a5acd;">)]</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">reference</span>;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#888;">// 2 &#8211; utiliza o mesmo select</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>_select&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">reference</span><span style="color:#2e8b57;">-&gt;</span>select<span style="color:#6a5acd;">()</span>;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#888;">// 3 &#8211; faz JOIN entre as tabelas (código relacionado ao Zend Framework)</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">fromTable</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">reference</span><span style="color:#2e8b57;">-&gt;</span>table<span style="color:#6a5acd;">()</span><span style="color:#2e8b57;">-&gt;</span><span style="color:#008b8b;">info</span><span style="color:#6a5acd;">(</span>Zend_Db_Table_Abstract<span style="color:#a52a2a;">::</span>NAME<span style="color:#6a5acd;">)</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">fromModel</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#008b8b;">get_class</span><span style="color:#6a5acd;">(</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">reference</span><span style="color:#2e8b57;">-&gt;</span>table<span style="color:#6a5acd;">())</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">joinTable</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>table<span style="color:#6a5acd;">()</span><span style="color:#2e8b57;">-&gt;</span><span style="color:#008b8b;">info</span><span style="color:#6a5acd;">(</span>Zend_Db_Table_Abstract<span style="color:#a52a2a;">::</span>NAME<span style="color:#6a5acd;">)</span>;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">referenceMap</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>table<span style="color:#6a5acd;">()</span><span style="color:#2e8b57;">-&gt;</span>getReference<span style="color:#6a5acd;">(</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">fromModel</span><span style="color:#6a5acd;">)</span>;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">clauses</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#2e8b57;">array</span><span style="color:#6a5acd;">()</span>;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">foreach</span>&nbsp;<span style="color:#6a5acd;">(</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">referenceMap</span><span style="color:#6a5acd;">[</span>&#39;<span style="color:#ff00ff;">columns</span>&#39;<span style="color:#6a5acd;">]</span>&nbsp;<span style="color:#a52a2a;">as</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">key</span>&nbsp;<span style="color:#a52a2a;">=</span><span style="color:#a52a2a;">&gt;</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">column</span><span style="color:#6a5acd;">)</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">refColumn</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">referenceMap</span><span style="color:#6a5acd;">[</span>&#39;<span style="color:#ff00ff;">refColumns</span>&#39;<span style="color:#6a5acd;">][</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">key</span><span style="color:#6a5acd;">]</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">clauses</span><span style="color:#6a5acd;">[]</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;&quot;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">fromTable</span><span style="color:#ff00ff;">.</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">refColumn</span><span style="color:#ff00ff;">&nbsp;= </span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">joinTable</span><span style="color:#ff00ff;">.</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">column</span>&quot;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">clauses</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#008b8b;">implode</span><span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">&nbsp;AND </span>&#39;, <span style="color:#a52a2a;">$</span><span style="color:#008b8b;">clauses</span><span style="color:#6a5acd;">)</span>;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>_select<span style="color:#2e8b57;">-&gt;</span>join<span style="color:#6a5acd;">(</span><span style="color:#2e8b57;">array</span><span style="color:#6a5acd;">(</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">joinTable</span>&nbsp;<span style="color:#a52a2a;">=</span><span style="color:#a52a2a;">&gt;</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">joinTable</span><span style="color:#6a5acd;">)</span>, <span style="color:#a52a2a;">$</span><span style="color:#008b8b;">clauses</span>, <span style="color:#2e8b57;">array</span><span style="color:#6a5acd;">())</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
<span style="color:#6a5acd;">}</span></div>
<p>Acompanhando o código:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#fff;color:#000;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">alunos</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#a020f0;">new</span>&nbsp;Catalogo_Aluno<span style="color:#6a5acd;">()</span>;<br />
<span style="color:#888;">// SELECT `aluno`.* FROM `aluno`</span><br />
&nbsp;<br />
<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">alunos</span><span style="color:#2e8b57;">-&gt;</span>emOrdem<span style="color:#6a5acd;">()</span><br />
<span style="color:#888;">// ORDER BY `aluno`.`nome` ASC</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#2e8b57;">-&gt;</span>daCidade<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">Rio de Janeiro</span>&#39;<span style="color:#6a5acd;">)</span><br />
<span style="color:#888;">// INNER JOIN `cidade` ON aluno.id_cidade = cidade.id</span><br />
<span style="color:#888;">// WHERE (cidade.nome = &#39;Rio de Janeiro&#39;)</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#2e8b57;">-&gt;</span>matriculados<span style="color:#6a5acd;">()</span><br />
<span style="color:#888;">// instancia e retorna catálogo de matrículas</span><br />
<span style="color:#888;">// passando o catálogo de alunos como parâmetro pro construtor</span><br />
&nbsp;<br />
<span style="color:#888;">// __construct de Catalogo_Matricula adiciona à query:</span><br />
<span style="color:#888;">// INNER JOIN `matricula` ON aluno.id = matricula.id_aluno</span><br />
&nbsp;<br />
<span style="color:#888;">// A partir daqui, os métodos são do catálogo de matrículas</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#2e8b57;">-&gt;</span>noCurso<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">Enfermagem</span>&#39;<span style="color:#6a5acd;">)</span>;<br />
<span style="color:#888;">// INNER JOIN `curso` ON matricula.id_curso = curso.id</span><br />
<span style="color:#888;">// WHERE (curso.nome = &#39;Enfermagem&#39;)</span><br />
&nbsp;<br />
<span style="color:#a020f0;">echo</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">alunos</span><span style="color:#2e8b57;">-&gt;</span>select<span style="color:#6a5acd;">()</span>;</div>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#fff;color:#000;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#a52a2a;">SELECT</span>&nbsp;aluno.*<br />
<span style="color:#a52a2a;">FROM</span>&nbsp;aluno<br />
<span style="color:#a52a2a;">INNER</span>&nbsp;<span style="color:#a52a2a;">JOIN</span>&nbsp;cidade <span style="color:#a52a2a;">ON</span>&nbsp;aluno.id_cidade = cidade.id<br />
<span style="color:#a52a2a;">INNER</span>&nbsp;<span style="color:#a52a2a;">JOIN</span>&nbsp;matricula <span style="color:#a52a2a;">ON</span>&nbsp;aluno.id = matricula.id_aluno<br />
<span style="color:#a52a2a;">INNER</span>&nbsp;<span style="color:#a52a2a;">JOIN</span>&nbsp;curso <span style="color:#a52a2a;">ON</span>&nbsp;matricula.id_curso = curso.id<br />
<span style="color:#a52a2a;">WHERE</span>&nbsp;(cidade.nome = <span style="color:#ff00ff;">&#39;Rio de Janeiro&#39;</span>)<br />
&nbsp;&nbsp;<span style="color:#a52a2a;">AND</span>&nbsp;(curso.nome = <span style="color:#ff00ff;">&#39;Enfermagem&#39;</span>)<br />
<span style="color:#a52a2a;">ORDER</span>&nbsp;<span style="color:#a52a2a;">BY</span>&nbsp;aluno.nome <span style="color:#a52a2a;">ASC</span></div>
<h3>Voltando ao contexto anterior (até porque voltar ao próximo é mais complicado)</h3>
<p>O catálogo de alunos já se relaciona com o de matrículas, mas uma vez no contexto de matrículas, ainda não é possível voltar a utilizar os critérios de alunos.</p>
<p>Observando a consulta em português puro, é correto afirmar que a lista se trata de &#8220;alunos matriculados no curso Enfermagem em que os alunos sejam da cidade do Rio de Janeiro&#8221;.</p>
<p>Assim como o método &#8220;matriculados&#8221; serve como ligação semântica entre os alunos e suas matrículas, nada mais justo que criar um método para a ligação &#8220;em que os alunos sejam&#8221;.</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#fff;color:#000;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#2e8b57;">class</span>&nbsp;Catalogo_Matricula <span style="color:#2e8b57;">extends</span>&nbsp;Catalogo_Abstract <span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#888;">/* complementando o código */</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">public</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;dosAlunos<span style="color:#6a5acd;">()</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>_reference<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">Catalogo_Aluno</span>&#39;<span style="color:#6a5acd;">)</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">public</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;emQueOsAlunosSejam<span style="color:#6a5acd;">()</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>dosAlunos<span style="color:#6a5acd;">()</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">public</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;emQueOsAlunosEstejam<span style="color:#6a5acd;">()</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>dosAlunos<span style="color:#6a5acd;">()</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
<span style="color:#6a5acd;">}</span></div>
<p>Os três novos métodos fazem a mesma coisa e existem para deixar a chamada mais natural. Dessa forma, fica transparente iniciar a consulta pelo catálogo de matrículas e filtrar por <em>$matriculas-&gt; dosAlunos()-&gt; daCidade(&#8216;Rio de Janeiro&#8217;)</em>, ou voltar para o contexto de alunos e aplicar um método de estado, como <em>$matriculas-&gt; emQueOsAlunosEstejam()-&gt; desativados()</em>.</p>
<p>De certa forma a escolha das palavras foi tendenciosa. A frase talvez devesse ser &#8220;alunos matriculados no curso Enfermagem que sejam da cidade Rio de Janeiro&#8221;, mas nesse caso seria difícil determinar o contexto a qual &#8220;que sejam&#8221; se refere, principalmente se a consulta iniciar pelo catálogo de matrículas.</p>
<p>Quando as chamadas começam pelo catálogo de alunos e seguem pelo método <em>matriculados</em>, o método <em>dosAlunos</em> não precisa instanciar o catálogo de alunos, porque o construtor já o adicionou como referência no array <em>_references</em>.</p>
<h3>Quando mudar de contexto</h3>
<p>Ao filtrar pela cidade do aluno ou pelo curso da matrícula, o JOIN foi feito no mesmo método e o contexto não mudou. Esta decisão foi totalmente baseada na prática.</p>
<p>Olhando a API, não era necessário ter algo como <em>$alunos-&gt; daCidade(&#8216;Rio de Janeiro&#8217;)-&gt; emQueOsAlunosEstejam()-&gt; emOrdem()</em>, porque a partir dos alunos não haveria nenhum critério específico das cidades.</p>
<p>De qualquer forma, pode ser interessante criar um catálogo de cidades e utilizá-lo ao filtrar os alunos, mesmo não mudando de contexto.</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#fff;color:#000;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#2e8b57;">class</span>&nbsp;Catalogo_Aluno <span style="color:#2e8b57;">extends</span>&nbsp;Catalogo_Abstract <span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#888;">/* apenas alterando o método daCidade */</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">public</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;daCidade<span style="color:#6a5acd;">(</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">cidade</span><span style="color:#6a5acd;">)</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">cidades</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>_reference<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">Catalogo_Cidade</span>&#39;<span style="color:#6a5acd;">)</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">cidades</span><span style="color:#2e8b57;">-&gt;</span>chamadas<span style="color:#6a5acd;">(</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">cidade</span><span style="color:#6a5acd;">)</span>;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
<span style="color:#6a5acd;">}</span></div>
<p>Com um catálogo próprio fica natural iniciar a consulta pelo contexto de cidades, possibilitando algo como <em>$cidades-&gt; comAlunos()-&gt; matriculados()-&gt; noCurso(&#8216;Psicologia&#8217;)</em>.</p>
<h3>Exemplo completo</h3>
<div style="background-color:#eaeaea;border:1px solid #ccc;padding:.25em;">Uma implementação <strong>mais recente</strong>, já com interface para consulta pelo usuário, está disponível <strong>no post sobre <a href="/domain-specific-language-externa-com-php/">Domain Specific Language externa</a></strong>.</div>
<p>Publiquei os testes no link abaixo, incluindo as classes necessárias do Zend Framework e SQL de amostra utilizando SQLite na memória. É só baixar e executar o index.php.</p>
<p><a href="http://garotosopa.com/codigo-fluent-interface-php/">Código fonte navegável</a><br />
<a href="http://garotosopa.com/codigo-fluent-interface-php.zip">Exemplo para download</a></p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/188/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/188/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/188/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/188/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/188/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/188/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/188/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/188/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/188/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/188/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=188&subd=garotosopa&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2008/10/29/contexto-fluent-interface/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>
	</item>
		<item>
		<title>Fluent Interface no PHP</title>
		<link>http://garotosopa.wordpress.com/2008/10/29/fluent-interface-php/</link>
		<comments>http://garotosopa.wordpress.com/2008/10/29/fluent-interface-php/#comments</comments>
		<pubDate>Wed, 29 Oct 2008 23:43:45 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[OOP]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[domain specific language]]></category>
		<category><![CDATA[dsl]]></category>
		<category><![CDATA[fluent interface]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=106</guid>
		<description><![CDATA[Uma implementação mais recente, já com interface para consulta pelo usuário, está disponível no post sobre Domain Specific Language externa.
Esses dias testei o uso de Fluent Interface para consulta de dados de forma semântica, tentando criar uma API legível e reutilizável que eventualmente servisse diretamente ao usuário.
Em uma API comum, uma classe de negócio tem [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=106&subd=garotosopa&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><div style="background-color:#eaeaea;border:1px solid #ccc;padding:.25em;">Uma implementação <strong>mais recente</strong>, já com interface para consulta pelo usuário, está disponível <strong>no post sobre <a href="/domain-specific-language-externa-com-php/">Domain Specific Language externa</a></strong>.</div>
<p>Esses dias testei o uso de Fluent Interface para consulta de dados de forma semântica, tentando criar uma API legível e reutilizável que eventualmente servisse diretamente ao usuário.</p>
<p>Em uma API comum, uma classe de negócio tem diversos métodos que retornam uma lista de acordo com diferentes critérios. As consultas ficam próximas do seguinte:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#fff;color:#000;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">alunos</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#a020f0;">new</span>&nbsp;Alunos<span style="color:#6a5acd;">()</span>;<br />
&nbsp;<br />
<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">alunosDoRio</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">alunos</span><span style="color:#2e8b57;">-&gt;</span>getPorCidade<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">Rio de Janeiro</span>&#39;<span style="color:#6a5acd;">)</span>;<br />
<span style="color:#0000ff;">/* &#8230; */</span><br />
<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">lista</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">alunos</span><span style="color:#2e8b57;">-&gt;</span>getMatriculadosPorCursoCidade<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">Enfermagem</span>&#39;, &#39;<span style="color:#ff00ff;">Rio de Janeiro</span>&#39;<span style="color:#6a5acd;">)</span>;<br />
<span style="color:#0000ff;">/* &#8230; */</span><br />
<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">emOrdem</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">alunos</span><span style="color:#2e8b57;">-&gt;</span>getMatriculadosPorCursoCidade<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">Enf&#8230;</span>&#39;, &#39;<span style="color:#ff00ff;">Rio&#8230;</span>&#39;, &#39;<span style="color:#ff00ff;">nome</span>&#39;<span style="color:#6a5acd;">)</span>;</div>
<p>Em um sistema real são muitas as variações de critérios e a classe acaba crescendo em quantidade de código e dificuldade de uso e manutenção.</p>
<p>A proposta é eliminar a necessidade de um método para cada tipo de consulta. Os critérios apenas configuram a consulta que será realizada uma única vez quando necessário, possibilitando que esses critérios de busca funcionem independentemente.</p>
<p>As chamadas passam a ser realizadas assim:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#fff;color:#000;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">alunos</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#a020f0;">new</span>&nbsp;Alunos<span style="color:#6a5acd;">()</span>;<br />
&nbsp;<br />
<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">alunos</span><span style="color:#2e8b57;">-&gt;</span>daCidade<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">Rio de Janeiro</span>&#39;<span style="color:#6a5acd;">)</span>;<br />
<span style="color:#0000ff;">/* &#8230; */</span><br />
<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">alunos</span><span style="color:#2e8b57;">-&gt;</span>emOrdem<span style="color:#6a5acd;">()</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#2e8b57;">-&gt;</span>daCidade<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">Rio de Janeiro</span>&#39;<span style="color:#6a5acd;">)</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#2e8b57;">-&gt;</span>matriculados<span style="color:#6a5acd;">()</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#2e8b57;">-&gt;</span>noCurso<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">Enfermagem</span>&#39;<span style="color:#6a5acd;">)</span>;</div>
<p>Para conseguir esta API é preciso:</p>
<ol>
<li>encadear os métodos</li>
<li>ter a possibilidade de configurar a query dinamicamente
<li>identificar quando a configuração termina para então realizar a consulta.</li>
</ol>
<p>Ainda que existam outras técnicas para refatorar a primeira API, o uso de Fluent Interface é um avanço significativo até a implementação de Domain Specific Language para uso do usuário.</p>
<div style="background-color:#eaeaea;border:1px solid #ccc;padding:.25em;">Uma implementação <strong>mais recente</strong>, já com interface para consulta pelo usuário, está disponível <strong>no post sobre <a href="/domain-specific-language-externa-com-php/">Domain Specific Language externa</a></strong>.</div>
<p><span id="more-106"></span></p>
<h3>Method Chaining</h3>
<p>O primeiro passo é perceber a simplicidade do encadeamento de métodos. Geralmente as propriedades de uma classe são definidas por métodos <em>setters</em> que não retornam nada. O objetivo é retornar o próprio objeto a partir de cada um desses métodos.</p>
<p>Esta técnica por si só apenas reduz a quantidade de código uma vez que não precisamos repetir a instância do objeto para cada <em>setter</em>.</p>
<h3>Fluent Interface</h3>
<p>Feito o encadeamento, é necessária uma mudança conceitual. O ponto principal é que a nomenclatura dos métodos deixe que a interface flua naturalmente.</p>
<p>Renomeando os métodos e retornando o próprio objeto é possível fazer a chamada de forma amigável:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#fff;color:#000;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#2e8b57;">class</span>&nbsp;Alunos <span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#0000ff;">// anteriormente chamado de setFiltroCidade</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">public</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;daCidade<span style="color:#6a5acd;">(</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">cidade</span><span style="color:#6a5acd;">)</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a020f0;">echo</span>&nbsp;&quot;<span style="color:#ff00ff;">Alunos serão filtrados pela cidade </span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">cidade</span>&quot;;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#0000ff;">// anteriormente chamado de setOrderByNome</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">public</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;emOrdem<span style="color:#6a5acd;">()</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a020f0;">echo</span>&nbsp;&quot;<span style="color:#ff00ff;">Alunos serão ordenados pelo nome</span>&quot;;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
<span style="color:#6a5acd;">}</span><br />
&nbsp;<br />
<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">alunos</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#a020f0;">new</span>&nbsp;Alunos<span style="color:#6a5acd;">()</span>;<br />
<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">alunos</span><span style="color:#2e8b57;">-&gt;</span>daCidade<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">Rio de Janeiro</span>&#39;<span style="color:#6a5acd;">)</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#2e8b57;">-&gt;</span>emOrdem<span style="color:#6a5acd;">()</span>;</div>
<p>Acima de tudo é importante manter consistência para que fique claro quais são as classes que trabalham com Method Chaining, evitando que o programador espere o próprio objeto como retorno equivocadamente.</p>
<p>Nestes exemplos será utilizado o prefixo <em>Catalogo</em> como tentativa de identificar essas classes. O uso de namespaces seria extremamente bem-vindo se a linguagem permitisse.</p>
<h3>Montando a query</h3>
<p>Diferente de uma API tradicional, os métodos anteriores devem apenas configurar o critério da consulta.</p>
<p>Mesmo sendo possível montar a SQL manualmente, uma camada de persistência que permita queries orientadas a objeto diminui muito a complexidade do código com o qual você precisa se preocupar. Os exemplos utilizam a modesta Zend_Db, mas uma biblioteca mais madura pode ser necessária no futuro.</p>
<p>Sobre o Zend Framework, basta saber que cada tabela é representada por uma classe que estende Zend_Db_Table_Abstract. Nessa classe, o método <em>select</em> retorna uma representação de SELECT na tabela, que pode ser configurada até o momento de executar a SQL.</p>
<p>Cada catálogo utilizará uma classe abstrata como base e implementará um método para identificar a tabela à qual está associado:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#fff;color:#000;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#2e8b57;">abstract</span>&nbsp;<span style="color:#2e8b57;">class</span>&nbsp;Catalogo_Abstract <span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">private</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">_table</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">private</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">_select</span>;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">abstract</span>&nbsp;<span style="color:#2e8b57;">protected</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;_factoryTable<span style="color:#6a5acd;">()</span>;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">public</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;table<span style="color:#6a5acd;">()</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">if</span>&nbsp;<span style="color:#6a5acd;">(</span><span style="color:#2e8b57;">null</span>&nbsp;<span style="color:#a52a2a;">===</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>_table<span style="color:#6a5acd;">)</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>_table&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>_factoryTable<span style="color:#6a5acd;">()</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">public</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;select<span style="color:#6a5acd;">()</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">if</span>&nbsp;<span style="color:#6a5acd;">(</span><span style="color:#2e8b57;">null</span>&nbsp;<span style="color:#a52a2a;">===</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>_select<span style="color:#6a5acd;">)</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>_select&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>table<span style="color:#6a5acd;">()</span><span style="color:#2e8b57;">-&gt;</span>select<span style="color:#6a5acd;">()</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>_select;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
<span style="color:#6a5acd;">}</span></div>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#fff;color:#000;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#2e8b57;">class</span>&nbsp;Model_Aluno_Table <span style="color:#2e8b57;">extends</span>&nbsp;Zend_Db_Table_Abstract <span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">protected</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">_name</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;&#39;<span style="color:#ff00ff;">aluno</span>&#39;;<br />
<span style="color:#6a5acd;">}</span></div>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#fff;color:#000;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#2e8b57;">class</span>&nbsp;Catalogo_Aluno <span style="color:#2e8b57;">extends</span>&nbsp;Catalogo_Abstract <span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">protected</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;_factoryTable<span style="color:#6a5acd;">()</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a020f0;">new</span>&nbsp;Model_Aluno_Table<span style="color:#6a5acd;">()</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">public</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;daCidade<span style="color:#6a5acd;">(</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">cidade</span><span style="color:#6a5acd;">)</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>select<span style="color:#6a5acd;">()</span><span style="color:#2e8b57;">-&gt;</span>where<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">aluno.cidade = ?</span>&#39;, <span style="color:#a52a2a;">$</span><span style="color:#008b8b;">cidade</span><span style="color:#6a5acd;">)</span>;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">public</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;emOrdem<span style="color:#6a5acd;">()</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>select<span style="color:#6a5acd;">()</span><span style="color:#2e8b57;">-&gt;</span>order<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">aluno.nome ASC</span>&#39;<span style="color:#6a5acd;">)</span>;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
<span style="color:#6a5acd;">}</span></div>
<p>Desta forma já é possível combinar os métodos para consulta de alunos:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#fff;color:#000;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">alunos</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#a020f0;">new</span>&nbsp;Catalogo_Alunos<span style="color:#6a5acd;">()</span>;<br />
&nbsp;<br />
<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">alunos</span><span style="color:#2e8b57;">-&gt;</span>emOrdem<span style="color:#6a5acd;">()</span>;<br />
<span style="color:#0000ff;">/* &#8230; */</span><br />
<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">alunos</span><span style="color:#2e8b57;">-&gt;</span>daCidade<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">Rio de Janeiro</span>&#39;<span style="color:#6a5acd;">)</span>;<br />
<span style="color:#0000ff;">/* &#8230; */</span><br />
<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">alunos</span><span style="color:#2e8b57;">-&gt;</span>emOrdem<span style="color:#6a5acd;">()</span><span style="color:#2e8b57;">-&gt;</span>daCidade<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">Rio de Janeiro</span>&#39;<span style="color:#6a5acd;">)</span>;<br />
<span style="color:#0000ff;">/* &#8230; */</span><br />
<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">alunos</span><span style="color:#2e8b57;">-&gt;</span>daCidade<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">Rio de Janeiro</span>&#39;<span style="color:#6a5acd;">)</span><span style="color:#2e8b57;">-&gt;</span>emOrdem<span style="color:#6a5acd;">()</span>;</div>
<p>As últimas duas consultas resultariam na seguinte SQL:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#fff;color:#000;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#a52a2a;">SELECT</span>&nbsp;aluno.*<br />
<span style="color:#a52a2a;">FROM</span>&nbsp;aluno<br />
<span style="color:#a52a2a;">WHERE</span>&nbsp;(aluno.cidade = <span style="color:#ff00ff;">&#39;Rio de Janeiro&#39;</span>)<br />
<span style="color:#a52a2a;">ORDER</span>&nbsp;<span style="color:#a52a2a;">BY</span>&nbsp;aluno.nome <span style="color:#a52a2a;">ASC</span></div>
<h3>Determinando o momento da consulta com SPL</h3>
<p>Até então, os dois métodos do catálogo de alunos apenas configuram a consulta e retornam o próprio catálogo. Falta uma forma de executar a query.</p>
<p>Uma solução é adicionar um método <em>consultar</em> que vai utilizar a SQL gerada e retornar a lista de alunos. Esse método, contudo, não impressionaria em nada as gatinhas, sem contar que não fluiria tão bem se comparado a uma frase em português.</p>
<p>Tratando-se de um catálogo, espera-se dele uma lista de objetos que serão iterados em um loop. No cenário ideal, o código abaixo deve ser suficiente:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#fff;color:#000;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">alunos</span>&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#a020f0;">new</span>&nbsp;Catalogo_Aluno<span style="color:#6a5acd;">()</span>;<br />
&nbsp;<br />
<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">alunos</span><span style="color:#2e8b57;">-&gt;</span>emOrdem<span style="color:#6a5acd;">()</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#2e8b57;">-&gt;</span>daCidade<span style="color:#6a5acd;">(</span>&#39;<span style="color:#ff00ff;">Rio de Janeiro</span>&#39;<span style="color:#6a5acd;">)</span>;<br />
&nbsp;<br />
<span style="color:#a52a2a;">foreach</span>&nbsp;<span style="color:#6a5acd;">(</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">alunos</span>&nbsp;<span style="color:#a52a2a;">as</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">aluno</span><span style="color:#6a5acd;">)</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a020f0;">echo</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">aluno</span><span style="color:#2e8b57;">-&gt;</span>nome, &#39;<span style="color:#ff00ff;">&lt;br /&gt;</span>&#39;;<br />
<span style="color:#6a5acd;">}</span></div>
<p>E esse de fato é o cenário real (Ohhh).</p>
<p>Para controlar a iteração de um objeto em um <em>foreach</em>, o PHP dispõe da interface <em>Iterator</em> da Standard PHP Library. Quando utilizada, é necessário implementar os seguintes métodos, que serão chamados nessa ordem:</p>
<ol>
<li><em>rewind</em>: reinicia a iteração;</li>
<li><em>valid</em>: determina se a iteração deve continuar;</li>
<li><em>current</em>: retorna o valor da iteração atual;</li>
<li><em>key</em>: retorna o índice da iteração atual;</li>
<li><em>next</em>: avança a iteração.</li>
</ol>
<p>A consulta no Zend_Db retorna um objeto Zend_Db_Table_Rowset_Abstract, que já implementa a interface Iterator da SPL. Como a iteração no catálogo deve representar uma iteração neste <em>rowset</em>, basta direcionar os métodos para o objeto da consulta.</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#fff;color:#000;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#2e8b57;">abstract</span>&nbsp;<span style="color:#2e8b57;">class</span>&nbsp;Catalogo_Abstract <span style="color:#2e8b57;">implements</span>&nbsp;<span style="color:#ff00ff;">Iterator</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#0000ff;">/* complementando o código anterior &#8230; */</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">private</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">_rowset</span>;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">public</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;rowset<span style="color:#6a5acd;">()</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">if</span>&nbsp;<span style="color:#6a5acd;">(</span><span style="color:#2e8b57;">null</span>&nbsp;<span style="color:#a52a2a;">===</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>_rowset<span style="color:#6a5acd;">)</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>_rowset&nbsp;<span style="color:#a52a2a;">=</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>table<span style="color:#6a5acd;">()</span><span style="color:#2e8b57;">-&gt;</span>fetchAll<span style="color:#6a5acd;">(</span><span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>select<span style="color:#6a5acd;">())</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>_rowset;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">public</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;<span style="color:#008b8b;">rewind</span><span style="color:#6a5acd;">()</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>rowset<span style="color:#6a5acd;">()</span><span style="color:#2e8b57;">-&gt;</span>rewind<span style="color:#6a5acd;">()</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">public</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;valid<span style="color:#6a5acd;">()</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>rowset<span style="color:#6a5acd;">()</span><span style="color:#2e8b57;">-&gt;</span>valid<span style="color:#6a5acd;">()</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">public</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;<span style="color:#008b8b;">current</span><span style="color:#6a5acd;">()</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>rowset<span style="color:#6a5acd;">()</span><span style="color:#2e8b57;">-&gt;</span>current<span style="color:#6a5acd;">()</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">public</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;<span style="color:#008b8b;">key</span><span style="color:#6a5acd;">()</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>rowset<span style="color:#6a5acd;">()</span><span style="color:#2e8b57;">-&gt;</span><span style="color:#008b8b;">key</span><span style="color:#6a5acd;">()</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2e8b57;">public</span>&nbsp;<span style="color:#a020f0;">function</span>&nbsp;<span style="color:#008b8b;">next</span><span style="color:#6a5acd;">()</span>&nbsp;<span style="color:#6a5acd;">{</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a52a2a;">return</span>&nbsp;<span style="color:#a52a2a;">$</span><span style="color:#008b8b;">this</span><span style="color:#2e8b57;">-&gt;</span>rowset<span style="color:#6a5acd;">()</span><span style="color:#2e8b57;">-&gt;</span><span style="color:#008b8b;">next</span><span style="color:#6a5acd;">()</span>;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#6a5acd;">}</span><br />
<span style="color:#6a5acd;">}</span></div>
<p>Para ficar mais claro como os métodos são chamados, vale a pena dar uma olhada <a href="http://talks.somabo.de/200407_oscon_introduction_to_iterators_debug.pdf">nestes slides</a>.</p>
<h3>O problema do contexto</h3>
<p>O filtro por cidade foi um exemplo simples para ilustrar o conceito de Fluent Interface, imaginando que exista a coluna <em>cidade</em> na tabela de alunos, sem chave estrangeira. No mundo real é mais complicado que isso.</p>
<p>No primeiro exemplo lá em cima, a proposta era filtrar os alunos matriculados no curso de Enfermagem, mas, na minha realidade, não existe vínculo direto entre curso e aluno, apenas pela tabela de matrícula.</p>
<p>A solução que encontrei foi criar um catálogo específico de matrículas que é instanciado pelo catálogo de alunos, já criando o relacionamento entre as duas classes, resultando em um JOIN entre as três tabelas.</p>
<p>Para evitar que este texto ficasse ainda mais longo, separei os detalhes em um post específico sobre <a href="/contexto-fluent-interface">problema de contexto nas Fluent Interfaces</a>.</p>
<h3>Domain Specific Language</h3>
<p>Talvez ainda não pareça justificável todo o trabalho que uma Fluent Interface consistente vai gerar.</p>
<p>A grande vantagem só ficou clara pra mim quando o Eclipse começou a auto-completar os métodos dos catálogos. Se estou no catálogo de alunos, ele já mostra o filtro de cidade. Se eu escrevo a cidade, ele ainda permite filtrar pelos já matriculados. Uma vez na matrícula, posso filtrar pelo curso, e assim por diante.</p>
<p>Isso é o mínimo que se espera de uma IDE que ocupa tanta memória. Mas e se o usuário tivesse a mesma facilidade?</p>
<p>Ao invés de me ligarem falando &#8220;Garoto, preciso de uma lista de alunos da região norte inscritos essa semana no curso de Gestão em Saúde pelo edital da UAB que tenham blah blah blah&#8221;, a (quase) mesma fala seria digitada numa caixa de texto com auto-complete.</p>
<p>Não que o problema não possa ser resolvido com um formulário gigante incluindo todos os filtros de consulta possíveis, mas estamos falando de usabilidade. Interfaces amigáveis para o usuário, código amigável para o programador. Quem não achou o plugin <a href="http://labs.mozilla.com/projects/ubiquity/">Ubiquity</a> minimamente interessante?</p>
<p>E pra quem concorda que digitar a busca nem sempre é a melhor opção, os catálogos seriam facilmente exportados para ambientes visuais. Combinados com ações específicas de cada entidade (como matricular aluno, aprovar inscrição, desativar tutor&#8230;), o código passa a ser extremamente plugável.</p>
<p>Para tornar isso possível, a idéia é utilizar reflexão nas classes e expor os métodos na interface do usuário. <del datetime="00">Assim que parar de fazer sol na praia e eu tiver algum tempo, vou tentar expandir estes exemplos para DSL externa.</del> <ins datetime="00">O post de <a href="/domain-specific-language-externa-com-php/">Domain Specific Language externa no PHP</a> demonstra a implementação.</ins></p>
<p>De qualquer forma, no fundo vou sentir falta das tais ligações.</p>
<h3>Exemplo completo</h3>
<p>Uma implementação <strong>mais recente</strong>, já com interface para consulta pelo usuário, está disponível <strong>no post sobre <a href="/domain-specific-language-externa-com-php/">Domain Specific Language externa</a></strong>.</p>
<h3>Referências</h3>
<ul>
<li>Martin Fowler &#8211; Fluent Interface<br />
<a href="http://martinfowler.com/bliki/FluentInterface.html">http://martinfowler.com/bliki/FluentInterface.html</a></li>
<li>Post de Guilherme Chapiewski que clareou minhas idéias sobre Fluent Interface<br />
<a href="http://gc.blog.br/2007/09/25/refatorando-para-fluent-interface/">http://gc.blog.br/2007/09/25/refatorando-para-fluent-interface/</a></li>
<li>Zend Framework &#8211; Documentação da Zend_Db<br />
<a href="http://martinfowler.com/bliki/FluentInterface.html">http://framework.zend.com/manual/en/zend.db.html</a></li>
<li>Documentação da Standard PHP Library no PHP<br />
<a href="http://www.php.net/~helly/php/ext/spl/">http://www.php.net/~helly/php/ext/spl/</a></li>
<li>Resolvendo problema de contexto nas Fluent Interfaces<br />
<a href="/contexto-fluent-interface">http://garotosopa.wordpress.com/contexto-fluent-interface</a></li>
<li>Câmera pra ver se está sol na praia<br />
<a href="http://transito.rio.rj.gov.br/imagens1/31.jpg">http://transito.rio.rj.gov.br/imagens1/31.jpg</a></li>
</ul>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/106/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/106/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/106/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/106/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/106/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/106/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/106/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/106/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/106/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/106/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=106&subd=garotosopa&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2008/10/29/fluent-interface-php/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>
	</item>
		<item>
		<title>Comet &#8211; Server Push com XHR Multipart</title>
		<link>http://garotosopa.wordpress.com/2008/09/21/comet-server-push-xhr-multipart/</link>
		<comments>http://garotosopa.wordpress.com/2008/09/21/comet-server-push-xhr-multipart/#comments</comments>
		<pubDate>Sun, 21 Sep 2008 20:00:06 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[comet]]></category>
		<category><![CDATA[server push]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=95</guid>
		<description><![CDATA[Em 1995 a Netscape[1] teve a idéia de utilizar respostas HTTP multipart como implementação de server push, onde o servidor envia múltiplas respostas a uma mesma requisição. Treze anos depois eu me dei conta que esse streaming de dados realmente torna aplicações web muito mais dinâmicas, caracterizando o que alguns chamam de Comet[2].
Outras opções para [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=95&subd=garotosopa&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Em 1995 a Netscape<sup><a href="#referencia-netscape">[1]</a></sup> teve a idéia de utilizar respostas HTTP multipart como implementação de <em>server push</em>, onde o servidor envia múltiplas respostas a uma mesma requisição. Treze anos depois eu me dei conta que esse streaming de dados realmente torna aplicações web muito mais dinâmicas, caracterizando o que alguns chamam de Comet<sup><a href="#referencia-comet">[2]</a></sup>.</p>
<p>Outras opções para aplicações dinâmicas incluem deixar um iframe carregando tags Javascript eternamente; abrir uma conexão XMLHttpRequest a cada intervalo de tempo; ou implementar Long Polling, onde o servidor segura a conexão enquanto não houver conteúdo novo e, quando a resposta for enviada, um novo XMLHttpRequest é criado pelo navegador.</p>
<p>O grande conceito de <em>server push</em> é o servidor poder se comunicar com o cliente em tempo real sem que o navegador tenha que ficar pedindo atualizações. Nenhuma das soluções acima consegue atingir o estado da arte neste ponto.</p>
<p><span id="more-95"></span></p>
<h3>Multipart</h3>
<p>O conceito de multipart é o mesmo que utilizamos em e-mails MIME<sup><a href="#referencia-mime">[3]</a></sup>, como quando enviamos e-mails com anexo. Um cabeçalho deve ser enviado definindo que o tipo da resposta é com várias partes separadas por um delimitador (<em>boundary</em>):</p>
<p><code style="display:block;border:1px solid #ccc;background:#eaeaea;">Content-type: multipart/mixed; boundary="<strong>delimitador</strong>"</code></p>
<p>E então cada uma das partes fica entre este delimitador, acompanhada do seu próprio content-type:</p>
<p><code style="display:block;border:1px solid #ccc;background:#eaeaea;">--delimitador<br />
Content-type: text/plain<br />
&nbsp;<br />
Primeira mensagem<br />
<code>-</code><code>-</code>delimitador<br />
Content-type: text/plain<br />
&nbsp;<br />
Segunda mensagem<br />
<code>-</code><code>-</code>delimitador<br />
Content-type: text/plain<br />
&nbsp;<br />
Mensagem final<br />
<code>-</code><code>-</code>delimitador<code>-</code><code>-</code></code></p>
<p>O delimitador é iniciado por dois hífens e o último deles também termina com dois hífens, indicando o final do conteúdo. Sem este último delimitador, o cliente vai ficar esperando por outras partes até que os dois hífens depois do delimitador indiquem o final do conteúdo.</p>
<p>&nbsp;</p>
<h3>Javascript</h3>
<p>A diferença no Javascript para receber respostas multipart é apenas um parâmetro extra no objeto XMLHttpRequest:</p>
<p><code style="display:block;border:1px solid #ccc;background:#eaeaea;">var xhr = new XMLHttpRequest();<br />
<strong>xhr.multipart = true;</strong><br />
xhr.open('GET', 'script-multipart.php', true);<br />
xhr.onreadystatechange = function(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;if( this.readyState == 4 &amp;&amp; this.status == 200 ){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;document.body.innerHTML = this.responseText;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
};<br />
window.onload = function(){ xhr.send(null); }</code></p>
<p>Quando configurado para respostas multipart, a requisição é dada como concluída pra cada uma das partes recebidas. A propriedade <em>readyState</em> recebe o valor 4 (Loaded) e o evento <em>onReadyStateChange</em> é disparado. A parte carregada vai estar disponível em <em>responseText</em>, da mesma forma que em requisições normais.</p>
<p>Se o XMLHttpRequest estiver configurado para multipart, é importante que o servidor responda como multipart e vice-versa.</p>
<p>&nbsp;</p>
<h3>Servidor</h3>
<p>No servidor é necessário enviar o cabeçalho HTTP para definir o tipo de resposta como multipart. Mas diferente das mensagens MIME, o tipo de conteúdo multipart no HTTP é <strong>multipart/x-mixed-replace</strong>. A partir daí basta respeitarmos a saída com os delimitadores.</p>
<p><code style="display:block;border:1px solid #ccc;background:#eaeaea;">&lt;?php<br />
set_time_limit(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
header('Content-type: multipart/x-mixed-replace;boundary="delimitador"');<br />
echo "<code>-</code><code>-</code>delimitador\n";<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
while( true ){<br />
&nbsp;&nbsp;&nbsp;&nbsp;echo "Content-type: text/plain\n\n";<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;echo date("d/m/Y H:i:s"), "\n";<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;echo "<code>-</code><code>-</code>delimitador\n";<br />
&nbsp;&nbsp;&nbsp;&nbsp;flush();<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;sleep(1);<br />
}</code></p>
<p>Ao acessar o script acima pelo navegador já é possível ver as partes sendo trocadas na tela (daí o tipo <em>replace</em>).</p>
<p>O <em>time limit</em> foi desabilitado para que o script fique em execução enquanto o cliente estiver conectado. Sem ele, pela configuração normal do PHP, o script daria timeout em 30 segundos.</p>
<p>O content-type principal (multipart/x-mixed-replace) foi enviado com a função header por fazer parte dos <em>response headers</em> da requisição HTTP. Já os content-type&#8217;s de cada mensagem são enviados como saída normal, pois fazem parte do conteúdo como um todo, e não dos cabeçalhos HTTP. Para diferenciar o cabeçalho do conteúdo em si, ele deve ser terminado com uma linha em branco (\n\n). Caso não seja necessário o envio de nenhum cabeçalho, é importante ter uma linha vazia entre o delimitador e o conteúdo.</p>
<p>Assim que cada parte é montada, é preciso ter certeza que ela será enviada ao cliente ao invés de ficar no buffer do PHP. Dependendo do seu ambiente, pode ser necessário o uso da função ob_flush() em conjunto com flush()<sup><a href="#referencia-flush">[4]</a></sup>.</p>
<p>&nbsp;</p>
<h3>Problemas</h3>
<h4>Somente Gecko</h4>
<p>Até o momento, a interpretação de multipart pelo XMLHttpRequest está disponível apenas em navegadores que utilizam a engine Gecko, como o Firefox, por exemplo. Para manter o código compatível com outros browsers é possível checar o suporte com <strong>if( xhr.multipart != null )</strong> e implementar outra solução como contingência. Uma boa saída é utilizar multipart nos navegadores que o suportarem e long polling nos demais.</p>
<p><code style="display:block;border:1px solid #ccc;background:#eaeaea;">if( window.XMLHttpRequest ){<br />
&nbsp;&nbsp;&nbsp;&nbsp;var xhr = new XMLHttpRequest();<br />
}else if( window.ActiveXObject ){<br />
&nbsp;&nbsp;&nbsp;&nbsp;var xhr = new ActiveXObject('Microsoft.XMLHTTP');<br />
}<br />
function iniciar(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;xhr.abort();<br />
&nbsp;&nbsp;&nbsp;&nbsp;if( xhr.multipart != null ){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xhr.multipart = true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xhr.open('GET', 'script-multipart.php?multipart', true);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}else{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xhr.open('GET', 'script-multipart.php', true);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;xhr.onreadystatechange = ler;<br />
&nbsp;&nbsp;&nbsp;&nbsp;xhr.send(null);<br />
}<br />
function ler(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;if( xhr.readyState == 4 ){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if( xhr.status == 200 ){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;document.body.innerHTML = xhr.responseText;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if( ! xhr.multipart ){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iniciar();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
window.onload = iniciar;</code></p>
<p><code style="display:block;border:1px solid #ccc;background:#eaeaea;">&lt;?php<br />
set_time_limit(0);<br />
if( isset($_GET['multipart']) ){<br />
&nbsp;&nbsp;&nbsp;&nbsp;header('Content-type: multipart/x-mixed-replace;boundary="delimitador"');<br />
&nbsp;&nbsp;&nbsp;&nbsp;echo "<code>-</code><code>-</code>delimitador\n";<br />
}<br />
while( true ){<br />
&nbsp;&nbsp;&nbsp;&nbsp;if( isset($_GET['multipart']) ){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo "Content-type: text/plain\n\n";<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;echo date("d/m/Y H:i:s"), "\n";<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;if( isset($_GET['multipart']) ){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo "<code>-</code><code>-</code>delimitador\n";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flush();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep(1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}else{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep(1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</code></p>
<h4>Controle de falha</h4>
<p>Nestes exemplos, o script nunca terminará a requisição e o navegador vai ficar esperando novas partes enquanto a página estiver aberta. Essa é realmente a idéia. Contudo, é possível que a execução do script ou a conexão com o servidor seja interrompida inesperadamente.</p>
<p>Como o navegador não recebeu a indicação do fim da resposta multipart (delimitador seguido de dois hífens), o XMLHttpRequest vai ficar esperando novas partes sem que haja qualquer aviso de erro ou timeout. Uma solução razoável é implementar o controle de timeout manualmente:</p>
<p><code style="display:block;border:1px solid #ccc;background:#eaeaea;">var xhr = new XMLHttpRequest();<br />
var t;<br />
function iniciar(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;xhr.abort();<br />
&nbsp;&nbsp;&nbsp;&nbsp;xhr.multipart = true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;xhr.open('GET', 'script-multipart.php', true);<br />
&nbsp;&nbsp;&nbsp;&nbsp;xhr.onreadystatechange = ler;<br />
&nbsp;&nbsp;&nbsp;&nbsp;xhr.send(null);<br />
&nbsp;&nbsp;&nbsp;&nbsp;contarTimeout();<br />
}<br />
function ler(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;if( xhr.readyState == 4 &amp;&amp; xhr.status == 200 ){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;contarTimeout();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;document.body.innerHTML = xhr.responseText;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
function contarTimeout(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;clearTimeout(t);<br />
&nbsp;&nbsp;&nbsp;&nbsp;t = setTimeout(iniciar, 5000);<br />
}<br />
window.onload = iniciar();</code></p>
<h4>FastCGI buffer</h4>
<p>Um problema que não consegui resolver foi o buffer do FastCGI. Por mais que o script faça flush e ob_flush, parece que o FastCGI mantém um buffer intocável. Neste caso essa solução não funcionaria.</p>
<p>No meu host, eu tenho a alternativa de executar scripts diretamente como CGI. Ao invés de ter um arquivo com extensão .php, criei o script com extensão .cgi e coloquei #!/usr/bin/php na primeira linha. Esta solução funcionou para testes, mas em produção é melhor procurar outra saída, como utilizar mod_php ou até mesmo uma forma de desabilitar o buffer do FastCGI.</p>
<p>&nbsp;</p>
<h3>Chat em PHP</h3>
<p>Eu já tinha publicado um Chat em PHP utilizando Long Polling<sup><a href="#referencia-chat-long-polling">[5]</a></sup> e acabei reescrevendo parte dele para utilizar XMLHttpRequest com requisição multipart.</p>
<p>Assim como no último o exemplo, o Javascript faz o controle manual de timeout. Para evitar reconexões quando ninguém mandar mensagem por muito tempo, o servidor envia um ping de tempos em tempos para manter a conexão ativa. Em navegadores que não utilizam a engine Gecko, a solução de Long Polling é utilizada.</p>
<p>Código fonte:<br />
<a href="http://code.google.com/p/chatildis/source/browse/trunk/chat-multipart.php?r=10">http://code.google.com/p/chatildis/source/browse/trunk/chat-multipart.php?r=10</a></p>
<p>Script para download:<br />
<a href="http://chatildis.googlecode.com/files/chat-multipart.php">http://chatildis.googlecode.com/files/chat-multipart.php</a></p>
<p>Da mesma forma que o chat anterior, esta implementação ainda utiliza o MySQL com tabela na memória para repassar as mensagens para todos os clientes. Este método está longe do ideal. Talvez em uma próxima ocasião eu tente alguma coisa com threads e Observer Pattern.</p>
<p>&nbsp;</p>
<h3>Referências</h3>
<ol>
<li><a id="referencia-netscape" href="http://web.archive.org/web/20070204030549/http://wp.netscape.com/assist/net_sites/pushpull.html">An exploration of dynamic documents</a></li>
<li><a id="referencia-comet" href="http://en.wikipedia.org/wiki/Comet_(programming)">Comet (programming)</a></li>
<li><a id="referencia-mime" href="http://en.wikipedia.org/wiki/MIME#Multipart_messages">Multipurpose Internet Mail Extensions (MIME), Multipart messages</a></li>
<li><a id="referencia-flush" href="http://www.php.net/manual/en/function.flush.php">PHP: flush &#8211; manual</a></li>
<li><a id="referencia-chat-long-polling" href="http://garotosopa.wordpress.com/2008/07/27/chat-php-com-xhr-long-polling/">Chat PHP com XHR Long Polling</a></li>
</ol>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/95/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/95/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/95/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/95/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/95/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/95/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/95/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/95/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/95/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/95/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=95&subd=garotosopa&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2008/09/21/comet-server-push-xhr-multipart/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>
	</item>
		<item>
		<title>Chat PHP com XHR Long Polling</title>
		<link>http://garotosopa.wordpress.com/2008/07/27/chat-php-com-xhr-long-polling/</link>
		<comments>http://garotosopa.wordpress.com/2008/07/27/chat-php-com-xhr-long-polling/#comments</comments>
		<pubDate>Sun, 27 Jul 2008 22:55:09 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[chat]]></category>
		<category><![CDATA[comet]]></category>
		<category><![CDATA[long polling]]></category>
		<category><![CDATA[xhr]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=47</guid>
		<description><![CDATA[Esses dias surgiu a questão da melhor forma de notificar o usuário sobre alterações no servidor em tempo (quase) real, como novas mensagens de um chat, por exemplo.
A forma mais intuitiva pra mim seria fazer requisições XMLHttpRequest em pequenos intervalos, checando por mensagens mais novas que a última mensagem já recebida. Este método, entretanto, desperdiçaria [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=47&subd=garotosopa&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Esses dias surgiu a questão da melhor forma de notificar o usuário sobre alterações no servidor em tempo (quase) real, como novas mensagens de um chat, por exemplo.</p>
<p>A forma mais intuitiva pra mim seria fazer requisições XMLHttpRequest em pequenos intervalos, checando por mensagens mais novas que a última mensagem já recebida. Este método, entretanto, desperdiçaria muitas requisições se o intervalo fosse muito curto ou comprometeria a experiência do usuário se o intervalo fosse maior.</p>
<p>A idéia proposta é manter uma única conexão XHR aberta enquanto o servidor não responder com uma mensagem nova. Uma vez que exista mensagens novas, o cliente processa a resposta e em seguida cria uma nova conexão XHR que permanecerá aberta até a próxima resposta. Dessa forma o cliente fará no máximo 1 requisição por mensagem.</p>
<p>Depois eu acabei descobrindo que esta é a implementação de <a href="http://en.wikipedia.org/wiki/Comet_(programming)#XMLHttpRequest_long_polling">XMLHttpRequest long polling</a>.<br />
<span id="more-47"></span></p>
<div style="background-color:#eaeaea;border:1px solid #ccc;margin:1em;padding:1em;">Veja também a versão mais recente do chat <a href="/comet-server-push-xhr-multipart">comet com server push utilizando XHR Multipart</a></div>
<p>O código funciona da seguinte forma:</p>
<p><code>Ajax:<br />
&nbsp;&nbsp;&nbsp;&nbsp;url: 'chat.php?ultimo_id=' +  ultimo_id<br />
&nbsp;&nbsp;&nbsp;&nbsp;success:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;processar retorno json<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;guardar ultimo_id<br />
&nbsp;&nbsp;&nbsp;&nbsp;complete:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;executar requisição novamente</code><br />
<code>PHP:<br />
&nbsp;&nbsp;&nbsp;&nbsp;Loop infinito:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;consultar mensagens mais novas que ultimo_id<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;se houver mensagens:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;escrever mensagens em json<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parar o loop para o cliente ler o json</code></p>
<p>Funcionou muito bem em rede local com 16 clientes, cada um enviando uma mensagem por segundo. As mensagens ficaram no MySQL numa <a href="http://dev.mysql.com/doc/refman/5.0/en/memory-storage-engine.html">tabela na memória</a> com <a href="http://dev.mysql.com/doc/refman/5.0/en/query-cache.html">Query Cache</a> habilitado e não tive problemas com processamento do banco, ficando sempre abaixo de 6%. O Apache também não sofreu sobrecarga, tendo no máximo 3% de CPU em cada um dos 3 processos.</p>
<p>Sem dúvida esta implementação tem menos overhead que requisições em pequenos intervalos. Melhor que isso somente a implementação de streaming com XMLHttpRequest, que não fecharia a conexão a cada mensagem nova, <del datetime="00">mas isso fica pra depois</del> <ins datetime="00"><a href="http://garotosopa.wordpress.com/2008/09/21/comet-server-push-xhr-multipart/">utilizando requisições multipart</a></ins>.</p>
<div style="background-color:#eaeaea;border:1px solid #ccc;margin:1em;padding:1em;">Veja também a versão mais recente do chat <a href="/comet-server-push-xhr-multipart">comet com server push utilizando XHR Multipart</a></div>
<p>Código-fonte:<br />
<a href="http://code.google.com/p/chatildis/source/browse/trunk/chat.php?r=7">http://code.google.com/p/chatildis/source/browse/trunk/chat.php?r=7</a></p>
<p>Script para download:<br />
<a href="http://chatildis.googlecode.com/files/chat.php">http://chatildis.googlecode.com/files/chat.php</a></p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/garotosopa.wordpress.com/47/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/garotosopa.wordpress.com/47/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/47/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/47/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/47/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/47/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/47/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=47&subd=garotosopa&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2008/07/27/chat-php-com-xhr-long-polling/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>
	</item>
		<item>
		<title>Gerando planilhas XLS para o Excel pelo PHP</title>
		<link>http://garotosopa.wordpress.com/2008/02/06/gerando-planilhas-xls-para-o-excel-pelo-php/</link>
		<comments>http://garotosopa.wordpress.com/2008/02/06/gerando-planilhas-xls-para-o-excel-pelo-php/#comments</comments>
		<pubDate>Wed, 06 Feb 2008 23:21:52 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[excel]]></category>
		<category><![CDATA[pear]]></category>
		<category><![CDATA[spreadsheet]]></category>
		<category><![CDATA[xls]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=43</guid>
		<description><![CDATA[Recentemente, precisei migrar alguns relatórios CSV para XLS, de forma que pudessem ser abertos diretamente no Excel sem aquelas telas chatas de importação de dados. Utilizei a classe Spreadsheet_Excel_Writer do PEAR e o resultado foi melhor do que o esperado.

Criando planilhas
O arquivo do Excel é organizado em uma pasta de trabalho (workbook) onde ficam uma [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=43&subd=garotosopa&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Recentemente, precisei migrar alguns relatórios CSV para XLS, de forma que pudessem ser abertos diretamente no Excel sem aquelas telas chatas de importação de dados. Utilizei a classe <a href="http://pear.php.net/package/Spreadsheet_Excel_Writer">Spreadsheet_Excel_Writer</a> do <a href="http://pear.php.net/manual/en/introduction.php#about.pear">PEAR</a> e o resultado foi melhor do que o esperado.</p>
<p><span id="more-43"></span></p>
<h3><a href="#criando-planilhas" name="criando-planilhas">Criando planilhas</a></h3>
<p>O arquivo do Excel é organizado em uma pasta de trabalho (workbook) onde ficam uma ou mais planilhas (worksheets). O código PHP seguirá a mesma lógica, instanciando a pasta de trabalho e adicionando a ela um objeto para cada planilha. As planilhas poderão ser preenchidas conforme a posição da linha e coluna, ambas começando do zero.</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#bdb76b;">&lt;?php</span><br />
<span style="color:#ff0000;">require_once</span>&nbsp;&quot;<span style="color:#87ceeb;">Spreadsheet/Excel/Writer.php</span>&quot;;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">workbook</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffd700;">new</span>&nbsp;Spreadsheet_Excel_Writer<span style="color:#bdb76b;">()</span>;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">worksheet</span>&nbsp;<span style="color:#6495ed;">=&amp;</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">workbook</span><span style="color:#00ff00;">-&gt;</span>addWorksheet<span style="color:#bdb76b;">(</span>&quot;<span style="color:#87ceeb;">Título da planilha</span>&quot;<span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">worksheet</span><span style="color:#00ff00;">-&gt;</span>write<span style="color:#bdb76b;">(</span><span style="color:#ffa0a0;">0</span>, <span style="color:#ffa0a0;">0</span>, &quot;<span style="color:#87ceeb;">Primeira linha, primeira coluna</span>&quot;<span style="color:#bdb76b;">)</span>;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">worksheet</span><span style="color:#00ff00;">-&gt;</span>write<span style="color:#bdb76b;">(</span><span style="color:#ffa0a0;">0</span>, <span style="color:#ffa0a0;">1</span>, &quot;<span style="color:#87ceeb;">Primeira linha, segunda coluna</span>&quot;<span style="color:#bdb76b;">)</span>;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">worksheet</span><span style="color:#00ff00;">-&gt;</span>write<span style="color:#bdb76b;">(</span><span style="color:#ffa0a0;">1</span>, <span style="color:#ffa0a0;">0</span>, &quot;<span style="color:#87ceeb;">Segunda linha, primeira coluna</span>&quot;<span style="color:#bdb76b;">)</span>;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">worksheet</span><span style="color:#00ff00;">-&gt;</span>write<span style="color:#bdb76b;">(</span><span style="color:#ffa0a0;">1</span>, <span style="color:#ffa0a0;">1</span>, &quot;<span style="color:#87ceeb;">Segunda linha, segunda coluna</span>&quot;<span style="color:#bdb76b;">)</span>;</div>
<p>Observe que a planilha foi adicionada utilizando o <a href="http://www.php.net/manual/language.references.return.php">operador de referência <strong>&amp;</strong></a>. No PHP 4 isto é necessário para que a variável <em>$worksheet</em> deste escopo represente efetivamente a planilha dentro da pasta de trabalho <em>$workbook</em>. Do PHP 5 em diante este recurso não é necessário, já que variáveis apontam sempre para o mesmo objeto (exceto, claro, quando propositalmente clonados).</p>
<p><strong>void Worksheet::write ( integer $row , integer $col , mixed $token , mixed $format=0 )</strong></p>
<ul>
<li><em>integer $row</em> &#8211; número da linha onde escrever (começando do 0)</li>
<li><em>integer $col</em> &#8211; número da coluna onde escrever (começando do 0)</li>
<li><em>mixed $token</em> &#8211; conteúdo da célula</li>
<li><em>mixed $format</em> &#8211; opcional, especifica a <a href="#formatando-a-celula">formatação</a> da célula</li>
</ul>
<p>O método <em>write</em> tenta identificar o tipo do conteúdo como texto, número, link, fórmula ou vazio. Esta identificação automágica acabou me levando a um <strong>resultado inesperado ao preencher células com número de CPF</strong>, já que alguns começavam com zero e, ao serem convertidos de texto para número, acabaram tendo os primeiros dígitos removidos. Para ter certeza do formato da célula, é possível utilizar diretamente as demais funções de escrita:</p>
<ul>
<li><strong>writeBlank</strong> para escrever uma célula vazia, útil para formatar o estilo sem especificar valor</li>
<li><strong>writeFormula</strong> para escrever uma fórmula, da mesma forma que seria feito no Excel</li>
<li><strong>writeNumber</strong> para escrever um número</li>
<li><strong>writeString</strong> para escrever um texto livre</li>
<li><strong>writeUrl</strong> para escrever um link; o texto visível pode ser especificado no quarto parâmetro e a formatação, se alguma, no quinto parâmetro</li>
</ul>
<p>Como a identificação de tipo pelo método <em>write</em> é feita com uma série de expressões regulares, utilizar os métodos de escrita para determinado tipo pode melhorar o desempenho do script com planilhas muito grandes.</p>
<p>Além da escrita por célula, é possível preenchermos toda uma linha ou coluna a partir de um array. Estes métodos são especialmente úteis para preencher a planilha a partir de uma consulta ao banco de dados:</p>
<p><strong>mixed Worksheet::writeRow ( integer $row , integer $col , array $val , mixed $format =null  )</strong></p>
<ul>
<li><em>integer $row</em> &#8211; número da linha onde escrever</li>
<li><em>integer $col</em> &#8211; número da coluna onde começar a escrever os valores</li>
<li><em>array $val</em> &#8211; valores das células que serão escritas na linha</li>
<li><em>mixed $format</em> &#8211; opcional, especifica a <a href="#formatando-a-celula">formatação</a> da célula</li>
</ul>
<p><strong>mixed Worksheet::writeCol ( integer $row , integer $col , array $val , mixed $format =null  )</strong></p>
<ul>
<li><em>integer $row</em> &#8211; número da linha onde começar a escrever os valores</li>
<li><em>integer $col</em> &#8211; número da coluna onde escrever</li>
<li><em>array $val</em> &#8211; valores das células que serão escritas na coluna</li>
<li><em>mixed $format</em> &#8211; opcional, especifica a <a href="#formatando-a-celula">formatação</a> da célula</li>
</ul>
<h3><a href="#formatando-a-celula" name="formatando-a-celula">Formatando a célula</a></h3>
<p>Enquanto eu migrava alguns relatórios para XLS, percebi que outra grande novidade pro usuário em comparação à importação de CSV seria melhorar o visual da planilha. A formatação de estilo é adicionada à pasta de trabalho e em seguida associada às células que receberão o estilo.</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#ff0000;">$</span><span style="color:#fa8072;">header</span>&nbsp;<span style="color:#6495ed;">=&amp;</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">workbook</span><span style="color:#00ff00;">-&gt;</span>addFormat<span style="color:#bdb76b;">()</span>;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">header</span><span style="color:#00ff00;">-&gt;</span>setFgColor<span style="color:#bdb76b;">(</span><span style="color:#ffa0a0;">15</span><span style="color:#bdb76b;">)</span>;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">header</span><span style="color:#00ff00;">-&gt;</span>setBold<span style="color:#bdb76b;">()</span>;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">relatorio</span>&nbsp;<span style="color:#6495ed;">=&amp;</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">workbook</span><span style="color:#00ff00;">-&gt;</span>addWorksheet<span style="color:#bdb76b;">()</span>;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">relatorio</span><span style="color:#00ff00;">-&gt;</span>write<span style="color:#bdb76b;">(</span><span style="color:#ffa0a0;">0</span>, <span style="color:#ffa0a0;">0</span>, &quot;<span style="color:#87ceeb;">Aluno</span>&quot;, <span style="color:#ff0000;">$</span><span style="color:#fa8072;">header</span><span style="color:#bdb76b;">)</span>;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">relatorio</span><span style="color:#00ff00;">-&gt;</span>write<span style="color:#bdb76b;">(</span><span style="color:#ffa0a0;">0</span>, <span style="color:#ffa0a0;">1</span>, &quot;<span style="color:#87ceeb;">Matrícula</span>&quot;, <span style="color:#ff0000;">$</span><span style="color:#fa8072;">header</span><span style="color:#bdb76b;">)</span>;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">relatorio</span><span style="color:#00ff00;">-&gt;</span>write<span style="color:#bdb76b;">(</span><span style="color:#ffa0a0;">0</span>, <span style="color:#ffa0a0;">2</span>, &quot;<span style="color:#87ceeb;">E-mail</span>&quot;, <span style="color:#ff0000;">$</span><span style="color:#fa8072;">header</span><span style="color:#bdb76b;">)</span>;</div>
<p>O estilo adicionado define um tom claro de cinza para o fundo e a fonte em negrito. O Excel utiliza uma <a href="http://www.mvps.org/dmcritchie/excel/colors.htm#colorindex">paleta de cores própria</a>; para adicionar uma cor diferente, o método <em>setCustomColor</em> deve ser utilizado, passando o índice da cor como primeiro argumento (que será utilizado para identificar a cor em funções como <em>setFgColor</em> e <em>setColor</em>) e os níveis RGB como segundo, terceiro e quarto argumentos, respectivamente.</p>
<p>Também é possível passar um array com as configurações diretamente para o método <em>addFormat</em>:</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#ff0000;">$</span><span style="color:#fa8072;">estilo_padrao</span>&nbsp;<span style="color:#6495ed;">=&amp;</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">workbook</span><span style="color:#00ff00;">-&gt;</span>addFormat<span style="color:#bdb76b;">(</span><span style="color:#6495ed;">array</span><span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">Size</span>&#39;&nbsp;<span style="color:#ff0000;">=</span><span style="color:#ff0000;">&gt;</span>&nbsp;<span style="color:#ffa0a0;">10</span><span style="color:#bdb76b;">))</span>;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">estilo_aluno</span>&nbsp;<span style="color:#6495ed;">=&amp;</span>&nbsp;<span style="color:#ff0000;">$</span><span style="color:#fa8072;">workbook</span><span style="color:#00ff00;">-&gt;</span>addFormat<span style="color:#bdb76b;">(</span><span style="color:#6495ed;">array</span><span style="color:#bdb76b;">(</span>&#39;<span style="color:#87ceeb;">Size</span>&#39;&nbsp;<span style="color:#ff0000;">=</span><span style="color:#ff0000;">&gt;</span>&nbsp;<span style="color:#ffa0a0;">10</span>, &#39;<span style="color:#87ceeb;">Align</span>&#39;&nbsp;<span style="color:#ff0000;">=</span><span style="color:#ff0000;">&gt;</span>&nbsp;&#39;<span style="color:#87ceeb;">right</span>&#39;, &#39;<span style="color:#87ceeb;">Bold</span>&#39;&nbsp;<span style="color:#ff0000;">=</span><span style="color:#ff0000;">&gt;</span>&nbsp;<span style="color:#ffa0a0;">1</span><span style="color:#bdb76b;">))</span>;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">linha</span>&nbsp;<span style="color:#ff0000;">=</span>&nbsp;<span style="color:#ffa0a0;">0</span>;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">relatorio</span><span style="color:#00ff00;">-&gt;</span>writeString<span style="color:#bdb76b;">(</span><span style="color:#ff0000;">++</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">linha</span>, <span style="color:#ffa0a0;">0</span>, &quot;<span style="color:#87ceeb;">Homer</span>&quot;, <span style="color:#ff0000;">$</span><span style="color:#fa8072;">estilo_aluno</span><span style="color:#bdb76b;">)</span>;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">relatorio</span><span style="color:#00ff00;">-&gt;</span>writeString<span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">linha</span>, <span style="color:#ffa0a0;">1</span>, &quot;<span style="color:#87ceeb;">S0001</span>&quot;, <span style="color:#ff0000;">$</span><span style="color:#fa8072;">estilo_padrao</span><span style="color:#bdb76b;">)</span>;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">relatorio</span><span style="color:#00ff00;">-&gt;</span>writeString<span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">linha</span>, <span style="color:#ffa0a0;">2</span>, &quot;<span style="color:#87ceeb;">homer@example.com</span>&quot;, <span style="color:#ff0000;">$</span><span style="color:#fa8072;">estilo_padrao</span><span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">relatorio</span><span style="color:#00ff00;">-&gt;</span>writeString<span style="color:#bdb76b;">(</span><span style="color:#ff0000;">++</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">linha</span>, <span style="color:#ffa0a0;">0</span>, &quot;<span style="color:#87ceeb;">Bart</span>&quot;, <span style="color:#ff0000;">$</span><span style="color:#fa8072;">estilo_aluno</span><span style="color:#bdb76b;">)</span>;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">relatorio</span><span style="color:#00ff00;">-&gt;</span>writeString<span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">linha</span>, <span style="color:#ffa0a0;">1</span>, &quot;<span style="color:#87ceeb;">S0002</span>&quot;, <span style="color:#ff0000;">$</span><span style="color:#fa8072;">estilo_padrao</span><span style="color:#bdb76b;">)</span>;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">relatorio</span><span style="color:#00ff00;">-&gt;</span>writeString<span style="color:#bdb76b;">(</span><span style="color:#ff0000;">$</span><span style="color:#fa8072;">linha</span>, <span style="color:#ffa0a0;">2</span>, &quot;<span style="color:#87ceeb;">bart@example.com</span>&quot;, <span style="color:#ff0000;">$</span><span style="color:#fa8072;">estilo_padrao</span><span style="color:#bdb76b;">)</span>;</div>
<p>Todas as opções de formatação podem ser vistas na <a href="http://pear.php.net/manual/en/package.fileformats.spreadsheet-excel-writer.spreadsheet-excel-writer-workbook.addformat.php">documentação do <em>addFormat</em></a>.</p>
<p>Não vi nenhuma forma de deixar as colunas com largura automática, como quando damos dois cliques no divisor de colunas e a largura é reajustada automaticamente, mas o método <em>setColumn</em> pode ser utilizado para determinar uma largura fixa para um conjunto de colunas.</p>
<p><strong>void Worksheet::setColumn ( integer $firstcol , integer $lastcol , float $width , mixed $format=0 , integer $hidden=0 )</strong></p>
<ul>
<li><em>integer $firstcol</em> &#8211; primeira coluna do intervalo onde aplicar a formatação</li>
<li><em>integer $lastcol</em> &#8211; última coluna do intervalo</li>
<li><em>float $width</em> &#8211; largura das colunas</em>
<li><em>mixed $format</em> &#8211; opcional, especifica a <a href="#formatando-a-celula">formatação</a> da célula</li>
<li><em>integer $hidden</em> &#8211; define se as colunas devem estar ocultas</li>
</ul>
<h3><a href="#enviando-para-download" name="enviando-para-download">Enviando para download</a></h3>
<p>Uma vez que a pasta de trabalho esteja montada, basta enviar o header com o tipo de conteúdo e o nome do arquivo adequados para que o browser faça o download corretamente.</p>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#262626;color:#fff;border-left:3px solid #ccc;margin:1em 0;padding:.5em;"><span style="color:#ff0000;">$</span><span style="color:#fa8072;">workbook</span><span style="color:#00ff00;">-&gt;</span>send<span style="color:#bdb76b;">(</span>&quot;<span style="color:#87ceeb;">teste.xls</span>&quot;<span style="color:#bdb76b;">)</span>;<br />
&nbsp;<br />
<span style="color:#ff0000;">$</span><span style="color:#fa8072;">workbook</span><span style="color:#00ff00;">-&gt;</span>close<span style="color:#bdb76b;">()</span>;</div>
<p>O método <em>send</em> envia os headers necessários e o <em>close</em> carrega o arquivo binário.</p>
<h3><a href="#instalando-a-classe" name="instalando-a-classe">Instalando a classe</a></h3>
<p>A instalação da classe é feita pelo próprio PEAR, com o detalhe de resolver as dependências necessárias e especificar que a classe ainda está em estado beta:</p>
<div style="background-color:#262626;color:#fff;margin:1em 0;padding:.5em;"><span style="color:#f00;">#</span> pear install &#8211;alldeps Spreadsheet_Excel_Writer-beta</div>
<p>Como utilizei a classe na intranet, o comando pôde ser executado como root pelo administrador do servidor para instalar a classe no sistema. Veja o link <a href="http://pear.php.net/manual/en/installation.shared.php">Installation of a local PEAR copy on a shared host</a> para instruções de como utilizar classes PEAR em servidores compartilhados.</p>
<h3><a href="#documentacao" name="documentacao">Documentação</a></h3>
<p>Veja ainda a <a href="http://pear.php.net/manual/en/package.fileformats.spreadsheet-excel-writer.php">documentação da classe Spreadsheet_Excel_Writer</a> para mais detalhes sobre diversos outros recursos.</p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/garotosopa.wordpress.com/43/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/garotosopa.wordpress.com/43/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/43/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/43/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/43/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/43/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/43/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/43/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/43/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/43/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/43/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/43/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=43&subd=garotosopa&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2008/02/06/gerando-planilhas-xls-para-o-excel-pelo-php/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>
	</item>
		<item>
		<title>Escopo e variáveis super poderosas</title>
		<link>http://garotosopa.wordpress.com/2007/06/22/escopo-e-variaveis-super-poderosas/</link>
		<comments>http://garotosopa.wordpress.com/2007/06/22/escopo-e-variaveis-super-poderosas/#comments</comments>
		<pubDate>Fri, 22 Jun 2007 08:16:54 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/2007/06/22/escopo-e-variaveis-super-poderosas/</guid>
		<description><![CDATA[Variáveis globais são aquelas definidas na raiz do script, fora de qualquer outro escopo, e que não existem dentro de uma função ou método, da mesma forma que variáveis criadas em um desses escopos deixarão de existir fora dele.
As variáveis superglobais, entretanto, podem ser acessadas em qualquer escopo, e são elas $GLOBALS, $_SERVER, $_GET, $_POST, [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=27&subd=garotosopa&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Variáveis globais são aquelas definidas na raiz do script, fora de qualquer outro escopo, e que não existem dentro de uma função ou método, da mesma forma que variáveis criadas em um desses escopos deixarão de existir fora dele.</p>
<p>As variáveis superglobais, entretanto, podem ser acessadas em qualquer escopo, e são elas $GLOBALS, $_SERVER, $_GET, $_POST, $_COOKIE, $_FILES, $_ENV, $_REQUEST e $_SESSION. Acontece que não é possível definir uma outra variável como superglobal (ao menos não sem o uso da Runkit), e aí a confusão começa.</p>
<p><span id="more-27"></span>A partir de um escopo, para declarar que uma variável pertence ao escopo global, utiliza-se a keyword <em>global</em> <strong>dentro</strong> desse escopo, mesmo que a variável ainda não tenha sido definida, quando nesse caso passará a existir se definida pela função.</p>
<p><code style="background:#fcfcfc;font-size:95%;display:block;"><span style="color:#000000;"><span style="color:#0000BB;">&lt;?php<br />
$chamadas&nbsp;</span><span style="color:#007700;">=&nbsp;</span><span style="color:#0000BB;">0</span><span style="color:#007700;">;<br />
&nbsp;<br />
function&nbsp;</span><span style="color:#0000BB;">carregar</span><span style="color:#007700;">(){<br />
&nbsp;global&nbsp;</span><span style="color:#0000BB;">$chamadas</span><span style="color:#007700;">,&nbsp;</span><span style="color:#0000BB;">$artista</span><span style="color:#007700;">;<br />
&nbsp;<br />
&nbsp;</span><span style="color:#0000BB;">$chamadas</span><span style="color:#007700;">++;<br />
&nbsp;</span><span style="color:#0000BB;">$artista&nbsp;</span><span style="color:#007700;">=&nbsp;</span><span style="color:#DD0000;">"Whitesnake"</span><span style="color:#007700;">;<br />
}<br />
&nbsp;<br />
</span><span style="color:#0000BB;">carregar</span><span style="color:#007700;">();<br />
echo&nbsp;</span><span style="color:#0000BB;">$artista</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">"&nbsp;-&nbsp;"</span><span style="color:#007700;">,&nbsp;</span><span style="color:#0000BB;">$chamadas</span><span style="color:#007700;">;&nbsp;</span><span style="color:#FF8000;">//&nbsp;Whitesnake&nbsp;-&nbsp;1<br />
</span><span style="color:#0000BB;">?&gt;</span></span></code></p>
<p>Contudo, são inúmeras as vezes que observei o uso incorreto do <em>global</em>, fora de qualquer escopo, com o objetivo de tornar a variável uma superglobal. Mas na realidade, além de constatar o óbvio declarando que uma variável global pertence ao próprio escopo global, isso simplesmente não funciona e obriga o desenvolvedor a utilizar a keyword <em>global</em> novamente dentro do escopo onde deseja ter o acesso.</p>
<p style="text-align:center;"><img src='http://garotosopa.files.wordpress.com/2007/06/the-variables-scope.jpg' alt='The Variables Scope' /></p>
<p>O diagrama acima evidencia as superglobais na direita, acessíveis de qualquer lugar, as variáveis ao fundo limitadas aos seus respectivos escopos e, compondo a linha de frente, as variáveis globais, existentes ao longo do script e que podem ser utilizadas em um determinado escopo com o uso da keyword <em>global</em>. <strong>Então mesmo que você chame sua variável de Docinho, ela não vai se tornar uma superglobal</strong>.</p>
<p>Outra maneira de utilizar variáveis globais é pela superglobal $GLOBALS, uma array associativa com referência às variáveis no escopo global.</p>
<p>É importante observar ainda que, de uma forma geral, variáveis globais são uma causa comum de problemas, já que você não sabe se o valor é realmente o que você espera que seja. Um método simples de evitar isso é passar as variáveis necessárias como parâmetro para a função ou objeto que vai utilizá-las.</p>
<p>Eu só consegui perceber o problema de confiar em variáveis globais com a ajuda da minha mãe. Certa vez ela deixou um pudim delicioso na geladeira, e na manhã seguinte colocou uma travessa de peixe na prateleira de baixo. Pronto, o pudim ficou com gosto de sardinha o resto da semana. E foi assim que eu aprendi que devo separar minhas varáveis em lugares seguros, evitando que fatores externos acabem estragando tudo sem que eu sequer perceba.</p>
<p>E pra ficar claro, o que foi abordado nada tem a ver com o uso da diretiva <em>register_globals</em> que, quando ativada, define o conteúdo de $_ENV, $_GET, $_POST, $_COOKIE e $_SERVER como variáveis globais. Então $_POST['nome'] também passa a existir como $nome, $_GET['pagina'] também como $pagina, e assim por diante. Este terrível fenômeno está desativado por padrão desde a versão 4.2 e será removido por completo no PHP 6.</p>
<h4>Referências</h4>
<ul>
<li><a href="http://br2.php.net/language.variables.scope">Escopo de variáveis</a></li>
<li><a href="http://br2.php.net/language.variables.predefined">Superglobais predefinidas</a></li>
<li><a href="http://br2.php.net/security.globals">(Não) Utilizando a diretiva Register Globals</a></li>
<li><a href="http://www.cartoonnetwork.com/games/ppg/snapshot/index.html">Ferramenta case utilizada no diagrama de escopo de variáveis</a></li>
</ul>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/garotosopa.wordpress.com/27/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/garotosopa.wordpress.com/27/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/27/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/27/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/27/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/27/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/27/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/27/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/27/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/27/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/27/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/27/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=27&subd=garotosopa&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2007/06/22/escopo-e-variaveis-super-poderosas/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>

		<media:content url="http://garotosopa.files.wordpress.com/2007/06/the-variables-scope.jpg" medium="image">
			<media:title type="html">The Variables Scope</media:title>
		</media:content>
	</item>
		<item>
		<title>Headers sent e a canonização do ob_start</title>
		<link>http://garotosopa.wordpress.com/2007/06/20/headers-sent-e-a-canonizacao-do-ob_start/</link>
		<comments>http://garotosopa.wordpress.com/2007/06/20/headers-sent-e-a-canonizacao-do-ob_start/#comments</comments>
		<pubDate>Thu, 21 Jun 2007 00:24:23 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/2007/06/20/headers-sent-e-a-canonizacao-do-ob_start/</guid>
		<description><![CDATA[Eu considero o ano de 2004 como sendo o ápice da quantidade de dúvidas sobre a mensagem Headers already sent, quando era comum muitos usuários perguntarem a solução diariamente no IRC. Um saco. Ainda hoje o Google retorna quase 2 milhões de resultados para esse termo, e a maioria deles como sendo erros legítimos que [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=29&subd=garotosopa&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Eu considero o ano de 2004 como sendo o ápice da quantidade de dúvidas sobre a mensagem <em>Headers already sent</em>, quando era comum muitos usuários perguntarem a solução diariamente no IRC. Um saco. Ainda hoje o Google retorna quase 2 milhões de resultados para esse termo, e a maioria deles como sendo erros legítimos que o crawler encontrou enquanto navegava.</p>
<p><span id="more-29"></span>Para entender o problema é preciso compreender um pouco como funciona a comunicação HTTP. Quando é feita uma requisição ao endereço <a href="#">http://meudominio/caminho/script.php</a>, o navegador conecta na porta 80 do servidor meudominio e envia um cabeçalho (Request headers) semelhante a este seguido de uma linha em branco:</p>
<p><code style="background:#fcfcfc;font-size:95%;display:block;">GET /caminho/script.php HTTP/1.1<br />
Host: meudominio</code></p>
<p>O servidor recebe essa requisição, nesse caso chama o PHP para interpretar o script, e responde, começando pelo cabeçalho (Response headers), seguido de uma linha em branco e o conteúdo da resposta, se houver:</p>
<p><code style="background:#fcfcfc;font-size:95%;display:block;">HTTP/1.1 200 OK<br />
Date: Mon, 18 Jun 2007 05:49:07 GMT<br />
Server: Apache<br />
Transfer-Encoding: chunked<br />
Content-Type: text/html; charset=ISO-8859-1<br />
&nbsp;<br />
&lt;html&gt;<br />
&lt;body&gt;<br />
Oi mundo.<br />
&lt;/body&gt;<br />
&lt;/html&gt;</code></p>
<p>Cada uma das primeiras linhas representa um cabeçalho (header) e começa mostrando o status da resposta (tal como sucesso, não encontrado, erro interno, etc) além de informações como tempo de expiração, encoding, cookies, entre outras.</p>
<p><strong>A mensagem de erro <em>Headers already sent</em> ocorre porque o script tenta enviar um header após o trecho destinado a eles já ter sido enviado ao cliente</strong> por razão do conteúdo da resposta ter começado, seja ele HTML, texto, mensagens de erro e até mesmo linhas em branco ou comentários fora das tags do PHP.</p>
<p>O mais comum é ter problemas com as funções <a href="http://br2.php.net/setcookie">setcookie</a>, porque o cookie é enviado ao cliente no cabeçalho da resposta, <a href="http://br2.php.net/session_start">session_start</a>, por precisar enviar um cookie para iniciar a sessão, e, obviamente, com a função <a href="http://br2.php.net/header">header</a> em si, que é muito utilizada para redirecionar o usuário para outro endereço.</p>
<p><strong>A resposta definitiva para o problema é mudar a disposição do script de forma que os headers necessários sejam realmente enviados antes da apresentação HTML</strong>, que é a forma natural do modelo MVC. Quando isso não é possível, ou é difícil de ser mudado, é um sinal claro de que o script está mal estruturado, uma vez que toda a lógica deve ocorrer antes, e não misturada com o que o usuário está vendo.</p>
<p>O modelo inapropriado da aplicação fica ainda mais evidente quando o erro ocorre com o header Location, usado para redirecionamento. Chega a ser desperdício de recursos e banda, além de não fazer nenhum sentido, enviar um trecho HTML, ou qualquer tipo de conteúdo, se o browser deve seguir pra outra página sem mostrar nada na tela.</p>
<p>Em função disso surgiu também o mito de colocar funções que enviam um header na primeira linha do script, em especial a <a href="http://br2.php.net/session_start">session_start</a>, o que não é exatamente verdade. A necessidade essencial é de utilizá-las antes de qualquer saída (output) ao usuário, não importando exatamente onde no script, desde que nada tenha sido enviado ainda.</p>
<p>De qualquer forma, o PHP possui o recurso de Output Buffering que armazena a saída em um buffer e envia o conteúdo ao cliente de uma só vez (ou em pedaços determinados, dependendo do tamanho do buffer), e é aí que a ilusão de muitos começa.</p>
<p>Quando utilizado de forma adequada para o propósito adequado, o Output Buffering é extremamente benéfico em termos de desempenho, pois diminui o número de vezes que ocorre a comunição PHP &#8211; Servidor Web &#8211; Sistema Operacional &#8211; Rede &#8211; Usuário. Outros usos comuns são na compressão da saída em Gzip, para diminuir o consumo de banda, e ao encapsular a saída em uma string, como por exemplo em alguma técnica de template.</p>
<p>Todavia esse recurso costuma ser utilizado indevidamente por desenvolvedores esotéricos, que têm a função <a href="http://br2.php.net/ob_start">ob_start</a> como varinha mágica para os mais diversos tipos de bruxaria. Uma vez que o conteúdo passa a ficar em um buffer, aquele início da resposta HTTP não terminou, ainda existindo então a possibilidade de enviar headers, seja ele um cookie, início de sessão ou até mesmo redirecionamento.</p>
<p>Mas que fique claro que contar com Output Buffering como mágica para enviar headers no meio da apresentação é apenas concordar com a péssima estrutura montada.</p>
<p style="text-align:center;"><img src='http://garotosopa.files.wordpress.com/2007/06/headers-sent.jpg' alt='Headers Sent e a canonização do ob_start' /></p>
<h4>Referências</h4>
<ul>
<li><a href="http://pt.wikipedia.org/wiki/HTTP">O protocolo HTTP</a></li>
<li><a href="http://br2.php.net/outcontrol">Controle de saída</a></li>
<li>Funções <a href="http://br2.php.net/ob_start">ob_start</a>, <a href="http://br2.php.net/session_start">session_start</a>, <a href="http://br2.php.net/setcookie">setcookie</a> e <a href="http://br2.php.net/header">header</a></li>
<li><a href="http://www.oracle.com/technology/pub/articles/deployphp/alshanetsky_deployphp.html">Accelerating PHP Code Performance for Oracle</a>, artigo de Ilia Alshanetsky que menciona o uso de output buffering</li>
</ul>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/garotosopa.wordpress.com/29/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/garotosopa.wordpress.com/29/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/29/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/29/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/29/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/29/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/29/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/29/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/29/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/29/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/29/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/29/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=29&subd=garotosopa&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2007/06/20/headers-sent-e-a-canonizacao-do-ob_start/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>

		<media:content url="http://garotosopa.files.wordpress.com/2007/06/headers-sent.jpg" medium="image">
			<media:title type="html">Headers Sent e a canonização do ob_start</media:title>
		</media:content>
	</item>
		<item>
		<title>Voltas e mais voltas com SPL</title>
		<link>http://garotosopa.wordpress.com/2007/04/18/voltas-e-mais-voltas-com-spl/</link>
		<comments>http://garotosopa.wordpress.com/2007/04/18/voltas-e-mais-voltas-com-spl/#comments</comments>
		<pubDate>Thu, 19 Apr 2007 01:06:58 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[OOP]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[orientação a objetos]]></category>
		<category><![CDATA[spl]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/2007/04/18/voltas-e-mais-voltas-com-spl/</guid>
		<description><![CDATA[Recentemente, precisei de um banco de dados de provérbios e fiz um singelo script para ler alguns sites, mas era chato ter que fazer um script inteiro ou aglomerar laços pra cada site que eu encontrava. Pra evitar repetição de código, mantive uma classe por site, que, em conjunto com as classes e interfaces da [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=24&subd=garotosopa&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Recentemente, precisei de um banco de dados de provérbios e fiz um singelo script para ler alguns sites, mas era chato ter que fazer um script inteiro ou aglomerar laços pra cada site que eu encontrava. Pra evitar repetição de código, mantive uma classe por site, que, em conjunto com as classes e interfaces da Standard PHP Library (SPL), resumiram o código final a um único foreach:</p>
<pre class="brush: php;">
$proverbios = new Proverbios;
$proverbios-&gt;append(new Proverbios_LifesABirch);
$proverbios-&gt;append(new Proverbios_Aborla);
$proverbios-&gt;append(new Proverbios_JangadaBrasil);

foreach($proverbios as $proverbio){
    echo $proverbio, “\n”;
}
</pre>
<p><span id="more-24"></span></p>
<h4>Iterator</h4>
<p>Para que isso fosse possível, cada classe implementou a interface Iterator disponível na extensão SPL, assumindo o comportamento de um iterador e podendo então ser utilizada normalmente em um loop.</p>
<p>O papel de uma interface é definir o que um objeto deverá ser capaz de fazer, e essa define o seguinte:</p>
<p><code style="background:#fcfcfc;font-size:95%;display:block;"><span style="color:#000000;"><span style="color:#007700;">interface </span><span style="color:#0000BB;">Iterator </span><span style="color:#007700;">extends </span><span style="color:#0000BB;">Traversable<br />
</span><span style="color:#007700;">{<br />
     function </span><span style="color:#0000BB;">rewind</span><span style="color:#007700;">();</p>
<p>     function </span><span style="color:#0000BB;">current</span><span style="color:#007700;">();</p>
<p>     function </span><span style="color:#0000BB;">key</span><span style="color:#007700;">();</p>
<p>     function </span><span style="color:#0000BB;">next</span><span style="color:#007700;">();</p>
<p>     function </span><span style="color:#0000BB;">valid</span><span style="color:#007700;">();<br />
}</span></span></code></p>
<p>Então, todo objeto a ser utilizado como iterador precisa ter esses métodos implementados, que são executados na seguinte ordem durante um foreach:</p>
<ol>
<li>rewind() &#8211; recomeça a iteração, reiniciando um possível índice interno;</li>
<li>valid() &#8211; este método deve retornar true para continuar, ou false quando não houver mais iteração;</li>
<li>current() &#8211; retorna o valor atual;</li>
<li>key() &#8211; retorna o índice atual e somente é executado caso a chave seja pedida, como em <span style="color:#007700;">foreach(</span><span style="color:#0000BB;">$it </span><span style="color:#007700;">as </span><span style="color:#0000BB;">$key </span><span style="color:#007700;">=&gt; </span><span style="color:#0000BB;">$value</span><span style="color:#007700;">)</span>;</li>
<li>next() &#8211; deve mover o índice interno para a próxima iteração;</li>
<li>Volta ao passo número 2.</li>
</ol>
<h4>ArrayIterator</h4>
<p>No primeiro site, a busca foi apenas uma expressão regular que retornava os provérbios em uma array que seria lida depois em um loop.</p>
<p>Como a iteração em array é bastante óbvia, a SPL dispõe da classe ArrayIterator, que já implementa as interfaces ArrayAccess, Countable e SeekableIterator, que por sua vez estende a Iterator, sendo esta última a única que interessa no momento.</p>
<p>A classe recebe uma array ou objeto no constructor, e tem o mesmo resultado como se estes elementos fossem utilizados diretamente em um foreach. Se a ArrayIterator não existisse, seria necessário implementar a interface Iterator e manipular a array manual e repetidamente onde fosse necessário.</p>
<p><code style="background:#fcfcfc;font-size:95%;display:block;"><span style="color:#000000;"><span style="color:#007700;">class&nbsp;</span><span style="color:#0000BB;">Proverbios_LifesABirch&nbsp;</span><span style="color:#007700;">extends&nbsp;</span><span style="color:#0000BB;">ArrayIterator<br />
</span><span style="color:#007700;">{<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color:#0000BB;">__construct</span><span style="color:#007700;">()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">$url&nbsp;</span><span style="color:#007700;">=&nbsp;</span><span style="color:#DD0000;">'http://www.lifesabirch.org/proverbios/index.php'</span><span style="color:#007700;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">$contents&nbsp;</span><span style="color:#007700;">=&nbsp;</span><span style="color:#0000BB;">file_get_contents</span><span style="color:#007700;">(</span><span style="color:#0000BB;">$url</span><span style="color:#007700;">);<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">preg_match_all</span><span style="color:#007700;">(</span><span style="color:#DD0000;">'/^(?:&lt;\/?p&gt;)?(\S.+)&nbsp;&lt;br\/&gt;$/mU'</span><span style="color:#007700;">,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">$contents</span><span style="color:#007700;">,&nbsp;</span><span style="color:#0000BB;">$matches</span><span style="color:#007700;">);<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(isset(</span><span style="color:#0000BB;">$matches</span><span style="color:#007700;">[</span><span style="color:#0000BB;">1</span><span style="color:#007700;">])&nbsp;&amp;&amp;&nbsp;</span><span style="color:#0000BB;">is_array</span><span style="color:#007700;">(</span><span style="color:#0000BB;">$matches</span><span style="color:#007700;">[</span><span style="color:#0000BB;">1</span><span style="color:#007700;">])){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">parent</span><span style="color:#007700;">::</span><span style="color:#0000BB;">__construct</span><span style="color:#007700;">(</span><span style="color:#0000BB;">$matches</span><span style="color:#007700;">[</span><span style="color:#0000BB;">1</span><span style="color:#007700;">]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</span></span></code></p>
<p>Ao instanciar esta classe, o constructor é executado, a leitura do site é efetuada e a array retornada é passada para o constructor da ArrayIterator. A partir daí, o objeto passa a ser, de certa forma, a própria array retornada pela expressão regular, onde cada item representa um provérbio do site.</p>
<p>A leitura poderia ser feita da seguinte forma:</p>
<p><code style="background:#fcfcfc;font-size:95%;display:block;"><span style="color:#000000;"><span style="color:#007700;">foreach(new&nbsp;</span><span style="color:#0000BB;">Proverbios_LifesABirch&nbsp;</span><span style="color:#007700;">as&nbsp;</span><span style="color:#0000BB;">$proverbio</span><span style="color:#007700;">){<br />
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;</span><span style="color:#0000BB;">$proverbio</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">"\n"</span><span style="color:#007700;">;<br />
}</span></span></code></p>
<h4>RecursiveIterator</h4>
<p>O segundo site que encontrei estava dividido por letras, sendo necessário percorrê-las e retornar os provérbios de cada uma delas.</p>
<p>Em uma estrutura básica, existiria um loop para as letras e dentro dele um outro para os provérbios. Esta estrutura é fácil de ser percebida, mas difícil de ser integrada a um sistema maior sem que todos os provérbios sejam lidos antes e retornados depois em um único array.</p>
<p>Utilizando iteradores recursivos, é possível navegar por entre estas divisões sem nenhuma alteração no código final, que continua sendo um único foreach. A interface RecursiveIterator estende a Iterator e acrescenta dois métodos:</p>
<p><code style="background:#fcfcfc;font-size:95%;display:block;"><span style="color:#000000;"><span style="color:#007700;">interface&nbsp;</span><span style="color:#0000BB;">RecursiveIterator&nbsp;</span><span style="color:#007700;">extends&nbsp;</span><span style="color:#0000BB;">Iterator<br />
</span><span style="color:#007700;">{<br />
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;</span><span style="color:#0000BB;">hasChildren</span><span style="color:#007700;">();<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;</span><span style="color:#0000BB;">getChildren</span><span style="color:#007700;">();<br />
}</span></span></code></p>
<p>Durante a iteração, o método hasChildren() é chamado pra identificar se o item atual é ou não um iterador a ser percorrido. Caso seja, o iterador, que também deve implementar a interface RecursiveIterator, é recuperado pelo getChildren() e começa uma nova iteração a partir dele até que não haja mais itens. Quando isso acontece, o processo continua no próximo item do iterador anterior, ou é finalizado caso seja o principal. Se hasChildren() retornar false, então trata-se de um item normal e o current() é chamado para recuperar seu valor.</p>
<p>Na classe deste site foi usada uma array com as letras a serem percorridas, e pra cada uma delas, uma classe é retornada como filha.</p>
<p>Para percorrer arrays multi-dimensionais, existe a classe RecursiveArrayIterator, que verifica no método hasChildren() se o item atual é uma outra array e retorna no getChildren() uma nova instância de si mesma a partir dela, fazendo o efeito recursivo.</p>
<p>Nesse caso a RecursiveArrayIterator não poderia ser utilizada, porque a array de letras não é multi-dimensional. Ao invés dela, foi usada a própria ArrayIterator para percorrer a array, e implementada a interface RecursiveIterator manualmente para retornar o objeto dos provérbios de cada letra.</p>
<p><code style="background:#fcfcfc;font-size:95%;display:block;"><span style="color:#000000;"><span style="color:#007700;">class&nbsp;</span><span style="color:#0000BB;">Proverbios_Aborla_Letras&nbsp;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#007700;">extends&nbsp;</span><span style="color:#0000BB;">ArrayIterator&nbsp;</span><span style="color:#007700;">implements&nbsp;</span><span style="color:#0000BB;">RecursiveIterator<br />
</span><span style="color:#007700;">{<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color:#0000BB;">__construct</span><span style="color:#007700;">()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">parent</span><span style="color:#007700;">::</span><span style="color:#0000BB;">__construct</span><span style="color:#007700;">(array(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#DD0000;">'a'</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">'b'</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">'c'</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">'d'</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">'e'</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">'f'</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">'g'</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">'h'</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">'i'</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">'j'</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">'l'</span><span style="color:#007700;">,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#DD0000;">'m'</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">'n'</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">'o'</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">'p'</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">'q'</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">'r'</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">'s'</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">'t'</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">'u'</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">'v'</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">'z'</span><span style="color:#007700;">));<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color:#0000BB;">hasChildren</span><span style="color:#007700;">()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color:#0000BB;">true</span><span style="color:#007700;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color:#0000BB;">getChildren</span><span style="color:#007700;">()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;</span><span style="color:#0000BB;">Proverbios_Aborla_Proverbios</span><span style="color:#007700;">(</span><span style="color:#0000BB;">$this</span><span style="color:#007700;">-&gt;</span><span style="color:#0000BB;">current</span><span style="color:#007700;">());<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</span></code></p>
<h4>RecursiveIteratorIterator</h4>
<p>Diferente de um iterador sem filhos, a classe acima não poderia ser utilizada diretamente em um foreach, mesmo com a interface RecursiveIterator, porque ele apenas recupera o valor atual pelo método current(), e retornaria somente as letras a cada iteração.</p>
<p>Uma vez implementados os métodos hasChildren() e getChildren(), é preciso que eles sejam utilizados de fato, e quem faz uso deles é o iterador externo RecursiveIteratorIterator, que recebe o iterador recursivo como parâmetro no constructor e coordena a recursividade. Portanto, a classe principal deste site fica assim:</p>
<p><code style="background:#fcfcfc;font-size:95%;display:block;"><span style="color:#007700;">class&nbsp;</span><span style="color:#0000BB;">Proverbios_Aborla&nbsp;</span><span style="color:#007700;">extends&nbsp;</span><span style="color:#0000BB;">RecursiveIteratorIterator<br />
</span><span style="color:#007700;">{<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color:#0000BB;">__construct</span><span style="color:#007700;">()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">parent</span><span style="color:#007700;">::</span><span style="color:#0000BB;">__construct</span><span style="color:#007700;">(new&nbsp;</span><span style="color:#0000BB;">Proverbios_Aborla_Letras</span><span style="color:#007700;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</span></code></p>
<p>E já que a classe RecursiveIteratorIterator executa o método hasChildren() em todos os elementos que passam por ela, o retorno de getChildren() deve obrigatoriamente implementar a interface RecursiveIterator pra garantir ao iterador externo que os métodos existem, mesmo que não seja recursiva, como é o caso da classe de provérbios:</p>
<p><code style="background:#fcfcfc;font-size:95%;display:block;"><span style="color:#007700;">class&nbsp;</span><span style="color:#0000BB;">Proverbios_Aborla_Proverbios&nbsp;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#007700;">extends&nbsp;</span><span style="color:#0000BB;">ArrayIterator&nbsp;</span><span style="color:#007700;">implements&nbsp;</span><span style="color:#0000BB;">RecursiveIterator<br />
</span><span style="color:#007700;">{<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color:#0000BB;">__construct</span><span style="color:#007700;">(</span><span style="color:#0000BB;">$letra</span><span style="color:#007700;">)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">$url&nbsp;</span><span style="color:#007700;">=&nbsp;</span><span style="color:#DD0000;">"http://proverbios.aborla.net/p"&nbsp;</span><span style="color:#007700;">.&nbsp;</span><span style="color:#0000BB;">$letra&nbsp;</span><span style="color:#007700;">.&nbsp;</span><span style="color:#DD0000;">".php"</span><span style="color:#007700;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">$contents&nbsp;</span><span style="color:#007700;">=&nbsp;</span><span style="color:#0000BB;">file_get_contents</span><span style="color:#007700;">(</span><span style="color:#0000BB;">$url</span><span style="color:#007700;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">$start&nbsp;</span><span style="color:#007700;">=&nbsp;</span><span style="color:#0000BB;">strpos</span><span style="color:#007700;">(</span><span style="color:#0000BB;">$contents</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">'&lt;/h2&gt;&lt;p&gt;'</span><span style="color:#007700;">)&nbsp;+&nbsp;</span><span style="color:#0000BB;">8</span><span style="color:#007700;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">$length&nbsp;</span><span style="color:#007700;">=&nbsp;</span><span style="color:#0000BB;">strpos</span><span style="color:#007700;">(</span><span style="color:#0000BB;">$contents</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">'&lt;br&gt;&lt;/p&gt;'</span><span style="color:#007700;">)&nbsp;-&nbsp;</span><span style="color:#0000BB;">$start</span><span style="color:#007700;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">$array&nbsp;</span><span style="color:#007700;">=&nbsp;</span><span style="color:#0000BB;">explode</span><span style="color:#007700;">(</span><span style="color:#DD0000;">'&lt;br&gt;'</span><span style="color:#007700;">,&nbsp;</span><span style="color:#0000BB;">substr</span><span style="color:#007700;">(</span><span style="color:#0000BB;">$contents</span><span style="color:#007700;">,&nbsp;</span><span style="color:#0000BB;">$start</span><span style="color:#007700;">,&nbsp;</span><span style="color:#0000BB;">$length</span><span style="color:#007700;">));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">parent</span><span style="color:#007700;">::</span><span style="color:#0000BB;">__construct</span><span style="color:#007700;">(</span><span style="color:#0000BB;">$array</span><span style="color:#007700;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color:#0000BB;">hasChildren</span><span style="color:#007700;">()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color:#0000BB;">false</span><span style="color:#007700;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color:#0000BB;">getChildren</span><span style="color:#007700;">(){}<br />
}</span></code></p>
<p>De uma forma bastante semelhante à primeira classe feita, o conteúdo do site é lido no constructor, e os provérbios passados como array para o constructor do parent, que é a ArrayIterator. Por esse iterador nunca conter um filho, o método getChildren() foi somente declarado, já que não será chamado pelo RecursiveIteratorIterator, dado que o hasChildren() retorna sempre false.</p>
<p><code style="background:#fcfcfc;font-size:95%;display:block;"><span style="color:#007700;">foreach(new&nbsp;</span><span style="color:#0000BB;">Proverbios_Aborla&nbsp;</span><span style="color:#007700;">as&nbsp;</span><span style="color:#0000BB;">$proverbio</span><span style="color:#007700;">){<br />
&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;</span><span style="color:#0000BB;">$proverbio</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">"\n"</span><span style="color:#007700;">;<br />
}</span></code></p>
<p>Acompanhando o código:</p>
<ol>
<li>O foreach ocorre em um objeto da classe Proverbios_Aborla, que estende RecursiveIteratorIterator. Esse iterador externo recebe o iterador recursivo Proverbios_Aborla_Letras como parâmetro no constructor e começa a iteração;</li>
<li>A cada iteração em Proverbios_Aborla_Letras, o método hasChildren() é consultado pelo RecursiveIteratorIterator. Como o retorno é sempre true, o iterador filho é requisitado;</li>
<li>Ao chamar Proverbios_Aborla_Letras::getChildren(), uma nova instância de Proverbios_Aborla_Proverbios é criada para a letra da iteração atual e repassada para o iterador externo;</li>
<li>Ao ser instanciada, Proverbios_Aborla_Proverbios obtém os dados do site e os utiliza na ArrayIterator;</li>
<li>O iterador externo consulta o método hasChildren() na classe Proverbios_Aborla_Proverbios, que vai sempre retornar false;</li>
<li>Então o método Proverbios_Aborla_Proverbios::current(), estendido da ArrayIterator, é executado e retorna um provérbio da página lida do site;</li>
<li>O iterador externo repassa o provérbio para o foreach, disponibilizando-o no código final. Os passos 5, 6 e 7 se repetem até acabarem os provérbios e o método Proverbios_Aborla_Proverbios::valid() retornar false;</li>
<li>Quando isso acontece, o iterador externo avança com o método Proverbios_Aborta_Letras::next() que foi estendido da ArrayIterator, e recomeça o processo a partir do número 2 enquanto houver letras no primeiro iterador recursivo.</li>
</ol>
<p>O último site que usei como fonte também exigiu iteradores recursivos, e precisou ainda de mais um nível de recursividade. Os provérbios estavam divididos em letras, e em cada uma delas havia paginação de resultados.</p>
<p>Os passos iniciais foram os mesmos, primeiro criando o iterador externo RecursiveIteratorIterator para percorrer as letras e seus filhos.</p>
<p><code style="background:#fcfcfc;font-size:95%;display:block;"><span style="color:#007700;">class&nbsp;</span><span style="color:#0000BB;">Proverbios_JangadaBrasil&nbsp;</span><span style="color:#007700;">extends&nbsp;</span><span style="color:#0000BB;">RecursiveIteratorIterator<br />
</span><span style="color:#007700;">{<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color:#0000BB;">__construct</span><span style="color:#007700;">()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">parent</span><span style="color:#007700;">::</span><span style="color:#0000BB;">__construct(new&nbsp;<span style="color:#0000BB;">Proverbios_JangadaBrasil_Letras</span><span style="color:#007700;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</span></span></code></p>
<p>A classe que representa as letras funciona da mesma forma que a do site anterior, passando a array de letras para o constructor da classe que estende, ArrayIterator.</p>
<p><code style="background:#fcfcfc;font-size:95%;display:block;"><span style="color:#007700;">class&nbsp;</span><span style="color:#0000BB;">Proverbios_JangadaBrasil_Letras<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#007700;">extends&nbsp;</span><span style="color:#0000BB;">ArrayIterator&nbsp;</span><span style="color:#007700;">implements&nbsp;</span><span style="color:#0000BB;">RecursiveIterator<br />
</span><span style="color:#007700;">{<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color:#0000BB;">__construct</span><span style="color:#007700;">()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">parent</span><span style="color:#007700;">::</span><span style="color:#0000BB;">__construct</span><span style="color:#007700;">(</span><span style="color:#0000BB;">range</span><span style="color:#007700;">(</span><span style="color:#DD0000;">'a'</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">'z'</span><span style="color:#007700;">));<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color:#0000BB;">hasChildren</span><span style="color:#007700;">()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color:#0000BB;">true</span><span style="color:#007700;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color:#0000BB;">getChildren</span><span style="color:#007700;">()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;</span><span style="color:#0000BB;">Proverbios_JangadaBrasil_Paginas</span><span style="color:#007700;">(</span><span style="color:#0000BB;">$this</span><span style="color:#007700;">-&gt;</span><span style="color:#0000BB;">current</span><span style="color:#007700;">());<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</span></code></p>
<p>Ao contrário das letras, a paginação não tem uma array fixa. A solução mais prática foi implementar um iterador contínuo que a cada iteração carrega os provérbios para a letra solicitada naquela página, e continua lendo a páginas seguinte enquanto provérbios forem encontrados.</p>
<p><code style="background:#fcfcfc;font-size:95%;display:block;"><span style="color:#007700;">class&nbsp;</span><span style="color:#0000BB;">Proverbios_JangadaBrasil_Paginas&nbsp;</span><span style="color:#007700;">implements&nbsp;</span><span style="color:#0000BB;">RecursiveIterator<br />
</span><span style="color:#007700;">{<br />
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;</span><span style="color:#0000BB;">$_letra</span><span style="color:#007700;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;</span><span style="color:#0000BB;">$_pagina</span><span style="color:#007700;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;</span><span style="color:#0000BB;">$_valid</span><span style="color:#007700;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color:#0000BB;">__construct</span><span style="color:#007700;">(</span><span style="color:#0000BB;">$letra</span><span style="color:#007700;">)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">$this</span><span style="color:#007700;">-&gt;</span><span style="color:#0000BB;">_letra&nbsp;</span><span style="color:#007700;">=&nbsp;</span><span style="color:#0000BB;">$letra</span><span style="color:#007700;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color:#0000BB;">rewind</span><span style="color:#007700;">()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">$this</span><span style="color:#007700;">-&gt;</span><span style="color:#0000BB;">_pagina&nbsp;</span><span style="color:#007700;">=&nbsp;</span><span style="color:#0000BB;">1</span><span style="color:#007700;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">$this</span><span style="color:#007700;">-&gt;</span><span style="color:#0000BB;">_valid&nbsp;</span><span style="color:#007700;">=&nbsp;</span><span style="color:#0000BB;">true</span><span style="color:#007700;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color:#0000BB;">valid</span><span style="color:#007700;">()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color:#0000BB;">$this</span><span style="color:#007700;">-&gt;</span><span style="color:#0000BB;">_valid</span><span style="color:#007700;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color:#0000BB;">hasChildren</span><span style="color:#007700;">()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color:#0000BB;">true</span><span style="color:#007700;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color:#0000BB;">getChildren</span><span style="color:#007700;">()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">$it&nbsp;</span><span style="color:#007700;">=&nbsp;new&nbsp;</span><span style="color:#0000BB;">Proverbios_JangadaBrasil_Proverbios</span><span style="color:#007700;">(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">$this</span><span style="color:#007700;">-&gt;</span><span style="color:#0000BB;">_letra</span><span style="color:#007700;">,&nbsp;</span><span style="color:#0000BB;">$this</span><span style="color:#007700;">-&gt;</span><span style="color:#0000BB;">_pagina</span><span style="color:#007700;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">$this</span><span style="color:#007700;">-&gt;</span><span style="color:#0000BB;">_valid&nbsp;</span><span style="color:#007700;">=&nbsp;</span><span style="color:#0000BB;">count</span><span style="color:#007700;">(</span><span style="color:#0000BB;">$it</span><span style="color:#007700;">)&nbsp;&gt;&nbsp;</span><span style="color:#0000BB;">0</span><span style="color:#007700;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color:#0000BB;">$it</span><span style="color:#007700;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color:#0000BB;">current</span><span style="color:#007700;">()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color:#0000BB;">$this</span><span style="color:#007700;">-&gt;</span><span style="color:#0000BB;">_pagina</span><span style="color:#007700;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color:#0000BB;">key</span><span style="color:#007700;">()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color:#0000BB;">$this</span><span style="color:#007700;">-&gt;</span><span style="color:#0000BB;">_pagina</span><span style="color:#007700;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color:#0000BB;">next</span><span style="color:#007700;">()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">$this</span><span style="color:#007700;">-&gt;</span><span style="color:#0000BB;">_pagina</span><span style="color:#007700;">++;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</span></code></p>
<p>Ao ser instanciada, a letra atual é recebida como argumento no constructor. No próximo passo, o método rewind() é chamado, a página definida como 1 e uma variável interna definida como true. Esta variável será usada pelo método valid() para definir se a iteração deve continuar na próxima página dessa letra. Como o hasChildren() retorna sempre true, o RecursiveIteratorIterator recupera o iterador filho pelo método getChildren(). A classe de provérbios é instanciada, e a variável interna usada pelo valid() é atualizada; se a quantidade de provérvios nesta página não for maior que zero, o valid() retornará false e a iteração neste nível pára e recomeça na letra seguinte.</p>
<p>Finalizando, a classe de provérbios segue a mesma lógica da classe do site anterior, sendo que essa recebe no constructor a letra e a página, que são utilizadas pra montar o link do site:</p>
<p><code style="background:#fcfcfc;font-size:95%;display:block;"><span style="color:#007700;">class&nbsp;</span><span style="color:#0000BB;">Proverbios_JangadaBrasil_Proverbios<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#007700;">extends&nbsp;</span><span style="color:#0000BB;">ArrayIterator&nbsp;</span><span style="color:#007700;">implements&nbsp;</span><span style="color:#0000BB;">RecursiveIterator<br />
</span><span style="color:#007700;">{&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color:#0000BB;">__construct</span><span style="color:#007700;">(</span><span style="color:#0000BB;">$letra</span><span style="color:#007700;">,&nbsp;</span><span style="color:#0000BB;">$pagina</span><span style="color:#007700;">)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">$url&nbsp;</span><span style="color:#007700;">=&nbsp;</span><span style="color:#DD0000;">'http://www.jangadabrasil.com.br/proverbios/'<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#007700;">.&nbsp;</span><span style="color:#0000BB;">$letra&nbsp;</span><span style="color:#007700;">.&nbsp;</span><span style="color:#DD0000;">'.asp?PageIndex='&nbsp;</span><span style="color:#007700;">.&nbsp;</span><span style="color:#0000BB;">$pagina</span><span style="color:#007700;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">$contents&nbsp;</span><span style="color:#007700;">=&nbsp;</span><span style="color:#0000BB;">file_get_contents</span><span style="color:#007700;">(</span><span style="color:#0000BB;">$url</span><span style="color:#007700;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">preg_match_all</span><span style="color:#007700;">(</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#DD0000;">'/&lt;div&nbsp;class="textoproverbios"&gt;([^&lt;]+)&lt;\/div&gt;/i'</span><span style="color:#007700;">,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">$contents</span><span style="color:#007700;">,&nbsp;</span><span style="color:#0000BB;">$matches</span><span style="color:#007700;">);<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(isset(</span><span style="color:#0000BB;">$matches</span><span style="color:#007700;">[</span><span style="color:#0000BB;">1</span><span style="color:#007700;">])&nbsp;&amp;&amp;&nbsp;</span><span style="color:#0000BB;">is_array</span><span style="color:#007700;">(</span><span style="color:#0000BB;">$matches</span><span style="color:#007700;">[</span><span style="color:#0000BB;">1</span><span style="color:#007700;">])){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">parent</span><span style="color:#007700;">::</span><span style="color:#0000BB;">__construct</span><span style="color:#007700;">(</span><span style="color:#0000BB;">$matches</span><span style="color:#007700;">[</span><span style="color:#0000BB;">1</span><span style="color:#007700;">]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color:#0000BB;">hasChildren</span><span style="color:#007700;">()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color:#0000BB;">false</span><span style="color:#007700;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color:#0000BB;">getChildren</span><span style="color:#007700;">(){}<br />
}</span></code></p>
<h4>AppendIterator</h4>
<p>Agora que as classes já estão funcionando individualmente, basta utilizar a AppendIterator para unir todas elas. Esta classe possui o método append(), que recebe um iterador como parâmetro. Ao ser utilizada em um foreach, ela percorre cada um dos iteradores em seqüência, resultando em todos os provérbios de todos os sites em um único loop.</p>
<p><code style="background:#fcfcfc;font-size:95%;display:block;"><span style="color:#007700;">class&nbsp;</span><span style="color:#0000BB;">Proverbios&nbsp;</span><span style="color:#007700;">extends&nbsp;</span><span style="color:#0000BB;">AppendIterator<br />
</span><span style="color:#007700;">{<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color:#0000BB;">current</span><span style="color:#007700;">()<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">$proverbio&nbsp;</span><span style="color:#007700;">=&nbsp;</span><span style="color:#0000BB;">parent</span><span style="color:#007700;">::</span><span style="color:#0000BB;">current</span><span style="color:#007700;">();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">$proverbio&nbsp;</span><span style="color:#007700;">=&nbsp;</span><span style="color:#0000BB;">trim</span><span style="color:#007700;">(</span><span style="color:#0000BB;">$proverbio</span><span style="color:#007700;">,&nbsp;</span><span style="color:#DD0000;">"&nbsp;.\"'\t\n\x0B\r"</span><span style="color:#007700;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">$proverbio&nbsp;</span><span style="color:#007700;">=&nbsp;</span><span style="color:#0000BB;">html_entity_decode</span><span style="color:#007700;">(</span><span style="color:#0000BB;">$proverbio</span><span style="color:#007700;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color:#0000BB;">$proverbio&nbsp;</span><span style="color:#007700;">=&nbsp;</span><span style="color:#0000BB;">strip_tags</span><span style="color:#007700;">(</span><span style="color:#0000BB;">$proverbio</span><span style="color:#007700;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color:#0000BB;">$proverbio</span><span style="color:#007700;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</span></code></p>
<p>Aproveitando que todos os provérbios são retornados para o foreach pelo método current() desta classe, apliquei alguns filtros básicos pra garantir que os dados estão no formato desejado pro que eu precisava.</p>
<h4>Foreach</h4>
<p>Enfim, o script final simplificado de uma forma complexa:</p>
<p><code style="background:#fcfcfc;font-size:95%;display:block;"><span style="color:#000000;"><span style="color:#0000BB;">$proverbios</span> <span style="color:#007700;">= new </span><span style="color:#0000BB;">Proverbios</span><span style="color:#007700;">;<br />
</span><span style="color:#0000BB;">$proverbios</span><span style="color:#007700;">-&gt;</span><span style="color:#0000BB;">append</span><span style="color:#007700;">(new </span><span style="color:#0000BB;">Proverbios_LifesABirch</span><span style="color:#007700;">);<br />
</span><span style="color:#0000BB;">$proverbios</span><span style="color:#007700;">-&gt;</span><span style="color:#0000BB;">append</span><span style="color:#007700;">(new </span><span style="color:#0000BB;">Proverbios_Aborla</span><span style="color:#007700;">);<br />
</span><span style="color:#0000BB;">$proverbios</span><span style="color:#007700;">-&gt;</span><span style="color:#0000BB;">append</span><span style="color:#007700;">(new </span><span style="color:#0000BB;">Proverbios_JangadaBrasil</span><span style="color:#007700;">);</p>
<p>foreach(</span><span style="color:#0000BB;">$proverbios </span><span style="color:#007700;">as </span><span style="color:#0000BB;">$proverbio</span><span style="color:#007700;">){<br />
    echo </span><span style="color:#0000BB;">$proverbio</span><span style="color:#007700;">, </span><span style="color:#DD0000;">"\n"</span><span style="color:#007700;">;<br />
}</span></span></code></p>
<h4>Referências</h4>
<p><a href="http://www.php.net/~helly/php/ext/spl/">http://www.php.net/~helly/php/ext/spl/</a><br />
<a href="http://somabo.de/talks/200509_toronto_iterator_debug_session_2.pdf">http://somabo.de/talks/200509_toronto_iterator_debug_session_2.pdf</a></p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/garotosopa.wordpress.com/24/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/garotosopa.wordpress.com/24/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/24/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/24/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/24/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/24/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/24/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/24/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/24/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/24/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/24/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/24/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=24&subd=garotosopa&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2007/04/18/voltas-e-mais-voltas-com-spl/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>
	</item>
	</channel>
</rss>