Laravel Collections & Eloquent ORM, uma breve introdução (Parte 2)

Leonardo Cavalcante
sysvale
Published in
7 min readAug 8, 2018

Na parte 1 deste post discutimos sobre as collections do Laravel e seus métodos. Chegamos, finalmente, a hora de mostrar um dos casos de uso mais recorrentes delas, as queries do Eloquent ORM.

Preparação

para uma melhor sintonia entre post, conteúdo e aprendizado, é interessante que tenhamos em mãos um ambiente em que seja possível realizar as queries e exemplos deste post.

Precisaremos de um servidor rodando uma instalação do Laravel 5.6 e de um servidor MongoDB 3.4.x. Além disso, utilizaremos parte do código disponível no projeto laravel-for-knights, no branch code-along.

Uma vez o repositório clonado, é possível seguir os passos descritos no arquivo README.mdpara fazer um setup “semi-automático” do servidor Laravel e MongoDB, ou, alternativamente, configurar um setup próprio.

Se tudo ocorrer bem, acessar o endereço e porta do servidor o levará a elegante página mostrada abaixo.

Muito embora motivadora, não trabalharemos nela, e sim na página apresentada após clicar no botão GO TO TERMINAL. Todos os exemplos de comandos artisan aqui apresentados serão executados nessa página, que não possui a necessidade de executar o artisan através de uma chamada ao comando php. Isto é, ao invés de executar $ php artisan foo em uma instalação usual do Laravel, utilizaremos $ artisan foo no terminal web.

Vale ressaltar que, como o Laravel não suporta, até o momento, o MongoDB, estaremos utilizando a biblioteca Laravel MongoDB, que, segundo sua própria documentação, em tradução livre, trata-se de

Um Eloquent model e Query builder com suporte para o MongoDB e que utiliza a API original do Laravel. Esta biblioteca estende as classes originais do Laravel, de modo que ela utiliza exatamente os mesmos métodos.

A base de dados utilizada

Trabalharemos em uma base de dados bem simples e que foi pensada somente como um modo de exemplificar o uso dos Models e outros aspectos do Laravel. Seu modelo ER (Entidade e Relacionamento) é mostrado abaixo.

Começaremos construindo os Models para essas entidades e os utilizaremos nos exemplos subsequentes.

Construindo os Models

Ao trabalhar com Models e o Eloquent ORM, devemos ter em mente, como diz a documentação do Laravel, que

Cada tabela do banco de dados tem um “Model” correspondente que é utilizado para interagir com essa tabela. Os Models permitem a busca e inserção de dados nesssas tabelas.

Começaremos criando o model para a tabela knight_types. O modo mais transparente para realizar tal tarefa é através do comando artisan

artisan make:model KnightType

Ele cria todo o boilerplate do Model, no arquivo app/KnightType.php . Seu conteúdo é mostrado abaixo.

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class KnightType extends Model
{
//
}

O Laravel assume, neste caso, que o nome da classe, em Camel Case e no singular, refere-se à tabela, de mesmo nome e no plural, em snake_case. São convenções que o framework utiliza, e tudo acontece automagicamente. É possível modificar o comportamento padrão assumido pelo Laravel, porém não discutiremos isso aqui, e mais detalhes podem ser consultados na documentação.

Continuando… podemos realizar o mesmo procedimento para a tabela knights, obtendo o arquivo app\Knight.php , cujo conteúdo é mostrado abaixo

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Knight extends Model
{
//
}

Existe, porém, um problema com os Models criados. Estamos utilizando o MongoDB, e, para que possamos utilizar os Models, sem que ocorra nenhum erro, precisamos extender da classe Moloquent, já pré-configurada no repositório aqui utilizado e clonado na seção de preparação. Os Models resultantes são mostrados abaixo.

// app/KnightType.php<?phpnamespace App;use Moloquent;class KnightType extends Moloquent
{
//
}
// app/Knight.php<?phpnamespace App;use Moloquent;class Knight extends Moloquent
{
//
}

Se executarmos o comando tinker no nosso terminal web, é possível realizar a query App\\KnightType::all()->toArray() , que deve produzir como saída

=> array ()

Estamos aptos a serguir para o próximo passo.

Populando as tabelas

No repositório aqui utilizado, é disponibilizado o comando artisanpopulate:knights , que preenche as Collections Knight e KnightType automagicamente. No terminal web, ele pode ser executado através da linha

artisan populate:knights

Desta vez, executar a linha App\\KnightType::all()->toArray() , no tinker, produz o resultado

