Construtor de Consultas e ORM no Lumen

Para executar instruções SQL puras, utilize:

DB::statement($consulta);

A seguir, apresento os principais métodos da classe Illuminate\Database\Query\Builder:

Definição de Colunas

select — Especifica as colunas desejadas:

Aviso::select('titulo')->obter();
Aviso::select(['titulo', 'conteudo'])->obter();

selectRaw — Permite expressões SQL personalizadas:

Aviso::selectRaw("COUNT('id') AS total_avisos")->obter();

addSelect — Adiciona colunas a uma consulta existente:

$consulta = DB::table('usuarios')->select('nome');
$usuarios = $consulta->addSelect('idade')->obter();

distinct — Força resultados únicos:

$usuarios = DB::table('usuarios')->distinct()->obter();

Definição de Tabela

from — Define a tabela de origem (o método table() utiliza internamente este método):

DB::table('usuarios')
    ->ondeExiste(function ($consulta) {
        $consulta->select(DB::raw(1))
                 ->from('pedidos')
                 ->whereRaw('pedidos.usuario_id = usuarios.id');
    })
    ->obter();

O SQL gerado:

SELECT * FROM usuarios
WHERE EXISTS (
    SELECT 1 FROM pedidos WHERE pedidos.usuario_id = usuarios.id
)

Relacionamentos entre Modelos

hasOne — Relacionamento um-para-um onde a chave estrangiera está no modelo filho:

public function cliente($classe = Cliente::class)
{
    return $this->hasOne($classe, 'id', 'cliente_id');
}

Para obter o registro mais recente:

public function ultimoPedido($classe = Pedido::class)
{
    return $this->hasOne($classe, 'cliente_id', 'id')
                ->ordenarPor('id', 'desc');
}

Com condições adicionais:

public function pedidoAtivo($classe = Pedido::class)
{
    return $this->hasOne($classe, 'cliente_id', 'id')
                ->onde('situacao', Pedido::SITUACAO_ABERTO);
}

hasMany — Relacionamento um-para-muitos:

public function pedidos($classe = Pedido::class)
{
    return $this->hasMany($classe, 'cliente_id', 'id');
}

belongsTo — Relacionamento inverso, onde a chave estrangeira está no modelo atual:

public function cliente($classe = Cliente::class)
{
    return $this->belongsTo($classe, 'cliente_id', 'id');
}

Diferença fundamental: hasOne/hasMany é usado quando o modelo atual possui a relação (chave estrangeira na outra tabela). belongsTo/belongsToMany é usado quando o modelo atual é "possuído" (chave estrangeira na própria tabela).

belongsToMany — Relacionamento muitos-para-muitos com tabela intermediária:

public function permissoes()
{
    return $this->belongsToMany(
        \App\Models\Permissao::class,
        'usuario_possui_permissoes',
        'usuario_id',
        'permissao_id'
    );
}

Junções (Joins)

O método join() aceita parâmetros para tipo de junção (inner, left, right, cross) e condição (on, where).

join — Junção interna:

$usuarios = DB::table('usuarios')
    ->join('contatos', 'usuarios.id', '=', 'contatos.usuario_id')
    ->join('pedidos', 'usuarios.id', '=', 'pedidos.usuario_id')
    ->select('usuarios.*', 'contatos.telefone', 'pedidos.valor')
    ->obter();

joinWhere — Junção com condição WHERE em vez de ON:

$usuarios = DB::table('usuarios')
    ->joinWhere('contatos', 'contatos.tipo', '=', '1')
    ->join('pedidos', 'usuarios.id', '=', 'pedidos.usuario_id')
    ->select('usuarios.*', 'contatos.telefone', 'pedidos.valor')
    ->obter();

leftJoin / leftJoinWhere — Junção à esquerda:

$usuarios = DB::table('usuarios')
    ->leftJoin('publicacoes', 'usuarios.id', '=', 'publicacoes.usuario_id')
    ->obter();

$usuarios = DB::table('usuarios')
    ->leftJoinWhere('publicacoes', 'publicacoes.tipo', '=', '1')
    ->obter();

rightJoin / rightJoinWhere — Junção à direita (mesma lógica).

crossJoin — Produto cartesiano:

DB::table('usuarios')->crossJoin('preferencias')->obter();

Cláusulas WHERE

O método onde() aceita múltiplos formatos, com parâmetro $boolean padrão and (pode ser or):

$usuario = DB::table('usuarios')->onde('nome', 'João')->primeiro();
$usuario = DB::table('usuarios')->onde('nome', '=', 'João')->primeiro();
$usuario = DB::table('usuarios')->onde([['nome', '=', 'João'], ['telefone', '=', '11999998888']])->primeiro();

ouOnde:

