Estava fazendo alguns testes com PDO e SQLite e descobri uma coisa muito interessante sobre o PDO: classe de resultados. O que isso quer dizer, que quando você faz um fetchObject você pode usar sua própria classe com seus próprios métodos.
Atenção! Este post é totalmente NERD e destinado para programadores com algum conhecimento em PHP e banco de dados. Caso este não seja seu perfil aconselho a desistir enquanto é tempo.
O código começou mais ou menos assim, eu queria desenvolver um model específico para o ICEPHP, e com o advento do PDO decidi usá-lo como base. Então precisei de alguns definitions: diretório onde se encontra o arquivo (script) e o separador de pastas que em linux é barra e no windows é contra-barra. Também criei duas tabelas no banco de dados, post e categoria:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | define('DS', DIRECTORY_SEPARATOR); define('ICE_DIR', dirname(__FILE__)); $bd = new PDO('sqlite:'.ICE_DIR.DS.'banco.db'); # A conexão do PDO não é linda?! $bd->query(" CREATE TABLE IF NOT EXISTS categoria ( id INTEGER PRIMARY KEY AUTOINCREMENT, nome VARCHAR(40), slug VARCHAR(40) ); "); $bd->query(" CREATE TABLE IF NOT EXISTS post ( id INTEGER PRIMARY KEY AUTOINCREMENT, titulo VARCHAR(40), slug VARCHAR(40), post TEXT, data TIMESTAMP ); "); |
Após isso fiz um select no banco de dados e se não me retornasse resultados, inseri um dado no banco de dados:
1 2 3 4 5 6 7 8 9 10 11 12 | $c=$bd->query("SELECT COUNT(*) as c FROM post;"); if (!$c->fetchObject()->c) { $bd->query(" INSERT INTO post (titulo, slug, post, data) VALUES ( 'Apenas um teste', 'apenas-um-teste', 'Este post é apenas um teste do novo Framework: ICEPHP', CURRENT_DATE ); "); } |
Com isso eu consigo usar o resultado de forma linda (orientado a objetos):
1 2 3 4 5 | $c=$bd->query("SELECT * FROM post;"); $r = $c->fetchObject(); echo $r->titulo; // Isto retorna "Apenas um teste" |
Lendo a documentação sobre o fetchObject do PDO vi que é possivel passar como parâmetro uma string com o nome da Classe que você deseja que seja utilizado para o resultado, lembrando que (!), o padrão é o stdClass. Entao passei minha classe resultado como exemplo e o que descobri. Coisas lindas de se fazer. Eis a classe Resultado:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | class Resultado { var $_data = array(); var $_updated = false; function __toString() { return "O resultado é: ".$this->titulo . ' ('.date('d-m-Y h:i:s', $this->data).")\n"; } function __get($k) { return $this->_data[$k]; } function __set($k, $v) { if (isset($this->_data[$k]) AND $this->_data[$k] != $v) { $this->_updated = true; } $this->_data[$k] = $v; } function salvaPost() { global $bd; $sql = "UPDATE post SET "; foreach ($this->_data as $k=>$v) { if ($k!='id' || $k != 'data') { $sql .= "\n $k = '$v',"; } } $sql = substr($sql, 0, -1); $sql .= "\n WHERE id = ".$this->id; $bd->query($sql); } function __destruct() { if ($this->_updated) { $this->salvaPost(); } } } |
Veja, apenas usei um método de verdade, todos os outros usei os métodos mágicos do PHP (__toString, __get, __set, __destruct). Recomendo que leia sobre estes métodos e use-os, eles podem salvar sua vida. Whatever, com essa classe Resultado é possivel fazer o que eu sempre quis fazer, um objeto de resultado de banco de dados que atualiza o banco sem usar o estilo seta parametros e depois salva. Veja como é feito na maioria dos ORMs por aí:
1 2 3 | $r=$post->get(1); $r->titulo = 'Titulo Alterado'; $r->save(); |
Pense comigo, se você atribuiu um valor, você quer que ele seja salvo, correto? Então não ficaria mais fácil se forsse assim?
1 2 | $r=$post->get(1); $r->titulo = 'Titulo Alterado'; |
Sim!!! Às vezes você atribui um valor que não deseja salvar, faz isso apenas para configurar os dados e etc, mas pense, quantas vezes você faz isso? Além disso, óbvio que é possivel fazer tudo o que deseja gastando um pouco mais de massa cinzenta, mas a proposta não é essa no momento.
Usando a classe Resultado é possivel fazer o update quase que “on the fly”. Na verdade, para o programador parece que é instantâneo, mas não é. O update se dá no destruct do objeto, normalmente quando o script finaliza, mas pode ser quando damos um novo fetchObject nessa variável. Se ele não for alterado ele, obviamente, não salva as alterações no banco de dados. Veja como fica o exemplo do que estou falando.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | $c=$bd->query("SELECT * FROM post;"); # Pegando o objeto e jogando-o na classe de resultados $r = $c->fetchObject('Resultado'); # Imprimindo, devido ao método __toString aparece: # O resultado é: Apenas um teste (31-12-1969 09:33:29) print ($r); # Alterando o resultado $r->titulo = 'Teste'; # Imprimindo mais uma vez, aparece # O resultado é: Teste (31-12-1969 09:33:29) # mas isto está em 'cache' print ($r); # Quando o objeto é destruído, ao finalizar o script # ele faz o update necessário |
Testei isso no foreach e também funcionou, então é fazer updates de objetos em escala, mas não exagere, o ideal é fazer isso no sql. Veja como fica com o foreach:
1 2 3 4 5 | $c=$bd->query("SELECT * FROM post;"); while ($x = $c->fetchObject('Resultado')) { $x->data = time(); } |
Isso me deixa com várias ideias para criar o ORM do ICEPHP. Mas fica a dica para vocês desenvolverem seus códigos, experimente criar um método FORM que já cria um formulário html para você facilitar sua vida.

No @vorticephp já trabalho assim… e tenho um componente para CRUD que é bem parecido com o seu Resultado:
http://github.com/caferrari/vorticephp
http://github.com/caferrari/vorticephp-crud
porém tive que desabilitar o cast de objetos, não estava funcionando, deve ser por causa da minha versão do PHP, hj vou revisar isso e, se funcionar ok, vou reativar
Posted by Carlos A. Ferrari on October 23rd, 2009.