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.