$usuarios = DB::table('usuarios')
    ->onde('votos', '>', 100)
    ->ouOnde('nome', 'João')
    ->obter();

Argupamento e Ordenação

agruparPor — Aceita array ou múltiplos argumentos:

Aviso::agruparPor('titulo', 'id')->obter();
Aviso::agruparPor(['titulo', 'id'])->obter();

tendo / ouTendo / tendoRaw / ouTendoRaw:

Aviso::tendo('titulo', '=', '2')->obter();
Aviso::tendo('titulo', '=', '2')->ouTendo('titulo', '=', '1')->obter();

$pedidos = DB::table('pedidos')
    ->select('departamento', DB::raw('SUM(valor) AS total_vendas'))
    ->agruparPor('departamento')
    ->tendoRaw('SUM(valor) > ?', [2500])
    ->obter();

ordenarPor / ordenarPorDesc:

Aviso::ordenarPor('titulo')->obter();
Aviso::ordenarPor('titulo')->ordenarPor('conteudo')->obter();
Aviso::ordenarPorDesc('titulo')->obter();

maisRecente / maisAntigo — Ordenam por created_at:

public function maisRecente($coluna = 'created_at')
{
    return $this->ordenarPor($coluna, 'desc');
}

public function maisAntigo($coluna = 'created_at')
{
    return $this->ordenarPor($coluna, 'asc');
}

emOrdemAleatoria — Ordenação aleatória (seed opcional):

Aviso::emOrdemAleatoria()->obter();
Aviso::emOrdemAleatoria(1)->obter();

ordenarPorRaw:

Aviso::ordenarPorRaw('titulo, conteudo')->obter();

Recuperação de Registros

encontrar — Busca por chave primária (aceita array para múltiplos registros):

Aviso::encontrar(1);
Aviso::encontrar(1, ['titulo']);
Aviso::encontrar([1, 2], ['titulo']);

valor — Obtém valor de uma única coluna:

Aviso::onde('titulo', 1)->valor('titulo');

obter — Retorna coleção (array vazio se não encontrar):

Aviso::onde('titulo', 1)->obter();

paginar / paginarSimples:

DB::table('avisos')->paginar();
DB::table('avisos')->paginarSimples(); // Mais performático para grandes volumes

cursor — Iterador eficiente para grandes volumes:

foreach (DB::table('avisos')->cursor() as $aviso) {
    var_dump($aviso);
}

agruparPorId — Processamento em lotes (cuidado com atualizações):

$resultados = [];
DB::table('avisos')->agruparPorId(10, function($avisos) use (&$resultados) {
    $resultados[] = json_decode(json_encode($avisos, 256), true);
}, 'aviso_id');

extrair — Obtém valores de uma coluna como array:

DB::table('funcoes')->extrair('titulo');
DB::table('funcoes')->extrair('titulo', 'nome'); // Chave-valor

juntar — Concatena valores com delimitador:

DB::table('avisos')->juntar('titulo', ','); // titulo1,titulo2,titulo3

Verificação de Existência

DB::table('avisos')->onde('situacao', 1)->existe();      // true/false
DB::table('avisos')->onde('situacao', 1)->naoExiste();   // inverso

Funções de Agregação

DB::table('avisos')->onde('situacao', 1)->contar();
DB::table('avisos')->minimo('aviso_id');
DB::table('avisos')->maximo('aviso_id');
DB::table('avisos')->soma('aviso_id');
DB::table('avisos')->media('aviso_id');

DB::table('avisos')->agregar('soma', ['aviso_id']);
DB::table('avisos')->agregarNumerico('soma', ['aviso_id']); // Retorna número

Operações de Escrita

inserir — Retorna booleano:

Aviso::inserir(['titulo' => 'Novo']);
Aviso::inserir(['titulo' => 'Novo', 'status' => 1]);

inserirObterId — Retorna o ID gerado:

Aviso::inserirObterId(['titulo' => 'Novo']);

atualizar:

$aviso = Aviso::encontrar(1);
$aviso->atualizar(['titulo' => 'Atualizado']);

atualizarOuInserir:

Aviso::atualizarOuInserir(['titulo' => 'Novo'], ['conteudo' => 'Descrição']);

incrementar / decrementar:

Aviso::incrementar('visualizacoes');      // +1
Aviso::incrementar('visualizacoes', 5);   // +5
Aviso::decrementar('visualizacoes');      // -1
Aviso::decrementar('visualizacoes', 5);   // -5

excluir:

$aviso = Aviso::encontrar(1);
$aviso->excluir();

truncar — Remove todos os registros e reseta auto-incremento:

DB::table('avisos')->truncar();

Consultas Avançadas

novaConsulta — Nova instância do construtor:

$consulta = (new Aviso())->novaConsulta();
return $consulta->encontrar(1);

