Uso do Modelo de Banco de Dados (Estilo Laravel)
O modelo webman é baseado no Eloquent ORM. Cada tabela do banco de dados possui um modelo correspondente que interage com essa tabela. Você pode usar o modelo para consultar dados na tabela e inserir novos registros.
Antes de começar, verifique se a conexão do banco de dados está configurada em config/database.php
.
Nota: Para que o Eloquent ORM suporte observadores de modelo, você precisa importar adicionalmente
composer require "illuminate/events"
exemplo
Exemplo de Modelo de Banco de Dados
<?php
namespace app\model;
use support\Model;
class User extends Model
{
/**
* Nome da tabela associada ao modelo
*
* @var string
*/
protected $table = 'user';
/**
* Redefinir a chave primária, que por padrão é id
*
* @var string
*/
protected $primaryKey = 'uid';
/**
* Indica se os timestamps devem ser gerenciados automaticamente
*
* @var bool
*/
public $timestamps = false;
}
Nome da Tabela
Você pode especificar uma tabela de dados personalizada definindo a propriedade table no modelo:
class User extends Model
{
/**
* Nome da tabela associada ao modelo
*
* @var string
*/
protected $table = 'user';
}
Chave Primária
O Eloquent também pressupõe que cada tabela de dados tem uma coluna de chave primária chamada id. Você pode definir uma propriedade protegida $primaryKey para sobrescrever essa convenção.
class User extends Model
{
/**
* Redefinir a chave primária, que por padrão é id
*
* @var string
*/
protected $primaryKey = 'uid';
}
O Eloquent assume que a chave primária é um valor inteiro auto-incrementado, o que significa que, por padrão, a chave primária será automaticamente convertida para o tipo int. Se você deseja usar uma chave primária não auto-incrementada ou não numérica, deve definir a propriedade pública $incrementing como false.
class User extends Model
{
/**
* Indica se a chave primária do modelo é auto-incrementada
*
* @var bool
*/
public $incrementing = false;
}
Se a sua chave primária não for um inteiro, você precisará definir a propriedade protegida $keyType do modelo como string:
class User extends Model
{
/**
* "Tipo" do ID auto-incrementado.
*
* @var string
*/
protected $keyType = 'string';
}
Timestamps
Por padrão, o Eloquent espera que sua tabela de dados contenha created_at e updated_at. Se você não quiser que o Eloquent gerencie automaticamente essas duas colunas, deve definir a propriedade $timestamps no modelo como false:
class User extends Model
{
/**
* Indica se os timestamps devem ser gerenciados automaticamente
*
* @var bool
*/
public $timestamps = false;
}
Se precisar personalizar o formato dos timestamps, defina a propriedade $dateFormat no seu modelo. Esta propriedade determina a forma em que os atributos de data são armazenados no banco de dados e o formato em que o modelo é serializado como array ou JSON:
class User extends Model
{
/**
* Formato de armazenamento dos timestamps
*
* @var string
*/
protected $dateFormat = 'U';
}
Se você precisar personalizar os nomes dos campos que armazenam os timestamps, pode definir os valores das constantes CREATED_AT e UPDATED_AT no modelo:
class User extends Model
{
const CREATED_AT = 'creation_date';
const UPDATED_AT = 'last_update';
}
Conexão com Banco de Dados
Por padrão, os modelos Eloquent usarão a conexão de banco de dados padrão configurada para sua aplicação. Se você deseja especificar uma conexão diferente para o modelo, defina a propriedade $connection:
class User extends Model
{
/**
* Nome da conexão do modelo
*
* @var string
*/
protected $connection = 'connection-name';
}
Valores Padrão de Propriedade
Se você deseja definir valores padrão para algumas propriedades do modelo, pode definir a propriedade $attributes no modelo:
class User extends Model
{
/**
* Valores padrão para as propriedades do modelo.
*
* @var array
*/
protected $attributes = [
'delayed' => false,
];
}
Recuperação de Modelos
Depois de criar o modelo e a tabela de banco de dados associada, você pode consultar dados do banco de dados. Imagine cada modelo Eloquent como uma poderosa construção de consultas, que você pode usar para consultar rapidamente a tabela de dados associada. Por exemplo:
$users = app\model\User::all();
foreach ($users as $user) {
echo $user->name;
}
Dica: Como os modelos Eloquent também são construtores de consultas, você deve ler todos os métodos disponíveis no construtor de consultas. Você pode usar esses métodos nas consultas Eloquent.
Restrições Adicionais
O método all do Eloquent retornará todos os resultados do modelo. Como cada modelo Eloquent age como um construtor de consultas, você também pode adicionar condições de consulta e, em seguida, usar o método get para obter os resultados da consulta:
$users = app\model\User::where('name', 'like', '%tom')
->orderBy('uid', 'desc')
->limit(10)
->get();
Recarregar Modelos
Você pode usar os métodos fresh e refresh para recarregar modelos. O método fresh irá recuperar novamente o modelo do banco de dados. As instâncias de modelo existentes não serão afetadas:
$user = app\model\User::where('name', 'tom')->first();
$fresh_user = $user->fresh();
O método refresh reatribui o modelo existente com novos dados do banco de dados. Além disso, as relações que já foram carregadas serão recarregadas:
$user = app\model\User::where('name', 'tom')->first();
$user->name = 'jerry';
$user = $user->fresh();
$user->name; // "tom"
Coleções
Os métodos all e get do Eloquent podem retornar vários resultados, retornando uma instância de Illuminate\Database\Eloquent\Collection
. A classe Collection
oferece uma vasta gama de funções auxiliares para manipular os resultados do Eloquent:
$users = $users->reject(function ($user) {
return $user->disabled;
});
Usando Cursores
O método cursor permite que você use cursores para iterar pelo banco de dados, fazendo uma única consulta. Ao lidar com grandes volumes de dados, o método cursor pode reduzir significativamente o uso de memória:
foreach (app\model\User::where('sex', 1')->cursor() as $user) {
//
}
O cursor retorna uma instância de Illuminate\Support\LazyCollection
. Lazy collections permitem que você use a maioria dos métodos de coleção da Laravel com a vantagem de carregar apenas um único modelo na memória por vez:
$users = app\model\User::cursor()->filter(function ($user) {
return $user->id > 500;
});
foreach ($users as $user) {
echo $user->id;
}
Subconsultas Select
O Eloquent oferece suporte avançado para subconsultas, permitindo que você recupere informações de tabelas relacionadas com uma única consulta. Por exemplo, suponha que temos uma tabela de destinos destinations
e uma tabela de voos para destinos flights
. A tabela flights
contém um campo arrival_at
, que indica quando o voo chega ao destino.
Usando as funcionalidades de subconsulta, fornecidas pelos métodos select e addSelect, podemos consultar todos os destinos destinations
, bem como o nome do último voo para cada destino:
use app\model\Destination;
use app\model\Flight;
return Destination::addSelect(['last_flight' => Flight::select('name')
->whereColumn('destination_id', 'destinations.id')
->orderBy('arrived_at', 'desc')
->limit(1)
])->get();
Ordenação com Base em Subconsultas
Além disso, a função orderBy do construtor de consultas também suporta subconsultas. Podemos usar essa funcionalidade para ordenar todos os destinos com base no momento em que o último voo chegou ao destino. Isso também poderá ser feito com apenas uma única consulta no banco de dados:
return Destination::orderByDesc(
Flight::select('arrived_at')
->whereColumn('destination_id', 'destinations.id')
->orderBy('arrived_at', 'desc')
->limit(1)
)->get();
Recuperar Um Único Modelo / Coleção
Além de recuperar todos os registros de uma tabela específica, você pode usar os métodos find, first ou firstWhere para recuperar um único registro. Esses métodos retornam uma única instância de modelo, em vez de uma coleção de modelos:
// Encontrar um modelo pelo ID...
$flight = app\model\Flight::find(1);
// Encontrar o primeiro modelo que corresponde ao critério de consulta...
$flight = app\model\Flight::where('active', 1)->first();
// Implementação rápida para encontrar o primeiro modelo que corresponde ao critério de consulta...
$flight = app\model\Flight::firstWhere('active', 1);
Você também pode passar um array de chaves primárias como parâmetro para o método find, que retornará uma coleção das gravações correspondentes:
$flights = app\model\Flight::find([1, 2, 3]);
Às vezes, você pode querer executar outra ação caso o primeiro resultado não seja encontrado. O método firstOr retornará o primeiro resultado se encontrado, ou executará o callback fornecido se não houver resultados. O retorno do callback será o retorno do método firstOr:
$model = app\model\Flight::where('legs', '>', 100)->firstOr(function () {
// ...
});
O método firstOr também aceita arrays de colunas para consulta:
$model = app\model\Flight::where('legs', '>', 100)
->firstOr(['id', 'legs'], function () {
// ...
});
Exceção de "Não Encontrado"
Às vezes, você pode querer lançar uma exceção se o modelo não for encontrado. Isso é muito útil em controladores e rotas. Os métodos findOrFail e firstOrFail recuperam o primeiro resultado da consulta e, se não encontrado, lançam a exceção Illuminate\Database\Eloquent\ModelNotFoundException:
$model = app\model\Flight::findOrFail(1);
$model = app\model\Flight::where('legs', '>', 100)->firstOrFail();
Recuperar Coleções
Você também pode usar os métodos count, sum e max fornecidos pelo construtor de consultas, assim como outras funções de coleção, para manipular coleções. Esses métodos retornam apenas os valores escalares adequados, em vez de uma instância de modelo:
$count = app\model\Flight::where('active', 1)->count();
$max = app\model\Flight::where('active', 1)->max('price');
Inserir
Para adicionar um novo registro ao banco de dados, primeiro crie uma nova instância do modelo, defina as propriedades da instância e, em seguida, chame o método save:
<?php
namespace app\controller;
use app\model\User;
use support\Request;
use support\Response;
class FooController
{
/**
* Adiciona um novo registro na tabela de usuários
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
// Validar a requisição
$user = new User;
$user->name = $request->get('name');
$user->save();
}
}
Os timestamps created_at e updated_at serão configurados automaticamente (quando a propriedade $timestamps no modelo for true), não sendo necessário atribuir manualmente.
Atualizar
O método save também pode ser usado para atualizar modelos que já existem no banco de dados. Para atualizar um modelo, você precisa primeiro recuperá-lo, definir as propriedades que deseja atualizar e, em seguida, chamar o método save. Da mesma forma, o timestamp updated_at será atualizado automaticamente, portanto, também não será necessário atribuir manualmente:
$user = app\model\User::find(1);
$user->name = 'jerry';
$user->save();
Atualização em Lote
app\model\User::where('uid', '>', 10)
->update(['name' => 'tom']);
Verificação de Mudanças nas Propriedades
O Eloquent fornece os métodos isDirty, isClean e wasChanged para verificar o estado interno do modelo e determinar como suas propriedades mudaram desde o carregamento inicial.
O método isDirty determina se alguma propriedade foi alterada desde que o modelo foi carregado. Você pode passar um nome de propriedade específico para determinar se uma propriedade específica ficou "suja". O método isClean é o oposto de isDirty e também aceita um parâmetro de propriedade opcional:
$user = User::create([
'first_name' => 'Taylor',
'last_name' => 'Otwell',
'title' => 'Developer',
]);
$user->title = 'Painter';
$user->isDirty(); // true
$user->isDirty('title'); // true
$user->isDirty('first_name'); // false
$user->isClean(); // false
$user->isClean('title'); // false
$user->isClean('first_name'); // true
$user->save();
$user->isDirty(); // false
$user->isClean(); // true
O método wasChanged determina se alguma propriedade foi alterada na última vez que o modelo foi salvo durante o ciclo de solicitação atual. Você também pode passar um nome de propriedade para verificar se uma propriedade específica foi alterada:
$user = User::create([
'first_name' => 'Taylor',
'last_name' => 'Otwell',
'title' => 'Developer',
]);
$user->title = 'Painter';
$user->save();
$user->wasChanged(); // true
$user->wasChanged('title'); // true
$user->wasChanged('first_name'); // false
Atribuição em Lote
Você também pode usar o método create para salvar um novo modelo. Este método retornará a instância do modelo. No entanto, antes de usá-lo, você deve especificar as propriedades fillable ou guarded no modelo, pois todos os modelos Eloquent são, por padrão, não atribuíveis em lote.
Uma vulnerabilidade de atribuição em lote pode ocorrer quando o usuário envia parâmetros HTTP inesperados por meio da requisição, e esse parâmetro altera campos que você não precisa mudar no banco de dados. Por exemplo: um usuário mal-intencionado pode enviar um parâmetro is_admin na requisição HTTP e, em seguida, passá-lo para o método create, o que poderia permitir que o usuário se tornasse um administrador.
Portanto, antes de começar, você deve definir quais propriedades no modelo podem ser atribuídas em lote. Você pode fazer isso usando a propriedade $fillable no modelo. Por exemplo: permitir que a propriedade name do modelo Flight seja atribuída em lote:
<?php
namespace app\model;
use support\Model;
class Flight extends Model
{
/**
* Propriedades que podem ser atribuídas em lote.
*
* @var array
*/
protected $fillable = ['name'];
}
Uma vez que você definiu as propriedades que podem ser atribuídas em lote, pode usar o método create para inserir novos dados no banco de dados. O método create retornará a instância do modelo salvo:
$flight = app\model\Flight::create(['name' => 'Flight 10']);
Se você já tiver uma instância de modelo, pode passar um array para o método fill para atribuir valores:
$flight->fill(['name' => 'Flight 22']);
$fillable pode ser visto como uma "lista branca" para atribuição em lote, e você também pode usar a propriedade $guarded para implementar isso. A propriedade $guarded contém um array de propriedades que não são permitidas para atribuição em lote. Ou seja, $guarded funciona mais como uma "lista negra". Observe: você pode usar apenas uma das duas, $fillable ou $guarded, não ambas ao mesmo tempo. No exemplo abaixo, todas as propriedades, exceto a price, podem ser atribuídas em lote:
<?php
namespace app\model;
use support\Model;
class Flight extends Model
{
/**
* Propriedades que não podem ser atribuídas em lote.
*
* @var array
*/
protected $guarded = ['price'];
}
Se você quiser permitir que todas as propriedades possam ser atribuídas em lote, você pode definir $guarded como um array vazio:
/**
* Propriedades que não podem ser atribuídas em lote.
*
* @var array
*/
protected $guarded = [];
Outros Métodos de Criação
firstOrCreate / firstOrNew
Aqui estão dois métodos que você pode usar para atribuição em lote: firstOrCreate e firstOrNew. O método firstOrCreate tentará combinar dados no banco de dados usando pares de chave/valor fornecidos. Se o modelo não for encontrado no banco de dados, um novo registro será inserido com as propriedades do primeiro parâmetro e as propriedades adicionais (opcionais) do segundo parâmetro.
O método firstOrNew tenta encontrar registros no banco de dados usando propriedades fornecidas, assim como o método firstOrCreate. No entanto, se o método firstOrNew não encontrar o modelo correspondente, ele retornará uma nova instância de modelo. Note que a instância do modelo retornada pelo firstOrNew ainda não foi salva no banco de dados, você precisará chamar manualmente o método save para salvar:
// Recuperar voo por nome, criar se não existir...
$flight = app\model\Flight::firstOrCreate(['name' => 'Flight 10']);
// Recuperar voo por nome, ou criar usando os atributos delayed e arrival_time...
$flight = app\model\Flight::firstOrCreate(
['name' => 'Flight 10'],
['delayed' => 1, 'arrival_time' => '11:30']
);
// Recuperar voo por nome, criar uma instância se não existir...
$flight = app\model\Flight::firstOrNew(['name' => 'Flight 10']);
// Recuperar voo por nome, ou criar uma instância usando os atributos delayed e arrival_time...
$flight = app\model\Flight::firstOrNew(
['name' => 'Flight 10'],
['delayed' => 1, 'arrival_time' => '11:30']
);
Você também pode encontrar situações em que deseja atualizar um modelo existente ou criar um novo se não houver. O método updateOrCreate combina as duas operações em uma. Assim como o método firstOrCreate, updateOrCreate persiste o modelo, portanto, não é necessário chamar save():
// Se existir um voo de Oakland para San Diego, defina o preço como $99.
// Se não for encontrado um modelo correspondente, crie um novo.
$flight = app\model\Flight::updateOrCreate(
['departure' => 'Oakland', 'destination' => 'San Diego'],
['price' => 99, 'discounted' => 1]
);
Remover Modelos
Você pode chamar o método delete em uma instância de modelo para removê-la:
$flight = app\model\Flight::find(1);
$flight->delete();
Remover Modelos pela Chave Primária
app\model\Flight::destroy(1);
app\model\Flight::destroy(1, 2, 3);
app\model\Flight::destroy([1, 2, 3]);
app\model\Flight::destroy(collect([1, 2, 3]));
Remover Modelos pela Consulta
$deletedRows = app\model\Flight::where('active', 0)->delete();
Copiar Modelos
Você pode usar o método replicate para copiar uma nova instância que ainda não foi salva no banco de dados. Esse método é útil quando as instâncias de modelo compartilham muitas propriedades iguais.
$shipping = App\Address::create([
'type' => 'shipping',
'line_1' => '123 Example Street',
'city' => 'Victorville',
'state' => 'CA',
'postcode' => '90001',
]);
$billing = $shipping->replicate()->fill([
'type' => 'billing'
]);
$billing->save();
Comparação de Modelos
Às vezes, pode ser necessário determinar se dois modelos são "iguais". O método is pode ser usado para verificar rapidamente se dois modelos possuem a mesma chave primária, tabela e conexão de banco de dados:
if ($post->is($anotherPost)) {
//
}
Observadores de Modelos
Referência: Eventos de Modelos e Observadores em Laravel
Nota: Para que o Eloquent ORM suporte observadores de modelo, você precisa importar adicionalmente composer require "illuminate/events"
.
<?php
namespace app\model;
use support\Model;
use app\observer\UserObserver;
class User extends Model
{
public static function boot()
{
parent::boot();
static::observe(UserObserver::class);
}
}
Transações
Consulte Transações de Banco de Dados