Archive for the 'PHP5' Category

Dezembro 1st 2008

Palestra no PHPConference 2008

Neste último sábado dia 29/11, estive em São Paulo dando minha palestra sobre Integração Contínua no PHPConference 2008. Deixo aqui meu muito obrigado pelo convite, e dizer que também que fico muito grato aos que com pareceram a minha palestra.
Abaixo os slides da palestra:

Aos que quiserem fazer o download do material em PDF, basta ir até o slideshare.

[]s

No Comments yet »

Novembro 29th 2008

Injeção de dependência com Zend Framework

É comum ver por ai, as pessoas fazendo o setup da aplicação sempre no arquivo de bootstrap do Zend, algo do tipo:

arquivo: index.php

PHP:
  1. require_once 'Initializer.php';
  2. require_once 'Zend/Loader.php';
  3.  
  4. Zend_Loader::registerAutoload();
  5.  
  6. $frontController = Zend_Controller_Front::getInstance();
  7.  
  8. //inicializando configuração do banco de dados
  9. $db = new Zend_Db_Adapter_Oracle(array(
  10.     'username' => 'xxxxxx',
  11.     'password' => 'xxxxxx',
  12.     'dbname'   => 'xe'
  13. ));
  14.  
  15. Zend_Db_Table_Abstract::setDefaultAdapter($db);
  16.  
  17. //inicializando configuração de routes
  18. //...
  19.  
  20. // inicializando layout
  21. Zend_Layout::startMvc();
  22.  
  23. // inicializando componente tal ....
  24.  
  25. $frontController->addControllerDirectory(dirname(__FILE__) . '/application/default/controllers', 'default');
  26. $frontController->dispatch();

Porém, existem maneiras mais fáceis (e mais elegantes) de fazer isso. Injeção de Dependência é uma delas. Com o Zend Framework existem alguns pontos onde podemos aplicar este tipo de abordagem, utilizando Action Helpers, View Helpers e Plugins. Já expliquei aqui no blog como utilizar plugins, no post Não estenda. Plugue!.

O exemplo abaixo é uma alternativa para setup utilizando plugins, para os usuários do Zend Studio for Eclipse isso é talvez seja familiar, já que a IDE gera o projeto mais ou menos desta mesma forma.

Primeiro nosso plugin:

