<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>garotosopa &#187; Javascript</title>
	<atom:link href="http://garotosopa.wordpress.com/category/javascript/feed/" rel="self" type="application/rss+xml" />
	<link>http://garotosopa.wordpress.com</link>
	<description>juntando as letrinhas desde 1986</description>
	<lastBuildDate>Mon, 05 Oct 2009 12:00:34 +0000</lastBuildDate>
	<generator>http://wordpress.com/</generator>
	<language>pt-br</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<cloud domain='garotosopa.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://www.gravatar.com/blavatar/1aa997062c21c77622f350c2011b4705?s=96&#038;d=http://s.wordpress.com/i/buttonw-com.png</url>
		<title>garotosopa &#187; Javascript</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[alert]]></category>
		<category><![CDATA[disable]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[preference]]></category>
		<category><![CDATA[settings]]></category>

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

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

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

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

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

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

		<media:content url="http://garotosopa.files.wordpress.com/2008/11/dscatalogdemoappnc.png" medium="image">
			<media:title type="html">DSL Catalog Banco de dados da Aplicação de exemplo</media:title>
		</media:content>
	</item>
		<item>
		<title>Comet &#8211; Server Push com XHR Multipart</title>
		<link>http://garotosopa.wordpress.com/2008/09/21/comet-server-push-xhr-multipart/</link>
		<comments>http://garotosopa.wordpress.com/2008/09/21/comet-server-push-xhr-multipart/#comments</comments>
		<pubDate>Sun, 21 Sep 2008 20:00:06 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[comet]]></category>
		<category><![CDATA[server push]]></category>

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

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