=> array (
0 =>
array (
'_id' => '5b676739a71631009108f962',
'name' => 'Deuses',
'updated_at' => '2018-08-05 21:08:09',
'created_at' => '2018-08-05 21:08:09',
),
1 =>
array (
'_id' => '5b676739a71631009108f963',
'name' => 'Ouro',
'updated_at' => '2018-08-05 21:08:09',
'created_at' => '2018-08-05 21:08:09',
),
2 =>
array (
'_id' => '5b676739a71631009108f964',
'name' => 'Prata',
'updated_at' => '2018-08-05 21:08:09',
'created_at' => '2018-08-05 21:08:09',
),
3 =>
array (
'_id' => '5b676739a71631009108f965',
'name' => 'Bronze',
'updated_at' => '2018-08-05 21:08:09',
'created_at' => '2018-08-05 21:08:09',
),
4 =>
array (
'_id' => '5b676739a71631009108f966',
'name' => 'Espectros',
'updated_at' => '2018-08-05 21:08:09',
'created_at' => '2018-08-05 21:08:09',
),
5 =>
array (
'_id' => '5b676739a71631009108f967',
'name' => 'Marcianos',
'updated_at' => '2018-08-05 21:08:09',
'created_at' => '2018-08-05 21:08:09',
),
6 =>
array (
'_id' => '5b676739a71631009108f968',
'name' => 'Mais',
'updated_at' => '2018-08-05 21:08:09',
'created_at' => '2018-08-05 21:08:09',
),
)

Nota sobre os próximos exemplos

No repositório que clonamos, é disponibilizado um comando artisan para executarmos alguns exemplos, um “ambiente de trabalho”. É o comando wokplace , no arquivo app/Console/Commands/WorkplaceCommand.php . Não discutiremos aqui os detalhes de implementação de um comando artisan no Laravel, somente utilizaremos este artefato para que executar e editar os exemplos se torne mais cômodo. O código dele é mostrado abaixo.

Colocaremos nossos códigos de exemplo no método handle desse comando, de modo que será possível executar esse código através da linha artisan workplace . Daqui em diante, será assumido que os exemplos discutidos seguirão essa regra.

Realizando consultas

Uma vez os Models criados, podemos realizar várias consultas interessantes. O Query Builder disponibiliza diversos métodos e, assim como as collections, uma interface fluente. Falaremos de alguns deles aqui.

O primeiro deles é o all , utilizado na seção anterior. Ele retorna uma collection (ELAS VOLTARAM!) com todos os registros da tabela.

Nada melhor do que um exemplo para testar isso. O código abaixo imprime o nome de todos os cavaleiros na collection knights.

O fato do resultado ser uma collection, torna possivel executar, ainda, o mesmo código, utilizando o método each discutido na parte 1 (Tente isso!).

É também possível restringir o resultado de buscas utilizando cláusulas where, utilizando os métodos where , orWhere , whereNull , whereNotNull , whereIn , etc. Estes métodos podem ser concatenados uns aos outros, gerando uma cadeia de restrições que funcionam como uma sequência de “ANDs” lógicos.

No código abaixo, recuperamos todos os cavaleiros cujo o nome é ‘Shiryu’ e cuja constelação é ‘Dragão’.

que imprime como resultado

Shiryu é cavaleiro de DRAGÃO!

Observe que o método get foi utilizado para recuperar os resultados da query. Alternativamente, se soubermos que só existe um resultado para uma query, podemos utilizar o método first , que retorna o primeiro (e no caso único) resultado da query.

Além disso, adicionar a linha $this->info(get_class($knights)) ao fim desse exemplo, faz com que seja impresso Illuminate\Database\Eloquent\Collection , relembrando que resultados de queries, no Laravel, são collections.

Se quisermos pesquisar por todos os cavaleiros que sejam ou Shiryu, ou Ikki, ou Shun, podemos usar o whereIn , como no caso abaixo.

O restante dos métodos é bastante intuitivo, e a documentação do Laravel, como sempre, não decepciona neste ponto, valendo a sua leitura.

E sobre os relacionamentos?

Uma rápida olhada no diagrama ER deste exemplo nos mostra que um KnightType possui vários Knights. Além disso, o comando populate:knights atribui um campo knight_type_id a cada Knight, construindo o relacionamento.

Estamos em território NoSQL, e o Moloquent não disponibiliza joins. Uma alternativa é construir um Mapa associando id e KnightType, e essa relação é explorada no código abaixo.

Esse código imprime como saída (resumida), o resultado

...
Hyoga é do tipo Bronze
Kouga é do tipo Bronze
Yato é do tipo Bronze
Yuna é do tipo Bronze
Minos é do tipo Espectros
Aiacos é do tipo Espectros
Radamanthys é do tipo Espectros
Lune é do tipo Espectros
Faraó é do tipo Espectros
Suikyo é do tipo Espectros
Vermeer é do tipo Espectros
Kagaho é do tipo Espectros
Veronica é do tipo Espectros
Sonia é do tipo Marcianos
Ordykia é do tipo Marcianos
...

Podemos perceber que essa não é uma abordagem elegante. Estamos guardando na memória todos os registros da collection KnightType. Isso se tornaria inviável, caso essa collection fosse suficientemente grande. Além disso, pense no trabalho que deveria ser feito, caso quiséssemos listar todos os Knights para cada KnightType.

Felizmente alguém, em algum momento da história, já passou por um problema parecido, e por essa razão o Laravel disponibiliza meios muito poderosos e ELOQUENTES para lidar com relacionamentos!

Este tema porém, já que este post se tornou algo bem grande (e talvez cansativo), será discutido na parte 3: Lidando com relacionamentos! Afinal, quem disse que computeiros não são seres sociáveis?!!

Até mais!

--

--