PHP:
  1. <?php
  2.  
  3. require_once 'Zend/Controller/Plugin/Abstract.php';
  4. require_once 'Zend/Controller/Front.php';
  5. require_once 'Zend/Controller/Request/Abstract.php';
  6. require_once 'Zend/Controller/Action/HelperBroker.php';
  7.  
  8. /**
  9.  * plugin de inicialização da aplicação
  10.  *
  11.  */
  12. class Initializer extends Zend_Controller_Plugin_Abstract
  13. {
  14.    
  15.     protected static $_config;
  16.  
  17.     protected $_env;
  18.  
  19.     protected $_front;
  20.  
  21.     protected $_root;
  22.  
  23.     /**
  24.      * Constructor
  25.      *
  26.      * inicializa configurações
  27.      *
  28.      * @param  string $env (development, test, production)
  29.      * @param  string|null $root
  30.      * @return void
  31.      */
  32.     public function __construct($env, $root = null)
  33.     {
  34.         $this->_setEnv($env);
  35.         if (null === $root) {
  36.             $root = realpath(dirname(__FILE__) . '/../');
  37.         }
  38.         $this->_root = $root;
  39.  
  40.         $this->_front = Zend_Controller_Front::getInstance();
  41.        
  42.         $this->initPhpConfig();
  43.     }
  44.  
  45.     /**
  46.      * seta ambiente
  47.      *
  48.      * @param  string $env
  49.      * @return void
  50.      */
  51.     protected function _setEnv($env)
  52.     {
  53.         $this->_env = $env;     
  54.     }
  55.    
  56.  
  57.     /**
  58.      * inicializa configurações do php
  59.      *
  60.      * @return void
  61.      */
  62.     public function initPhpConfig()
  63.     {
  64.         // seta parametros para ambiente de teste
  65.         if ($this->_env == 'test') {
  66.             // habilita todos os erros do php 
  67.             error_reporting(E_ALL | E_STRICT); 
  68.             ini_set('display_startup_errors', 1); 
  69.             ini_set('display_errors', 1);
  70.  
  71.             $this->_front->throwExceptions(true); 
  72.         }
  73.     }
  74.    
  75.     /**
  76.      * faz todas as inicializações antes do inicio do roteamento para os controllers
  77.      *
  78.      * @return void
  79.      */
  80.     public function routeStartup(Zend_Controller_Request_Abstract $request)
  81.     {
  82.         $this->initDb();
  83.         $this->initHelpers();
  84.         $this->initView();
  85.         $this->initPlugins();
  86.         $this->initRoutes();
  87.         $this->initControllers();
  88.     }
  89.    
  90.     /**
  91.      * inicializa banco de dados
  92.      *
  93.      * @return void
  94.      */
  95.     public function initDb()
  96.     {
  97.         $db = new Zend_Db_Adapter_Oracle(array(
  98.             'username' => 'xxxxx',
  99.             'password' => 'xxxxx',
  100.             'dbname'   => 'xe'
  101.         ));
  102.        
  103.         Zend_Db_Table_Abstract::setDefaultAdapter($db);
  104.     }
  105.  
  106.     /**
  107.      * inicializa os action helpers
  108.      *
  109.      * @return void
  110.      */
  111.     public function initHelpers()
  112.     {
  113.         Zend_Controller_Action_HelperBroker::addPath('../application/default/helpers', 'Zend_Controller_Action_Helper');
  114.     }
  115.    
  116.     /**
  117.      * inicializa o view
  118.      *
  119.      * @return void
  120.      */
  121.     public function initView()
  122.     {
  123.         Zend_Layout::startMvc(array(
  124.             'layoutPath' => $this->_root .  '/application/default/layouts',
  125.             'layout' => 'main'
  126.         ));
  127.        
  128.     }
  129.    
  130.     /**
  131.      * inicializa plugins
  132.      *
  133.      * @return void
  134.      */
  135.     public function initPlugins()
  136.     {
  137.     }
  138.    
  139.     /**
  140.      * inicializa routes
  141.      *
  142.      * @return void
  143.      */
  144.     public function initRoutes()
  145.     {
  146.     }
  147.  
  148.     /**
  149.      * inicializa os controllers
  150.      *
  151.      * @return void
  152.      */
  153.     public function initControllers()
  154.     {
  155.         $this->_front->addControllerDirectory($this->_root . '/application/default/controllers', 'default');
  156.     }
  157. }

Após isso, nosso arquivo de bootstrap:

PHP:
  1. require_once 'Initializer.php';
  2. require_once 'Zend/Loader.php';
  3.  
  4. Zend_Loader::registerAutoload();
  5.  
  6. $frontController = Zend_Controller_Front::getInstance();
  7. $frontController->registerPlugin(new Initializer('development'));
  8. $frontController->dispatch();

Dessa forma criamos as rotinas de setup e deixamos que o próprio Zend inicialize as coisas para nós.

[]s

3 Comments »

Novembro 27th 2008

Validação de CNPJ utilizando Zend_Validate

Simplesmente adaptei a validação de CPF e alterei algumas coisas, é muito parecido.

Segue o código:

PHP:
  1. <?php
  2.  
  3. require_once 'Zend/Validate/Abstract.php';
  4.  
  5. /**
  6.  * Validador para fazer a validação de CNPJ (Cadastro Nacional da Pessoa Jurídica)
  7.  *
  8.  * @author Diego Tremper <diegotremper@gmail.com>
  9.  */
  10. class Validate_Cnpj extends Zend_Validate_Abstract
  11. {
  12.     const INVALID_DIGITS = 'i_number';
  13.    
  14.     const INVALID_FORMAT = 'i_format';
  15.    
  16.     protected $_messageTemplates = array (
  17.                     self::INVALID_DIGITS => "O CNPJ '%value%' não é válido",
  18.                     self::INVALID_FORMAT => "O formato do CNPJ '%value%' não é válido"
  19.               );
  20.               
  21.     private $_pattern = '/(\d{2})\.(\d{3})\.(\d{3})\/(\d{4})-(\d{2})/i';
  22.    
  23.     private $_skipFormat = false;
  24.    
  25.     /**
  26.      * Inicializa a instância do validador
  27.      *
  28.      * @param bool $skipFormat ignorar validação no formato?
  29.      */
  30.     public function __construct($skipFormat = false) {
  31.         $this->_skipFormat = $skipFormat;
  32.     }
  33.    
  34.     /**
  35.      * verifica se o cnpj é válido
  36.      *
  37.      * @param string $value cnpj a ser validado
  38.      * @return bool
  39.      */
  40.     public function isValid($value)
  41.     {
  42.         $this->_setValue ( $value );
  43.        
  44.         if (!$this->_skipFormat && preg_match($this->_pattern, $value) == false) {
  45.             $this->_error(self::INVALID_FORMAT);
  46.             return false;
  47.         }
  48.        
  49.         $digits = preg_replace('/[^\d]+/i', '', $value);
  50.         $firstSum = 0;
  51.         $secondSum = 0;
  52.        
  53.         $firstSum += (5*$digits{0}) + (4*$digits{1}) + (3*$digits{2}) + (2*$digits{3});
  54.         $firstSum += (9*$digits{4}) + (8*$digits{5}) + (7*$digits{6}) + (6*$digits{7});
  55.         $firstSum += (5*$digits{8}) + (4*$digits{9}) + (3*$digits{10}) + (2*$digits{11});
  56.        
  57.         $firstDigit = 11 - fmod($firstSum, 11);
  58.        
  59.         if ($firstDigit>= 10) {
  60.             $firstDigit = 0;
  61.         }
  62.        
  63.         $secondSum += (6*$digits{0}) + (5*$digits{1}) + (4*$digits{2}) + (3*$digits{3});
  64.         $secondSum += (2*$digits{4}) + (9*$digits{5}) + (8*$digits{6}) + (7*$digits{7});
  65.         $secondSum += (6*$digits{8}) + (5*$digits{9}) + (4*$digits{10}) + (3*$digits{11});
  66.         $secondSum += ($firstDigit*2);
  67.        
  68.         $secondDigit = 11 - fmod($secondSum, 11);
  69.        
  70.         if ($secondDigit>= 10) {
  71.             $secondDigit = 0;
  72.         }
  73.        
  74.         if (substr($digits, -2) != ($firstDigit . $secondDigit)) {
  75.             $this->_error(self::INVALID_DIGITS);
  76.             return false;
  77.         }
  78.        
  79.         return true;
  80.     }
  81. }

Para testar:

PHP:
  1. <?php
  2.  
  3. require_once 'Validate/Cnpj.php';
  4.  
  5. /**
  6.  * testar cnpj com validação no formato e digito verificador
  7.  */
  8. $v = new Validate_Cnpj ( );
  9. var_dump ( $v->isValid ( "03.847.655/0001-98" ) ); //cnpj válido
  10. print_r ( $v->getMessages () );
  11.  
  12. var_dump ( $v->isValid ( "03.847.655/000198" ) ); //cnpj com formato inválido
  13. print_r ( $v->getMessages () );
  14.  
  15. var_dump ( $v->isValid ( "03.847.655/0001-90" ) ); //cnpj com digito verificador inválido
  16. print_r ( $v->getMessages () );
  17.  
  18. /**
  19.  * testar cnpj com validação de digito verificador e SEM validação de formato
  20.  */
  21. $v = new Validate_Cnpj ( true );
  22. var_dump ( $v->isValid ( "03.847.655/0001-98" ) ); //cnpj válido
  23. var_dump ( $v->isValid ( "03847655000198" ) ); //cnpj válido
  24. print_r ( $v->getMessages () );
  25.  
  26. $v = new Validate_Cnpj ( true );
  27. var_dump ( $v->isValid ( "03847655000190" ) ); //cnpj com digito verificador inválido
  28. print_r ( $v->getMessages () );

