Utilisation du modèle de base de données (style Laravel)
Le modèle webman est basé sur Eloquent ORM. Chaque table de base de données a un « modèle » correspondant pour interagir avec cette table. Vous pouvez utiliser le modèle pour interroger les données dans la table, ainsi que pour insérer de nouveaux enregistrements dans la table.
Avant de commencer, assurez-vous que vous avez configuré la connexion de base de données dans config/database.php
.
Attention : Pour que l'Eloquent ORM prenne en charge les observateurs de modèle, il est nécessaire d'importer
composer require "illuminate/events"
exemple
Exemple de modèle de base de données
<?php
namespace app\model;
use support\Model;
class User extends Model
{
/**
* Le nom de la table associée au modèle
*
* @var string
*/
protected $table = 'user';
/**
* Redéfinir la clé primaire, par défaut c'est id
*
* @var string
*/
protected $primaryKey = 'uid';
/**
* Indique si les timestamps sont gérés automatiquement
*
* @var bool
*/
public $timestamps = false;
}
Nom de la table
Vous pouvez spécifier une table de données personnalisée en définissant la propriété table sur le modèle :
class User extends Model
{
/**
* Le nom de la table associée au modèle
*
* @var string
*/
protected $table = 'user';
}
Clé primaire
Eloquent suppose également que chaque table de base de données a une colonne de clé primaire nommée id. Vous pouvez définir une propriété $primaryKey protégée pour réécrire cette convention.
class User extends Model
{
/**
* Redéfinir la clé primaire, par défaut c'est id
*
* @var string
*/
protected $primaryKey = 'uid';
}
Eloquent suppose que la clé primaire est un entier auto-incrementé, ce qui signifie que, par défaut, la clé primaire sera automatiquement convertie en type int. Si vous souhaitez utiliser une clé primaire non incrémentale ou non numérique, il est nécessaire de définir la propriété publique $incrementing sur false :
class User extends Model
{
/**
* Indique si la clé primaire du modèle est incrémentale
*
* @var bool
*/
public $incrementing = false;
}
Si votre clé primaire n'est pas un entier, vous devez définir la propriété protégée $keyType sur string dans le modèle :
class User extends Model
{
/**
* Le « type » de l'ID automatique.
*
* @var string
*/
protected $keyType = 'string';
}
Timestamps
Par défaut, Eloquent s'attend à ce que votre table de données contienne created_at et updated_at. Si vous ne souhaitez pas que Eloquent gère automatiquement ces deux colonnes, veuillez définir la propriété $timestamps du modèle sur false :
class User extends Model
{
/**
* Indique si les timestamps sont gérés automatiquement
*
* @var bool
*/
public $timestamps = false;
}
Si vous devez personnaliser le format des timestamps, définissez la propriété $dateFormat dans votre modèle. Cette propriété détermine la manière dont les attributs de date sont stockés dans la base de données, ainsi que le format lors de la sérialisation du modèle en tableau ou JSON :
class User extends Model
{
/**
* Format de stockage des timestamps
*
* @var string
*/
protected $dateFormat = 'U';
}
Si vous devez personnaliser les noms de champs pour stocker les timestamps, vous pouvez définir les valeurs des constantes CREATED_AT et UPDATED_AT dans le modèle :
class User extends Model
{
const CREATED_AT = 'creation_date';
const UPDATED_AT = 'last_update';
}
Connexion à la base de données
En général, les modèles Eloquent utiliseront la connexion de base de données par défaut configurée dans votre application. Si vous souhaitez spécifier une connexion différente pour le modèle, définissez la propriété $connection :
class User extends Model
{
/**
* Le nom de la connexion du modèle
*
* @var string
*/
protected $connection = 'connection-name';
}
Valeurs par défaut des attributs
Pour définir des valeurs par défaut pour certains attributs du modèle, vous pouvez définir la propriété $attributes sur le modèle :
class User extends Model
{
/**
* Valeurs par défaut des attributs du modèle.
*
* @var array
*/
protected $attributes = [
'delayed' => false,
];
}
Récupération de modèles
Une fois que vous avez créé le modèle et sa table de base de données associée, vous pouvez interroger les données de la base de données. Considérez chaque modèle Eloquent comme un puissant constructeur de requêtes, que vous pouvez utiliser pour interroger plus rapidement les données associées à sa table. Par exemple :
$users = app\model\User::all();
foreach ($users as $user) {
echo $user->name;
}
Astuce : Puisque les modèles Eloquent sont également des constructeurs de requêtes, vous devriez aussi lire le constructeur de requêtes pour connaître toutes les méthodes disponibles. Vous pouvez utiliser ces méthodes dans les requêtes Eloquent.
Contraintes supplémentaires
La méthode all d'Eloquent retourne tous les résultats du modèle. Comme chaque modèle Eloquent agit comme un constructeur de requêtes, vous pouvez également ajouter des conditions de requête, puis utiliser la méthode get pour obtenir les résultats de la requête :
$users = app\model\User::where('name', 'like', '%tom')
->orderBy('uid', 'desc')
->limit(10)
->get();
Recharger un modèle
Vous pouvez utiliser les méthodes fresh et refresh pour recharger le modèle. La méthode fresh récupère à nouveau le modèle à partir de la base de données. L'instance de modèle existante n'est pas affectée :
$user = app\model\User::where('name', 'tom')->first();
$fresh_user = $user->fresh();
La méthode refresh réaffecte les données du modèle existant à partir de la base de données. De plus, les relations déjà chargées seront rechargées :
$user = app\model\User::where('name', 'tom')->first();
$user->name = 'jerry';
$user = $user->fresh();
$user->name; // "tom"
Collection
Les méthodes all et get d'Eloquent peuvent interroger plusieurs résultats et retournent une instance de Illuminate\Database\Eloquent\Collection
. La classe Collection
propose de nombreuses fonctions d'assistance pour traiter les résultats Eloquent :
$users = $users->reject(function ($user) {
return $user->disabled;
});
Utiliser un curseur
La méthode cursor vous permet de parcourir la base de données avec un curseur, elle exécute une seule requête. Lors du traitement d'un grand volume de données, la méthode cursor peut réduire considérablement la consommation de mémoire :
foreach (app\model\User::where('sex', 1)->cursor() as $user) {
//
}
Le curseur retourne une instance de Illuminate\Support\LazyCollection
. Les collections paresseuses vous permettent d'utiliser la plupart des méthodes de collection de Laravel, tout en chargeant uniquement un modèle à la fois en mémoire :
$users = app\model\User::cursor()->filter(function ($user) {
return $user->id > 500;
});
foreach ($users as $user) {
echo $user->id;
}
Sous-requêtes Select
Eloquent offre un support avancé pour les sous-requêtes, vous pouvez extraire des informations des tables associées avec une seule instruction. Par exemple, supposons que nous avons une table de destinations destinations
et une table de vols vers ces destinations flights
. La table flights
contient un champ arrival_at
, indiquant quand le vol est arrivé à destination.
Utilisant les méthodes select et addSelect fournies par la fonctionnalité de sous-requête, nous pouvons interroger toutes les destinations en une seule instruction, ainsi que le nom du dernier vol arrivé à chaque destination :
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();
Trier par sous-requête
De plus, la fonction orderBy du constructeur de requêtes prend également en charge les sous-requêtes. Nous pouvons utiliser cette fonctionnalité pour trier toutes les destinations en fonction du temps d'arrivée du dernier vol. Encore une fois, cela exécute une seule requête à la base de données :
return Destination::orderByDesc(
Flight::select('arrived_at')
->whereColumn('destination_id', 'destinations.id')
->orderBy('arrived_at', 'desc')
->limit(1)
)->get();
Récupérer un modèle / une collection unique
En plus de récupérer tous les enregistrements d'une table donnée, vous pouvez utiliser les méthodes find, first ou firstWhere pour récupérer un seul enregistrement. Ces méthodes retournent une instance de modèle unique au lieu de retourner une collection de modèles :
// Chercher un modèle par clé primaire...
$flight = app\model\Flight::find(1);
// Trouver le premier modèle correspondant à la condition de requête...
$flight = app\model\Flight::where('active', 1)->first();
// Trouver le premier modèle correspondant à la condition de requête de manière simplifiée...
$flight = app\model\Flight::firstWhere('active', 1);
Vous pouvez également utiliser un tableau de clés primaires comme paramètre pour appeler la méthode find, ce qui retournera une collection des enregistrements correspondants :
$flights = app\model\Flight::find([1, 2, 3]);
Parfois, vous voudrez probablement effectuer une autre action si vous ne trouvez pas de valeur lors de la recherche du premier résultat. La méthode firstOr exécutera un rappel donné si elle trouve un résultat. La valeur de retour du rappel sera la valeur de retour de la méthode firstOr :
$model = app\model\Flight::where('legs', '>', 100)->firstOr(function () {
// ...
});
La méthode firstOr accepte également un tableau de colonnes pour la requête :
$model = app\model\Flight::where('legs', '>', 100)
->firstOr(['id', 'legs'], function () {
// ...
});
Exception « Non trouvé »
Parfois, vous souhaitez lever une exception si un modèle n'est pas trouvé. Cela est très utile dans les contrôleurs et les routes. Les méthodes findOrFail et firstOrFail récupèrent le premier résultat de la requête, et si aucun n'est trouvé, elles lèvent une exception Illuminate\Database\Eloquent\ModelNotFoundException :
$model = app\model\Flight::findOrFail(1);
$model = app\model\Flight::where('legs', '>', 100)->firstOrFail();
Récupérer des collections
Vous pouvez également utiliser les méthodes count, sum et max fournies par le constructeur de requêtes, ainsi que d'autres fonctions de collection pour manipuler les collections. Ces méthodes retournent uniquement les valeurs scalaires appropriées plutôt qu'une instance de modèle :
$count = app\model\Flight::where('active', 1)->count();
$max = app\model\Flight::where('active', 1)->max('price');
Insertion
Pour ajouter un nouvel enregistrement à la base de données, commencez par créer une nouvelle instance de modèle, définissez les attributs sur l'instance, puis appelez la méthode save :
<?php
namespace app\controller;
use app\model\User;
use support\Request;
use support\Response;
class FooController
{
/**
* Ajouter un nouvel enregistrement dans la table des utilisateurs
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
// Valider la requête
$user = new User;
$user->name = $request->get('name');
$user->save();
}
}
Les timestamps created_at et updated_at seront automatiquement définis (lorsque la propriété $timestamps du modèle est true), sans nécessité de les définir manuellement.
Mise à jour
La méthode save peut également être utilisée pour mettre à jour un modèle déjà existant dans la base de données. Pour mettre à jour un modèle, vous devez d'abord le récupérer, définir les attributs à mettre à jour, puis appeler la méthode save. De même, le timestamp updated_at sera automatiquement mis à jour, donc aucune valeur manuelle n'est nécessaire :
$user = app\model\User::find(1);
$user->name = 'jerry';
$user->save();
Mise à jour par lot
app\model\User::where('uid', '>', 10)
->update(['name' => 'tom']);
Vérification des changements d'attributs
Eloquent propose les méthodes isDirty, isClean et wasChanged pour vérifier l'état interne d'un modèle et déterminer comment ses attributs ont changé depuis leur chargement initial.
La méthode isDirty détermine si des attributs ont été modifiés depuis le chargement du modèle. Vous pouvez passer un nom d'attribut spécifique pour voir si un attribut particulier a changé. La méthode isClean fait l'inverse d'isDirty, elle accepte également des paramètres d'attributs optionnels :
$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
La méthode wasChanged détermine si des attributs ont été modifiés lors de la dernière sauvegarde du modèle dans le cycle de requête actuel. Vous pouvez également passer des noms d'attributs pour voir si des attributs spécifiques ont été modifiés :
$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
Attribution par lot
Vous pouvez également utiliser la méthode create pour enregistrer un nouveau modèle. Cette méthode renvoie une instance de modèle. Toutefois, avant de l'utiliser, vous devez définir les propriétés fillable ou guarded sur le modèle, car tous les modèles Eloquent ne permettent pas par défaut l'attribution par lot.
L'attribution par lot peut devenir vulnérable lorsque l'utilisateur transmet des paramètres HTTP inattendus via la requête, et que ces paramètres modifient des champs que vous ne souhaitez pas changer dans la base de données. Par exemple : un utilisateur malveillant peut transmettre un paramètre is_admin via une requête HTTP, ce qui permettrait à cet utilisateur de se surclasser en administrateur en appelant la méthode create.
Donc, avant de commencer, vous devez définir les attributs qui peuvent être attribués par lot sur le modèle. Vous pouvez le faire via la propriété $fillable sur le modèle. Par exemple : permettre à l'attribut name du modèle Flight d'être attribué par lot :
<?php
namespace app\model;
use support\Model;
class Flight extends Model
{
/**
* Attributs pouvant être attribués par lot.
*
* @var array
*/
protected $fillable = ['name'];
}
Une fois que vous avez configuré les attributs pouvant être attribués par lot, vous pouvez insérer de nouvelles données dans la base de données via la méthode create. La méthode create renverra l'instance de modèle enregistrée :
$flight = app\model\Flight::create(['name' => 'Flight 10']);
Si vous avez déjà une instance de modèle, vous pouvez passer un tableau à la méthode fill pour définir les valeurs :
$flight->fill(['name' => 'Flight 22']);
$fillable peut être considéré comme une « liste blanche » pour l'attribution par lot. Vous pouvez également utiliser la propriété $guarded pour ce faire. La propriété $guarded contient un tableau des attributs qui ne peuvent pas être attribués par lot. En d'autres termes, $guarded fonctionnera comme une « liste noire ». Notez : vous ne pouvez utiliser que $fillable ou $guarded, pas les deux en même temps. Dans l'exemple suivant, tous les attributs sauf price peuvent être attribués par lot :
<?php
namespace app\model;
use support\Model;
class Flight extends Model
{
/**
* Attributs ne pouvant pas être attribués par lot.
*
* @var array
*/
protected $guarded = ['price'];
}
Si vous souhaitez que tous les attributs puissent être attribués par lot, vous pouvez définir $guarded comme un tableau vide :
/**
* Attributs ne pouvant pas être attribués par lot.
*
* @var array
*/
protected $guarded = [];
Autres méthodes de création
firstOrCreate/ firstOrNew
Voici deux méthodes que vous pourriez utiliser pour l'attribution par lot : firstOrCreate et firstOrNew. La méthode firstOrCreate tentera de faire correspondre les données dans la base de données via la paire clé / valeur donnée. Si le modèle n'est pas trouvé dans la base de données, il insérera un enregistrement contenant les attributs du premier paramètre, ainsi que ceux du second paramètre optionnel.
La méthode firstOrNew fonctionne de la même manière que firstOrCreate, mais si elle ne trouve pas le modèle correspondant, elle retournera une nouvelle instance de modèle. Notez que l'instance de modèle retournée par firstOrNew n'est pas sauvegardée dans la base de données ; vous devez appeler la méthode save manuellement pour la sauvegarder :
// Cherchez un vol par name, ou créez-le s'il n'existe pas...
$flight = app\model\Flight::firstOrCreate(['name' => 'Flight 10']);
// Cherchez un vol par name, ou créez-le avec les attributs delayed et arrival_time...
$flight = app\model\Flight::firstOrCreate(
['name' => 'Flight 10'],
['delayed' => 1, 'arrival_time' => '11:30']
);
// Cherchez un vol par name, ou créez-en un nouvel instance s'il n'existe pas...
$flight = app\model\Flight::firstOrNew(['name' => 'Flight 10']);
// Cherchez un vol par name, ou créez un modèle avec les attributs delayed et arrival_time...
$flight = app\model\Flight::firstOrNew(
['name' => 'Flight 10'],
['delayed' => 1, 'arrival_time' => '11:30']
);
Vous pourriez également rencontrer des scénarios où vous souhaitez mettre à jour un modèle existant ou en créer un nouveau s'il n'existe pas. La méthode updateOrCreate permet de le faire en une seule étape. Semblable à la méthode firstOrCreate, updateOrCreate persiste le modèle, donc vous n'avez pas besoin d'appeler save() :
// Si un vol d'Oakland à San Diego existe, son prix sera fixé à 99 dollars.
// Sinon, créez un nouveau modèle.
$flight = app\model\Flight::updateOrCreate(
['departure' => 'Oakland', 'destination' => 'San Diego'],
['price' => 99, 'discounted' => 1]
);
Suppression de modèle
Vous pouvez appeler la méthode delete sur l'instance du modèle pour supprimer celle-ci :
$flight = app\model\Flight::find(1);
$flight->delete();
Suppression de modèle par clé primaire
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]));
Suppression de modèle par requête
$deletedRows = app\model\Flight::where('active', 0)->delete();
Copier un modèle
Vous pouvez utiliser la méthode replicate pour copier un nouvel instance non sauvegardée dans la base de données, ce qui est très utile lorsque plusieurs attributs du modèle sont identiques.
$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();
Comparer des modèles
Il peut parfois être nécessaire de déterminer si deux modèles sont « identiques ». La méthode is peut être utilisée pour vérifier rapidement si deux modèles possèdent la même clé primaire, table et connexion de base de données :
if ($post->is($anotherPost)) {
//
}
Observateurs de modèle
Pour référence, consultez Événements de modèle et observateur dans Laravel
Notez : Pour que l'Eloquent ORM prenne en charge les observateurs de modèle, il est nécessaire d'importer 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);
}
}