
In dit artikel behandel ik de belangrijkste functies van Eloquent ORM.
Wat is Eloquent ORM?
Eloquent is de ORM van Laravel: de laag waarmee je je database benadert zonder zelf SQL te schrijven. De bekendste functies zijn soft deletes, automatische timestamps, de Active Record-implementatie, meerdere databaseverbindingen naast elkaar, eager loading, model-observers en model-events. Relaties zijn in Eloquent gewoon methoden op je modelklassen. Omdat ze een query builder teruggeven, knoop je er andere methoden aan vast en bouw je zo krachtige queries op.
Hoe werkt Eloquent ORM?
Eloquent leunt op het Active Record-patroon: elk model uit je MVC-structuur komt overeen met één tabel in de database. Je legt de relaties tussen die tabellen vast en werkt daarna met objecten in plaats van met queries. SQL met de hand schrijven kost tijd en levert lange, foutgevoelige strings op, met Eloquent doe je de gangbare database-operaties zonder die queries. Records invoegen, bijwerken, verwijderen en tussen verbindingen synchroniseren wordt daarmee een kwestie van een paar regels code.
Aan de slag met Eloquent
Laravel heeft een ingebouwde command line interface: Artisan. Die draait op de Console-component van Symfony en is je belangrijkste gereedschap tijdens de ontwikkeling.
Stel voordat je verdergaat je databaseverbinding in, in config/database.php.
Controleer daarna of Laravel al geïnstalleerd is. Zo niet, dan haal je Composer op via getcomposer.org en installeer je het project daarmee.
Wil je zien welke Artisan-commando’s beschikbaar zijn, voer dan dit uit:
php artisan listJe krijgt de volledige lijst met per commando een korte omschrijving. Heb je uitleg over één commando nodig, zet er dan help voor:
php artisan help migrateEloquent-modellen aanmaken
Voordat je iets anders doet, maak je een model aan. Het model is wat met je database praat: je bevraagt er je tabellen mee en je vult ze ermee via seeders en factories. Modellen staan doorgaans in App\Models, puur een kwestie van ordening, je mag ze ergens anders zetten zolang de autoloading in composer.json klopt. Elk Eloquent-model erft van Illuminate\Database\Eloquent\Model. Het basiscommando is make:model:
php artisan make: model StudentDe minimale definitie van een model ziet er zo uit:
class User extends Model {}Je laat de bijbehorende migratie meteen meegenereren door -m of --migration aan datzelfde commando toe te voegen.
php artisan make:model Student--migration
php artisan make:model Flight -mSeeders, factories, controllers en andere klassen genereer je op dezelfde manier, met de bijpassende optie van make:model:
php artisan make:model Flight --factory
php artisan make:model Flight -f
php artisan make:model Flight --seed
php artisan make:model Flight -s
php artisan make:model Flight --controller
php artisan make:model Flight -cDie opties combineren mag ook, zodat je alles in één keer aanmaakt.
php artisan make:model Flight -mfscHoud daarbij een paar conventies aan:
- Tabelnaam: Eloquent leidt de tabelnaam af uit de naam van je model, in het meervoud. Heet het model
Student, dan verwacht Eloquent de tabelstudents. Bestaat de modelnaam uit meerdere woorden, dan scheid je die in de tabelnaam met een underscore. - Primaire sleutel: Eloquent gaat uit van een kolom
id. Heet die bij jou anders, overschrijf dan$primaryKeyop je model. - Timestamps:
created_atenupdated_atworden automatisch bijgehouden. Wil je dat niet, zet dan$timestampsopfalse. Het formaat van die datums stel je in met$dateFormat.
Records bijwerken en verwijderen
Bijwerken
Een record werk je bij door het op te halen, het attribuut te wijzigen en save() aan te roepen. updated_at gaat daarbij vanzelf mee: die hoef je dus niet met de hand te zetten.
$student = Student::find(1);
$student->email = ‘xyz@example.com';
$student>save();Bulkupdates kunnen ook: je werkt dan in één keer elk model bij dat aan een bepaalde query voldoet.
Een bestaand record verwijderen
Verwijderen doe je met delete() op de instantie:
$student = Student::find(1);
$student>delete();Verwijderen op primaire sleutel:
Student::destroy(1);
Student::destroy([1, 2, 3]);
Student::destroy(1, 2, 3);En verwijderen op basis van een query kan net zo goed.
$affectedRows = Student::where('votes', '>', 100)->delete();Gerelateerde modellen
Modellen hangen vaak van elkaar af: staat de waarde van het ene model vast zodra je het andere kent, dan spreken we van gerelateerde modellen. Wil je bijvoorbeeld een nieuwe reactie aan een bericht koppelen, dan hoef je post_id niet zelf in te vullen. Je slaat de reactie op via het bovenliggende model.
$comment = new Comment(['message' => 'A new comment.']);
$post = Post::find(1);
$comment = $post->comments()->save($comment);Modellen aan elkaar koppelen
Met associate() zet je de foreign key op het model en koppel je het aan zijn parent. Modellen met meerdere relaties koppel je op precies dezelfde manier.
Model-events
Bij elke stap in de levenscyclus van een model, of je nu opslaat, bijwerkt of verwijdert, vuurt Eloquent een event af: een model-event. Beschikbaar zijn onder meer saving, saved, creating, created, updating, updated, deleting, deleted, restoring en restored. Sla je een nieuw record op, dan vuren creating en created, bestond het record al, dan vuren updating en updated.
Een opslagactie afbreken vanuit een event
Geeft de listener false terug, dan wordt de actie afgebroken. Dat werkt voor elk event: creating, updating, saving of deleting.
Student::creating(function($student)
{
if ( ! $student>isValid()) return false;
});Event listeners registreren
Zoals overal heeft een event een service provider nodig om geregistreerd te worden. Dat is hier EventServiceProvider: de plek waar je je model-events aan hun listeners bindt.
Bijvoorbeeld:
public function boot(DispatcherContract $events)
{
parent::boot($events);
Student::creating(function($student)
{
//
});
}Model-observers
Met een observer bundel je de afhandeling van je model-events in één klasse. Elke methode van die klasse hoort bij een model-event.
class StudentObserver {
public function saving($model)
{
//
}
public function saved($model)
{
//
}
}Een observer registreer je met de methode observe():
User::observe(new UserObserver);Model-URL’s genereren
Geef je een model mee aan route() of action(), dan zet Laravel de primaire sleutel van dat model in de URI.
Route::get('student/{student}', 'StudentController@show');
action('StudentController@show', [$student]);Hier komt dus het id van de student in de URL terecht. Wil je een andere eigenschap gebruiken, overschrijf dan getRouteKey() op je model.
public function getRouteKey()
{
return $this->slug;
}Meer functies van Laravel Eloquent
Omzetten naar array of JSON
Bouw je een API, dan is het antwoord vrijwel altijd JSON en moet je je modellen met hun relaties omzetten naar JSON of naar een array. Ook daar heeft Laravel Eloquent een antwoord op: met toArray() zet je een model inclusief zijn relaties om naar een array.
$student = Student::with('roles')->first();
return $student->toArray();Naar JSON gaat het net zo, met toJson():
return Student::find(1)->toJson();Geef je een model rechtstreeks terug uit een route, dan hoeft dat zelfs niet: zodra een model naar een string wordt omgezet, wordt het JSON. Je kunt Eloquent-objecten dus zo uit je routes teruggeven.
Route::get('student', function()
{
return Student::all();
});Gevoelige kolommen als een wachtwoord of een personal_id horen daar niet in thuis. Zet ze in de eigenschap $hidden van je model, dan laat Eloquent ze weg.
Attribute casting
Wil je het datatype van een attribuut omzetten, dan kun je voor elk attribuut een mutator schrijven, maar dat kost tijd en nodigt uit tot fouten. Handiger is casting: je zet het attribuut in de eigenschap $casts van je model. Naast boolean kun je onder meer casten naar integer, float, double, real, object, string en array.
Een voorbeeld:
protected $casts = [
'is_student' => 'boolean',
];In dit voorbeeld staat is_student met een ander datatype in de database, maar krijg je er bij het uitlezen altijd een boolean uit terug.
De cast naar array is vooral handig bij kolommen met geserialiseerde JSON. Serialiseren betekent hier dat een object als string in de kolom staat. Zet je op zo’n kolom de array-cast, dan zet Eloquent die string bij het uitlezen automatisch om naar een PHP-array.
protected $casts = [
'options' => 'array',
];Datummutators
Carbon is een uitbreiding van de PHP-klasse DateTime, met een hoop handige methoden erbij. Eloquent zet created_at en updated_at automatisch om naar Carbon-instanties. Wil je die automatische conversie aanpassen, dan overschrijf je getDates() op je model, geef je daar een lege array terug, dan schakel je haar helemaal uit. Een voorbeeld:
public function getDates()
{
return ['created_at'];
}Behandelt Eloquent een kolom als datum, dan heb je vier opties om hem te vullen: een UNIX-timestamp, een datumstring (Y-m-d), een datum met tijd, of een DateTime- of Carbon-instantie.
Accessors en mutators
Accessors en mutators zijn de getters en setters van Eloquent: ze formatteren een attribuut op het moment dat je het uitleest of instelt. Het verschil zit in de richting: een accessor werkt bij het ophalen van data, een mutator bij het wegschrijven ervan.
Een accessor definieer je als de methode getFooAttribute() op je model. Let op de naamgeving: de methodenaam staat in camelCase, ook als de kolomnaam volledig in kleine letters staat.
class User extends Model {
public function getFirstNameAttribute($value)
{
return ucfirst($value);
}
}Een mutator schrijf je op dezelfde manier, met setFooAttribute(), en ja, ook daar geldt de camelCase.
class User extends Model {
public function setFirstNameAttribute($value)
{
$this->attributes['first_name'] = strtolower($value);
}
}Soft deletes
Een soft delete haalt het record niet uit je database, maar zet er een timestamp deleted_at op. Je schakelt het in door de trait SoftDeletes in je model te gebruiken.
use Illuminate\Database\Eloquent\SoftDeletes;
class User extends Model {
use SoftDeletes;
protected $dates = ['deleted_at'];
}De kolom deleted_at voeg je in je migratie toe met softDeletes(). Een migratie is niets anders dan je database beheren in PHP in plaats van in SQL.
$table->softDeletes();Soms wil je die soft deleted records tóch in je resultaten zien. Gebruik dan withTrashed() in je query.
Wil je alleen de soft deleted records terugkrijgen, gebruik dan onlyTrashed().
$student = Student::onlyTrashed()->where('account_id', 1)->get();Moet zo’n record na al dat werk weer actief worden, dan gebruik je restore().
$student->restore();restore() werkt ook rechtstreeks op een query.
Student::withTrashed()->where('account_id', 1)->restore();Wil je een record na de soft delete definitief uit je database halen, gebruik dan forceDelete().
$student->posts()->forceDelete();En om te controleren of een model soft deleted is, gebruik je trashed().
if ($student->trashed())
{
//Todo
}Conclusie
Laravel is een van de bekendste PHP-frameworks, en Eloquent maakt het praten met je database er bijzonder eenvoudig in. In dit artikel heb ik de belangrijkste functies van Laravel Eloquent behandeld. Er zit nog veel meer in, en daarover lees je hier verder. Volg de link en ontdek waartoe Laravel Eloquent allemaal in staat is.