Os arquivos estão disponíveis no link a seguir: zend_validate_cnpj

[]s

1 Comment »

Novembro 26th 2008

Rolling File utilizando Zend_Log

Alguém já se perguntou porque diabos o Zend_Log não divide os arquivos de logs em vários arquivos? Para quem utiliza ou já utilizou o Log4PHP sabe do que estou falando. Aquela história, o arquivo de log ultrapassou 1MB por ex., é gerado um novo arquivo com o mesmo nome com um sufixo .1 (ex.: aplicacao.log.1) com os logs antigos, e os novos logs são inseridor no arquivo aplicacao.log.

Pois é, dei uma pesquisada sobre isso, alguns dizem que essa funcionalidade não é função do log... que existem outras aplicações que fazem isso... etc,etc. A questão é que isto não foi inserido no framework.

Discução: http://framework.zend.com/issues/browse/ZF-263

Então resolvi fazer uma classe para tratar isso, andei olhando como o Log4PHP faz, e adaptei para o Zend_Log.

PHP:
  1. <?php
  2.  
  3. require_once 'Zend/Log/Writer/Abstract.php';
  4. require_once 'Zend/Log/Formatter/Simple.php';
  5.  
  6. /**
  7.  * @package    Log
  8.  * @author     Diego Tremper <diegotremper@gmail.com>
  9.  */
  10. class Log_Writer_Rolling_File extends Zend_Log_Writer_Abstract {
  11.    
  12.     /**
  13.      * Holds the PHP stream to log to.
  14.      * @var null|stream
  15.      */
  16.     protected $_stream = null;
  17.    
  18.     /**
  19.      * default 1MB
  20.      */
  21.     protected $fileMaxSize = 1048576;
  22.    
  23.     protected $maxFiles = 10;
  24.    
  25.     protected $_filename = null;
  26.    
  27.     /**
  28.      * Class Constructor
  29.      *
  30.      * @param  streamOrUrl     Stream or URL to open as a stream
  31.      * @param  mode            Mode, only applicable if a URL is given
  32.      */
  33.     public function __construct($streamOrUrl, $mode = 'a') {
  34.         if (is_resource ( $streamOrUrl )) {
  35.             $stream_data = stream_get_meta_data ( $streamOrUrl );
  36.            
  37.             if (get_resource_type ( $streamOrUrl ) != 'plainfile') {
  38.                 require_once 'Zend/Log/Exception.php';
  39.                 throw new Zend_Log_Exception ( 'Resource is not a plainfile' );
  40.             }
  41.            
  42.             if ($mode != 'a') {
  43.                 require_once 'Zend/Log/Exception.php';
  44.                 throw new Zend_Log_Exception ( 'Mode cannot be changed on existing streams' );
  45.             }
  46.            
  47.             $filename = $stream_data ['uri'];
  48.             $this->_stream = $streamOrUrl;
  49.         } else {
  50.             if (! $this->_stream = @fopen ( $streamOrUrl, $mode, false )) {
  51.                 $msg = "\"$streamOrUrl\" cannot be opened with mode \"$mode\"";
  52.                 require_once 'Zend/Log/Exception.php';
  53.                 throw new Zend_Log_Exception ( $msg );
  54.             }
  55.            
  56.             $filename = $streamOrUrl;
  57.         }
  58.        
  59.         $this->_fileName = $filename;
  60.        
  61.         fseek ( $this->_stream, filesize ( $this->_fileName ) - 1 );
  62.        
  63.         $this->_formatter = new Zend_Log_Formatter_Simple ( );
  64.     }
  65.    
  66.     /**
  67.      * @return int
  68.      */
  69.     public function getFileMaxSize() {
  70.         return $this->fileMaxSize;
  71.     }
  72.    
  73.     /**
  74.      * Set the maximum size that the output file is allowed to reach
  75.      * before being rolled over to backup files.
  76.      *
  77.      * The maxFileSize option takes an long integer in the range 0 - 2^63.
  78.      * You can specify the value with the suffixes "KB", "MB" or "GB"
  79.      * so that the integer is interpreted being expressed respectively
  80.      * in kilobytes, megabytes or gigabytes. For example, the value "10KB"
  81.      * will be interpreted as 10240.
  82.      *
  83.      * @param int|string $fileMaxSize
  84.      */
  85.     public function setFileMaxSize($fileMaxSize) {
  86.         if (is_string($fileMaxSize)) {
  87.             $this->fileMaxSize = $this->_convertMaxFileSize($fileMaxSize);
  88.         } else {
  89.             $this->fileMaxSize = $fileMaxSize;
  90.         }
  91.     }
  92.    
  93.     /**
  94.      * @return int
  95.      */
  96.     public function getMaxFiles() {
  97.         return $this->maxFiles;
  98.     }
  99.    
  100.     /**
  101.      * @param int $maxFiles
  102.      */
  103.     public function setMaxFiles($maxFiles) {
  104.         $this->maxFiles = $maxFiles;
  105.     }
  106.    
  107.     /**
  108.      * Close the stream resource.
  109.      *
  110.      * @return void
  111.      */
  112.     public function shutdown() {
  113.         if (is_resource ( $this->_stream )) {
  114.             fclose ( $this->_stream );
  115.         }
  116.     }
  117.    
  118.     /**
  119.      * Write a message to the log.
  120.      *
  121.      * @param  array  $event  event data
  122.      * @return void
  123.      */
  124.     protected function _write($event) {
  125.         $line = $this->_formatter->format ( $event );
  126.        
  127.         if (false === @fwrite ( $this->_stream, $line )) {
  128.             require_once 'Zend/Log/Exception.php';
  129.             throw new Zend_Log_Exception ( "Unable to write to stream" );
  130.         }
  131.        
  132.         if (ftell ( $this->_stream )> $this->fileMaxSize)
  133.             $this->_rollOver ();
  134.     }
  135.    
  136.     protected function _rollOver() {
  137.         if ($this->maxFiles> 0) {
  138.             $file = $this->_fileName . '.' . $this->maxFiles;
  139.            
  140.             if (is_writable ( $file ))
  141.                 unlink ( $file );
  142.            
  143.             for($i = $this->maxFiles - 1; $i>= 1; $i --) {
  144.                 $file = $this->_fileName . '.' . $i;
  145.                 if (is_readable ( $file )) {
  146.                     $target = $this->_fileName . '.' . ($i + 1);
  147.                     rename ( $file, $target );
  148.                 }
  149.             }
  150.            
  151.             $target = $this->_fileName . '.1';
  152.            
  153.             $this->shutdown ();
  154.            
  155.             rename ( $this->_fileName, $target );
  156.         }
  157.        
  158.         $this->__construct ( $this->_fileName, 'w' );
  159.     }
  160.    
  161.     /**
  162.      * Convert maxFileSize value
  163.      *
  164.      * @param mixed $value
  165.      */
  166.     private function _convertMaxFileSize($value) {
  167.         $maxFileSize = null;
  168.         $numpart = substr ( $value, 0, strlen ( $value ) - 2 );
  169.         $suffix = strtoupper ( substr ( $value, - 2 ) );
  170.        
  171.         switch ($suffix) {
  172.             case 'KB' :
  173.                 $maxFileSize = ( int ) (( int ) $numpart * 1024);
  174.                 break;
  175.             case 'MB' :
  176.                 $maxFileSize = ( int ) (( int ) $numpart * 1024 * 1024);
  177.                 break;
  178.             case 'GB' :
  179.                 $maxFileSize = ( int ) (( int ) $numpart * 1024 * 1024 * 1024);
  180.                 break;
  181.             default :
  182.                 require_once 'Zend/Log/Exception.php';
  183.                 throw new Zend_Log_Exception ( 'Invalid size' );
  184.         }
  185.        
  186.         return $maxFileSize;
  187.     }
  188.  
  189. }

