<?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: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>
	<pubDate>Fri, 12 Dec 2008 21:55:43 +0000</pubDate>
	<generator>http://wordpress.org/?v=MU</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>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[dicas]]></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 [...]]]></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>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<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>
	
		<media:content url="http://www.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=identicon" 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 [...]]]></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>Teste online</h3>
<p>A aplicação de exemplo está disponível para testes no seguinte link:</p>
<p><span style="font-size:125%;"><a href="http://garotosopa.com/dslcatalog-r39/demo/public/index.php">http://garotosopa.com/dslcatalog-r39/demo/public/index.php</a></span></p>
<p>Foi publicada a versão da revisão 39, onde até então não houve nenhuma preocupação com compatibilidade do autocomplete <del datetime="00">em todos os browsers</del> <ins datetime="00">no Internet Explorer</ins>. Sugiro que teste no Firefox ou Opera.</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>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<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>
	
		<media:content url="http://www.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=identicon" 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 [...]]]></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 - 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 - 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 - 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>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<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>
	
		<media:content url="http://www.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=identicon" 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[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 diversos métodos que retornam uma lista de acordo com diferentes critérios. As consultas ficam próximas do seguinte:
$alunos&#160;=&#160;new&#160;Alunos();
&#160;
$alunosDoRio&#160;=&#160;$alunos-&#62;getPorCidade(&#39;Rio de Janeiro&#39;);
/* [...]]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><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>
<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>
<h3>Referências</h3>
<ul>
<li>Martin Fowler - 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 - 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>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<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>
	
		<media:content url="http://www.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=identicon" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>
	</item>
		<item>
		<title>Comet - 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 [...]]]></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>&#8220;</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(&#8217;GET&#8217;, &#8217;script-multipart.php&#8217;, 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(&#8217;Content-type: multipart/x-mixed-replace;boundary=&#8221;delimitador&#8221;&#8216;);<br />
echo &#8220;<code>-</code><code>-</code>delimitador\n&#8221;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
while( true ){<br />
&nbsp;&nbsp;&nbsp;&nbsp;echo &#8220;Content-type: text/plain\n\n&#8221;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;echo date(&#8221;d/m/Y H:i:s&#8221;), &#8220;\n&#8221;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;echo &#8220;<code>-</code><code>-</code>delimitador\n&#8221;;<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(&#8217;Microsoft.XMLHTTP&#8217;);<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(&#8217;GET&#8217;, &#8217;script-multipart.php?multipart&#8217;, true);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}else{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xhr.open(&#8217;GET&#8217;, &#8217;script-multipart.php&#8217;, 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(&#8217;Content-type: multipart/x-mixed-replace;boundary=&#8221;delimitador&#8221;&#8216;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;echo &#8220;<code>-</code><code>-</code>delimitador\n&#8221;;<br />
}<br />
while( true ){<br />
&nbsp;&nbsp;&nbsp;&nbsp;if( isset($_GET['multipart']) ){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo &#8220;Content-type: text/plain\n\n&#8221;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;echo date(&#8221;d/m/Y H:i:s&#8221;), &#8220;\n&#8221;;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;if( isset($_GET['multipart']) ){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo &#8220;<code>-</code><code>-</code>delimitador\n&#8221;;<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(&#8217;GET&#8217;, &#8217;script-multipart.php&#8217;, 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>
<ul>
<li><a href="http://garotosopa.com/chat-multipart.cgi">Chat funcionando</a></li>
<li><a href="http://garotosopa.com/chat-multipart.html">Código fonte com highlight</a></li>
<li><a href="http://garotosopa.com/chat-multipart.zip">Código fonte para download</a></li>
</ul>
<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