raw — Expresssões SQL brutas:

DB::table('avisos')->select(DB::raw('COUNT(*) AS total'))->obter();

Trait BuildsQueries

bloco — Processamento em lotes com controle de memória:

$estatisticas = ['sucesso' => 0, 'falha' => 0];
DB::table('avisos')->ordenarPor('aviso_id')->bloco(500, function ($avisos) use (&$estatisticas) {
    foreach ($avisos as $aviso) {
        $aviso->situacao == 1 ? $estatisticas['sucesso']++ : $estatisticas['falha']++;
    }
});

cada — Iteração automática:

$estatisticas = ['sucesso' => 0, 'falha' => 0];
DB::table('avisos')->ordenarPor('id')->cada(function ($aviso, $indice) use (&$estatisticas) {
    $aviso->situacao ? $estatisticas['sucesso']++ : $estatisticas['falha']++;
}, 500);

Métodos do Eloquent Builder

aPartirDaConsulta — Para consultas SQL complexas:

Aviso::aPartirDaConsulta("SELECT titulo FROM avisos");
Aviso::aPartirDaConsulta('SELECT titulo FROM avisos WHERE titulo = ?', [1]);

encontrarMuitos:

Aviso::encontrarMuitos([1, 2], ['titulo']);

encontrarOuFalhar — Lança ModelNotFoundException:

Aviso::encontrarOuFalhar(100);

encontrarOuNovo / primeiroOuNovo — Cria instância se não encontrar:

Aviso::encontrarOuNovo(100);
Aviso::primeiroOuNovo(['titulo' => 14]);
Aviso::primeiroOuNovo(['titulo' => 100], ['conteudo' => 123]);

novaInstanciaModelo:

Aviso::novaInstanciaModelo(['titulo' => 100, 'conteudo' => 123]);

primeiroOuCriar:

Aviso::primeiroOuCriar(['titulo' => 14], ['conteudo' => 123]);

atualizarOuCriar:

Aviso::atualizarOuCriar(['titulo' => 14], ['conteudo' => 1234]);

Implementação interna:

public function atualizarOuCriar(array $atributos, array $valores = [])
{
    return tap($this->primeiroOuNovo($atributos), function ($instancia) use ($valores) {
        $instancia->preencher($valores)->salvar();
    });
}

primeiroOuFalhar:

Aviso::primeiroOuFalhar();
Aviso::onde('titulo', 321)->primeiroOuFalhar();

primeiroOu — Executa callback se não encontrar:

$titulo = 1;
return Aviso::onde('titulo', 100)->primeiroOu(function() use ($titulo) {
    return Aviso::atualizarOuCriar(['titulo' => $titulo], ['conteudo' => 1234]);
});

Carregamento de Relacionamentos

com:

class Aviso {
    public function arquivosRelacionados()
    {
        return $this->hasMany(ArquivoRelacionado::class, 'relacao_id', 'id')
            ->onde('tipo_relacao', '=', ArquivoRelacionado::TIPO_AVISO)
            ->select('tipo_relacao', 'relacao_id', 'arquivo_id');
    }
}

class ArquivoRelacionado {
    public function arquivo()
    {
        return $this->hasOne(Arquivo::class, 'id', 'arquivo_id');
    }
}

Utilização:

Aviso::com('arquivosRelacionados')->obter();
Aviso::com('arquivosRelacionados.arquivo')->obter();

Aviso::com([
    'arquivosRelacionados' => function($consulta) {
        $consulta->select('relacao_id', 'arquivo_id');
    }
])->obter();

Aviso::com([
    'arquivosRelacionados' => function($consulta) {
        $consulta->select('relacao_id', 'arquivo_id')->com([
            'arquivo' => function($consulta) {
                $consulta->select('id', 'caminho');
            }
        ]);
    }
])->obter();

sem — Remove relacionamento carregado:

Aviso::com('arquivosRelacionados')->sem('arquivosRelacionados')->obter();

comContagem — Obtém apenas a contagem:

Aviso::comContagem('arquivosRelacionados')->obter();

Verificação de Nulos

->ondeNaoNulo('atualizado_em');
->ondeNulo('atualizado_em');

Junções Complexas

Para condições elaboradas, utilize closure:

DB::table('usuarios')
   ->join('contatos', function ($juncao) {
       $juncao->on('usuarios.id', '=', 'contatos.usuario_id')->ouOn(...);
   })
   ->obter();

DB::table('usuarios')
   ->join('contatos', function ($juncao) {
       $juncao->on('usuarios.id', '=', 'contatos.usuario_id')
            ->onde('contatos.usuario_id', '>', 5);
   })
   ->obter();

Tags: Lumen laravel Eloquent Query Builder ORM

Publicado em 10-10 02:31