Para testar:

PHP:
  1. <?php
  2.  
  3. require 'Zend/Log.php';
  4. require 'Log/Writer/Rolling/File.php';
  5.  
  6. $writer = new Log_Writer_Rolling_File('aplicacao.log');
  7. $writer->setFileMaxSize("10KB");
  8. $writer->setMaxFiles(10);
  9. $logger = new Zend_Log($writer);
  10.  
  11. for ($i=0; $i<1000; $i++) {
  12.     $logger->debug('Este é um debug para teste de rolling file utilizando zend_log : ' . $i);
  13. }

Para quem quiser os arquivos, segue o link: rolling_file_zend_log.

[]s

No Comments yet »

Novembro 25th 2008

Validação de CPF utilizando Zend_Validate

Há algum tempo eu estava devendo algum post técnico, então resolvi dar uma brincada com o Zend_Validate, posto aqui um validator que fiz para CPF (Cadastro de Pessoas Físicas). A quem possa servir segue o código:

PHP:
  1. <?php
  2.  
  3. require_once 'Zend/Validate/Abstract.php';
  4.  
  5. /**
  6.  * Validador para fazer a validação de CPF (Cadastro de Pessoas Físicas)
  7.  *
  8.  * @author Diego Tremper <diegotremper@gmail.com>
  9.  */
  10. class Validate_Cpf extends Zend_Validate_Abstract
  11. {
  12.     const INVALID_DIGITS = 'i_number';
  13.    
  14.     const INVALID_FORMAT = 'i_format';
  15.    
  16.     protected $_messageTemplates = array (
  17.                     self::INVALID_DIGITS => "O cpf '%value%' não é válido",
  18.                     self::INVALID_FORMAT => "O formato do cpf '%value%' não é válido"
  19.               );
  20.               
  21.     private $_pattern = '/(\d{3})\.(\d{3})\.(\d{3})-(\d{2})/i';
  22.    
  23.     private $_skipFormat = false;
  24.    
  25.     /**
  26.      * Inicializa a instância do validador
  27.      *
  28.      * @param bool $skipFormat fazer validação no formato?
  29.      */
  30.     public function __construct($skipFormat = false) {
  31.         $this->_skipFormat = $skipFormat;
  32.     }
  33.    
  34.     /**
  35.      * verifica se o cpf é válido
  36.      *
  37.      * @param string $value cpf a ser validado
  38.      * @return bool
  39.      */
  40.     public function isValid($value)
  41.     {
  42.         $this->_setValue ( $value );
  43.        
  44.         if (!$this->_skipFormat && preg_match($this->_pattern, $value) == false) {
  45.             $this->_error(self::INVALID_FORMAT);
  46.             return false;
  47.         }
  48.        
  49.         $digits = preg_replace('/[^\d]+/i', '', $value);
  50.         $firstSum = 0;
  51.         $secondSum = 0;
  52.        
  53.         for ($i=0; $i<9; $i++) {
  54.             $firstSum += $digits{$i} * (10 - $i);
  55.             $secondSum += $digits{$i} * (11 - $i);
  56.         }
  57.        
  58.         $firstDigit = 11 - fmod($firstSum, 11);
  59.        
  60.         if ($firstDigit>= 10) {
  61.             $firstDigit = 0;
  62.         }
  63.        
  64.         $secondSum = $secondSum + ($firstDigit*2);
  65.         $secondDigit = 11 - fmod($secondSum, 11);
  66.        
  67.         if ($secondDigit>= 10) {
  68.             $secondDigit = 0;
  69.         }
  70.        
  71.         if (substr($digits, -2) != ($firstDigit . $secondDigit)) {
  72.             $this->_error(self::INVALID_DIGITS);
  73.             return false;
  74.         }
  75.        
  76.         return true;
  77.     }
  78. }

