<?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:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>garotosopa</title>
	<atom:link href="http://garotosopa.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://garotosopa.wordpress.com</link>
	<description>juntando as letrinhas desde 1986</description>
	<lastBuildDate>Thu, 02 Jul 2009 23:24:31 +0000</lastBuildDate>
	<generator>http://wordpress.com/</generator>
	<language>pt-br</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<image>
		<url>http://www.gravatar.com/blavatar/1aa997062c21c77622f350c2011b4705?s=96&#038;d=http://s.wordpress.com/i/buttonw-com.png</url>
		<title>garotosopa</title>
		<link>http://garotosopa.wordpress.com</link>
	</image>
			<item>
		<title>Agrupamento parcial com WITH ROLLUP no MySQL</title>
		<link>http://garotosopa.wordpress.com/2009/06/19/agrupamento-parcial-com-with-rollup-no-mysql/</link>
		<comments>http://garotosopa.wordpress.com/2009/06/19/agrupamento-parcial-com-with-rollup-no-mysql/#comments</comments>
		<pubDate>Fri, 19 Jun 2009 11:00:11 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=628</guid>
		<description><![CDATA[Acho que desde que descobri o recurso de GROUP BY &#8230; WITH ROLLUP no MySQL, todas as consultas que faço pra relatórios incluem o modificador.
Uma query de exemplo seria pra consultar a quantidade de pessoas por estado, retornando também o total parcial por região.
Para que o MySQL já calcule este subtotal, basta incluir o modificador [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=628&subd=garotosopa&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Acho que desde que descobri o recurso de <em>GROUP BY &#8230; WITH ROLLUP</em> no MySQL, todas as consultas que faço pra relatórios incluem o modificador.</p>
<p>Uma query de exemplo seria pra consultar a quantidade de pessoas por estado, retornando também o total parcial por região.</p>
<p>Para que o MySQL já calcule este subtotal, basta incluir o modificador <strong>WITH ROLLUP</strong> logo após o GROUP BY:</p>
<p><span id="more-628"></span></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:#6495ed;">SELECT</span> uf.regiao, uf.nome, <span style="color:#bdb76b;">COUNT(</span>p.id<span style="color:#bdb76b;">)</span><br />
<span style="color:#6495ed;">FROM</span> uf<br />
<span style="color:#6495ed;">LEFT JOIN</span> pessoa p <span style="color:#6495ed;">ON</span> uf.id = p.id_uf<br />
<span style="color:#6495ed;">GROUP BY</span> uf.regiao, uf.nome <span style="color:#6495ed;">WITH ROLLUP</span>
</div>
<div style="font-size:12px;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';">
<pre>
+--------------+---------------------+-------------+
| regiao       | nome                | COUNT(p.id) |
+--------------+---------------------+-------------+
| Centro-Oeste | Distrito Federal    |          99 |
| Centro-Oeste | Goiás               |         114 |
| Centro-Oeste | Mato Grosso         |         102 |
| Centro-Oeste | Mato Grosso do Sul  |          91 |
<span style="background-color:#FFCCCC;">| Centro-Oeste | <em>NULL</em>                |         406 |</span>
| Nordeste     | Alagoas             |         107 |
| Nordeste     | Bahia               |          72 |
| Nordeste     | Ceará               |         100 |
| Nordeste     | Maranhão            |          89 |
| Nordeste     | Paraíba             |         128 |
| Nordeste     | Pernambuco          |         105 |
| Nordeste     | Piauí               |          92 |
| Nordeste     | Rio Grande do Norte |          83 |
| Nordeste     | Sergipe             |         115 |
<span style="background-color:#FFCCCC;">| Nordeste     | <em>NULL</em>                |         891 |</span>
| Norte        | Acre                |          87 |
| Norte        | Amapá               |          97 |
| Norte        | Amazonas            |         103 |
| Norte        | Pará                |         116 |
| Norte        | Rondônia            |         111 |
| Norte        | Roraima             |          93 |
| Norte        | Tocantins           |         101 |
<span style="background-color:#FFCCCC;">| Norte        | <em>NULL</em>                |         708 |</span>
| Sul          | Paraná              |         112 |
| Sul          | Rio Grande do Sul   |         110 |
| Sul          | Santa Catarina      |         115 |
<span style="background-color:#FFCCCC;">| Sul          | <em>NULL</em>                |         337 |</span>
<span style="background-color:#FFCCCC;">| <em>NULL</em>         | <em>NULL</em>                |        2342 |</span>
+--------------+---------------------+-------------+
</pre>
</div>
<p>&nbsp;<br />
Com o modificador <em>WITH ROLLUP</em>, para cada região existe um valor <strong><em>NULL</em></strong> na coluna do estado, representando o subtotal daquela região.</p>
<p>Esta regra vale para todos os níveis de agrupamento. As demais colunas agrupadas ficam com valor <em>NULL</em> quando a função de agregação, neste caso o <em>COUNT</em>, está representando um resultado parcial.</p>
<p>No final é retornado ainda o <strong>total geral</strong>, como se não houvesse agrupamento algum, deixando todas as colunas agrupadas com valor <em>NULL</em>.</p>
<p>Agora basta formatar o resultado pelo código e deixar as colunas de subtotal com algum estilo diferente e descrição apropriada.</p>
<p>Vale lembrar que o <em>WITH ROLLUP</em> retorna os <strong>rows ordenados pelas colunas agrupadas</strong>, não sendo permitido misturar uma cláusula <em>ORDER BY</em> na mesma query, até porque o MySQL se baseia na troca do valor da coluna para saber quando deve mostrar um total parcial (da mesma forma que faríamos manualmente). Caso seja realmente necessário, é possível utilizar o <em>WITH ROLLUP</em> em uma query derivada e a partir dela acrescentar o <em>ORDER BY</em>.</p>
<p>Veja mais detalhes sobre modificadores de agrupamento no capítulo <a href="http://dev.mysql.com/doc/refman/5.0/en/group-by-modifiers.html">GROUP BY Modifiers</a> do manual.</p>
<div style="font-size:80%;">* se alguém reparar que estão faltando os estados da região sudeste, é só porque eu esqueci de cadastrar no banco de testes mesmo.</div>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/628/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/628/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/628/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/628/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/628/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/628/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/628/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/628/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/628/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/628/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=628&subd=garotosopa&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2009/06/19/agrupamento-parcial-com-with-rollup-no-mysql/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>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>19</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>Aproveitando melhor o aptitude</title>
		<link>http://garotosopa.wordpress.com/2009/04/26/aproveitando-melhor-o-aptitude/</link>
		<comments>http://garotosopa.wordpress.com/2009/04/26/aproveitando-melhor-o-aptitude/#comments</comments>
		<pubDate>Sun, 26 Apr 2009 23:45:14 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=599</guid>
		<description><![CDATA[Pra quem usa Debian ou semelhante, como o Ubuntu, talvez as notas abaixo sejam úteis na hora de gerenciar os pacotes pelo aptitude.
Resumo

CTRL-T para acessar o menu
%D é o atributo de package size no display format
u para update
U para upgrade
g para executar e confirmar as alterações
: para ignorar a atualização de um pacote
= para deixar [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=599&subd=garotosopa&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Pra quem usa Debian ou semelhante, como o Ubuntu, talvez as notas abaixo sejam úteis na hora de gerenciar os pacotes pelo <strong>aptitude</strong>.</p>
<h3>Resumo</h3>
<ul>
<li><strong>CTRL-T</strong> para acessar o menu</li>
<li><strong>%D</strong> é o atributo de <em>package size</em> no <em>display format</em></li>
<li><strong>u</strong> para update</li>
<li><strong>U</strong> para upgrade</li>
<li><strong>g</strong> para executar e confirmar as alterações</li>
<li><strong>:</strong> para ignorar a atualização de um pacote</li>
<li><strong>=</strong> para deixar o pacote nesta versão até a segunda ordem</li>
<li><strong>G</strong> para filtrar ou alterar a exibição da lista de pacotes</li>
<li><strong>filter(~i !~M)</strong> mostra apenas os pacotes instalados manualmente</li>
<li><strong>m</strong> para marcar um pacote como instalado manualmente</li>
<li><strong>M</strong> para marcar um pacote como instalado automaticamente</li>
<li>Isso é só cultura inútil, ignore se tiver outra coisa pra fazer</li>
</ul>
<p><span id="more-599"></span></p>
<h3>Pacotes recomendados</h3>
<p>Uma boa coisa a se fazer ao instalar o sistema do zero é configurar o aptitude para não instalar os pacotes recomendados automaticamente, somente as dependências. Isso poupa dezena de pacotes que você provavelmente não quer.</p>
<p>A opção está disponível no menu <strong>Options -&gt; Preferences</strong>, que pode ser acessado pressionando <strong>CTRL-T</strong>. Desmarque a opção <em>Install recommended packages automatically</em>.</p>
<h3>Pacotes desnecessários</h3>
<p>Logo abaixo tem a opção <em>Remove unused packages automatically</em>. Confirme que ela esteja marcada para garantir que pacotes que foram instalados para satisfazer dependências sejam removidos quando não forem mais necessários.</p>
<h3>Package size</h3>
<p>Ainda nas preferências, acho legal incluir a coluna com o tamanho do pacote a ser baixado, em caso de atualização ou nova instalação.</p>
<p>Edite a opção <em>The display format for package views</em> e inclua o atributo <strong>%D</strong>. Aqui a configuração ficou <em><span style="background-color:#eaeaea;">%c%a%M%S %p %Z %D %v %V</span></em>.</p>
<p>Saber o tamanho do pacote ajuda na hora de priorizar alguns e desistir de outros, caso tenha muita coisa para atualizar.</p>
<h3>Ignorando atualizações</h3>
<p>Para atualizar o sistema, utiliza-se a tecla <strong>u</strong> (minúsculo) para atualizar a lista de pacotes do repositório (o mesmo que o comando aptitude update ou apt-get update) e depois a tecla <strong>U</strong> (maiúsculo) para marcar para atualização os pacotes com versões mais novas disponíveis (o mesmo que aptitude upgrade ou apt-get upgrade).</p>
<p>Para executar as alterações, pressione <strong>g</strong> (minúsculo). Você será levado para uma tela de preview. Pressione <strong>g</strong> novamente para confirmar.</p>
<p>Se quiser ignorar alguma atualização, pressione <strong>:</strong> em cima do pacote que deseja ignorar. Ele ficará como <em>upgradable</em> até o próximo upgrade (<strong>U</strong>).</p>
<p>Caso prefira manter o pacote na versão atual indefinidamente, pressione <strong>=</strong> em cima do pacote para deixá-lo em <em>hold</em>. Ele ficará aguardando neste status até que você remova o hold.</p>
<h3>Filtrando a lista de pacotes</h3>
<p>Na tela principal do aptitude estão listados todos os pacotes dos repositórios agrupados por tarefa, status e seção. Este agrupamento pode ser trocado através da tecla <strong>G</strong> (maiúsculo).</p>
<p>Uma visualização que faço frequentemente é filtrar os pacotes instalados com o filtro <em><span style="background-color:#eaeaeal;">filter(~i !~M)</span></em>. O atributo <em>~i</em> lista os pacotes instalados e o atributo <em>~M</em> lista os pacotes instalados automaticamente para satisfazer dependências (neste caso, utilizado com negação).</p>
<p>Ao pressionar <strong>G</strong>, o filtro e agrupamentos ficam <em><span style="background-color:#eaeaea;">filter(~i !~M),section</span></em>.</p>
<h3>Marcar pacotes como instalados automaticamente</h3>
<p>O benefício do filtro acima é poder diferenciar os pacotes que realmente se quer instalados dos que foram instalados por necessidade.</p>
<p>Utilizando o filtro e agrupmento como no exemplo anterior, a seção <em>libs</em> deveria mostrar uma quantidade mínima de pacotes, já que o que utilizamos são os programas, sendo as bibliotecas apenas para satisfazer dependências (salvo algumas exceções como a libdvdcss2, por exemplo).</p>
<p>Se com o filtro anterior forem exibidos vários pacotes na seção libs é porque, pro aptitude, estas bibliotecas foram instaladas manualmente. O problema disso é que, se todos os programas que utilizam a biblioteca forem removidos, ela vai continuar lá.</p>
<p>Para marcar os pacotes como instalados automaticamente, pressione <strong>M</strong> (maiúsculo) em cima do pacote, ou em cima da seção para marcar todos como automáticos, como no caso das libs.</p>
<p>Se esta é a primeira vez que você faz isso, é comum que vários pacotes sejam removidos. Nesse caso, ao pressionar <strong>g</strong> para concluir as alterações, vale a pena dar uma boa olhada no preview antes de pressionar <strong>g</strong> novamente para confirmar.</p>
<p>Para marcar um pacote como instalado manualmente e evitar que ele seja removido quando nenhum outro pacote depender mais dele, pressione <strong>m</strong> (minúsculo) em cima do pacote.</p>
<p>Caso você tenha muita paciência ou mais nada de interessante pra fazer, pode ser um <del>bom</del> longo passatempo percorrer toda a lista de pacotes (com <em>filter(~i !~M)</em>) e marcar como instalação automática aqueles que você desconhece ou acha que não precisa. </p>
<p>Na dúvida é melhor deixar instalado, principalmente se for algum relacionado a boot ou filesystem.</p>
<h3>Ignore tudo isso</h3>
<p>Em quase 100% dos casos os usuários vão preferir desconhecer os pacotes instalados e só usar o Synaptic de vez em quando. Eu entendo. Afinal são só pacotes no computador. É que eu estava sem o que fazer e precisava de algum lugar pra anotar isso, porque sempre esqueço.</p>
<p>Caso alguém se interesse, o User&#8217;s Manual disponível no menu (através de <strong>CTRL-T</strong>) é mais completo do que <em>man aptitude</em>.</p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/599/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/599/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/599/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/599/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/599/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/599/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/599/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/599/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/599/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/599/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=599&subd=garotosopa&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2009/04/26/aproveitando-melhor-o-aptitude/feed/</wfw:commentRss>
		<slash:comments>1</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>Desabilitar o uso de alert no Firefox</title>
		<link>http://garotosopa.wordpress.com/2008/12/01/desabilitar-alert-firefox/</link>
		<comments>http://garotosopa.wordpress.com/2008/12/01/desabilitar-alert-firefox/#comments</comments>
		<pubDate>Mon, 01 Dec 2008 11:00:03 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[alert]]></category>
		<category><![CDATA[disable]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[preference]]></category>
		<category><![CDATA[settings]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=438</guid>
		<description><![CDATA[Alguns sites insistem em atrapalhar a navegação utilizando alert() inadvertidamente, e isso sempre me irritou bastante. Resolvi procurar e acabei descobrindo uma forma no Firefox de desabilitar funcionalidades Javascript de acordo com políticas para cada site.

Como o Firefox ainda não tem uma interface para configurar estas regras, é necessário editar o arquivo user.js manualmente. Se [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=438&subd=garotosopa&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Alguns sites insistem em atrapalhar a navegação utilizando alert() inadvertidamente, e isso sempre me irritou bastante. Resolvi procurar e acabei descobrindo uma forma no Firefox de desabilitar funcionalidades Javascript de acordo com políticas para cada site.<br />
<span id="more-438"></span><br />
Como o Firefox ainda não tem uma interface para configurar estas regras, é necessário editar o arquivo <strong>user.js</strong> manualmente. Se o arquivo ainda não existir, basta criá-lo no seu diretório pessoal do Firefox. </p>
<p>Aqui o caminho é <strong>~/.mozilla/firefox/5mmyfmm7.default</strong>, mas provavelmente esta última parte será diferente.</p>
<div style="margin-bottom:1em;font-family:monospace,'Bitstream Vera Sans Mono','Courier New';background-color:#fff;color:#000;border-left:3px solid #ccc;padding:.5em;">user_pref(<span style="color:#0a0;">&quot;capability.policy.policynames&quot;</span>, <span style="color:#a00;">&quot;semAlert&quot;</span>);<br />
user_pref(<span style="color:#0a0;">&quot;capability.policy.semAlert.sites&quot;</span>, <span style="color:#a00;">&quot;http://oglobo.globo.com&quot;</span>);<br />
user_pref(<span style="color:#0a0;">&quot;capability.policy.semAlert.Window.alert&quot;</span>, <span style="color:#a00;">&quot;noAccess&quot;</span>);</div>
<p>Depois é só reiniciar o Firefox.</p>
<p>Quando o site tentar utilizar o recurso desabilitado o console do Javascript irá mostrar <em>Error: Permission denied to call method Window.alert</em>.</p>
<p>Para aplicar a mesma política para mais de um site, separe os endereços por espaço. Se precisar criar diferentes políticas, separe cada uma por vírgula na configuração <em>policynames</em>.</p>
<p>O legal é que dá pra desabilitar todas as funções ou propriedades do DOM. Quem quiser pode dar uma olhada nos links <a href="http://www.mozilla.org/projects/security/components/ConfigPolicy.html">Configurable Security Policies</a> e <a href="http://www.mozilla.org/unix/customizing.html">Customizing Mozilla</a> para mais detalhes.</p>
<p>E então, vai usar? Já faz isso de outra forma?</p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/438/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/438/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/438/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/438/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/438/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/438/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/438/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/438/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/438/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/438/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=438&subd=garotosopa&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2008/12/01/desabilitar-alert-firefox/feed/</wfw:commentRss>
		<slash:comments>1</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>7</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(&#8217;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(&#8217;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(&#8217;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>9</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>1</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>Could not create GL context com driver da Nvidia</title>
		<link>http://garotosopa.wordpress.com/2008/08/31/could-not-create-gl-context-com-driver-da-nvidia/</link>
		<comments>http://garotosopa.wordpress.com/2008/08/31/could-not-create-gl-context-com-driver-da-nvidia/#comments</comments>
		<pubDate>Sun, 31 Aug 2008 14:19:56 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=79</guid>
		<description><![CDATA[Ontem fui tentar jogar Frets On Fire e recebi o erro Could not create GL Context.
O problema ocorreu porque a biblioteca libglx.so deveria apontar para o arquivo da Nvidia, no entanto o arquivo original do Xorg estava sendo usado. Isso deve ter acontecido por causa de alguma atualização do Xorg depois de já ter instalado [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=79&subd=garotosopa&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Ontem fui tentar jogar Frets On Fire e recebi o erro Could not create GL Context.</p>
<p>O problema ocorreu porque a biblioteca <strong>libglx.so</strong> deveria apontar para o arquivo da <strong>Nvidia</strong>, no entanto o arquivo original do Xorg estava sendo usado. Isso deve ter acontecido por causa de alguma atualização do Xorg depois de já ter instalado o driver da Nvidia.</p>
<p>Pra não ter que instalar o driver da Nvidia de novo, fiz o seguinte:<br />
<span id="more-79"></span><br />
<code style="font-size:.9em;text-align:left;">root@olivia:~# <strong><span style="background-color:#FDD;">cd /usr/lib/xorg/modules/extensions/</span></strong><br />
&nbsp;<br />
root@olivia:/usr/lib/xorg/modules/extensions/# <strong><span style="background-color:#FDD;">ls -l</span></strong><br />
-rw-r--r-- 1 root root   19243 2008-08-02 18:44 libdbe.so<br />
-rw-r--r-- 1 root root   40804 2008-08-02 18:44 libdri.so<br />
-rw-r--r-- 1 root root  151848 2008-08-02 18:44 libextmod.so<br />
-rw-r--r-- 1 root root 2487120 2008-08-02 18:44 libGLcore.so<br />
-rw-r--r-- 1 root root  426657 2008-08-02 18:44 <strong>libglx.so</strong><br />
-rwxr-xr-x 1 root root  763656 2008-04-06 14:34 <strong>libglx.so.169.12</strong><br />
-rw-r--r-- 1 root root   28767 2008-08-02 18:44 librecord.so<br />
-rw-r--r-- 1 root root   40153 2008-08-02 18:44 libxtrap.so<br />
&nbsp;<br />
root@olivia:/usr/lib/xorg/modules/extensions/# <strong><span style="background-color:#FDD;">mv libglx.so libglx.so.xorg</span></strong><br />
&nbsp;<br />
root@olivia:/usr/lib/xorg/modules/extensions/# <strong><span style="background-color:#FDD;">ln -s $PWD/libglx.so.169.12 libglx.so</span></strong><br />
&nbsp;<br />
root@olivia:/usr/lib/xorg/modules/extensions/# <strong><span style="background-color:#FDD;">ls -l</span></strong><br />
-rw-r--r-- 1 root root   19243 2008-08-02 18:44 libdbe.so<br />
-rw-r--r-- 1 root root   40804 2008-08-02 18:44 libdri.so<br />
-rw-r--r-- 1 root root  151848 2008-08-02 18:44 libextmod.so<br />
-rw-r--r-- 1 root root 2487120 2008-08-02 18:44 libGLcore.so<br />
lrwxrwxrwx 1 root root      16 2008-08-30 15:36 <strong>libglx.so -&gt; libglx.so.169.12</strong><br />
-rwxr-xr-x 1 root root  763656 2008-04-06 14:34 libglx.so.169.12<br />
-rw-r--r-- 1 root root  426657 2008-08-02 18:44 libglx.so.xorg<br />
-rw-r--r-- 1 root root   28767 2008-08-02 18:44 librecord.so<br />
-rw-r--r-- 1 root root   40153 2008-08-02 18:44 libxtrap.so<br />
&nbsp;</code></p>
<p>Agora sim o Xorg vai utilizar a extensão GLX da Nvidia e finalmente vou conseguir jogar Frets On Fire :)</p>
<p>Se o outro arquivo libglx.so com o número da versão do driver não existir, daí não tem jeito, tem que instalar o driver da Nvidia.</p>
<p>Pra evitar que isso ocorra na próxima atualização do Xorg, sugiro <a href="http://wiki.debian.org/NvidiaGraphicsDrivers">instalar o driver da Nvidia do jeito Debian</a>.</p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/garotosopa.wordpress.com/79/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/garotosopa.wordpress.com/79/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/79/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/79/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/79/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/79/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/79/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/79/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/79/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/79/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/79/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/79/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=79&subd=garotosopa&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2008/08/31/could-not-create-gl-context-com-driver-da-nvidia/feed/</wfw:commentRss>
		<slash:comments>1</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>Por que implementar Interface em OOP?</title>
		<link>http://garotosopa.wordpress.com/2008/08/14/interface-em-oop/</link>
		<comments>http://garotosopa.wordpress.com/2008/08/14/interface-em-oop/#comments</comments>
		<pubDate>Thu, 14 Aug 2008 22:01:54 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[OOP]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=54</guid>
		<description><![CDATA[Acabei de ter esta conversa rápida sobre o porquê de implementar Interface em classes quando se trabalha com orientação a objetos e achei bastante pertinente.
Resposta curta: Interface serve para garantir que o código que utiliza o objeto vai ter determinada funcionalidade disponível; não importa como o objeto vai fazer, contanto que possa fazer. É como [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=54&subd=garotosopa&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Acabei de ter esta conversa rápida sobre o porquê de implementar Interface em classes quando se trabalha com orientação a objetos e achei bastante pertinente.</p>
<p><strong>Resposta curta:</strong> Interface serve para garantir que o código que utiliza o objeto vai ter determinada funcionalidade disponível; não importa como o objeto vai fazer, contanto que possa fazer. É como contratar alguém com diploma.</p>
<p>Referências:</p>
<ul>
<li><a href="http://http://www.php.net/language.oop5.interfaces">http://www.php.net/language.oop5.interfaces</a></li>
<li><a href="http://http://pt.wikipedia.org/wiki/Interface_(programa%C3%A7%C3%A3o)">http://pt.wikipedia.org/wiki/Interface_(programa%C3%A7%C3%A3o)</a></li>
<li><a href="http://http://java.sun.com/docs/books/tutorial/java/concepts/interface.html">http://java.sun.com/docs/books/tutorial/java/concepts/interface.html</a></li>
</ul>
<p><span id="more-54"></span></p>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/euler.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:06:24] paaaaaaaaaa&#8211;agora tomou susto num foi????</em>
<p>estive pensando sobre interfaces&#8230;. sobre o conceito de interfaces..</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/euler.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:06:57] paaaaaaaaaa&#8211;agora tomou susto num foi????</em>
<p>no que diz respeito a você apenas deixar a assinatura do método, daí a classe que implementá-la coloca o código nos métodos..</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/euler.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:07:27] paaaaaaaaaa&#8211;agora tomou susto num foi????</em>
<p>a primeira impressão nos faz pensar que isso não é nada pragmático, não acha?</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:08:19] diogo In Communist China, files share you!</em>
<p>http://www.rankmygf.com/</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/euler.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:08:27] paaaaaaaaaa&#8211;agora tomou susto num foi????</em>
<p>o que é isso?</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:08:34] diogo In Communist China, files share you!</em>
<p>não sei o que é uma coisa pragmática</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:08:38] diogo In Communist China, files share you!</em>
<p>um site pornô </p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/euler.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:08:48] paaaaaaaaaa&#8211;agora tomou susto num foi????</em>
<p>o título parece bem baum&#8230;.</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:09:08] diogo In Communist China, files share you!</em>
<p>a idéia é legal</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/euler.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:09:22] paaaaaaaaaa&#8211;agora tomou susto num foi????</em>
<p>a idéia da interface?</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/euler.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:09:40] paaaaaaaaaa&#8211;agora tomou susto num foi????</em>
<p>de certo modo faz o programador digitar mais códigos..</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:09:41] diogo In Communist China, files share you!</em>
<p>a idéia do site pornô.</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/euler.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:10:00] paaaaaaaaaa&#8211;agora tomou susto num foi????</em>
<p>ahh ta..</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:10:04] diogo In Communist China, files share you!</em>
<p>as interfaces servem de contrato entre duas pontas.</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/euler.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:10:05] paaaaaaaaaa&#8211;agora tomou susto num foi????</em>
<p>achei que fosse da interface..</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:10:13] diogo In Communist China, files share you!</em>
<p>também é interessante.</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:10:33] diogo In Communist China, files share you!</em>
<p>em uma ponta você tem um código que precisa que o objeto tenha determinado método.</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:10:44] diogo In Communist China, files share you!</em>
<p>na outra ponta você tem uma classe que implementa esse método.</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:11:03] diogo In Communist China, files share you!</em>
<p>a classe então implementa a interface e algum outro lugar exige que o objeto implemente esta interface.</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:11:20] diogo In Communist China, files share you!</em>
<p>esse é o propósito. não importa COMO o método faz o procedimento, contanto que o objeto saiba fazer.</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/euler.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:13:32] paaaaaaaaaa&#8211;agora tomou susto num foi????</em>
<p>eu sei como funciona o conceito&#8230; o que digo é que isso não parece pragmático, pois vou fazer uma interface que vai apenas me trazer a assinatura do método&#8230; na classe que estou implementando a interface terei que digitar tudo mesmo&#8230;. então!!!! não seria melhor digitar de vez sem implementar tal interface?</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:14:52] diogo In Communist China, files share you!</em>
<p>se você programa sozinho objetos que só servem pra você, e se você só utiliza os seus próprios objetos e só tem 1 classe que implementa tal função, sim. aí você não precisa de interface.</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/euler.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:16:42] paaaaaaaaaa&#8211;agora tomou susto num foi????</em>
<p>mas mesmo com vários objetos não me parece pragmático pelo simples fato de termos que escrever o código em cada objeto que implementa a interface. imagine que temos 10 objetos e temos uma interface. ao implementar essa interface nos 10 objetos escrevemos o código 10 vezes..</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:17:47] diogo In Communist China, files share you!</em>
<p>imagina que você tem uma classe que baixa arquivos. ela implementa um método <strong>public function baixar($url)</strong></p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:18:11] diogo In Communist China, files share you!</em>
<p>imagina também que você tem uma outra classe que precisa baixar arquivos. ela tem um método que recebe a instância de um browser, que é um objeto que sabe baixar arquivos.</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:18:55] diogo In Communist China, files share you!</em>
<p>então essa classe que precisa baixar arquivos tem um método <strong>public function setBrowser( MeuBrowser $browser )</strong> e um pouco depois, nela mesma, é feito algo como <strong>$this-&gt;browser-&gt;baixar(&#8221;http://&#8230;&#8221;);</strong></p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:19:17] diogo In Communist China, files share you!</em>
<p>só que amanhã você não tem mais só essa classe MeuBrowser. você tem também a classe BrowserDoDiogo.</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:19:57] diogo In Communist China, files share you!</em>
<p>as duas classes têm o método baixar($url) e a sua classe que precisa baixar arquivos não se importa se é a classe MeuBrowser ou BrowserDoDiogo que está sendo usada. sua classe só precisa que o browser tenha o método para baixar arquivos.</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:20:29] diogo In Communist China, files share you!</em>
<p>então você muda a assinatura da sua classe para <strong>setBrowser( IBrowser $browser )</strong>. e cria a interface <strong>IBrowser</strong> que vai exigir que as classes que a implementem tenham o método <strong>baixar($url)</strong>.</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:20:46] diogo In Communist China, files share you!</em>
<p>então as classes MeuBrowser e BrowserDoDiogo passam a implementar essa interface e todos ficam felizes.</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:20:48] diogo In Communist China, files share you!</em>
<p>captou?</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/euler.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:22:25] paaaaaaaaaa&#8211;agora tomou susto num foi????</em>
<p>poxa captei sim sua idéia..</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/euler.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:22:26] paaaaaaaaaa&#8211;agora tomou susto num foi????</em>
<p>mas&#8230;</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/euler.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:23:52] paaaaaaaaaa&#8211;agora tomou susto num foi????</em>
<p>você poderia muito bem definir o método baixar nas classes MeuBrowser e BrowserDoDiogo sem precisar da interface&#8230;</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:24:34] diogo In Communist China, files share you!</em>
<p>sim. mas aí a sua classe que precisa de um browser não ia ter como garantir que o objeto que ela recebe como browser realmente tem capacidade de baixar.</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:25:25] diogo In Communist China, files share you!</em>
<p>lembre-se que essa idéia de Interface é de engenheiros heheh eles precisam de uma garantia de que as coisas funcionarão sem dar erro em tempo de execução.</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/euler.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:26:10] paaaaaaaaaa&#8211;agora tomou susto num foi????</em>
<p>mas pensando assim&#8230;</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/euler.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:27:08] paaaaaaaaaa&#8211;agora tomou susto num foi????</em>
<p>eu poso fazer as classes MeuBrowser e BrowserDoDiogo implementarem uma interface e essa interface, no caso IBrowser, teria um método baixar&#8230; correto?</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:27:16] diogo In Communist China, files share you!</em>
<p>exatamente.</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/euler.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:28:18] paaaaaaaaaa&#8211;agora tomou susto num foi????</em>
<p>de qualquer forma eu iria implementar o código do método baixar() em MeuBrowser e em BrowserDoDiogo, ou seja, isso não iria garantir a integridade 100% de que o método saberia baixar&#8230;. seriam dois códigos diferentes</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:29:11] diogo In Communist China, files share you!</em>
<p>sim, mas a responsabilidade da interface é garantir que a classe TEM a capacidade de executar determinada função e não COMO ela executará! ter dois códigos diferentes é realmente a idéia da interface.</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:29:15] diogo In Communist China, files share you!</em>
<p>é como um diploma.</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:31:01] diogo In Communist China, files share you!</em>
<p>no PHP ainda não tem como definir o retorno do método, mas em Java é praxe você garantir também o tipo de retorno, especializando ainda mais a Interface e diminuindo as chances de falha.</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/euler.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:31:49] paaaaaaaaaa&#8211;agora tomou susto num foi????</em>
<p>em Java tem como garantir o retorno do método?</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:32:25] diogo In Communist China, files share you!</em>
<p>sim. o método precisaria, por exemplo, retornar sempre uma instância de MeuArquivo.</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/euler.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:34:16] paaaaaaaaaa&#8211;agora tomou susto num foi????</em>
<p>bom, em PHP é só você fazer um método que retorne um objeto, daí você teria um método retornando uma instância..</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:34:52] diogo In Communist China, files share you!</em>
<p>sim. mas a interface não pode garantir isso. em Java a interface pode garantir o retorno, e se o método não retornar a instância corretamente, provavelmente nem compila.</p>
</blockquote>
<blockquote><p>
<img src="http://garotosopa.files.wordpress.com/2008/08/euler.jpg?w=48&#038;h=48" align="right" width="48" height="48" /></p>
<p style="color:#999;"><em>[19:35:30] paaaaaaaaaa&#8211;agora tomou susto num foi????</em>
<p>tow ligado..</p>
</blockquote>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/garotosopa.wordpress.com/54/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/garotosopa.wordpress.com/54/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/54/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/54/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/54/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/54/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/54/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/54/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/54/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/54/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/54/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/54/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=54&subd=garotosopa&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2008/08/14/interface-em-oop/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/2008/08/euler.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/euler.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/euler.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/euler.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/euler.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/euler.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/euler.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/euler.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/euler.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/euler.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/euler.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/euler.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/euler.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/euler.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/euler.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/euler.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/euler.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/euler.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/euler.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/webcam21.jpg" medium="image" />

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/euler.jpg" medium="image" />
	</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>Janelas maximizadas sem borda com o Devilspie</title>
		<link>http://garotosopa.wordpress.com/2008/03/23/janelas-maximizadas-sem-borda-com-o-devilspie/</link>
		<comments>http://garotosopa.wordpress.com/2008/03/23/janelas-maximizadas-sem-borda-com-o-devilspie/#comments</comments>
		<pubDate>Sun, 23 Mar 2008 22:59:02 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/2008/03/23/janelas-maximizadas-sem-borda-com-o-devilspie/</guid>
		<description><![CDATA[Sempre gostei de interfaces minimalistas, e uma coisa que estava me chateando ultimamente era o desperdício de espaço com a barra de título em algumas janelas que eu só utilizo maximizadas. Nada que o Devil&#8217;s Pie não resolva.
O Devil&#8217;s Pie funciona observando as janelas que são abertas e, pra cada janela que se encaixar em [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=44&subd=garotosopa&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Sempre gostei de interfaces minimalistas, e uma coisa que estava me chateando ultimamente era o desperdício de espaço com a barra de título em algumas janelas que eu só utilizo maximizadas. Nada que o Devil&#8217;s Pie não resolva.</p>
<p>O Devil&#8217;s Pie funciona observando as janelas que são abertas e, pra cada janela que se encaixar em alguma regra predefinida, executa as ações desejadas.</p>
<p>Dentre as opções de ação, é possível maximizar, definir tamanho, colocar a janela em fullscreen, jogar para outra workspace, definir posição, entre outras coisas. O que me interessou foi poder utilizar o recurso <strong>undecorate</strong> para remover a <em>window decoration</em>, a borda com a barra de título.</p>
<p><span id="more-44"></span><br />
O primeiro passo é instalá-lo:<br />
<code># <strong>aptitude install devilspie</strong></code></p>
<p>O Devil&#8217;s Pie lê todos os arquivos com extensão <strong>.ds</strong> localizados em <strong>~/.devilspie/</strong>, então, sem seguida, cria-se um arquivo com as regras e ações.</p>
<p><strong>~/.devilspie/fullscreen.ds</strong><br />
<code style="display:block;background:#eaeaea;">(if<br />
&nbsp;&nbsp;&nbsp;&nbsp;(and<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(or<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(is&nbsp;(window_class)&nbsp;"Firefox-bin")<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(is&nbsp;(window_class)&nbsp;"Xchat")<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(contains&nbsp;(window_property&nbsp;"_NET_WM_STATE")&nbsp;"_NET_WM_STATE_MAXIMIZED_VERT")<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(contains&nbsp;(window_property&nbsp;"_NET_WM_STATE")&nbsp;"_NET_WM_STATE_MAXIMIZED_HORZ")<br />
&nbsp;&nbsp;&nbsp;&nbsp;)<br />
&nbsp;&nbsp;&nbsp;&nbsp;(begin<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(undecorate)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(unmaximize)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(maximize)<br />
&nbsp;&nbsp;&nbsp;&nbsp;)<br />
)</code></p>
<p>Neste caso o script verifica <strong>se a janela é do Firefox ou Xchat e se estão maximizadas vertical e horizontalmente</strong> e, caso a janela se enquadre nestes critérios, a decoração é removida e a janela remaximizada.</p>
<p>As ações de <em>unmaximize</em> e <em>maximize</em> são necessárias porque após remover a decoração sobraria um espaço vazio.</p>
<p>Agora basta executar <strong>devilspie</strong> que as alterações serão feitas e, se for o caso, colocar o comando para ser executado ao iniciar o X.</p>
<h3>Firefox maximizado ainda com a barra de título</h3>
<p><img src='http://garotosopa.com/wp-content/uploads/2008/03/devilspie-antes.png' alt='Antes do Devil’s Pie' /></p>
<h3>Firefox maximizado sem borda com o Devil&#8217;s Pie</h3>
<p><img src='http://garotosopa.com/wp-content/uploads/2008/03/devilspie-depois.png' alt='Depois do Devil’s Pie' /></p>
<p>Uma forma de descobrir o <em>window_name</em> para utilizar na regra é criando um script qualquer, <em>~/.devilspie/debug.ds</em> por exemplo, com a ação <em>(debug)</em>. Ao executar o devilspie novamente, serão mostrados no terminal alguns detalhes das janelas.</p>
<p>Para conhecer outras regras e ações, recomendo <a href="http://foosel.org/linux/devilspie">este ótimo artigo sobre o Devil&#8217;s Pie</a>.</p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/garotosopa.wordpress.com/44/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/garotosopa.wordpress.com/44/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/44/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/44/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/44/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/44/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/44/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=44&subd=garotosopa&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2008/03/23/janelas-maximizadas-sem-borda-com-o-devilspie/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.com/wp-content/uploads/2008/03/devilspie-antes.png" medium="image">
			<media:title type="html">Antes do Devil’s Pie</media:title>
		</media:content>

		<media:content url="http://garotosopa.com/wp-content/uploads/2008/03/devilspie-depois.png" medium="image">
			<media:title type="html">Depois do Devil’s Pie</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>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>Diminuindo a fonte do GTK 1 para o XMMS</title>
		<link>http://garotosopa.wordpress.com/2008/01/19/diminuindo-a-fonte-do-gtk-1-para-o-xmms/</link>
		<comments>http://garotosopa.wordpress.com/2008/01/19/diminuindo-a-fonte-do-gtk-1-para-o-xmms/#comments</comments>
		<pubDate>Sat, 19 Jan 2008 14:58:24 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[linux]]></category>
		<category><![CDATA[xmms]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/2008/01/19/diminuindo-a-fonte-do-gtk-1-para-o-xmms/</guid>
		<description><![CDATA[As novas dependências do Audacious me fizeram voltar de vez para o XMMS; mas se tem algo que me irrita mais que pacotes esquisitos sendo instalados, são interfaces com fontes gigantes.
O XMMS, por utilizar o velho, feio e bobo GTK 1, era uma dessas interfaces. Contudo, foi só editar o arquivo /etc/gtk/gtkrc.utf-8 para resolver o [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=39&subd=garotosopa&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>As novas dependências do Audacious me fizeram voltar de vez para o XMMS; mas se tem algo que me irrita mais que pacotes esquisitos sendo instalados, são interfaces com fontes gigantes.</p>
<p>O XMMS, por utilizar o velho, feio e bobo GTK 1, era uma dessas interfaces. Contudo, foi só editar o arquivo /etc/gtk/gtkrc.utf-8 para resolver o problema :)<br />
<span id="more-39"></span></p>
<h3>XMMS antes:</h3>
<p><img src='http://garotosopa.files.wordpress.com/2008/01/xmms-gtk1-font-120.png' alt='XMMS com GTK 1 utilizando fontes grandes' /></p>
<p>Editando o arquivo <strong>/etc/gtk/gtkrc.utf-8</strong>:</p>
<p><code>style "default-text" {<br />
       fontset = "-*-arial-medium-r-normal--*-<strong>120</strong>-*-*-*-*-iso10646-1,\<br />
                  -*-helvetica-medium-r-normal--*-<strong>120</strong>-*-*-*-*-*-*"<br />
}<br />
class "GtkWidget" style "default-text"</code></p>
<p><strong>Troquei o tamanho da fonte de 120 para 80</strong> e bastou recarregar o XMMS para ter uma interface muito mais amigável.</p>
<h3>XMMS depois:</h3>
<p><img src='http://garotosopa.files.wordpress.com/2008/01/xmms-gtk1-font-80.png' alt='XMMS com GTK 1 utilizando fontes pequenas' /></p>
<p>Caso o sistema não esteja configurado em UTF-8, será necessário editar o arquivo <em>gtkrc</em> correspondente no diretório /etc/gtkrc/.</p>
<p>&#8230; e adeus Audacious-e-suas-dependências!</p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/garotosopa.wordpress.com/39/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/garotosopa.wordpress.com/39/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/39/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/39/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/39/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/39/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/39/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/39/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/39/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/39/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/39/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/39/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=39&subd=garotosopa&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2008/01/19/diminuindo-a-fonte-do-gtk-1-para-o-xmms/feed/</wfw:commentRss>
		<slash:comments>1</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/01/xmms-gtk1-font-120.png" medium="image">
			<media:title type="html">XMMS com GTK 1 utilizando fontes grandes</media:title>
		</media:content>

		<media:content url="http://garotosopa.files.wordpress.com/2008/01/xmms-gtk1-font-80.png" medium="image">
			<media:title type="html">XMMS com GTK 1 utilizando fontes pequenas</media:title>
		</media:content>
	</item>
	</channel>
</rss>