Tenho recebido diversos e-mails com perguntas relacioandas a como fazer consultas nos dados armazenados. Então, resolvi escrever este artigo para dar continuidade ao primeiro. A base dos arquivos que vou utilizar são os apresentados no artigo anterior.
Preparações
1. Bootstrap
É interesssante fazermos um bootstrap, assim, quando instanciarmos uma entidade, o arquivo será carregado automaticamente e não precisaremos nos preocupar com includes. Para isso, utilizarei a função spl_autoload_register.
Vamos então criar um arquivo chamado “autoload_register”, que deve ficar dentro de “/application/libraries” com o seguinte código:
//Registra o autoload das classes
spl_autoload_register('Autoload_Register::register');
/**
* Executa o autoload de classes que não são do CI nem de PEAR
*/
class Autoload_Register
{
const CI_PREFIX = "CI_";
const PEAR = 'PEAR';
/**
* Faz o registro
*
* @param string $classe
* @return void
*/
public static function register($classe)
{
$paths = array();
$paths[] = APPPATH . 'models/Entities';
//Classes do CI e do PEAR são ignoradas
if (strstr($classe, self::CI_PREFIX) || stristr($classe, self::PEAR))
{
//Nada a fazer
return;
}
//Remove o namesapce
$vetClasse = explode('\\', $classe);
$classe = $vetClasse[count($vetClasse)-1];
//Garante que "$paths" seja um array
if (is_array($paths) && count($paths) > 0)
{
//Localiza arquivos nos paths determinados no inicio da classe
foreach ($paths as $dir)
{
$files = self::find($dir, $classe . EXT);
//Se tiver arquivos a serem incluidos, executa o require_once para cada um deles
if (is_array($files) && count($files) > 0)
{
foreach ($files as $file)
{
if (is_file($file))
require_once $file;
}
}
}
}
}
// ------------------------------------------------------------------------
/**
* Procura por arquivos
*
* @param string $dir
* @param string $pattern
* @return array
*/
private function find($dir, $pattern)
{
// Elimina caracteres inválidos para comandos shell
$dir = escapeshellcmd($dir);
// pega a lista de todas as coincidencias no diretorio corrente
$files = glob("$dir/$pattern");
// procura a lista de todos os sub diretorios no diretorio corrente
// diretorios iniciados por um ponto também são incluidos
foreach (glob("$dir/{.[^.]*,*}", GLOB_BRACE | GLOB_ONLYDIR) as $sub_dir)
{
$arr = self::find($sub_dir, $pattern); // chamada revursiva
$files = array_merge($files, $arr); // faz um merge no array com os arquivos do sub diretorio
}
// retorna todos os arquivos encontrados
return $files;
}
}
Criado o arquivo, precisamos colocá-lo no autoload do CI. A chave ‘libraries’ da matriz $autoload deve ficar da seguinte forma:
$autoload['libraries'] = array('database', 'Doctrine', 'autoload_register');
Pronto, quando o CI carregar essa library, a primeira coisa que ela vai fazer é registrar no SPL_AUTOLAD o método “register” da classe “Autoload_Register”. E sempre que for criada uma nova instância de uma classe, o PHP vai passar primeiro por esse método “register”, que por sua vez vai procurar dentro na pasta “models/Entities” o arquivo que ele deve fazer o require.
2. Preparando os dados
Antes de fazer o teste, vou adicionar um campo no banco de dados chamado “idade”. Para isso vou adicionar a propriedade $idade na classe “usuário”. Isso vai facilitar explicações futuras.
/** * @Column(type="integer", nullable=true) * @var type */ public $idade;
E vou rodar um comando do doctrine para atualizar a base de dados:
php doctrine orm:schema-tool:update --force
Feito isso, podemos fazer um teste alterando a forma popular do objeto “usuário” para o seguinte:
public function index()
{
$usuario = new usuario();
$usuario->set_nome('Ricardo');
$usuario->set_email('meuemail@mail.com.br');
$usuario->set_telefone('11-1122-3345');
$usuario->set_celular('11-9988-7765');
$usuario->set_idade(25);
$this->doctrine->em->persist($usuario);
$this->doctrine->em->flush();
}
Repare que foi retirado o “$this->load->model(‘Entities/usuario’, ‘usuario’);” do arquivo que fizemos no artigo anterior. Tembém foram implementados os getters e setters da classe “usuario”.
Para melhorar os testes e não precisar gastar a criatividade inserindo diversos usuários, podemos utilizar o site http://www.generatedata.com para gerar dados aleatórios e popular o banco.
Mão na massa
Finalmente vamos ao que interessa: fazer as consultas. Existem diversas formas de consultar um dado com o Doctrine. Vou citar aqui as que mais utilizo e a partir daí cada um poderá utilizar o que achar mais adequado para cada situação.
A documentação está disponível no site do Doctrine.
1. find()
A sintaxe é: $em->find($entidade, $id). A função find() vai procurar na entidade informada o registro com o ID solicitado. Podemos utilizar da segunte forma:
/**
* Localiza o usuario para ser editado
*
* @param int $id
*/
public function editar($id)
{
$usuario = $this->doctrine->em->find('usuario', $id);
if ($usuario instanceof usuario)
{
echo 'Nome: ' . $usuario->get_nome() . '<br>';
//Aqui pode carregar a view para editar o usuário
}
else
{
echo 'Usuário não localizado';
//Volta para a listagem informando que o usuário não existe
}
}
2. findOneBy()
A sintaxe é: $em->getRepository($entidade)->findOneBy(array($campo => $valor)). Esta função faz uma busca na entidade informada buscando pelo campo e valores solicitados. Veja um exemplo:
/**
* Consulta pelo campo e valor solicitado
*
* @param string $campo Nome do campo onde se deseja fazer a busca
* @param mixed $valor Valor que deve ser localizado
* @link http://doctrine-orm.readthedocs.org/en/latest/reference/working-with-objects.html#by-simple-conditions
*/
public function localizar($campo, $valor)
{
$usuario = $this->doctrine
->em
->getRepository('usuario')
->findOneBy(array($campo => $valor));
if ($usuario instanceof usuario)
{
echo 'Nome: ' . $usuario->get_nome() . '<br>';
}
else
{
echo 'Usuário não localizado';
}
}
Então, para buscar o usuário “ricardo” basta fazer o seguinte:
$this->localizar('nome', 'ricardo');
Isto irá gerar uma SQL assim: SELECT * FROM usuario WHERE nome = ‘ricardo’.
3. DQL – Doctrine Query Language
Para fazermos buscas mais avançadas, podemos utilizar as DQLs (Doctrine Query Language), onde iremos escrever um código muito parecido com a SQL com pequenos detalhe de diferença, veja:
/**
* Localiza um usuário que tenha a idade entre dois valores
*
* @param type $idade_menor
* @param type $idade_maior
* @link http://doctrine-orm.readthedocs.org/en/latest/reference/working-with-objects.html#by-dql DQL
*/
public function localizar_por_idade($idade_menor, $idade_maior)
{
$usrs = $this->doctrine
->em
->createQuery("SELECT u FROM usuario u WHERE u.idade >= {$idade_menor} and u.idade <= {$idade_maior}")
->getResult();
if (is_array($usrs) && count($usrs) > 0)
{
foreach ($usrs as $i => $usuario)
{
if ($usuario instanceof usuario)
{
echo "{$i} - Nome: {$usuario->get_nome()}<br>";
}
}
}
}
Veja que interessante, na SQL, no lugar do nome da tabela, utilizei o nome da entidade que criamos e em vez de utilizar um * para trazer todos os campos, utilizei o apelido dado à entidade.
Dessa forma, poderemos inclusive fazer joins quando necessário. No próximo artigo vou escrever sobre o relacionamento de entidades. Vamos gerar a entidade “endereco” e por fim faremos uma busca com join entre as tabelas para mostrar o poder da DQL.
Conclusão
O Doctrine nos dá muita rapidez no desenvolvimento – isso será percebido mais ainda no próximo artigo, quando eu mostrar os relacionamentos entre entidades e a facilidade de acessso aos dados.
Existem outras forma de fazer busca no Doctrine, mas espero que com essas que apresentei aqui, seja possivel você começar a entender melhor como ele funciona e partir para novas implementações. Os arquivos do artigo estão disponíveis aqui.
No próximo artigo irei abordar o relacionamento entre entidades.
Espero que esse artigo possa ajudar vocês. Um abraço e até o próximo!