Para utilizar:

PHP:
  1. <?php
  2.  
  3. require_once 'Validate/Cpf.php';
  4.  
  5. /**
  6.  * testar cpf com validação no formato e digito verificador
  7.  */
  8. $v = new Validate_Cpf ( );
  9. var_dump ( $v->isValid ( "123.456.789-09" ) ); //cpf válido
  10. print_r ( $v->getMessages () );
  11.  
  12. var_dump ( $v->isValid ( "123.456.78909" ) ); //cpf com formato inválido
  13. print_r ( $v->getMessages () );
  14.  
  15. var_dump ( $v->isValid ( "123.456.789-08" ) ); //cpf com digito verificador inválido
  16. print_r ( $v->getMessages () );
  17.  
  18. /**
  19.  * testar cpf com validação de digito verificador e SEM validação de formato
  20.  */
  21. $v = new Validate_Cpf ( true );
  22. var_dump ( $v->isValid ( "123.456.789-09" ) ); //cpf válido
  23. var_dump ( $v->isValid ( "12345678909" ) ); //cpf válido
  24. print_r ( $v->getMessages () );
  25.  
  26. $v = new Validate_Cpf ( true );
  27. var_dump ( $v->isValid ( "12345678900" ) ); //cpf com digito verificador inválido
  28. print_r ( $v->getMessages () );

