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

<channel>
	<title>garotosopa</title>
	<atom:link href="http://garotosopa.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://garotosopa.wordpress.com</link>
	<description>juntando as letrinhas desde 1986</description>
	<lastBuildDate>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</title>
		<link>http://garotosopa.wordpress.com</link>
	</image>
			<item>
		<title>Alterando software livre do jeito Debian &#8211; Patch para o Transmission</title>
		<link>http://garotosopa.wordpress.com/2009/10/05/alterando-software-livre-jeito-debian-patch-transmission/</link>
		<comments>http://garotosopa.wordpress.com/2009/10/05/alterando-software-livre-jeito-debian-patch-transmission/#comments</comments>
		<pubDate>Mon, 05 Oct 2009 12:00:34 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[linux]]></category>
		<category><![CDATA[debian]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[patch]]></category>
		<category><![CDATA[transmission]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://garotosopa.wordpress.com/?p=682</guid>
		<description><![CDATA[Um dos argumentos dos evangelistas de software livre é que, tendo acesso ao código fonte do programa, você altera o que quiser. Mas quem tem o mínimo de experiência em desenvolvimento sabe que o processo é um pouquinho trabalhoso.
Primeiro você baixa o código fonte do repositório oficial (às vezes tendo que baixar um programa diferente [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=682&subd=garotosopa&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Um dos argumentos dos evangelistas de software livre é que, tendo acesso ao <strong><span style="font-weight:normal;background-color:#df8;">código fonte</span></span></strong> do programa, você <strong><span style="font-weight:normal;background-color:#df8;">altera o que quiser</span></strong>. Mas quem tem o mínimo de experiência em desenvolvimento sabe que o processo é um <strong><span style="font-weight:normal;background-color:#df8;">pouquinho trabalhoso</span></strong>.</p>
<p>Primeiro você baixa o código fonte do repositório oficial (às vezes tendo que baixar um programa diferente de controle de versão), baixa todos os pacotes de desenvolvimento dependentes (quando eles dizem quais são), se familiariza com o código fonte (mesmo sem documentação), aprende uma nova linguagem e todas as APIs necessárias, tenta alterar e depois fica compilando até que tudo funcione (o que às vezes não ocorre).</p>
<p>Eu não sei vocês, mas só de imaginar tudo isso eu <strong><span style="font-weight:normal;background-color:#df8;">prefiro esperar</span></strong> e torcer pra que a funcionalidade que eu quero esteja disponível na versão seguinte.</p>
<p>Só que isso faz de você um <strong><span style="font-weight:normal;background-color:#df8;">mau menino</span></strong>, e os nerds olham feio pra você nos eventos de tecnologia e nas listas de discussão.</p>
<p>Abaixo você verá algumas <strong><span style="font-weight:normal;background-color:#df8;">etapas simples</span></strong> de como começar a <strong><span style="font-weight:normal;background-color:#df8;">alterar softwares</span></strong> utilizando os pacotes de <strong><span style="font-weight:normal;background-color:#df8;">source do Debian</span></strong> (Ubuntu ou qualquer derivado), através de passos reais que segui para adicionar uma pequena funcionalidade ao <a href="http://www.transmissionbt.com/">Transmission</a>, mesmo sem conhecer nada de C, Gtk ou do código fonte do programa (na verdade, ainda nem comecei, estou escrevendo o post e fazendo).</p>
<p>Prepare-se para <strong><span style="font-weight:normal;background-color:#df8;">impressionar as gatinhas</span></strong>!</p>
<p><span id="more-682"></span></p>
<h3>Baixando o código fonte e todas as dependências</h3>
<p>Antes de começar qualquer projeto de pacote Debian em C, é fundamental que você tenha o <em>essencial para construção</em> instalado, que inclui <strong><span style="font-weight:normal;background-color:#df8;">compilador e biblioteca para criar pacotes</span></strong>, além do pacote <em>fakeroot</em>, necessário ao montar o pacote no final de todas as etapas:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>/home/diogo/transmission# <strong><span style="background-color:#df8;">aptitude install build-essential fakeroot</span></strong></pre>
</div>
<p>Em seguida, baixe o <strong><span style="font-weight:normal;background-color:#df8;">fonte do programa</span></strong> que deseja alterar; no meu caso, o Transmission:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission$ <strong><span style="background-color:#df8;">apt-get source transmission</span></strong></pre>
</div>
<p>O comando <em>apt-get source</em> deve ser feito com o seu usuário mesmo, e não como root, apenas para baixar o código fonte no diretório atual.</p>
<p>Ao terminar, você terá os arquivos abaixo e todo o código fonte no diretório <em>transmission-1.75</em>:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission$ <strong>ls -l</strong>
total 6568
drwxr-x--- 15 diogo diogo    4096 2009-10-03 13:01 transmission-1.75
-rw-r-----  1 diogo diogo   17251 2009-09-20 19:30 transmission_1.75-1.diff.gz
-rw-r-----  1 diogo diogo    1519 2009-09-20 19:30 transmission_1.75-1.dsc
-rw-r-----  1 diogo diogo 6681496 2009-09-20 19:30 transmission_1.75.orig.tar.gz</pre>
</div>
<p>Depois, como root, é necessário instalar no sistema todas as <strong><span style="font-weight:normal;background-color:#df8;">bibliotecas necessárias para compilar</span></strong> o programa:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>/home/diogo/transmission# <strong><span style="background-color:#df8;">apt-get build-dep transmission</span></strong></pre>
</div>
<p>Aqui foi necessário baixar 70 pacotes (27MB) com todos os cabeçalhos (arquivos .h) e demais dependências necessárias. Talvez você queira copiar a lista de pacotes que o <em>apt-get</em> mostrou para poder removê-los depois de compilar o programa.</p>
<p>Finalizando, apenas para concluir o fluxo, assim que quiser <strong><span style="font-weight:normal;background-color:#df8;">compilar o programa e montar um pacote</span></strong>, basta executar o comando abaixo, a partir do diretório dos arquivos fonte:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission/transmission-1.75$ <strong><span style="background-color:#df8;">dpkg-buildpackage -rfakeroot -uc -b</span></strong></pre>
</div>
<p>O <strong><span style="font-weight:normal;background-color:#df8;">pacote <em>.deb</em> será gerado</span></strong> no diretório acima e poderá ser instalado com <em>dpkg -i nomedopacote.deb</em>.</p>
<h3>Alterando o código fonte</h3>
<p>Já tenho o código fonte e já sei como montar o pacote, mas <strong><span style="font-weight:normal;background-color:#df8;">não faço a menor idéia de como alterar</span></strong> o programa. Tentemos assim mesmo.</p>
<p>Sabendo que o Transmission é um cliente de torrent, o recurso que quero adicionar é poder <strong><span style="font-weight:normal;background-color:#df8;">salvar os arquivos no mesmo diretório onde está localizado o .torrent</span></strong>. Para isso, a idéia é incluir uma opção na tela de configuração como na montagem abaixo em vermelho:</p>
<p><img src="http://garotosopa.files.wordpress.com/2009/10/samedirectory.png?w=415&#038;h=356" alt="Included the checkbox: Save to the same directory as torrent file" title="Save to the same directory as torrent file" width="415" height="356" class="size-full wp-image-685" /></p>
<p>Antes de começar a bagunçar o código fonte que baixamos, é interessante fazer uma cópia do original para facilitar a geração de um <em>patch</em> depois:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission/transmission-1.75$ <strong><span style="background-color:#df8;">cp -r transmission-1.75/ transmission-1.75-original</span></strong></pre>
</div>
<p>Dando uma olhada no diretório do código fonte, temos o seguinte:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission/transmission-1.75$ <strong>ls -F</strong>
aclocal.m4     configure*    <strong><span style="font-weight:normal;background-color:#df8;">gtk/</span></strong>              Makefile.am  third-party/
AUTHORS        configure.ac  INSTALL           Makefile.in  transmission.spec.in
autogen.sh*    COPYING       install-sh*       missing*     Transmission.xcodeproj/
ChangeLog      daemon/       libtransmission/  NEWS         update-version-h.sh*
cli/           debian/       ltmain.sh*        po/          web/
config.guess*  depcomp*      m4/               qt/
config.sub*    doc/          macosx/           README</pre>
</div>
<p>Como estou interessado em alterar a interface Gtk, vamos ao seu diretório:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission/transmission-1.75/gtk$ <strong>ls -F</strong>
actions.c     icons.h         sexy-icon-entry.c        tr-core.h
actions.h     lock.h          sexy-icon-entry.h        tr-icon.c
add-dialog.c  logo.h          sexy-marshal.c           tr-icon.h
add-dialog.h  main.c          sexy-marshal.h           tr-prefs.c
<strong><span style="font-weight:normal;background-color:#df8;">conf.c</span></strong>        Makefile.am     stats.c                  tr-prefs.h
conf.h        Makefile.in     stats.h                  tr-torrent.c
details.c     makemeta-ui.c   torrent-cell-renderer.c  tr-torrent.h
details.h     makemeta-ui.h   torrent-cell-renderer.h  tr-window.c
dialogs.c     marshal.list    tracker-list.c           tr-window.h
dialogs.h     msgwin.c        tracker-list.h           turtles.h
file-list.c   msgwin.h        transmission.1           ui.h
file-list.h   notify.c        transmission.desktop.in  util.c
hig.c         notify.h        transmission.png         util.h
hig.h         options-icon.h  tr-core.c
icons/        relocate.c      tr-core-dbus.h
icons.c       relocate.h      tr-core-dbus.xml</pre>
</div>
<p>Mesmo não conhecendo nada sobre a estrutura do programa, depois de dar uma olhada no nome dos arquivos, um <strong><span style="font-weight:normal;background-color:#df8;">bom palpite é que o arquivo <em>conf.c</em></span></strong> esteja relacionado com o que preciso alterar, já que é o mais parecido com algo referente à janela de configuração. Edite-no-lo.</p>
<p>Como de praxe, o arquivo começa com alguns includes e em seguida passa para definições de funções. Todas estão com pelo menos uma linha de comentário e têm nomes legíveis. Até que um <strong><span style="font-weight:normal;background-color:#df8;">comentário chama atenção</span></strong>:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>/**
 * This is where we initialize the preferences file with the default values.
 * If you add a <strong><span style="font-weight:normal;background-color:#df8;">new preferences key, you /must/ add a default value here</span></strong>.
 */</pre>
</div>
<p>Vamos <strong><span style="font-weight:normal;background-color:#df8;">precisar adicionar uma <em>preference key</em></span></strong>, para determinar se o novo checkbox da janela de configuração está marcado ou não. Então, melhor <strong><span style="font-weight:normal;background-color:#df8;">seguir a recomendação do comentário</span></strong> e definir um valor padrão para a nova chave:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission$ <strong>diff -u transmission-1.75-original/gtk/conf.c transmission-1.75/gtk/conf.c</strong>
--- transmission-1.75-original/gtk/conf.c	2009-10-03 14:03:28.000000000 -0300
+++ transmission-1.75/gtk/conf.c	2009-10-03 14:20:54.000000000 -0300
@@ -192,6 +192,7 @@
 #endif
     if( !str ) str = tr_getDefaultDownloadDir( );
     tr_bencDictAddStr( d, TR_PREFS_KEY_DOWNLOAD_DIR, str );
+    <strong><span style="font-weight:normal;background-color:#df8;">tr_bencDictAddBool( d, PREF_KEY_DOWNLOAD_SAME_DIR, FALSE );</span></strong>

     tr_bencDictAddBool( d, PREF_KEY_ASKQUIT, TRUE );
</pre>
</div>
<p>Se você não está familiarizado com o <strong><span style="font-weight:normal;background-color:#df8;">commando <em>diff</em></span></strong>, basta saber que as primeiras linhas ali definem os arquivos comparados (o conf.c com o mesmo arquivo do diretório original), em seguida o numero da linha do trecho onde ocorreu a alteração, e logo abaixo a alteração: as linhas iniciadas com + foram adicionadas e com &#8211; removidas, as demais são apenas para referência da posição.</p>
<p>Contudo, a <strong><span style="font-weight:normal;background-color:#df8;">chave adicionada <em>PREF_KEY_DOWNLOAD_SAME_DIR</em> não existe ainda</span></strong>, foi inventada agora, e é necessário definí-la em algum lugar, que não sabemos onde. Meu primeiro palpite foi o arquivo <em>conf.h</em>, mas não tinha nada de relevante lá. Para não ter que ficar procurando arquivo por arquivo, vamos procurar onde uma outra chave qualquer já tenha sido definida:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission/transmission-1.75/gtk$ <strong><span style="background-color:#df8;">grep PREF_KEY_START *</span></strong>
conf.c:    tr_bencDictAddBool( d, PREF_KEY_START, TRUE );
tr-core.c:        tr_ctorSetPaused( ctor, TR_FORCE, !pref_flag_get( PREF_KEY_START ) );
tr-core.c:    const gboolean doStart = pref_flag_eval( start, PREF_KEY_START );
tr-prefs.c:    w = new_check_button( s, PREF_KEY_START, core );
tr-prefs.h:<strong><span style="font-weight:normal;background-color:#df8;">#define PREF_KEY_START</span></strong>                      "start-added-torrents"</pre>
</div>
<p>Pronto, agora sabemos que a definição de <em>PREF_KEY_START</em> (uma preferência de checkbox no mesmo lugar onde adicionaremos a nova) foi <strong><span style="font-weight:normal;background-color:#df8;">feita no arquivo <em>tr-prefs.h</em></span></strong>. Vamos lá adicionar nossa chave nova também:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission$ <strong>diff -u transmission-1.75-original/gtk/tr-prefs.h transmission-1.75/gtk/tr-prefs.h</strong>
--- transmission-1.75-original/gtk/tr-prefs.h	2009-10-03 14:03:28.000000000 -0300
+++ transmission-1.75/gtk/tr-prefs.h	2009-10-03 14:38:55.000000000 -0300
@@ -26,6 +26,7 @@
 #define PREF_KEY_INHIBIT_HIBERNATION        "inhibit-desktop-hibernation"
 #define PREF_KEY_DIR_WATCH                  "watch-dir"
 #define PREF_KEY_DIR_WATCH_ENABLED          "watch-dir-enabled"
+<strong><span style="font-weight:normal;background-color:#df8;">#define PREF_KEY_DOWNLOAD_SAME_DIR          "download-same-dir"</span></strong>
 #define PREF_KEY_SHOW_TRAY_ICON             "show-notification-area-icon"
 #define PREF_KEY_SHOW_DESKTOP_NOTIFICATION  "show-desktop-notification"
 #define PREF_KEY_START                      "start-added-torrents"</pre>
</div>
<p>Ainda olhando o resultado do último <em>grep</em>, é possível observar que o <strong><span style="font-weight:normal;background-color:#df8;">arquivo <em>tr-prefs.c</em> também será útil</span></strong>, pois nele tem uma <strong><span style="font-weight:normal;background-color:#df8;">chamada a <em>new_check_button</em></span></strong>, que apesar de não conhecer, dá a entender que cria um checkbox na janela de preferências. Editemos esse arquivo e adicionemos nosso checkbox novo:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission$ <strong>diff -u transmission-1.75-original/gtk/tr-prefs.c transmission-1.75/gtk/tr-prefs.c</strong>
--- transmission-1.75-original/gtk/tr-prefs.c	2009-10-03 14:03:28.000000000 -0300
+++ transmission-1.75/gtk/tr-prefs.c	2009-10-03 15:08:09.000000000 -0300
@@ -305,6 +305,10 @@
     w = new_path_chooser_button( TR_PREFS_KEY_DOWNLOAD_DIR, core );
     hig_workarea_add_row( t, &amp;row, _( "Save to _Location:" ), w, NULL );

+    <strong><span style="font-weight:normal;background-color:#df8;">s = _( "Save to the same directory as torrent file" );</span></strong>
+    <strong><span style="font-weight:normal;background-color:#df8;">w = new_check_button( s, PREF_KEY_DOWNLOAD_SAME_DIR, core );</span></strong>
+    <strong><span style="font-weight:normal;background-color:#df8;">hig_workarea_add_wide_control( t, &amp;row, w );</span></strong>
+
     hig_workarea_add_section_divider( t, &amp;row );
     hig_workarea_add_section_title( t, &amp;row, _( "Limits" ) );
 </pre>
</div>
<p>O trecho adicionado foi baseado numa opção já existente. Para o que precisamos, não é necessário saber pra que servem as funções utilizadas, apesar de que em alguns minutos é possível descobrir isso e se familiarizar melhor com o que está acontecendo.</p>
<p>Bem, a princípio, o <strong><span style="font-weight:normal;background-color:#df8;">checkbox</span></strong> para configurar se queremos salvar os arquivos no mesmo diretório foi <strong><span style="font-weight:normal;background-color:#df8;">adicionado</span></strong>. Falta só <strong><span style="font-weight:normal;background-color:#df8;">utilizar o valor desta opção na janela de adicionar torrents</span></strong>.</p>
<p>Olhando novamente o diretório <em>gtk</em>, o <strong><span style="font-weight:normal;background-color:#df8;">provável arquivo que monta a janela que precisamos é o <em>add-dialog.c</em></span></strong>. O que queremos nele é: caso o checkbox com a configuração <em>PREF_KEY_DOWNLOAD_SAME_DIR</em> esteja marcado, devemos usar o diretório do arquivo torrent ao invés do diretório configurado. Desta vez não teve muita mágica para encontrar onde mexer. A dica é ler as funções definidas e tentar identificar o que estamos procurando.</p>
<p>Dentro da <strong><span style="font-weight:normal;background-color:#df8;">função <em>addSingleTorrentDialog</em> no arquivo <em>add-dialog.c</em></span></strong> foi possível encontrar o seguinte trecho:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>    if( <strong><span style="font-weight:normal;background-color:#df8;">tr_ctorGetDownloadDir</span></strong>( ctor, TR_FORCE, <strong><span style="font-weight:normal;background-color:#df8;">&amp;str</span></strong> ) )
        g_assert_not_reached( );
    g_assert( str );

    data = g_new0( struct AddData, 1 );
    data-&gt;core = core;
    data-&gt;ctor = ctor;
    data-&gt;filename = g_strdup( tr_ctorGetSourceFile( ctor ) );
    <strong><span style="font-weight:normal;background-color:#df8;">data-&gt;downloadDir = g_strdup( str );</span></strong></pre>
</div>
<p>Julgando pelos nomes, a função <em>tr_ctorGetDownloadDir</em> preenche o diretório de download do torrent da variável <em>ctor</em> na variável <em>str</em>.</p>
<p>O que precisamos então é <strong><span style="font-weight:normal;background-color:#df8;">definir a variável <em>str</em> para o diretório do arquivo torrent</span></strong> caso o checkbox <em>PREF_KEY_DOWNLOAD_SAME_DIR</em> esteja marcado.</p>
<p>Olhando o trecho de código anterior, sabemos que o <strong><span style="font-weight:normal;background-color:#df8;">caminho do arquivo</span></strong> pode ser obtido através da função <em>tr_ctorGetSourceFile</em> e, ainda no mesmo arquivo, é possível ver que consultamos se o <strong><span style="font-weight:normal;background-color:#df8;">checkbox da configuração</span></strong> está marcado com a função <em>pref_flag_get</em>. A única coisa que fica faltando é conseguir o <strong><span style="font-weight:normal;background-color:#df8;">nome do diretório</span></strong> a partir do caminho completo.</p>
<p>É comum que o diretório de um caminho completo seja retornado pela função ou comando chamado <em>dirname</em>. Como <strong><span style="font-weight:normal;background-color:#df8;">não sei nada de C</span></strong> pra ter certeza de como fazer, dei um <em>grep</em> por <em>dirname</em> para saber como o resto do programa obtém essa informação. <strong><span style="font-weight:normal;background-color:#df8;">Achei</span></strong> o cabeçalho <em>libtransmission/utils.h</em> que define a <strong><span style="font-weight:normal;background-color:#df8;">função <em>tr_dirname</em></span></strong>. Tudo que eu precisava.</p>
<p>A alteração final, já incluindo o arquivo .h necessário para a função de diretório, ficou assim:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission$ <strong>diff -u transmission-1.75-original/gtk/add-dialog.c transmission-1.75/gtk/add-dialog.c</strong>
--- transmission-1.75-original/gtk/add-dialog.c	2009-10-03 14:03:28.000000000 -0300
+++ transmission-1.75/gtk/add-dialog.c	2009-10-03 15:26:40.000000000 -0300
@@ -17,6 +17,7 @@
 #include "file-list.h"
 #include "hig.h"
 #include "tr-prefs.h"
+<strong><span style="font-weight:normal;background-color:#df8;">#include "libtransmission/utils.h"</span></strong>

 /****
 *****
@@ -285,8 +286,12 @@
                                              GTK_RESPONSE_CANCEL,
                                              -1 );

-    if( tr_ctorGetDownloadDir( ctor, TR_FORCE, &amp;str ) )
-        g_assert_not_reached( );
+    if ( <strong><span style="font-weight:normal;background-color:#df8;">pref_flag_get( PREF_KEY_DOWNLOAD_SAME_DIR )</span></strong> ) {
+        str = <strong><span style="font-weight:normal;background-color:#df8;">tr_dirname</span></strong>( tr_strdup( <strong><span style="font-weight:normal;background-color:#df8;">tr_ctorGetSourceFile</span></strong>( ctor ) ) );
+    } else {
+        if( tr_ctorGetDownloadDir( ctor, TR_FORCE, &amp;str ) )
+            g_assert_not_reached( );
+    }
     g_assert( str );

     data = g_new0( struct AddData, 1 );</pre>
</div>
<p>O resto foi apenas <strong><span style="font-weight:normal;background-color:#df8;">baseado em código já existente</span></strong>.</p>
<h3>Compilando e instalando o pacote</h3>
<p>Para finalizar, basta deixar que o Debian compile e gere o pacote:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission/transmission-1.75$ <strong><span style="background-color:#df8;">dpkg-buildpackage -rfakeroot -uc -b</span></strong></pre>
</div>
<p>Em seguida, para instalar o pacote que foi gerado no diretório acima do diretório do código fonte, execute como root:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>/home/diogo/transmission# <strong><span style="background-color:#df8;">dpkg -i transmission-gtk_1.75-1_amd64.deb</span></strong></pre>
</div>
<h3>Gerando um patch</h3>
<p>A forma universal de trocar alterações em código é através de patch, um arquivo com todos os <em>diff</em>&#8217;s mostrados acima.</p>
<p>Mas antes de criar o patch, é preciso remover alguns arquivos gerados pela compilação:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission/transmission-1.75$ <strong><span style="background-color:#df8;">dpkg-buildpackage -rfakeroot -Tclean</span></strong></pre>
</div>
<p>Agora é possível utilizar o <em>diff</em> para comparar o diretório original com o diretório onde as alterações foram feitas:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission$ <strong><span style="background-color:#df8;">diff -ru transmission-1.75-original/ transmission-1.75/ &gt; download-same-directory.diff</span></strong></pre>
</div>
<p>Ao enviar o patch para alguém ou para simplesmente aplicá-lo no diretório original, basta fazer:</p>
<div style="margin-bottom:10px;background-color:#eaeaea;color:000;border-left:3px solid #ccc;padding:5px;">
<pre>~/transmission/transmission-1.75-original$ <strong><span style="background-color:#df8;">patch -p1 &lt; ../download-same-directory.diff</span></strong>
patching file gtk/add-dialog.c
patching file gtk/conf.c
patching file gtk/tr-prefs.c
patching file gtk/tr-prefs.h</pre>
</div>
<p>Se você abrir o patch vai reparar que o caminho para os arquivos inicia com o nome dos diretórios <em>transmission-1.75-original</em> e <em>transmission-1.75</em>. O argumento <em>-p1</em> do <em>patch</em> é justamente para ignorar esse primeiro pedaço do path, uma vez que já estamos no diretório onde as alterações devem ser aplicadas.</p>
<h3>Considerações finais</h3>
<p>Esta alteração, na verdade, foi extremamente <strong><span style="font-weight:normal;background-color:#df8;">simples e com fim didático</span></strong>. Para modificações reais, é fundamental ter <strong><span style="font-weight:normal;background-color:#df8;">mais dedicação</span></strong> para entender a estrutura do projeto e produzir um <strong><span style="font-weight:normal;background-color:#df8;">patch de qualidade</span></strong>, que eventualmente possa ser <strong><span style="font-weight:normal;background-color:#df8;">utilizado pelo autor</span></strong>. No caso mostrado, por exemplo, é provável que a melhor abordagem seria alterar o <em>downloadDir</em> do <em>optional_args</em> do <em>tr_ctor</em>, mas seria mais chato para descrever neste post.</p>
<p>Os passos acima são voltados mais para <strong><span style="font-weight:normal;background-color:#df8;">começar com pequenas alterações de forma prática, sem ter que participar ativamente do projeto</span></strong>.</p>
<p>Caso deseje realmente participar, a melhor forma continua sendo utilizar o <strong><span style="font-weight:normal;background-color:#df8;">repositório oficial</span></strong> e interagir com os <strong><span style="font-weight:normal;background-color:#df8;">colaboradores</span></strong>, até mesmo pra saber se a sua idéia já não está em desenvolvimento ou se você pode coloborar com tarefas mais importantes.</p>
<p>Além disso, é bem comum que os desenvolvedores <strong><span style="font-weight:normal;background-color:#df8;">não aceitem um patch</span></strong> porque ele foi feito baseado no <strong><span style="font-weight:normal;background-color:#df8;">código de uma versão anterior</span></strong> ao trunk / head (que é o caso dos releases de pacotes do Debian), não sendo mais possível aplicá-lo depois de tantas alterações na versão de desenvolvimento.</p>
<p>Já estou até imaginando a galera toda alterando seus programas agora&#8230; <strong><span style="font-weight:normal;background-color:#df8;">Boa sorte!</span></strong></p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/garotosopa.wordpress.com/682/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/garotosopa.wordpress.com/682/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/garotosopa.wordpress.com/682/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/garotosopa.wordpress.com/682/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/garotosopa.wordpress.com/682/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/garotosopa.wordpress.com/682/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/garotosopa.wordpress.com/682/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/garotosopa.wordpress.com/682/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/garotosopa.wordpress.com/682/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/garotosopa.wordpress.com/682/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=garotosopa.wordpress.com&blog=954761&post=682&subd=garotosopa&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://garotosopa.wordpress.com/2009/10/05/alterando-software-livre-jeito-debian-patch-transmission/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f427a182ea6627ec1e874ff21a5ad2d7?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">garotosopa</media:title>
		</media:content>

		<media:content url="http://garotosopa.files.wordpress.com/2009/10/samedirectory.png" medium="image">
			<media:title type="html">Save to the same directory as torrent file</media:title>
		</media:content>
	</item>
		<item>
		<title>Pequena utilidade para variáveis estáticas</title>
		<link>http://garotosopa.wordpress.com/2009/09/09/pequena-utilidade-para-variaveis-estaticas/</link>
		<comments>http://garotosopa.wordpress.com/2009/09/09/pequena-utilidade-para-variaveis-estaticas/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 12:50:10 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[PHP]]></category>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		<media:content url="http://garotosopa.files.wordpress.com/2008/08/euler.jpg" medium="image" />
	</item>
		<item>
		<title>Chat PHP com XHR Long Polling</title>
		<link>http://garotosopa.wordpress.com/2008/07/27/chat-php-com-xhr-long-polling/</link>
		<comments>http://garotosopa.wordpress.com/2008/07/27/chat-php-com-xhr-long-polling/#comments</comments>
		<pubDate>Sun, 27 Jul 2008 22:55:09 +0000</pubDate>
		<dc:creator>garotosopa</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[chat]]></category>
		<category><![CDATA[comet]]></category>
		<category><![CDATA[long polling]]></category>
		<category><![CDATA[xhr]]></category>

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

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

		<media:content url="http://garotosopa.com/wp-content/uploads/2008/03/devilspie-antes.png" medium="image">
			<media:title type="html">Antes do Devil’s Pie</media:title>
		</media:content>

		<media:content url="http://garotosopa.com/wp-content/uploads/2008/03/devilspie-depois.png" medium="image">
			<media:title type="html">Depois do Devil’s Pie</media:title>
		</media:content>
	</item>
	</channel>
</rss>