<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1762227843073442838</id><updated>2011-11-27T16:33:45.421-08:00</updated><category term='View Helper'/><category term='firefox'/><category term='Filter'/><category term='eeebuntu'/><category term='Plugin'/><category term='Transliteration'/><category term='comparative'/><category term='add-ons'/><category term='microtime'/><category term='Zend Framework'/><category term='complementos'/><category term='ubuntu'/><category term='eeepc'/><category term='Peacekeeper'/><category term='browsers'/><category term='Zend_Db_Table'/><title type='text'>Jaime Neto</title><subtitle type='html'>desenvolvimento para web</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://jaime-neto.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1762227843073442838/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://jaime-neto.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Jaime Neto</name><uri>http://www.blogger.com/profile/13866935986425738332</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_RAVPPc4er_Q/TMA_EKJjx6I/AAAAAAAAAIY/VigCHJ4RlQY/S220/jaimeneto.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>9</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1762227843073442838.post-6174623429410507517</id><published>2011-06-24T10:40:00.000-07:00</published><updated>2011-06-24T14:45:27.621-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Zend Framework'/><category scheme='http://www.blogger.com/atom/ns#' term='Plugin'/><category scheme='http://www.blogger.com/atom/ns#' term='View Helper'/><category scheme='http://www.blogger.com/atom/ns#' term='microtime'/><title type='text'>Cálculo de tempo decorrido com ZF</title><content type='html'>Não é muito raro vermos em alguns sites, principalmente no rodapé, a informação do tempo decorrido para exibir uma página. E nos sites em PHP, geralmente é usado a função &lt;code&gt;microtime&lt;/code&gt; para calcular esse tempo, chamando-a antes e depois do trecho de código que queremos calcular o tempo de execução, e depois subtraindo o primeiro do último.&lt;br /&gt;&lt;br /&gt;Isso é muito útil, principalmente para trabalharmos na melhora da performance do código. Foi daí que me deu a idéia de criar um plugin para Zend Framework para facilitar o uso dessa função, e eis o resultado:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;class My_Controller_Plugin_ElapsedTime &lt;br /&gt;    extends Zend_Controller_Plugin_Abstract&lt;br /&gt;{&lt;br /&gt;  /*&lt;br /&gt;   * Constantes que serão usadas para identificar a partir de &lt;br /&gt;   * que parte da execução deseja-se calcular o tempo decorrido. &lt;br /&gt;   * O nome das constantes é baseado no nome das funções que &lt;br /&gt;   * inicializam os valores correspondentes na propriedade &lt;br /&gt;   * $_startTime, logo abaixo &lt;br /&gt;   */&lt;br /&gt;  const EVENT_ROUTE_STARTUP = 1;&lt;br /&gt;  const EVENT_ROUTE_SHUTDOWN = 2;&lt;br /&gt;  const EVENT_DISPATCH_LOOP_STARTUP = 3;&lt;br /&gt;  const EVENT_PRE_DISPATCH = 4;&lt;br /&gt;  const EVENT_POST_DISPATCH = 5;&lt;br /&gt;  const EVENT_DISPATCH_LOOP_SHUTDOWN = 6;&lt;br /&gt;&lt;br /&gt;  // Guarda o tempo de inicialização de cada parte da execução&lt;br /&gt;  static protected $_startTime = array(&lt;br /&gt;    self::EVENT_ROUTE_STARTUP =&gt; null,&lt;br /&gt;    self::EVENT_ROUTE_SHUTDOWN =&gt; null,&lt;br /&gt;    self::EVENT_DISPATCH_LOOP_STARTUP =&gt; null,&lt;br /&gt;    self::EVENT_PRE_DISPATCH =&gt; null,&lt;br /&gt;    self::EVENT_POST_DISPATCH =&gt; null,&lt;br /&gt;    self::EVENT_DISPATCH_LOOP_SHUTDOWN =&gt; null&lt;br /&gt;  );&lt;br /&gt;&lt;br /&gt;  // Define o tempo de inicialização antes de as rotas serem &lt;br /&gt;  // inicializadas&lt;br /&gt;  public function routeStartup(&lt;br /&gt;     Zend_Controller_Request_Abstract $request)&lt;br /&gt;  {&lt;br /&gt;    self::$_startTime[self::EVENT_ROUTE_STARTUP] = &lt;br /&gt;        $this-&gt;microtime();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // Define o tempo de inicialização depois de as rotas serem &lt;br /&gt;  // inicializadas&lt;br /&gt;  public function routeShutdown(&lt;br /&gt;     Zend_Controller_Request_Abstract $request)&lt;br /&gt;  {&lt;br /&gt;    self::$_startTime[self::EVENT_ROUTE_SHUTDOWN] = &lt;br /&gt;        $this-&gt;microtime();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // Define o tempo de inicialização antes de iniciar o loop &lt;br /&gt;  // de dispatch&lt;br /&gt;  public function dispatchLoopStartup(&lt;br /&gt;      Zend_Controller_Request_Abstract $request)&lt;br /&gt;  {&lt;br /&gt;    self::$_startTime[self::EVENT_DISPATCH_LOOP_STARTUP] = &lt;br /&gt;        $this-&gt;microtime();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // Define o tempo de inicialização antes do dispatch de &lt;br /&gt;  // uma action&lt;br /&gt;  public function preDispatch(&lt;br /&gt;      Zend_Controller_Request_Abstract $request)&lt;br /&gt;  {&lt;br /&gt;    self::$_startTime[self::EVENT_PRE_DISPATCH] = &lt;br /&gt;        $this-&gt;microtime();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // Define o tempo de inicialização depois do dispatch de &lt;br /&gt;  // uma action&lt;br /&gt;  public function postDispatch(&lt;br /&gt;      Zend_Controller_Request_Abstract $request)&lt;br /&gt;  {&lt;br /&gt;    self::$_startTime[self::EVENT_POST_DISPATCH] = &lt;br /&gt;        $this-&gt;microtime();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // Define o tempo de inicialização depois de finalizar o &lt;br /&gt;  // loop de dispatch&lt;br /&gt;  public function dispatchLoopShutdown()&lt;br /&gt;  {&lt;br /&gt;    self::$_startTime[self::EVENT_DISPATCH_LOOP_SHUTDOWN] = &lt;br /&gt;        $this-&gt;microtime();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  /**&lt;br /&gt;   * Retorna o tempo de inicialização de cada evento do plugin, &lt;br /&gt;   * ou de um evento específico, que pode ser passado como &lt;br /&gt;   * parâmetro baseado no valor das contantes desta classe&lt;br /&gt;   * &lt;br /&gt;   * @param int $event&lt;br /&gt;   * @return mixed Float se receber $event, senão, array&lt;br /&gt;   */&lt;br /&gt;  public function getStartTime($event=null)&lt;br /&gt;  {&lt;br /&gt;    if ($event) {&lt;br /&gt;      if (!isset(self::$_startTime[$event])) {&lt;br /&gt;        throw new Zend_Exception('Invalid value for $event: ' &lt;br /&gt;           . $event);&lt;br /&gt;      }&lt;br /&gt;      return self::$_startTime[$event];&lt;br /&gt;    }&lt;br /&gt;    return self::$_startTime;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  /**&lt;br /&gt;   * Calcula o tempo decorrido de um trecho e código.&lt;br /&gt;   * &lt;br /&gt;   * @param int $event&lt;br /&gt;   * @return float&lt;br /&gt;   */&lt;br /&gt;  public function getElapsedTime(&lt;br /&gt;     $event=self::EVENT_ROUTE_STARTUP)&lt;br /&gt;  {&lt;br /&gt;    $startTime = $this-&gt;getStartTime($event);&lt;br /&gt;&lt;br /&gt;    // Lança uma excessão Caso o evento não tenha sido &lt;br /&gt;    // inicializado ainda&lt;br /&gt;    if (!$startTime) {&lt;br /&gt;      throw new Zend_Exception('Event has not been '&lt;br /&gt;        . 'initialized yet');&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Pega o microtime atual e substrai dele o tempo &lt;br /&gt;    // inicial para calcular o tempo decorrido&lt;br /&gt;    $endTime = $this-&gt;microtime();&lt;br /&gt;    $elapsedTime = $endTime - $startTime;&lt;br /&gt;&lt;br /&gt;    return $elapsedTime;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  /**&lt;br /&gt;   * Pega o microtime em formato float, levando em conta as &lt;br /&gt;   * variações sofridas pela função de acordo com a versão do &lt;br /&gt;   * PHP&lt;br /&gt;   */&lt;br /&gt;  private function _microtime()&lt;br /&gt;  {&lt;br /&gt;    if (version_compare(PHP_VERSION, '5.0.0', '&gt;=')) {&lt;br /&gt;      // O parâmetro já converte o restulado da função para &lt;br /&gt;      // float a partir da versão 5.0.0&lt;br /&gt;      return microtime(true);&lt;br /&gt;    } else {&lt;br /&gt;      // Antes da versão 5.0.0, a conversão para float tinha &lt;br /&gt;      // que ser feita manualmente&lt;br /&gt;      list($usec, $sec) = explode(" ", microtime());&lt;br /&gt;      return ((float)$usec + (float)$sec);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;Ufa, parece coisa demais pra uma coisa tão simples, não é? Mas tudo isso nos dá a possibilidade de medir o tempo de execução a partir de várias partes diferentes do código, que é uma facilidade que os plugins do ZF nos oferece, então, por que não aproveitar isso pra fazer um plugin mais completo, não é? &lt;br /&gt;&lt;br /&gt;Feito o plugin, agora vamos ao View Helper, que vai se encarregar de pegar o valor definido no plugin e subtraí-lo de um novo &lt;code&gt;microtime&lt;/code&gt; para exibir na página:&lt;br /&gt;&lt;pre&gt;class My_View_Helper_ElapsedTime &lt;br /&gt;     extends Zend_View_Helper_Abstract&lt;br /&gt;{&lt;br /&gt;  /**&lt;br /&gt;   * Exibe o tempo decorrido de um trecho de código &lt;br /&gt;   * baseado nos valores inicializados no plugin &lt;br /&gt;   * 'My_Controller_Plugin_ElapsedTime'&lt;br /&gt;   * &lt;br /&gt;   * @param int $precision&lt;br /&gt;   * @param string|Zend_Locale $locale&lt;br /&gt;   * @return float&lt;br /&gt;   * @throws Zend_Exception&lt;br /&gt;   */&lt;br /&gt;  public function elapsedTime($precision = null, &lt;br /&gt;      $locale = null, $event = &lt;br /&gt;      My_Controller_Plugin_ElapsedTime::EVENT_ROUTE_STARTUP)&lt;br /&gt;  {&lt;br /&gt;    $pluginClass = 'My_Controller_Plugin_ElapsedTime';&lt;br /&gt;&lt;br /&gt;    // Verifica se o plugin foi registrado&lt;br /&gt;    if (!Zend_Controller_Front::getInstance()&lt;br /&gt;            -&gt;hasPlugin($pluginClass)) {&lt;br /&gt;      throw new Exception("Plugin '{$_pluginClass}' is not '&lt;br /&gt;          . 'registered");&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Primeiro vamos pegar o plugin lá do front controller, &lt;br /&gt;    // que já foi inicializado&lt;br /&gt;    $elapsedTimePlugin = Zend_Controller_Front::getInstance()&lt;br /&gt;         -&gt;getPlugin($pluginClass);&lt;br /&gt;    &lt;br /&gt;    // Agora vamos pegar o valor calculado do tempo decorrido, &lt;br /&gt;    // passando como parâmetro uma daquelas constantes definidas &lt;br /&gt;    // na classe do plugin, pra dizer a partir de que ponto do &lt;br /&gt;    // código onde calcular o tempo de execução. O padrão é de &lt;br /&gt;    // antes da inicialização das rotas.&lt;br /&gt;    $elapsedTime = $elapsedTimePlugin-&gt;getElapsedTime($event);&lt;br /&gt;&lt;br /&gt;    // Retorna o tempo decorrido formatado, levando em conta o &lt;br /&gt;    // número de decimais a ser exibido e a localização, para &lt;br /&gt;    // apresentar os símbolos de separação de milhares e de &lt;br /&gt;    // decimais corretos&lt;br /&gt;    return Zend_Locale_Format::toFloat($elapsedTime, array(&lt;br /&gt;      'precision' =&gt; $precision, 'locale' =&gt; $locale));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;Agora é só chamar o view helper lá no script pra exibir o tempo? Não, ainda falta uma coisa. É preciso inicializar o plugin primeiro. Basta colocar lá no &lt;code&gt;application.ini&lt;/code&gt; uma linhazinha de código, que ele será inicializado automaticamente:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;resources.frontController.plugins[] = My_Controller_Plugin_ElapsedTime&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Agora sim, vamos ao script &lt;code&gt;phtml&lt;/code&gt; chamar nosso view helper e ver ele funcionando:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Essa página foi carregada em &amp;lt;?php echo $this-&gt;elapsedTime(2) ?&amp;gt; segundos&lt;/pre&gt;Agora vamos experimentar alterar os parâmetros pra ver os tempo decorrido a partir de diferentes trechos do código:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;ul&amp;gt;&amp;lt;?php &lt;br /&gt;$events = array(&lt;br /&gt;  1 =&gt; 'routeStartup',&lt;br /&gt;  2 =&gt; 'routeShutdown',&lt;br /&gt;  3 =&gt; 'dispatchLoopStartup',&lt;br /&gt;  4 =&gt; 'preDispatch',&lt;br /&gt;  5 =&gt; 'postDispatch',&lt;br /&gt;//  6 =&gt; 'dispatchLoopShutdown'&lt;br /&gt;);&lt;br /&gt;foreach($events as $eventId =&gt; $eventName) {&lt;br /&gt;  echo '&amp;lt;li&amp;gt;' . $eventName . ': ' &lt;br /&gt;     . $this-&gt;elapsedTime(2, 'pt_BR', $eventId) &lt;br /&gt;     . ' segundos&amp;lt;/li&amp;gt;';&lt;br /&gt;}  &lt;br /&gt;?&amp;gt;&amp;lt;/ul&amp;gt;&lt;/pre&gt;O último tipo de evento (dispatchLoopShutdown) ficou comentado por uma boa razão. Quando a view é executada, esse ponto do código ainda não foi alcançado, portanto será lançada uma excessão, como foi definido na classe do plugin. Esse caso é usado mais para fins de debug mesmo, e para ver o resultado desse cálculo, é preciso chamar o plugin diretamente do front controller. Um exemplo, é chamá-lo no index.php no fim do arquivo:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$application-&gt;bootstrap()-&gt;run();&lt;br /&gt;echo Zend_Controller_Front::getInstance()&lt;br /&gt;    -&gt;getPlugin('Case_Controller_Plugin_ElapsedTime')&lt;br /&gt;    -&gt;getElapsedTime(6);&lt;/pre&gt;Prontinho. Façam bom proveito!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1762227843073442838-6174623429410507517?l=jaime-neto.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jaime-neto.blogspot.com/feeds/6174623429410507517/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://jaime-neto.blogspot.com/2011/06/calculo-de-tempo-decorrido-com-zf.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1762227843073442838/posts/default/6174623429410507517'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1762227843073442838/posts/default/6174623429410507517'/><link rel='alternate' type='text/html' href='http://jaime-neto.blogspot.com/2011/06/calculo-de-tempo-decorrido-com-zf.html' title='Cálculo de tempo decorrido com ZF'/><author><name>Jaime Neto</name><uri>http://www.blogger.com/profile/13866935986425738332</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_RAVPPc4er_Q/TMA_EKJjx6I/AAAAAAAAAIY/VigCHJ4RlQY/S220/jaimeneto.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1762227843073442838.post-3655133961557694999</id><published>2011-06-20T18:39:00.000-07:00</published><updated>2011-06-20T19:38:55.113-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Zend Framework'/><category scheme='http://www.blogger.com/atom/ns#' term='Filter'/><category scheme='http://www.blogger.com/atom/ns#' term='View Helper'/><category scheme='http://www.blogger.com/atom/ns#' term='Transliteration'/><title type='text'>Filtro de transliteração para o ZF</title><content type='html'>Já por várias vezes trabalhando em sites, tive a necessidade de converter strings para um formato sem acentos, cedilha, espaços, caracteres especiais, ou letras maiúsculas. Seja pra renomear um arquivo, renomear o título de uma notícia para a url ou criar um &lt;em&gt;alias&lt;/em&gt; para um nome de usuário, a idéia é sempre a mesma, ou no mínimo muito semelhante. Isso é chamado &lt;a href="http://pt.wikipedia.org/wiki/Translitera%C3%A7%C3%A3o"&gt;transliteração&lt;/a&gt;, ou mais comumente, em inglês &lt;em&gt;transliteration&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;Procurando na internet achei várias expressões regulares que fazem o trabalho, mas nenhuma dela tinha tudo que eu queria, então resolvi fazer uma classe seguindo o modelo de classes do Zend Framework, e acabei fazendo duas: uma de filtro, e um &lt;em&gt;view helper&lt;/em&gt;, que usa o filtro.&lt;br /&gt;&lt;pre&gt;class My_Filter_Transliterate implements Zend_Filter_Interface &lt;br /&gt;{&lt;br /&gt;  public function filter($string)&lt;br /&gt;  {&lt;br /&gt;     &lt;span style="color:#ccc"&gt;// Lista de caracteres que devem ser substituídos&lt;/span&gt;&lt;br /&gt;     $a = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ$ßàáâãäåæ@çèéêë&amp;amp;'&lt;br /&gt;        . 'ìíîïðñòóôõöøùúûüýýþÿŔŕ°ºª,.;:\|/"^~*%# ()[]{}=!?`‘’' &lt;br /&gt;        . "'";&lt;br /&gt;&lt;br /&gt;     &lt;span style="color:#ccc"&gt;// Lista que irá substituir os caracteres acima&lt;/span&gt;&lt;br /&gt;     $b = 'aaaaaaaceeeeiiiidnoooooouuuuybssaaaaaaaaceeeee'&lt;br /&gt;        . 'iiiidnoooooouuuuyybyRrooa--------------------------' &lt;br /&gt;        . '-';&lt;br /&gt;&lt;br /&gt;     &lt;span style="color:#ccc"&gt;// Efetua a substituição&lt;/span&gt;&lt;br /&gt;     $string = strtr($string, $a, $b); &lt;br /&gt;&lt;br /&gt;     &lt;span style="color:#ccc"&gt;// Deixa tudo minúsculo&lt;/span&gt;&lt;br /&gt;     $string = strtolower($string);&lt;br /&gt;&lt;br /&gt;     &lt;span style="color:#ccc" &gt;// Evita hífens repetidos&lt;/span&gt;&lt;br /&gt;     $string = preg_replace('/--+/', '-', $string); &lt;br /&gt;     return $string;&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Pronto, tá feito o filtro. Agora pra usar em qualquer lugar, é só instanciar o filtro e chamar a função &lt;code&gt;filter()&lt;/code&gt;. Como no exemplo:&lt;br /&gt;&lt;pre&gt;$filterTransliterate = new My_Filter_Transliterate();&lt;br /&gt;$string = 'Já não era sem tempo de Jaime lançar um post novo '&lt;br /&gt;        . 'nesse blog!!!';&lt;br /&gt;echo $filterTransliterate-&amp;gt;filter($string);&lt;br /&gt;&lt;span style="color:#ccc"&gt;// ja-nao-era-sem-tempo-de-jaime-lancar-um-post-novo-nesse-blog-&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;Agora, só pra facilitar ainda mais, vamos criar um &lt;em&gt;view helper&lt;/em&gt; pra usarmos nos nossos &lt;em&gt;scripts&lt;/em&gt;.&lt;br /&gt;&lt;pre&gt;class My_View_Helper_Transliterate &lt;br /&gt;    extends Zend_View_Helper_Abstract&lt;br /&gt;{&lt;br /&gt;  public function transliterate($value)&lt;br /&gt;  {&lt;br /&gt;      $filterTransliterate = new My_Filter_Transliterate();&lt;br /&gt;      return = $filterAlias-&amp;gt;filter($value);&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Simples assim... Agora, dentro dos arquivos de layout ou view, é só chamar como no exemplo abaixo:&lt;br /&gt;&lt;code&gt;&amp;lt;?php echo transliterate($this-&amp;gt;post-&amp;gt;title) ?&amp;gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1762227843073442838-3655133961557694999?l=jaime-neto.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jaime-neto.blogspot.com/feeds/3655133961557694999/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://jaime-neto.blogspot.com/2011/06/filtro-de-transliteracao-para-o-zf.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1762227843073442838/posts/default/3655133961557694999'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1762227843073442838/posts/default/3655133961557694999'/><link rel='alternate' type='text/html' href='http://jaime-neto.blogspot.com/2011/06/filtro-de-transliteracao-para-o-zf.html' title='Filtro de transliteração para o ZF'/><author><name>Jaime Neto</name><uri>http://www.blogger.com/profile/13866935986425738332</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_RAVPPc4er_Q/TMA_EKJjx6I/AAAAAAAAAIY/VigCHJ4RlQY/S220/jaimeneto.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1762227843073442838.post-6893209866102845600</id><published>2010-11-10T02:25:00.000-08:00</published><updated>2010-11-10T04:38:03.476-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Zend Framework'/><category scheme='http://www.blogger.com/atom/ns#' term='Zend_Db_Table'/><title type='text'>Melhorando o Zend_Db_Table - Parte 4: Fazendo JOIN automático com tabelas relacionadas</title><content type='html'>Uma das coisas chatas em se usar o &lt;code&gt;Zend_Db_Table&lt;/code&gt; é quando você precisa de informações que se encontram em tabelas associadas à tabela que você está usando. Para isso, o &lt;code&gt;Zend_Db_Table&lt;/code&gt; oferece a opção de você configurar a variável &lt;code&gt;$_referenceMap&lt;/code&gt; para definir os relacionamentos entre as tabelas, e usar métodos como &lt;code&gt;findDependentRowset()&lt;/code&gt;, ou algo do tipo &lt;code&gt;find&amp;lt;tableclass&amp;gt;By&amp;lt;rule&amp;gt;()&lt;/code&gt;, que são na verdade métodos de &lt;code&gt;Zend_Db_Table_Row&lt;/code&gt; (&lt;a href="http://zendframework.com/manual/en/zend.db.table.relationships.html#zend.db.table.relationships.defining" target="_blank"&gt;Saber mais&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;A utilização desses métodos pode ser boa no caso de poucos dados, mas se você estiver querendo pegar as informações completas das tabelas associadas de uma lista muito grande de registros, a quantidade de acessos ao banco para pegar essas informações vai ser proporcional à quantidade registros. Veja o seguinte cenário como exemplo:&lt;br /&gt;&lt;br /&gt;Você quer pegar de uma tabela &lt;code&gt;Usuarios&lt;/code&gt; a lista dos usuários com o nome da cidade em que vivem. Sendo que em &lt;code&gt;Usuarios&lt;/code&gt; Você só tem o código da cidade, que é chave estrangeira para a tabela Cidades, onde está o nome.&lt;br /&gt;&lt;br /&gt;Agora imagine que você quer pegar essa informação de todos os 300 usuários da sua lista. Você teria que fazer uma consulta ao banco para pegar a lista de usuários, iterar sobre a lista e fazer uma consulta para cada usuário para pegar o nome da cidade usando os métodos de &lt;code&gt;Zend_Db_Table_Row&lt;/code&gt;, totalizando 301 acessos ao banco de dados e muito trabalho de código.&lt;br /&gt;&lt;br /&gt;Por esse motivo, eu sempre me perguntei porque a classe &lt;code&gt;Zend_Db_Table&lt;/code&gt; não tinha métodos para trazer as informações das tabelas associadas juntamente com a tabela em questão. E isso é o que vai ser mostrado neste post como ser feito.&lt;br /&gt;&lt;br /&gt;A idéia é aproveitar a estrutura original da &lt;code&gt;Zend_Db_Table&lt;/code&gt;, sem alterá-la, para que se necessário possa ser usada da forma usual. Então, para começar, vamos criar o método principal, que vai montar o &lt;code&gt;select&lt;/code&gt; com as &lt;em&gt;joins&lt;/em&gt; baseadas em &lt;code&gt;$_referenceMap&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Vou colocar logo o código completo e explicando com comentários:&lt;br /&gt;&lt;pre&gt;&lt;span style="color:#ccc"&gt;/**&lt;br /&gt;* Gera automaticamente um Zend_Db_Table_Select fazendo join nas tabelas&lt;br /&gt;* baseado nas informações do atributo $_referenceMap&lt;br /&gt;*&lt;br /&gt;* @param array $columns Lista de campos a serem retornados&lt;br /&gt;*  do banco de dados (usado para ganho de performance).&lt;br /&gt;*  Se for  null, todos as colunos serão retornados.&lt;br /&gt;* @param array $referenceTables Lista de "rules" das tabelas a serem&lt;br /&gt;*  acrescentadas na query (usado para ganho de performance)&lt;br /&gt;*  Se null, todas as tabelas serão acrescentadas na query.&lt;br /&gt;* return Zend_Db_Table_Select&lt;br /&gt;*/&lt;/span&gt;&lt;br /&gt;public function selectWithJoins(array $columns = null,&lt;br /&gt; array $referenceTables = null)&lt;br /&gt;{&lt;br /&gt; $select = $this-&gt;select();&lt;br /&gt;&lt;br /&gt; &lt;span style="color:#ccc"&gt;// Verifica se há restrições nos campos a serem acrescentados&lt;/span&gt;&lt;br /&gt; $retrieveColumns = '*';&lt;br /&gt; if($columns) {&lt;br /&gt;   $tableCols = $this-&gt;info('cols');&lt;br /&gt;   $retrieveColumns = array_intersect($tableCols, $columns);&lt;br /&gt; }&lt;br /&gt; $select-&gt;from($this-&gt;_name, $retrieveColumns);&lt;br /&gt;&lt;br /&gt; &lt;span style="color:#ccc"&gt;// Verifica se há tabelas a serem acrescentadas com join na query&lt;br /&gt; // baseado no $_referenceMap&lt;/span&gt;&lt;br /&gt; if (count($this-&gt;_referenceMap) &gt; 0) {&lt;br /&gt;   $select-&gt;setIntegrityCheck(false);&lt;br /&gt;   if (!isset($tableCols)) {&lt;br /&gt;     $tableCols = $this-&gt;info('cols');&lt;br /&gt;   }&lt;br /&gt;   foreach($this-&gt;_referenceMap as $rule=&gt;$rm) {&lt;br /&gt;     &lt;span style="color:#ccc"&gt;// Verifica se há restrições nas tabelas a serem&lt;br /&gt;     // acrescentadas&lt;/span&gt;&lt;br /&gt;     if (null === $referenceTables ||&lt;br /&gt;       in_array($rule, $referenceTables))&lt;br /&gt;     {&lt;br /&gt;       $refTableClass = new $rm['refTableClass'];&lt;br /&gt;&lt;br /&gt;       &lt;span style="color:#ccc"&gt;// Campos das tabelas a serem acrescentadas&lt;br /&gt;       // são renomeadas&lt;br /&gt;       // para "NomeDaRule_NomeDoCampo"&lt;/span&gt;&lt;br /&gt;       $refTableColumns = array();&lt;br /&gt;       foreach ($refTableClass-&gt;info('cols') as $col) {&lt;br /&gt;         $colAlias = "{$rule}_{$col}";&lt;br /&gt;         &lt;span style="color:#ccc"&gt;// Verifica se há restrições nos campos a&lt;br /&gt;         // serem acrescentados&lt;/span&gt;&lt;br /&gt;         if (!$columns || in_array($colAlias, $columns)) {&lt;br /&gt;           $refTableColumns[$colAlias] = $col;&lt;br /&gt;         }&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;       &lt;span style="color:#ccc"&gt;// Se não há campos a serem acrescentados,&lt;br /&gt;       // a tabela não será acrescentada&lt;/span&gt;&lt;br /&gt;       if (count($refTableColumns)) {&lt;br /&gt;         $refTableName = $refTableClass-&gt;info(self::NAME);&lt;br /&gt;         if (is_string($rm['refColumns'])) {&lt;br /&gt;         &lt;span style="color:#ccc"&gt;// Se a chave primária é única&lt;/span&gt;&lt;br /&gt;         $joinOnString =&lt;br /&gt;           "{$refTableName}.{$rm['refColumns']}"&lt;br /&gt;           . " = {$this-&gt;_name}.{$rm['columns']}";&lt;br /&gt;         } else if (is_array($rm['refColumns'])) {&lt;br /&gt;           &lt;span style="color:#ccc"&gt;// Se a chave primária é concatenada&lt;/span&gt;&lt;br /&gt;           $joinOnArray = array();&lt;br /&gt;           foreach($rm['refColumns'] as $key=&gt;$rc) {&lt;br /&gt;             $joinOnArray[] = "{$refTableName}.{$rc} = "&lt;br /&gt;             . "{$this-&gt;_name}.{$rm['columns'][$k]}";&lt;br /&gt;           }&lt;br /&gt;           $joinOnString = implode(' AND ', $joinOnArray);&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         $select-&gt;joinLeft(&lt;br /&gt;           $refTableName,&lt;br /&gt;           $joinOnString,&lt;br /&gt;           $refTableColumns&lt;br /&gt;         );&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; return $select;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Pronto, feito o &lt;code&gt;select&lt;/code&gt;, já é possível gerar a query com os &lt;em&gt;joins&lt;/em&gt; e usar, por exemplo, em um &lt;code&gt;Zend_Paginator&lt;/code&gt;, ou fazer um &lt;code&gt;fetchAll()&lt;/code&gt; e usar o resultado normalmente.&lt;br /&gt;Mas, pra ficar ainda mais prático, vamos acrescentar o método &lt;em&gt;fetch&lt;/em&gt; lá na nossa classe e também um método &lt;em&gt;find&lt;/em&gt; pra retornar um único registro, baseado na chave primária.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="color:#ccc"&gt;/**&lt;br /&gt;* Faz uma busca no banco de dados com joins nas tabelas relacionadas&lt;br /&gt;* baseado no atributo $_referenceMap&lt;br /&gt;*&lt;br /&gt;* @param string|array $where  OPTIONAL An SQL WHERE clause.&lt;br /&gt;* @param string|array $order  OPTIONAL An SQL ORDER BY clause.&lt;br /&gt;* @param array    $columns OPTIONAL Campos a serem retornados&lt;br /&gt;* @param array    $referenceTables OPTIONAL Tabelas a serem acrescentadas&lt;br /&gt;* @param mixed    $fetchMode OPTIONAL Define o formato do resultado da busca&lt;br /&gt;* @return mixed     Depende do valor de $fetchMode.&lt;br /&gt;*/&lt;/span&gt;&lt;br /&gt;public function fetchWithJoins($where = null, $order = null,&lt;br /&gt;array $columns = null, array $referenceTables = null,&lt;br /&gt;$fetchMode = Zend_Db::FETCH_OBJ)&lt;br /&gt;{&lt;br /&gt;$select = $this-&gt;selectWithJoins($columns, $referenceTables);&lt;br /&gt;&lt;br /&gt;if ($where !== null) {&lt;br /&gt;  $this-&gt;_where($select, $where);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;if ($order) {&lt;br /&gt;  $select-&gt;order($order);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;return $this-&gt;getAdapter()-&gt;fetchAll($select, null, $fetchMode);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#ccc"&gt;/**&lt;br /&gt;* Faz uma busca usando a chave primária no banco de dados com joins&lt;br /&gt;* nas tabelas relacionadas baseado no atributo $_referenceMap&lt;br /&gt;*&lt;br /&gt;* @param string|array $pkey  Valor da chave primária&lt;br /&gt;* @param array    $columns OPTIONAL Campos a serem retornados&lt;br /&gt;* @param array    $referenceTables OPTIONAL Tabelas a serem acrescentadas&lt;br /&gt;* @param mixed    $fetchMode OPTIONAL Define o formato do resultado da busca&lt;br /&gt;* @return mixed     Depende do valor de $fetchMode.&lt;br /&gt;*/&lt;/span&gt;&lt;br /&gt;public function findWithJoins($pkey, array $columns = null,&lt;br /&gt;array $referenceTables = null, $fetchMode = null)&lt;br /&gt;{&lt;br /&gt;&lt;span style="color:#ccc"&gt;// Ver posts anteriores para entender este método &lt;/span&gt;&lt;br /&gt;$where = $this-&gt;_generateRestrictionsFromPrimaryKeys($pkey);&lt;br /&gt;&lt;br /&gt;$result = $this-&gt;fetchWithJoins($where, null, $columns,&lt;br /&gt;        $referenceTables, $fetchMode);&lt;br /&gt;return count($result) == 1 ? current($result) : $result;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Agora fica fácil fazer uma busca com &lt;em&gt;joins&lt;/em&gt; nas tabelas. Vamos reaproveitar o exemplo de &lt;code&gt;Usuarios&lt;/code&gt; e &lt;code&gt;Cidades&lt;/code&gt;.&lt;br /&gt;Digamos que essas sejam as respectivas classes:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;class Cidades extends My_Db_Table_Abstract&lt;br /&gt;{&lt;br /&gt; protected $_name    = 'cidades';&lt;br /&gt; protected $_primary = 'id_cidade';&lt;br /&gt;&lt;br /&gt; protected $_dependentTables = array('Usuarios');&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class Usuarios extends My_Db_Table_Abstract&lt;br /&gt;{&lt;br /&gt; protected $_name    = 'usuarios';&lt;br /&gt; protected$_primary = 'id_usuario';&lt;br /&gt;&lt;br /&gt; protected $_referenceMap = array(&lt;br /&gt;   'Cidade' =&gt; array(&lt;br /&gt;     'columns'       =&gt; 'id_cidade',&lt;br /&gt;     'refTableClass' =&gt; 'Cidades',&lt;br /&gt;     'refColumns'    =&gt; 'id_cidade'&lt;br /&gt;   ),&lt;br /&gt; )&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Perceba que os relacionamentos estão bem definidos em &lt;code&gt;$_referenceMap&lt;/code&gt;. Agora vamos fazer a busca que no interessa.&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$idUsuario = 1;&lt;br /&gt;$tbUsuarios = new Usuarios();&lt;br /&gt;$usuario = $tbUsuarios-&gt;findWithJoins($idUsuario);&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Se considerarmos que a tabela &lt;em&gt;usuarios&lt;/em&gt; só tem os campos id_usuario, nome e id_cidade, e a tabela &lt;em&gt;cidades&lt;/em&gt; tem id_cidade, nome e estado, teremos um resultado como o seguinte:&lt;br /&gt;&lt;pre&gt;$usuarios = StdClass(&lt;br /&gt;  'id_usuario'       =&gt; 1,&lt;br /&gt;  'nome'             =&gt; 'Fulano de Tal',&lt;br /&gt;  'id_cidade'        =&gt; 40,&lt;br /&gt;  'Cidade_id_cidade' =&gt; 40,&lt;br /&gt;  'Cidade_nome'      =&gt; 'João Pessoa',&lt;br /&gt;  'Cidade_estado'    =&gt; 'PB'&lt;br /&gt;);&lt;/pre&gt;Veja que os campos de cidade ganharam um prefixo com o nome da &lt;em&gt;rule&lt;/em&gt; que foi definida no atributo &lt;code&gt;$_referenceMap&lt;/code&gt;. Isso é pra evitar conflito entre nomes de campos iguais, como ocorre neste exemplo com id_cidade e nome, por exemplo.&lt;br /&gt;Para obter mais resultados, você pode usar da mesma forma o método &lt;code&gt;fetchWithJoins()&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;No caso de uma classe que faça raferência a muitas outras tabelas, essa consulta pode ficar muito pesada, e muitas vezes nem nos interessa num certo momento todos aqueles dados, então, pode ser passado como parâmetro apenas as tabelas que temos interesse, ou mesmo os campos que nos interessa, diminuindo, dessa forma, a carga sobre o banco de dados, já que diminuirá significativamente a quantidade de dados a serem retornados na consulta.&lt;br /&gt;&lt;br /&gt;No exemplo seguinte, a query retornará apenas os campos &lt;code&gt;nome&lt;/code&gt; e &lt;code&gt;Cidade_nome&lt;/code&gt; de todos os usuários do estado da Paraíba ordenados pelo nome da cidade:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$where = array('estado = ?' =&gt; 'PB');&lt;br /&gt;$order = array('cidades.nome ASC');&lt;br /&gt;$usuarios = $tbUsuarios-&gt;fetchWithJoins($where, $order, array('nome', 'Cidade_nome'));&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Imaginando que a tabela &lt;code&gt;Usuarios&lt;/code&gt; faça referências a outras tabelas, e para a consulta só me interessam os dados da tabela de cidades (além das de usuarios, claro), o exemplo seguinte mostra como limitar os &lt;em&gt;joins&lt;/em&gt; apenas as tabelas de interesse, utilizando as &lt;em&gt;rules&lt;/em&gt; definidas em &lt;code&gt;$_referenceMap&lt;/code&gt;:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$order = array('usuarios.nome ASC');&lt;br /&gt;$usuarios = $tbUsuarios-&gt;fetchWithJoins(null, $order, null, array('Cidade'));&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Perceba que a classe como está aqui apresentada só faz &lt;em&gt;join&lt;/em&gt; em um nível de relacionamento. Por exemplo, se a tabela &lt;code&gt;Cidades&lt;/code&gt; fizesse referência a uma tabela &lt;code&gt;Estados&lt;/code&gt;, os dados de estados não entrariam no resultado dos exemplos citados. Quem sabe numa versão futura...&lt;br /&gt;&lt;br /&gt;Ok. Agora ficou fácil fazer &lt;em&gt;joins&lt;/em&gt; sem precisar ficar montando os selects toda hora, nem ficar fazendo centenas de acessos desnecessários ao banco.&lt;br /&gt;&lt;br /&gt;Ainda assim, isso deve ser usado com cautela, já que consultas com &lt;em&gt;join&lt;/em&gt; também pesam no banco, devendo-se optar sempre que possível pela utilização de &lt;em&gt;Views&lt;/em&gt; de banco de dados ou tabelas tamporárias. Vale também uma olhada nas dicas de performance no site do Zend Framework a respeito da utilização da &lt;code&gt;Zend_Db_Table&lt;/code&gt; (&lt;a href="http://zendframework.com/manual/en/performance.database.html" target="_blank"&gt;Saber mais&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;Espero que tenham gostado! ^__^&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1762227843073442838-6893209866102845600?l=jaime-neto.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jaime-neto.blogspot.com/feeds/6893209866102845600/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://jaime-neto.blogspot.com/2010/11/melhorando-o-zenddbtable-parte-4.html#comment-form' title='2 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1762227843073442838/posts/default/6893209866102845600'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1762227843073442838/posts/default/6893209866102845600'/><link rel='alternate' type='text/html' href='http://jaime-neto.blogspot.com/2010/11/melhorando-o-zenddbtable-parte-4.html' title='Melhorando o Zend_Db_Table - Parte 4: Fazendo JOIN automático com tabelas relacionadas'/><author><name>Jaime Neto</name><uri>http://www.blogger.com/profile/13866935986425738332</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_RAVPPc4er_Q/TMA_EKJjx6I/AAAAAAAAAIY/VigCHJ4RlQY/S220/jaimeneto.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1762227843073442838.post-5060554980432665690</id><published>2010-01-30T12:19:00.000-08:00</published><updated>2010-11-09T03:45:01.957-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Zend Framework'/><category scheme='http://www.blogger.com/atom/ns#' term='Zend_Db_Table'/><title type='text'>Melhorando o Zend_Db_Table - Parte 3: Contando registros da tabela</title><content type='html'>Tá... o Zend_Db_Table já me dá métodos pra inserir, alterar, excluir e fazer busca de registros. Mas... e se eu só quiser saber quantos registros tenho na tabela? Ele não tem por padrão um método para me dizer isso. Eu precisaria fazer um &lt;code&gt;fetchAll()&lt;/code&gt; e depois um &lt;code&gt;count()&lt;/code&gt; no resultado, ou montar uma query pra me devolver esse resultado, ou passar como parâmetro no &lt;span style="font-style: italic;"&gt;bind &lt;/span&gt;uma string &lt;code&gt;'COUNT(*)'&lt;/code&gt;... Mas tudo isso parece pouco prático, quando poderíamos ter um método &lt;code&gt;count()&lt;/code&gt; pra fazer isso pra nós...&lt;br /&gt;&lt;br /&gt;Então é isso que fiz... Implementei na minha classe &lt;code&gt;My_Db_Table_Abstract&lt;/code&gt; a interface &lt;code&gt;Coutable&lt;/code&gt;, que ficou dessa forma:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class My_Db_Table_Abstract extends Zend_Db_Table_Abstract &lt;br /&gt;  &lt;strong&gt;implements Countable&lt;/strong&gt;&lt;br /&gt;{&lt;br /&gt;  &lt;span style="color: #ccc"&gt;/* Aqui ficam os métodos citados nos posts anteriores */&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  public function count($where = null)&lt;br /&gt;  {&lt;br /&gt;     $select = $this-&gt;select();&lt;br /&gt;&lt;br /&gt;     if ($where !== null) {&lt;br /&gt;         $this-&gt;_where($select, $where);&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;     $select-&gt;from($this-&gt;_name, array('count' =&gt; 'COUNT(*)'));&lt;br /&gt;&lt;br /&gt;     $count = $this-&gt;getAdapter()-&gt;fetchRow($select);&lt;br /&gt;     return intval($count['count']);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Pra ficar ainda mais completo, o método pode receber como parâmetro algumas restrições, caso não se queria contar a quantidade total, e sim algo mais específico. Agora, fica bem mais fácil:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$tbUsuarios = new Usuarios();&lt;br /&gt;$qtty = $tbUsuarios-&gt;count();&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Se quisermos, por exemplo, saber quantos usuários usam gmail:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$qtty = $tbUsuarios-&gt;count("email LIKE '%@gmail.com'");&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Simples assim...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1762227843073442838-5060554980432665690?l=jaime-neto.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jaime-neto.blogspot.com/feeds/5060554980432665690/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://jaime-neto.blogspot.com/2010/01/melhorando-o-zenddbtable-parte-3.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1762227843073442838/posts/default/5060554980432665690'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1762227843073442838/posts/default/5060554980432665690'/><link rel='alternate' type='text/html' href='http://jaime-neto.blogspot.com/2010/01/melhorando-o-zenddbtable-parte-3.html' title='Melhorando o Zend_Db_Table - Parte 3: Contando registros da tabela'/><author><name>Jaime Neto</name><uri>http://www.blogger.com/profile/13866935986425738332</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_RAVPPc4er_Q/TMA_EKJjx6I/AAAAAAAAAIY/VigCHJ4RlQY/S220/jaimeneto.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1762227843073442838.post-7149048097742801994</id><published>2010-01-30T09:24:00.001-08:00</published><updated>2010-12-01T02:20:13.261-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Zend Framework'/><category scheme='http://www.blogger.com/atom/ns#' term='Zend_Db_Table'/><title type='text'>Melhorando o Zend_Db_Table - Parte 2: Simplificando UPDATE e DELETE</title><content type='html'>Continuando as melhorias na utilização da &lt;code&gt;Zend_Db_Table&lt;/code&gt;, do Zend Framework. Outra melhoria a ser feita é nos métodos &lt;code&gt;update()&lt;/code&gt; e &lt;code&gt;delete()&lt;/code&gt;. O que há de comum entre esses dois métodos é que ambos recebem como parâmetro uma ou mais restrições para identificar em que registro a  alteração ou exclusão será feita. Sendo que a grande maioria das vezes que você usa esses métodos, o registro é relativo à chave primária da tabela, e mais raramente à alguma outra coluna. Como no exemplo:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$id = $this-&gt;_request-&gt;getPost('id');&lt;br /&gt;  &lt;br /&gt;$tbUsuarios = new Usuarios();&lt;br /&gt;// Imaginemos que esses dados vieram de um formulário&lt;br /&gt;$dados = array(&lt;br /&gt;  'nome' =&gt; 'Fulaninho de Tal',&lt;br /&gt;  'email' =&gt; 'fulaninho@email.com'&lt;br /&gt;);&lt;br /&gt;$where = $tbUsuarios-&gt;getAdapter()-&gt;quoteInto('id = ?', $id);&lt;br /&gt;// Vamos atualizar o usuário&lt;br /&gt;$tbUsuarios-&gt;update($dados, $where);&lt;br /&gt;  &lt;br /&gt;// E agora excluímos&lt;br /&gt;$tbUsuarios-&gt;delete($where);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Pra não ter que toda vez montar a restrição para esses métodos, adicionei à minha classe &lt;code&gt;My_Db_Table_Abstract&lt;/code&gt;. métodos de update e delete para um registro específico, onde o parâmetro de restrição é sempre a chave primária. Vejamos:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class My_Db_Table_Abstract extends Zend_Db_Table_Abstract&lt;br /&gt;{&lt;br /&gt;  protected function _filterData(array $data)&lt;br /&gt;  {&lt;br /&gt;    &lt;span style="color: #ccc"&gt;/* Permanece a mesma coisa */&lt;/span&gt;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  &lt;span style="color: #ccc"&gt;/**&lt;br /&gt;   * Gera restricoes SQL de acordo com a(s) chave(s) primária(s)&lt;br /&gt;   * @param  String|array $pkey chave(s) primária(s) &lt;br /&gt;   *                            [nome_do_campo =&gt; valor]&lt;br /&gt;   * @return String|array SQL where&lt;br /&gt;   **/&lt;/span&gt;&lt;br /&gt;  protected function _generateRestrictionsFromPrimaryKeys($pkey)&lt;br /&gt;  {&lt;br /&gt;    $where = array();&lt;br /&gt;    if (is_array($this-&gt;_primary)) {&lt;br /&gt;      foreach($this-&gt;_primary as $key) {&lt;br /&gt;        if (is_array($pkey)) {&lt;br /&gt;          $where[] = $this-&gt;getAdapter()&lt;br /&gt;            -&gt;quoteInto($this-&gt;_name.'.'.$key . ' = ?', &lt;br /&gt;                        $pkey[$key]);&lt;br /&gt;        } else {&lt;br /&gt;          $where = $this-&gt;getAdapter()&lt;br /&gt;            -&gt;quoteInto($this-&gt;_name.'.'.$key . ' = ?', &lt;br /&gt;                        $pkey);&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    } else {&lt;br /&gt;      $where = $this-&gt;getAdapter()&lt;br /&gt;        -&gt;quoteInto($this-&gt;_name.'.'.$this-&gt;_primary . ' = ?', &lt;br /&gt;                    $pkey);&lt;br /&gt;    }&lt;br /&gt;    return $where;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  public function insert(array $data)&lt;br /&gt;  {&lt;br /&gt;    &lt;span style="color: #ccc"&gt;/* Permanece a mesma coisa */&lt;/span&gt;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  public function update(array $data, $where)&lt;br /&gt;  {&lt;br /&gt;    $data = $this-&gt;_filterData($data);&lt;br /&gt;    return parent::update($data, $where);&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  &lt;span style="color: #ccc"&gt;/**&lt;br /&gt;   * Update de um registro único, baseado na chave primária&lt;br /&gt;   * @param array $data Dados a serem atualizados&lt;br /&gt;   * @param string|array $pkey Valor da chave primária&lt;br /&gt;   **/&lt;/span&gt;&lt;br /&gt;   public function updateRow(array $data, $pkey)&lt;br /&gt;   {&lt;br /&gt;    $where = $this-&gt;_generateRestrictionsFromPrimaryKeys($pkey);&lt;br /&gt;    return $this-&gt;update($data, $where);&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  &lt;span style="color: #ccc"&gt;/**&lt;br /&gt;   * Delete de um registro único, baseado na chave primária&lt;br /&gt;   * @param string|array $pkey Valor da chave primária&lt;br /&gt;   **/&lt;/span&gt;&lt;br /&gt;  public function deleteRow($pkey)&lt;br /&gt;  {&lt;br /&gt;    $where = $this-&gt;_generateRestrictionsFromPrimaryKeys($pkey);&lt;br /&gt;    return $this-&gt;delete($where);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Veja que o método &lt;code&gt;updateRow()&lt;/code&gt; é uma variação do método &lt;code&gt;update()&lt;/code&gt;, com a diferença de que este recebe apenas o valor da chave primária, assim como o método &lt;code&gt;deleteRow()&lt;/code&gt;. Esse valor pode ser um &lt;code&gt;array&lt;/code&gt;, caso a tabela tenha chave primária concatenada.&lt;br /&gt;&lt;br /&gt;O código agora resume-se a:&lt;pre&gt;&lt;br /&gt;&lt;span style="color: #ccc"&gt;// para atualizar um usuário&lt;/span&gt;&lt;br /&gt;$tbUsuarios-&gt;updateRow($dados, $id);&lt;br /&gt;&lt;span style="color: #ccc"&gt;// para excluí-lo&lt;/span&gt;&lt;br /&gt;$tbUsuarios-&gt;deleteRow($id);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Nada mais de ficar montando os "wheres" toda vez que for atualizar ou excluir um registro. Agora é só jogar o valor da chave primária lá e pronto.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1762227843073442838-7149048097742801994?l=jaime-neto.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jaime-neto.blogspot.com/feeds/7149048097742801994/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://jaime-neto.blogspot.com/2010/01/melhorando-o-zenddbtable-parte-2.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1762227843073442838/posts/default/7149048097742801994'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1762227843073442838/posts/default/7149048097742801994'/><link rel='alternate' type='text/html' href='http://jaime-neto.blogspot.com/2010/01/melhorando-o-zenddbtable-parte-2.html' title='Melhorando o Zend_Db_Table - Parte 2: Simplificando UPDATE e DELETE'/><author><name>Jaime Neto</name><uri>http://www.blogger.com/profile/13866935986425738332</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_RAVPPc4er_Q/TMA_EKJjx6I/AAAAAAAAAIY/VigCHJ4RlQY/S220/jaimeneto.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1762227843073442838.post-2209423596280580766</id><published>2010-01-30T08:11:00.000-08:00</published><updated>2010-11-09T03:52:31.288-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Zend Framework'/><category scheme='http://www.blogger.com/atom/ns#' term='Zend_Db_Table'/><title type='text'>Melhorando o Zend_Db_Table - Parte 1: Evitando chaves que não correspondem à colunas</title><content type='html'>Faz muito tempo que não posto nada no blog, então resolvi começar a compartilhar algumas soluções que venho desenvolvendo para Zend Framework, que pode ser útil pra muita gente que o utiliza.&lt;br /&gt;&lt;br /&gt;Uma das grandes críticas que vejo sobre o ZF é o uso do &lt;code&gt;Zend_Db_Table&lt;/code&gt;, por diversos motivos, então, para começar vou postar algumas soluções que venho desenvolvendo para facilitar meu trabalho no uso dessa abstração de banco de dados.&lt;br /&gt;&lt;br /&gt;Para começar, uma das coisas que me aborrecia sempre que ia dar um &lt;span style="font-style: italic"&gt;insert &lt;/span&gt;ou &lt;span style="font-style: italic"&gt;update &lt;/span&gt;na tabela, era quando eu passava os dados do formulário para um desses métodos, e o ZF me jogava uma excessão dizendo que não existe uma coluna de nome tal, que foi passada no &lt;code&gt;array&lt;/code&gt; de dados. Pra deixar mais claro, vamos pegar o seguinte cenário:&lt;br /&gt;&lt;br /&gt;Temos uma tabela "Usuarios", com os campos "id", "nome" e "email", por exemplo. E uma classe modelo &lt;code&gt;Usuarios&lt;/code&gt; que herda de &lt;code&gt;Zend_Db_Table_Abstract&lt;/code&gt;. Ao inserirmos os dados de um usuário, o formulário está mandando também o nome do botão "Salvar".&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$tbUsuarios = new Usuarios();&lt;br /&gt;$dados = $this-&gt;_request-&gt;getPost();&lt;br /&gt;&lt;span style="color: #ccc"&gt;/*&lt;br /&gt;  Digamos que esse seja o valor de $dados:&lt;br /&gt;  $dados = array(&lt;br /&gt;    'nome' =&gt; 'Fulano de Tal',&lt;br /&gt;    'email' =&gt; 'fulano@email.com',&lt;br /&gt;    'salvar' =&gt; 'Salvar'&lt;br /&gt;  )&lt;br /&gt;*/&lt;/span&gt;&lt;br /&gt;unset($dados['salvar']);&lt;br /&gt;$tbUsuarios-&gt;insert($dados);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Veja que foi necessário um &lt;code&gt;unset()&lt;/code&gt; para remover a chave que não corresponde à colunas da tabela. Óbvio que esse é um exemplo simplificado, e pode parecer uma bobagem, mas imagine um cenário maior e mais complicado onde cada chave não correspondente à uma coluna teria que ser excluída do &lt;code&gt;array&lt;/code&gt; a fim de evitar a excessão lançada pelo &lt;code&gt;Zend_Db_Table&lt;/code&gt;. E, acredite, isso pode se tornar um pé-no-saco, principalmente quando você tem que fazer alterações no formulário e acaba colocando mais uma chave que não corresponde à uma coluna, daí vem mais um &lt;code&gt;unset()&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Então, entendido o problema, vejamos a forma que encontrei para que não seja mais necessário nos preocuparmos com dados não correspondentes à colunas:&lt;br /&gt;&lt;pre&gt;require_once 'Zend/Db/Table/Abstract.php';&lt;br /&gt;&lt;br /&gt;class My_Db_Table_Abstract extends Zend_Db_Table_Abstract&lt;br /&gt;{&lt;br /&gt;  &lt;span style="color: #ccc"&gt;/**&lt;br /&gt;   * Filtra os itens do array de dados, verificando se as&lt;br /&gt;   * chaves correspondem a campos da tabela&lt;br /&gt;   *&lt;br /&gt;   * @param array $data Array de dados&lt;br /&gt;   * @return array Array de dados filtrados&lt;br /&gt;  **/&lt;/span&gt;&lt;br /&gt;  protected function _filterData(array $data)&lt;br /&gt;  {&lt;br /&gt;    $cols = $this-&gt;info('cols');&lt;br /&gt;    $filteredData = array();&lt;br /&gt;    if($data) {&lt;br /&gt;      foreach($data as $key=&gt;$value) {&lt;br /&gt;        if (in_array($key, $cols)) {&lt;br /&gt;          $filteredData[$key] = $value;&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    return $filteredData;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public function insert(array $data)&lt;br /&gt;  {&lt;br /&gt;    $data = $this-&gt;_filterData($data);&lt;br /&gt;    return parent::insert($data);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public function update(array $data, $where)&lt;br /&gt;  {&lt;br /&gt;    $data = $this-&gt;_filterData($data);&lt;br /&gt;    return parent::update($data, $where);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Agora é só fazer com que a classe &lt;code&gt;Usuarios&lt;/code&gt; herde de &lt;code&gt;My_Db_Table_Abstract&lt;/code&gt; e pronto.&lt;br /&gt;Veja que, desta forma, as chaves do &lt;code&gt;array&lt;/code&gt; não correspondentes à colunas da tabela serão automaticamente filtrados, e não será mais exibida excessão relativa a esse caso específico.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1762227843073442838-2209423596280580766?l=jaime-neto.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jaime-neto.blogspot.com/feeds/2209423596280580766/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://jaime-neto.blogspot.com/2010/01/melhorando-o-zenddbtable-parte-1.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1762227843073442838/posts/default/2209423596280580766'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1762227843073442838/posts/default/2209423596280580766'/><link rel='alternate' type='text/html' href='http://jaime-neto.blogspot.com/2010/01/melhorando-o-zenddbtable-parte-1.html' title='Melhorando o Zend_Db_Table - Parte 1: Evitando chaves que não correspondem à colunas'/><author><name>Jaime Neto</name><uri>http://www.blogger.com/profile/13866935986425738332</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_RAVPPc4er_Q/TMA_EKJjx6I/AAAAAAAAAIY/VigCHJ4RlQY/S220/jaimeneto.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1762227843073442838.post-6066232572662334518</id><published>2009-06-13T11:48:00.000-07:00</published><updated>2009-06-17T17:30:51.418-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Peacekeeper'/><category scheme='http://www.blogger.com/atom/ns#' term='firefox'/><category scheme='http://www.blogger.com/atom/ns#' term='complementos'/><category scheme='http://www.blogger.com/atom/ns#' term='comparative'/><category scheme='http://www.blogger.com/atom/ns#' term='add-ons'/><category scheme='http://www.blogger.com/atom/ns#' term='browsers'/><title type='text'>Qual o navegador mais rápido?</title><content type='html'>O &lt;a href="http://service.futuremark.com/peacekeeper/"&gt;Peacekeeper&lt;/a&gt; é uma ferramenta online para verificação e comparação de desempenho de browsers. Funciona de forma bastante simples, você entra no &lt;a href="http://service.futuremark.com/peacekeeper/"&gt;site&lt;/a&gt; e clica em 'Benchmark Your Browser'. Se não tiver java instalado, ele vai pedir para instalar. Depois é só mandar rodar e esperar uns 5 minutos, no máximo. Ele vai medir o desempenho do browser que você está usando e irá fornecer um link para você usar com outros browsers e fazer o comparativo.&lt;br /&gt;&lt;br /&gt;Eu fiz a experiência, e eis o resultado:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_RAVPPc4er_Q/SjP-wXX5LQI/AAAAAAAAAHk/6_9X-u4IeNg/s1600-h/BrowsersComparative.JPG"&gt;&lt;img style="cursor: pointer; width: 400px; height: 258px;" src="http://4.bp.blogspot.com/_RAVPPc4er_Q/SjP-wXX5LQI/AAAAAAAAAHk/6_9X-u4IeNg/s400/BrowsersComparative.JPG" alt="" id="BLOGGER_PHOTO_ID_5346897289480318210" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;O Safari 4.0 e o Chrome estão de parabéns em desempenho. Isso não fez com que eu trocasse o firefox por eles, já que nenhum oferece todos os recursos (complementos) que eu gosto de usar no firefox, mas a diferença é impressionante.&lt;br /&gt;&lt;br /&gt;Fiz o teste antes de atualizar o firefox para a nova versão (3.11) e fiz novamente depois da atualização, pra minha surpresa o desempenho caiu bastante...&lt;br /&gt;&lt;br /&gt;O Opera que usei era uma versão que tinha instalado no meu pen drive U3. Não sei se isso influenciou muito no resultado do desempenho, mas me desapontou bastante... mais lento que o IE8!? Não dá, né...&lt;br /&gt;&lt;br /&gt;Ainda assim, para mim o firefox permanece como a melhor opção, pois facilita muito meu trabalho graças aos complementos úteis que tenho instalados: &lt;a href="https://addons.mozilla.org/pt-BR/firefox/addon/1843"&gt;Firebug&lt;/a&gt;, &lt;a href="https://addons.mozilla.org/pt-BR/firefox/addon/6149"&gt;FirePHP&lt;/a&gt;, &lt;a href="https://addons.mozilla.org/pt-BR/firefox/addon/249"&gt;HTML Validator&lt;/a&gt;, &lt;a href="https://addons.mozilla.org/pt-BR/firefox/addon/60"&gt;Web Developper&lt;/a&gt;, &lt;a href="https://addons.mozilla.org/pt-BR/firefox/addon/5648"&gt;Fireshot&lt;/a&gt;, &lt;a href="https://addons.mozilla.org/pt-BR/firefox/addon/1419"&gt;IE Tab&lt;/a&gt;, &lt;a href="https://addons.mozilla.org/pt-BR/firefox/addon/5369"&gt;Yslow&lt;/a&gt;, &lt;a href="https://addons.mozilla.org/pt-BR/firefox/addon/198"&gt;LoremIpsum Content Generator&lt;/a&gt; entre outros... Isso sem falar dos outros que não estão relacionados a meu trabalho, mas que são bastante úteis: &lt;a href="https://addons.mozilla.org/pt-BR/firefox/addon/2410"&gt;Xmarks&lt;/a&gt;, &lt;a href="https://addons.mozilla.org/pt-BR/firefox/addon/5081"&gt;TwitterFox&lt;/a&gt;, &lt;a href="https://addons.mozilla.org/pt-BR/firefox/addon/1320"&gt;Gmail Manager&lt;/a&gt;, &lt;a href="https://addons.mozilla.org/pt-BR/firefox/addon/6076"&gt;Better Gmail 2&lt;/a&gt;, &lt;a href="https://addons.mozilla.org/pt-BR/firefox/addon/4072"&gt;Smart Bookmarks Bar&lt;/a&gt;, &lt;a href="https://addons.mozilla.org/pt-BR/firefox/addon/5579"&gt;Cooliris&lt;/a&gt;, entre outros...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1762227843073442838-6066232572662334518?l=jaime-neto.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jaime-neto.blogspot.com/feeds/6066232572662334518/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://jaime-neto.blogspot.com/2009/06/qual-o-navegador-mais-rapido.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1762227843073442838/posts/default/6066232572662334518'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1762227843073442838/posts/default/6066232572662334518'/><link rel='alternate' type='text/html' href='http://jaime-neto.blogspot.com/2009/06/qual-o-navegador-mais-rapido.html' title='Qual o navegador mais rápido?'/><author><name>Jaime Neto</name><uri>http://www.blogger.com/profile/13866935986425738332</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_RAVPPc4er_Q/TMA_EKJjx6I/AAAAAAAAAIY/VigCHJ4RlQY/S220/jaimeneto.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_RAVPPc4er_Q/SjP-wXX5LQI/AAAAAAAAAHk/6_9X-u4IeNg/s72-c/BrowsersComparative.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1762227843073442838.post-2409092278510351628</id><published>2009-03-11T21:57:00.000-07:00</published><updated>2009-03-12T08:28:45.116-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><category scheme='http://www.blogger.com/atom/ns#' term='eeepc'/><category scheme='http://www.blogger.com/atom/ns#' term='eeebuntu'/><title type='text'>Instalando eeebuntu no eeepc</title><content type='html'>Pois é, comprei meu eeepc 900 depois de muito namorar com a prateleira e usando ele, percebi que o sistema operacional que vem nele, o Xandros (Linux) não é muito bom. Resolvi então testar o eeebuntu, que é uma versão do ubuntu feita especialmente para o eeepc. Pesquisando nos fórums, vi que tem alguma particularidades na instalação dele.&lt;br /&gt;&lt;br /&gt;Antes de qualquer coisa, lembre de fazer backup de sua pasta /home e o que mais você deseja salvar do eeepc, pois vamos formatá-lo, ok?&lt;br /&gt;&lt;br /&gt;Vamos aos passos:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1. Baixe o eeebuntu&lt;/span&gt; (&lt;a href="http://www.eeebuntu.org/"&gt;http://www.eeebuntu.org&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;O eeebuntu está disponível em três versões:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Standard&lt;/span&gt; é o mais completo, visual desktop, já com diversos aplicativos instalados, incluindo Firefox, Open Office, Banshee, Thunderbird, VLC, etc.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Netbook&lt;/span&gt; é similar ao Standard, só que com as opções mais facilmente acessíveis, criado especialmente para telas pequenas como as do eeepc. (Obs: Se você pretende instalar o compiz, esqueça essa versão...)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Base&lt;/span&gt; é a versão mais enxuta de todas, vem com pouquíssima coisa instalada, ideal para quem tem pouco espaço e para usuários avançados que preferem instalar cada coisa separadamente.&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;2. Fazendo boot pelo pendrive&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Existem três formas básicas de se instalar um novo sistema operacional no eeepc: Usando um drive externo de CD, usando um SD Card, ou usando um pendrive. Eu usei a terceira opção.&lt;br /&gt;A primeira coisa é encontrar um pendrive de pelo menos 1 GB, e gravar nele uma imagem da ISO que você baixou anteriormente.&lt;br /&gt;&lt;br /&gt;Para gravar a imagem no pendrive, eu utilizei o programa &lt;span style="font-style: italic;"&gt;unetbootin&lt;/span&gt;, pra Windows (uh!? é... vai ter que usar outro computador, ou encontre outro programa pra fazer isso... :P), que pode ser encontrado facilmente no &lt;a href="http://www.baixaki.com.br/download/unetbootin.htm"&gt;baixaki&lt;/a&gt; ou no &lt;a href="http://superdownloads.uol.com.br/download/175/unetbootin-linux/"&gt;superdownloads&lt;/a&gt;. Tendo baixado o programa, é só executá-lo (não precisa instalar), selecionar a imagem do eeebuntu, e selecionar o pendrive em que vai ser gravada a imagem (lembre de fazer backup do que tiver no pendrive antes, pois ele será formatado!).&lt;br /&gt;&lt;br /&gt;Feita a imagem, plugue o pendrive no eeepc, ligue-o e na primeira tela que aparece quando é ligado, aperte ESC (repetidas vezes, pra garantir) para aparecer a tela em que você pode escolher fazer o boot pelo pendrive. Se não der certo, reinicie e na tela inicial aperte F2 (repetidas vezes) para entrar no setup. Vá em Boot, Selecione &lt;span style="font-style: italic;"&gt;Boot Device Priority&lt;/span&gt; e ponha &lt;span style="font-style: italic;"&gt;Removable Dev&lt;/span&gt; como &lt;span style="font-style: italic;"&gt;1st Boot device&lt;/span&gt;. Salve e saia, e tente novamente o ESC.&lt;br /&gt;Pronto, o eeebuntu deverá iniciar a partir do pendrive.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;3. Instalando o eeebuntu&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Agora estamos no eeebuntu via pendrive. Logo de cara você vai ver o ícone de instalação, a não ser que você esteja instalando a versão &lt;span style="font-style: italic;"&gt;Netbook&lt;/span&gt;, nesse caso, vá pelo gerenciador de arquivos até a pasta Desktop e clique no ícone de instalação lá.&lt;br /&gt;&lt;br /&gt;Siga normal com a instalação até a tela onde você pode particionar os discos. Selecione a opção "manual" e apague todas as partições criadas pelo Xandros. Com os discos vazios, selecione como formato de arquivos ext2, que é mais indicado para discos SSD, pois o ext3, apesar de oferecer mais segurança aos dados, faz muito mais acessos ao disco, o que não é bom para discos SSD. Se o seu eeepc tiver dois SSD, como o meu (um de 4 GB e outro de 16 GB), selecione o primeiro para ser o /, e o segundo para ser o /home, assim você vai estar deixando seus arquivos separados dos arquivos de programas. Siga em frente. Ignore a a mensagem dizendo que não foi escolhida nenhuma partição SWAP, e termine a instalação.&lt;br /&gt;&lt;br /&gt;Agora vamos atualizar os repositórios. Vá em Sistema -&gt; Administração -&gt; Canais de Software e clique para adicionar. Digite &lt;span style="font-weight: bold;"&gt;deb http://repos.eeebuntu.org intrepid main non-free contrib&lt;/span&gt;. Agora vá em Sistema -&gt; Administração -&gt; Gerenciador de Atualizações e instale as atualizações.&lt;br /&gt;&lt;br /&gt;Pronto, seu eeebuntu deve estar rodando bonitinho no seu eeepc. E pode ficar ainda mais bonito, se você instalar o compiz, mas não faça isso se tiver instalado a versão &lt;span style="font-style: italic;"&gt;Netbook&lt;/span&gt;, pois não vai dar certo.&lt;br /&gt;&lt;br /&gt;Mais dicas nos links:&lt;br /&gt;&lt;a href="http://ubuntuforum-br.org/index.php?topic=39896.0"&gt;http://ubuntuforum-br.org/index.php?topic=39896.0&lt;/a&gt;&lt;br /&gt;&lt;a href="http://wiki.eeeuser.com/getting_ubuntu_8.04_to_work_perfectly"&gt;http://wiki.eeeuser.com/getting_ubuntu_8.04_to_work_perfectly&lt;/a&gt;&lt;br /&gt;&lt;a href="http://wiki.ubuntu-br.org/ColocarHomeEmNovaParticao"&gt;http://wiki.ubuntu-br.org/ColocarHomeEmNovaParticao&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1762227843073442838-2409092278510351628?l=jaime-neto.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jaime-neto.blogspot.com/feeds/2409092278510351628/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://jaime-neto.blogspot.com/2009/03/instalando-eeebuntu-no-eeepc.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1762227843073442838/posts/default/2409092278510351628'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1762227843073442838/posts/default/2409092278510351628'/><link rel='alternate' type='text/html' href='http://jaime-neto.blogspot.com/2009/03/instalando-eeebuntu-no-eeepc.html' title='Instalando eeebuntu no eeepc'/><author><name>Jaime Neto</name><uri>http://www.blogger.com/profile/13866935986425738332</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_RAVPPc4er_Q/TMA_EKJjx6I/AAAAAAAAAIY/VigCHJ4RlQY/S220/jaimeneto.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1762227843073442838.post-8387828327798933671</id><published>2009-03-11T19:19:00.000-07:00</published><updated>2009-03-13T06:41:43.150-07:00</updated><title type='text'>O início...</title><content type='html'>&lt;div style="font-family: verdana;" class="entry-content"&gt;      &lt;p&gt;Olá,&lt;/p&gt; &lt;p&gt;Finalmente tomei coragem para criar meu blog, pois pesquisando aqui e ali na web para resolver problemas de programação, linux, e outros, me dei conta que as vezes acabo procurando a mesma coisa mais de uma vez. Foi quando pensei que seria uma boa idéia pôr todas essas informações que as vezes custo a encontrar tudo num só lugar, tanto pra facilitar minha própria vida quando precisar delas de novo, quanto para compartilhar com aqueles que procuram essas mesmas informações.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Quem quiser entrar em contato, é só mandar um email para contatoARROBAjaimenetoPONTOcom.&lt;/p&gt; &lt;p&gt;Abraços!&lt;/p&gt;     &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1762227843073442838-8387828327798933671?l=jaime-neto.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jaime-neto.blogspot.com/feeds/8387828327798933671/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://jaime-neto.blogspot.com/2009/03/o-inicio.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1762227843073442838/posts/default/8387828327798933671'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1762227843073442838/posts/default/8387828327798933671'/><link rel='alternate' type='text/html' href='http://jaime-neto.blogspot.com/2009/03/o-inicio.html' title='O início...'/><author><name>Jaime Neto</name><uri>http://www.blogger.com/profile/13866935986425738332</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_RAVPPc4er_Q/TMA_EKJjx6I/AAAAAAAAAIY/VigCHJ4RlQY/S220/jaimeneto.jpg'/></author><thr:total>0</thr:total></entry></feed>