Para quem quiser os arquivos segue o link: validate.zip. (Não há nada além do código acima!)

Referência: http://framework.zend.com/manual/en/zend.validate.html

[]s

5 Comments »

Outubro 22nd 2008

Palestra sobre Integração Contínua - CONAPHP 2008

No último domingo dia 19/10/2008, estive em São Paulo no CONAPHP, evento realizado pelo ProPHP juntamente com a organização do Conisli. No evento falei sobre Integração Contínua aplicada a equipes PHP.
Aos que se interessarem, abaixo estão os slides da palestra.

[]s

1 Comment »

Março 7th 2008

Criando objetos DateTime a partir de qualquer formato

Devido a reclamações de programadores PHP, sobre as funções strtotime() e date_create() atualmente analisarem apenas string de datas no formato americano, Derick Rethans adicionou uma nova função (date_create_from_format()) e um novo método a classe DateTime (DateTime::createFromFormat()) a release 5.3 do PHP (ainda em desenvolvimento), assim será possível criar objetos do tipo DateTime a partir de outros formatos de data.

O uso é muito simples:

PHP:
  1. <?php
  2. $dt = date_create_from_format( 'd/m/Y', "02/03/2008" );
  3. echo $dt->format( 'd/m/Y' ), "\n";
  4. ?>

O primeiro argumento deverá ser passado o formato da data que é passada no segundo argumento. O retorno será uma instância da classe DateTime, com a data informada no segundo parâmetro da função. Caso o PHP não consiga analisar a data informada a função retornará falsp e será possível recuperar as mensagens de erro a partir do método date_get_last_errors().

PHP:
  1. <?php
  2. $dt = date_create_from_format( 'Y-m-d', "02/03/2008" );
  3. if ( !$dt ) {
  4.       $errors = date_get_last_errors();
  5.       var_dump( $errors['errors']);
  6. }
  7. ?>

fonte: http://www.derickrethans.nl/british_date_format_parsing.php

[]'s

1 Comment »

Janeiro 15th 2008

Busca no site? Com Zend_Search_Lucene claro!

O Zend_Search_Lucene é uma módulo do Zend Framework que serve para indexar strings, o módulo é baseado no projeto Apache Lucene porém portado para PHP. Com ele é possível indexar o conteúdo de seu site e depois executar consultas baseadas no índice criado.

Nestes ultimos dias andei dando uma olhada no componente, então resolvi postar aqui no blog o exemplo que adaptei da apresentação de Wil Sinclair sobre o módulo do framework.

Não vou explicar detalhes sobre a implementação aqui no blog, sendo que o que fiz foi praticamente um copy e paste do exemplo dado na apresentação, mas aos que tiverem dúvidas, basta comentar aqui no blog ou postar lá no fórum http://www.zfbrasil.com/forum/, posso tentar dar uma ajuda.

Aos que quiserem mais informações a respeito do Zend_Search_Lucene, a uma boa documentação disponível no manual do framework.
http://framework.zend.com/manual/en/zend.search.lucene.html

Obs.: No exemplo que deixei dispoível para download abaixo, a um crawler com a url do meu blog apontada. Peço aos que testarem, que não fiquem executando muitas vezes o script com a url do blog, se não vai acabar estourando a minha cota de tranferência :).

Os arquivos do exemplo : zfsearch.zip

Abraço a todos.

20 Comments »

Dezembro 5th 2007

array X ArrayIterator == cópia X referência

A questão é a seguinte, imagine que você precise imprimmir todos os elementos de um array, qual a solução para isso? use um foreach, óbvio.

Agora vamo imaginar que dentro deste foreach onde você esta imprimindo os elementos de seu array, tenha alguma lógica que pode adicionar ou não mais elementos ao array que você esta iterando no momento. Ex.:

PHP:
  1. $a = array('PHP', 'Java', 'Ruby');
  2.  
  3. foreach ($a as $value) {
  4.   if ($value == 'PHP') {
  5.     $a[] = 'PHP-GTK';
  6.   }
  7.  
  8.   echo $value . "\r\n";
  9. }

Reparem que no exemplo acima a saida final seria:

PHP
Java
Ruby

E o PHP-GTK por que não imprimiu?
Isto acontece porque o PHP faz com que o foreach trabalhe com um 'cópia' do array que você passou como parametro assim quando você adiciona um elemento para o seus array, não irá influenciar na cópia que esta sendo usada pelo foreach.

Esta situação é facilmente resolvida se você utilizar um objeto que implemente a interface Iterator, como o ArrayIterator por exemplo.

Se você passar um objeto do tipo Iterator como parametro para o comando foreach ele não irá criar uma cópia de seu objeto, irá utilizar a referência. Desta maneira é possível garantir que todos os elementos de seu array serão iterados. Ex.:

PHP:
  1. $a = array('PHP', 'Java', 'Ruby');
  2. $a = new ArrayIterator($a);
  3.  
  4. foreach ($a as $value) {
  5.   if ($value == 'PHP') {
  6.     $a[] = 'PHP-GTK';
  7.   }
  8.  
  9.   echo $value . "\r\n";
  10. }

Espero que a informação tenha sido util, infelizmente na documentação do
PHP este tipo de situação não esta "bem documentada". :P

Abraço a todos.

2 Comments »

Dezembro 1st 2007

Palestra do PHP Conference

Após uma semana cheia de tarefas finalmente o PHP Conference 2007...
Infelizmente não aproveitei praticamente nada do evento, na sexta-feira meu vôo para São Paulo atrasou, assim acabei chegando no final do dia. Já no hotel conheci alguns palestrantes, o pessoal muito gente boa, fomos a uma churrascaria, foi a maior farra. Mas voltando ao que interessa, sábado apresentei minha palestra sobre qualidade de software com o PHPUnit, a palestra não estava completamente lotada, mas haviam muitos conferencistas, o pessoal mostrou interesse pelo assunto. Pelo que percebi, a utilização do PHPUnit ainda não é uma coisa muito comum entre a comunidade, procurei esclarecer as dúvidas de todos, espero ter conseguido. Tive alguns problemas com o projetor e o Ubuntu, então precisei que apresentar utilizando o Windows Vista, foi uma pena, pois havia preparado o ambiente com alguns exemplos legais para a apresentação. Após a palestra, apresentei a alguns conferencistas mais interessados alguns exemplos práticos e algumas configurações necessárias para rodar os softwares que mencionei na palestra.

Aos conferencistas que estiveram em minha palestra espero que tenham gostado, este neste post abro espaço para críticas, sugestões, elogios, etc. No caso de ter ficado alguma dúvida, é só fazer um contato que eu procuro ajudar.

Slides da palestra: Qualidade no desenvolvimento de Software com PHPUnit

Abraço a todos.

9 Comments »

Next »