WARNING You're browsing the documentation for an upcoming version of Laravel. The documentation and features of this release are subject to change.
Laravel includes Eloquent, an object-relational mapper (ORM) that makes it enjoyable to interact with your database. When using Eloquent, each database table has a corresponding "Model" that is used to interact with that table. In addition to retrieving records from the database table, Eloquent models allow you to insert, update, and delete records from the table as well.
Before getting started, be sure to configure a database connection in your application'sconfig/database.php configuration file. For more information on configuring your database, check outthe database configuration documentation.
To get started, let's create an Eloquent model. Models typically live in theapp\Models directory and extend theIlluminate\Database\Eloquent\Model class. You may use themake:modelArtisan command to generate a new model:
1phpartisanmake:modelFlightIf you would like to generate adatabase migration when you generate the model, you may use the--migration or-m option:
1phpartisanmake:modelFlight--migrationYou may generate various other types of classes when generating a model, such as factories, seeders, policies, controllers, and form requests. In addition, these options may be combined to create multiple classes at once:
1# Generate a model and a FlightFactory class... 2phpartisanmake:modelFlight--factory 3phpartisanmake:modelFlight-f 4 5# Generate a model and a FlightSeeder class... 6phpartisanmake:modelFlight--seed 7phpartisanmake:modelFlight-s 8 9# Generate a model and a FlightController class...10phpartisanmake:modelFlight--controller11phpartisanmake:modelFlight-c12 13# Generate a model, FlightController resource class, and form request classes...14phpartisanmake:modelFlight--controller--resource--requests15phpartisanmake:modelFlight-crR16 17# Generate a model and a FlightPolicy class...18phpartisanmake:modelFlight--policy19 20# Generate a model and a migration, factory, seeder, and controller...21phpartisanmake:modelFlight-mfsc22 23# Shortcut to generate a model, migration, factory, seeder, policy, controller, and form requests...24phpartisanmake:modelFlight--all25phpartisanmake:modelFlight-a26 27# Generate a pivot model...28phpartisanmake:modelMember--pivot29phpartisanmake:modelMember-pSometimes it can be difficult to determine all of a model's available attributes and relationships just by skimming its code. Instead, try themodel:show Artisan command, which provides a convenient overview of all the model's attributes and relations:
1phpartisanmodel:showFlightModels generated by themake:model command will be placed in theapp/Models directory. Let's examine a basic model class and discuss some of Eloquent's key conventions:
1<?php 2 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Model; 6 7classFlightextendsModel 8{ 9// ...10}After glancing at the example above, you may have noticed that we did not tell Eloquent which database table corresponds to ourFlight model. By convention, the "snake case", plural name of the class will be used as the table name unless another name is explicitly specified. So, in this case, Eloquent will assume theFlight model stores records in theflights table, while anAirTrafficController model would store records in anair_traffic_controllers table.
If your model's corresponding database table does not fit this convention, you may manually specify the model's table name by defining atable property on the model:
1<?php 2 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Model; 6 7classFlightextendsModel 8{ 9/**10 * The table associated with the model.11 *12 *@varstring13*/14protected$table='my_flights';15}Eloquent will also assume that each model's corresponding database table has a primary key column namedid. If necessary, you may define a protected$primaryKey property on your model to specify a different column that serves as your model's primary key:
1<?php 2 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Model; 6 7classFlightextendsModel 8{ 9/**10 * The primary key associated with the table.11 *12 *@varstring13*/14protected$primaryKey='flight_id';15}In addition, Eloquent assumes that the primary key is an incrementing integer value, which means that Eloquent will automatically cast the primary key to an integer. If you wish to use a non-incrementing or a non-numeric primary key you must define a public$incrementing property on your model that is set tofalse:
1<?php 2 3classFlightextendsModel 4{ 5/** 6 * Indicates if the model's ID is auto-incrementing. 7 * 8 *@varbool 9*/10public$incrementing=false;11}If your model's primary key is not an integer, you should define a protected$keyType property on your model. This property should have a value ofstring:
1<?php 2 3classFlightextendsModel 4{ 5/** 6 * The data type of the primary key ID. 7 * 8 *@varstring 9*/10protected$keyType='string';11}Eloquent requires each model to have at least one uniquely identifying "ID" that can serve as its primary key. "Composite" primary keys are not supported by Eloquent models. However, you are free to add additional multi-column, unique indexes to your database tables in addition to the table's uniquely identifying primary key.
Instead of using auto-incrementing integers as your Eloquent model's primary keys, you may choose to use UUIDs instead. UUIDs are universally unique alpha-numeric identifiers that are 36 characters long.
If you would like a model to use a UUID key instead of an auto-incrementing integer key, you may use theIlluminate\Database\Eloquent\Concerns\HasUuids trait on the model. Of course, you should ensure that the model has aUUID equivalent primary key column:
1use Illuminate\Database\Eloquent\Concerns\HasUuids; 2use Illuminate\Database\Eloquent\Model; 3 4classArticleextendsModel 5{ 6useHasUuids; 7 8// ... 9}10 11$article=Article::create(['title'=>'Traveling to Europe']);12 13$article->id;// "8f8e8478-9035-4d23-b9a7-62f4d2612ce5"By default, TheHasUuids trait will generate"ordered" UUIDs for your models. These UUIDs are more efficient for indexed database storage because they can be sorted lexicographically.
You can override the UUID generation process for a given model by defining anewUniqueId method on the model. In addition, you may specify which columns should receive UUIDs by defining auniqueIds method on the model:
1use Ramsey\Uuid\Uuid; 2 3/** 4 * Generate a new UUID for the model. 5*/ 6publicfunctionnewUniqueId():string 7{ 8return (string)Uuid::uuid4(); 9}10 11/**12 * Get the columns that should receive a unique identifier.13 *14 *@returnarray<int, string>15*/16publicfunctionuniqueIds():array17{18return ['id','discount_code'];19}If you wish, you may choose to utilize "ULIDs" instead of UUIDs. ULIDs are similar to UUIDs; however, they are only 26 characters in length. Like ordered UUIDs, ULIDs are lexicographically sortable for efficient database indexing. To utilize ULIDs, you should use theIlluminate\Database\Eloquent\Concerns\HasUlids trait on your model. You should also ensure that the model has aULID equivalent primary key column:
1use Illuminate\Database\Eloquent\Concerns\HasUlids; 2use Illuminate\Database\Eloquent\Model; 3 4classArticleextendsModel 5{ 6useHasUlids; 7 8// ... 9}10 11$article=Article::create(['title'=>'Traveling to Asia']);12 13$article->id;// "01gd4d3tgrrfqeda94gdbtdk5c"By default, Eloquent expectscreated_at andupdated_at columns to exist on your model's corresponding database table. Eloquent will automatically set these column's values when models are created or updated. If you do not want these columns to be automatically managed by Eloquent, you should define a$timestamps property on your model with a value offalse:
1<?php 2 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Model; 6 7classFlightextendsModel 8{ 9/**10 * Indicates if the model should be timestamped.11 *12 *@varbool13*/14public$timestamps=false;15}If you need to customize the format of your model's timestamps, set the$dateFormat property on your model. This property determines how date attributes are stored in the database as well as their format when the model is serialized to an array or JSON:
1<?php 2 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Model; 6 7classFlightextendsModel 8{ 9/**10 * The storage format of the model's date columns.11 *12 *@varstring13*/14protected$dateFormat='U';15}If you need to customize the names of the columns used to store the timestamps, you may defineCREATED_AT andUPDATED_AT constants on your model:
1<?php2 3classFlightextendsModel4{5constCREATED_AT='creation_date';6constUPDATED_AT='updated_date';7}If you would like to perform model operations without the model having itsupdated_at timestamp modified, you may operate on the model within a closure given to thewithoutTimestamps method:
1Model::withoutTimestamps(fn() =>$post->increment('reads'));By default, all Eloquent models will use the default database connection that is configured for your application. If you would like to specify a different connection that should be used when interacting with a particular model, you should define a$connection property on the model:
1<?php 2 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Model; 6 7classFlightextendsModel 8{ 9/**10 * The database connection that should be used by the model.11 *12 *@varstring13*/14protected$connection='mysql';15}By default, a newly instantiated model instance will not contain any attribute values. If you would like to define the default values for some of your model's attributes, you may define an$attributes property on your model. Attribute values placed in the$attributes array should be in their raw, "storable" format as if they were just read from the database:
1<?php 2 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Model; 6 7classFlightextendsModel 8{ 9/**10 * The model's default values for attributes.11 *12 *@vararray13*/14protected$attributes= [15'options'=>'[]',16'delayed'=>false,17 ];18}Laravel offers several methods that allow you to configure Eloquent's behavior and "strictness" in a variety of situations.
First, thepreventLazyLoading method accepts an optional boolean argument that indicates if lazy loading should be prevented. For example, you may wish to only disable lazy loading in non-production environments so that your production environment will continue to function normally even if a lazy loaded relationship is accidentally present in production code. Typically, this method should be invoked in theboot method of your application'sAppServiceProvider:
1use Illuminate\Database\Eloquent\Model;2 3/**4 * Bootstrap any application services.5*/6publicfunctionboot():void7{8Model::preventLazyLoading(!$this->app->isProduction());9}Also, you may instruct Laravel to throw an exception when attempting to fill an unfillable attribute by invoking thepreventSilentlyDiscardingAttributes method. This can help prevent unexpected errors during local development when attempting to set an attribute that has not been added to the model'sfillable array:
1Model::preventSilentlyDiscardingAttributes(!$this->app->isProduction());Once you have created a model andits associated database table, you are ready to start retrieving data from your database. You can think of each Eloquent model as a powerfulquery builder allowing you to fluently query the database table associated with the model. The model'sall method will retrieve all of the records from the model's associated database table:
1use App\Models\Flight;2 3foreach (Flight::all()as$flight) {4echo$flight->name;5}The Eloquentall method will return all of the results in the model's table. However, since each Eloquent model serves as aquery builder, you may add additional constraints to queries and then invoke theget method to retrieve the results:
1$flights=Flight::where('active',1)2->orderBy('name')3->take(10)4->get();Since Eloquent models are query builders, you should review all of the methods provided by Laravel'squery builder. You may use any of these methods when writing your Eloquent queries.
If you already have an instance of an Eloquent model that was retrieved from the database, you can "refresh" the model using thefresh andrefresh methods. Thefresh method will re-retrieve the model from the database. The existing model instance will not be affected:
1$flight=Flight::where('number','FR 900')->first();2 3$freshFlight=$flight->fresh();Therefresh method will re-hydrate the existing model using fresh data from the database. In addition, all of its loaded relationships will be refreshed as well:
1$flight=Flight::where('number','FR 900')->first();2 3$flight->number='FR 456';4 5$flight->refresh();6 7$flight->number;// "FR 900"As we have seen, Eloquent methods likeall andget retrieve multiple records from the database. However, these methods don't return a plain PHP array. Instead, an instance ofIlluminate\Database\Eloquent\Collection is returned.
The EloquentCollection class extends Laravel's baseIlluminate\Support\Collection class, which provides avariety of helpful methods for interacting with data collections. For example, thereject method may be used to remove models from a collection based on the results of an invoked closure:
1$flights=Flight::where('destination','Paris')->get();2 3$flights=$flights->reject(function(Flight$flight) {4return$flight->cancelled;5});In addition to the methods provided by Laravel's base collection class, the Eloquent collection class providesa few extra methods that are specifically intended for interacting with collections of Eloquent models.
Since all of Laravel's collections implement PHP's iterable interfaces, you may loop over collections as if they were an array:
1foreach ($flightsas$flight) {2echo$flight->name;3}Your application may run out of memory if you attempt to load tens of thousands of Eloquent records via theall orget methods. Instead of using these methods, thechunk method may be used to process large numbers of models more efficiently.
Thechunk method will retrieve a subset of Eloquent models, passing them to a closure for processing. Since only the current chunk of Eloquent models is retrieved at a time, thechunk method will provide significantly reduced memory usage when working with a large number of models:
1use App\Models\Flight;2use Illuminate\Database\Eloquent\Collection;3 4Flight::chunk(200,function(Collection$flights) {5foreach ($flightsas$flight) {6// ...7 }8});The first argument passed to thechunk method is the number of records you wish to receive per "chunk". The closure passed as the second argument will be invoked for each chunk that is retrieved from the database. A database query will be executed to retrieve each chunk of records passed to the closure.
If you are filtering the results of thechunk method based on a column that you will also be updating while iterating over the results, you should use thechunkById method. Using thechunk method in these scenarios could lead to unexpected and inconsistent results. Internally, thechunkById method will always retrieve models with anid column greater than the last model in the previous chunk:
1Flight::where('departed',true)2->chunkById(200,function(Collection$flights) {3$flights->each->update(['departed'=>false]);4 }, column:'id');Since thechunkById andlazyById methods add their own "where" conditions to the query being executed, you should typicallylogically group your own conditions within a closure:
1Flight::where(function($query) {2$query->where('delayed',true)->orWhere('cancelled',true);3})->chunkById(200,function(Collection$flights) {4$flights->each->update([5'departed'=>false,6'cancelled'=>true7 ]);8}, column:'id');Thelazy method works similarly tothechunk method in the sense that, behind the scenes, it executes the query in chunks. However, instead of passing each chunk directly into a callback as is, thelazy method returns a flattenedLazyCollection of Eloquent models, which lets you interact with the results as a single stream:
1use App\Models\Flight;2 3foreach (Flight::lazy()as$flight) {4// ...5}If you are filtering the results of thelazy method based on a column that you will also be updating while iterating over the results, you should use thelazyById method. Internally, thelazyById method will always retrieve models with anid column greater than the last model in the previous chunk:
1Flight::where('departed',true)2->lazyById(200, column:'id')3->each->update(['departed'=>false]);You may filter the results based on the descending order of theid using thelazyByIdDesc method.
Similar to thelazy method, thecursor method may be used to significantly reduce your application's memory consumption when iterating through tens of thousands of Eloquent model records.
Thecursor method will only execute a single database query; however, the individual Eloquent models will not be hydrated until they are actually iterated over. Therefore, only one Eloquent model is kept in memory at any given time while iterating over the cursor.
Since thecursor method only ever holds a single Eloquent model in memory at a time, it cannot eager load relationships. If you need to eager load relationships, consider usingthelazy method instead.
Internally, thecursor method uses PHPgenerators to implement this functionality:
1use App\Models\Flight;2 3foreach (Flight::where('destination','Zurich')->cursor()as$flight) {4// ...5}Thecursor returns anIlluminate\Support\LazyCollection instance.Lazy collections allow you to use many of the collection methods available on typical Laravel collections while only loading a single model into memory at a time:
1use App\Models\User;2 3$users=User::cursor()->filter(function(User$user) {4return$user->id>500;5});6 7foreach ($usersas$user) {8echo$user->id;9}Although thecursor method uses far less memory than a regular query (by only holding a single Eloquent model in memory at a time), it will still eventually run out of memory. This isdue to PHP's PDO driver internally caching all raw query results in its buffer. If you're dealing with a very large number of Eloquent records, consider usingthelazy method instead.
Eloquent also offers advanced subquery support, which allows you to pull information from related tables in a single query. For example, let's imagine that we have a table of flightdestinations and a table offlights to destinations. Theflights table contains anarrived_at column which indicates when the flight arrived at the destination.
Using the subquery functionality available to the query builder'sselect andaddSelect methods, we can select all of thedestinations and the name of the flight that most recently arrived at that destination using a single query:
1use App\Models\Destination;2use App\Models\Flight;3 4returnDestination::addSelect(['last_flight'=>Flight::select('name')5->whereColumn('destination_id','destinations.id')6->orderByDesc('arrived_at')7->limit(1)8])->get();In addition, the query builder'sorderBy function supports subqueries. Continuing to use our flight example, we may use this functionality to sort all destinations based on when the last flight arrived at that destination. Again, this may be done while executing a single database query:
1returnDestination::orderByDesc(2Flight::select('arrived_at')3->whereColumn('destination_id','destinations.id')4->orderByDesc('arrived_at')5->limit(1)6)->get();In addition to retrieving all of the records matching a given query, you may also retrieve single records using thefind,first, orfirstWhere methods. Instead of returning a collection of models, these methods return a single model instance:
1use App\Models\Flight; 2 3// Retrieve a model by its primary key... 4$flight=Flight::find(1); 5 6// Retrieve the first model matching the query constraints... 7$flight=Flight::where('active',1)->first(); 8 9// Alternative to retrieving the first model matching the query constraints...10$flight=Flight::firstWhere('active',1);Sometimes you may wish to perform some other action if no results are found. ThefindOr andfirstOr methods will return a single model instance or, if no results are found, execute the given closure. The value returned by the closure will be considered the result of the method:
1$flight=Flight::findOr(1,function() {2// ...3});4 5$flight=Flight::where('legs','>',3)->firstOr(function() {6// ...7});Sometimes you may wish to throw an exception if a model is not found. This is particularly useful in routes or controllers. ThefindOrFail andfirstOrFail methods will retrieve the first result of the query; however, if no result is found, anIlluminate\Database\Eloquent\ModelNotFoundException will be thrown:
1$flight=Flight::findOrFail(1);2 3$flight=Flight::where('legs','>',3)->firstOrFail();If theModelNotFoundException is not caught, a 404 HTTP response is automatically sent back to the client:
1use App\Models\Flight;2 3Route::get('/api/flights/{id}',function(string$id) {4returnFlight::findOrFail($id);5});ThefirstOrCreate method will attempt to locate a database record using the given column / value pairs. If the model cannot be found in the database, a record will be inserted with the attributes resulting from merging the first array argument with the optional second array argument:
ThefirstOrNew method, likefirstOrCreate, will attempt to locate a record in the database matching the given attributes. However, if a model is not found, a new model instance will be returned. Note that the model returned byfirstOrNew has not yet been persisted to the database. You will need to manually call thesave method to persist it:
1use App\Models\Flight; 2 3// Retrieve flight by name or create it if it doesn't exist... 4$flight=Flight::firstOrCreate([ 5'name'=>'London to Paris' 6]); 7 8// Retrieve flight by name or create it with the name, delayed, and arrival_time attributes... 9$flight=Flight::firstOrCreate(10 ['name'=>'London to Paris'],11 ['delayed'=>1,'arrival_time'=>'11:30']12);13 14// Retrieve flight by name or instantiate a new Flight instance...15$flight=Flight::firstOrNew([16'name'=>'London to Paris'17]);18 19// Retrieve flight by name or instantiate with the name, delayed, and arrival_time attributes...20$flight=Flight::firstOrNew(21 ['name'=>'Tokyo to Sydney'],22 ['delayed'=>1,'arrival_time'=>'11:30']23);When interacting with Eloquent models, you may also use thecount,sum,max, and otheraggregate methods provided by the Laravelquery builder. As you might expect, these methods return a scalar value instead of an Eloquent model instance:
1$count=Flight::where('active',1)->count();2 3$max=Flight::where('active',1)->max('price');Of course, when using Eloquent, we don't only need to retrieve models from the database. We also need to insert new records. Thankfully, Eloquent makes it simple. To insert a new record into the database, you should instantiate a new model instance and set attributes on the model. Then, call thesave method on the model instance:
1<?php 2 3namespace App\Http\Controllers; 4 5use App\Models\Flight; 6use Illuminate\Http\RedirectResponse; 7use Illuminate\Http\Request; 8 9classFlightControllerextendsController10{11/**12 * Store a new flight in the database.13*/14publicfunctionstore(Request$request):RedirectResponse15 {16// Validate the request...17 18$flight=newFlight;19 20$flight->name=$request->name;21 22$flight->save();23 24returnredirect('/flights');25 }26}In this example, we assign thename field from the incoming HTTP request to thename attribute of theApp\Models\Flight model instance. When we call thesave method, a record will be inserted into the database. The model'screated_at andupdated_at timestamps will automatically be set when thesave method is called, so there is no need to set them manually.
Alternatively, you may use thecreate method to "save" a new model using a single PHP statement. The inserted model instance will be returned to you by thecreate method:
1use App\Models\Flight;2 3$flight=Flight::create([4'name'=>'London to Paris',5]);However, before using thecreate method, you will need to specify either afillable orguarded property on your model class. These properties are required because all Eloquent models are protected against mass assignment vulnerabilities by default. To learn more about mass assignment, please consult themass assignment documentation.
Thesave method may also be used to update models that already exist in the database. To update a model, you should retrieve it and set any attributes you wish to update. Then, you should call the model'ssave method. Again, theupdated_at timestamp will automatically be updated, so there is no need to manually set its value:
1use App\Models\Flight;2 3$flight=Flight::find(1);4 5$flight->name='Paris to London';6 7$flight->save();Occasionally, you may need to update an existing model or create a new model if no matching model exists. Like thefirstOrCreate method, theupdateOrCreate method persists the model, so there's no need to manually call thesave method.
In the example below, if a flight exists with adeparture location ofOakland and adestination location ofSan Diego, itsprice anddiscounted columns will be updated. If no such flight exists, a new flight will be created which has the attributes resulting from merging the first argument array with the second argument array:
1$flight=Flight::updateOrCreate(2 ['departure'=>'Oakland','destination'=>'San Diego'],3 ['price'=>99,'discounted'=>1]4);Updates can also be performed against models that match a given query. In this example, all flights that areactive and have adestination ofSan Diego will be marked as delayed:
1Flight::where('active',1)2->where('destination','San Diego')3->update(['delayed'=>1]);Theupdate method expects an array of column and value pairs representing the columns that should be updated. Theupdate method returns the number of affected rows.
When issuing a mass update via Eloquent, thesaving,saved,updating, andupdated model events will not be fired for the updated models. This is because the models are never actually retrieved when issuing a mass update.
Eloquent provides theisDirty,isClean, andwasChanged methods to examine the internal state of your model and determine how its attributes have changed from when the model was originally retrieved.
TheisDirty method determines if any of the model's attributes have been changed since the model was retrieved. You may pass a specific attribute name or an array of attributes to theisDirty method to determine if any of the attributes are "dirty". TheisClean method will determine if an attribute has remained unchanged since the model was retrieved. This method also accepts an optional attribute argument:
1use App\Models\User; 2 3$user=User::create([ 4'first_name'=>'Taylor', 5'last_name'=>'Otwell', 6'title'=>'Developer', 7]); 8 9$user->title='Painter';10 11$user->isDirty();// true12$user->isDirty('title');// true13$user->isDirty('first_name');// false14$user->isDirty(['first_name','title']);// true15 16$user->isClean();// false17$user->isClean('title');// false18$user->isClean('first_name');// true19$user->isClean(['first_name','title']);// false20 21$user->save();22 23$user->isDirty();// false24$user->isClean();// trueThewasChanged method determines if any attributes were changed when the model was last saved within the current request cycle. If needed, you may pass an attribute name to see if a particular attribute was changed:
1$user=User::create([ 2'first_name'=>'Taylor', 3'last_name'=>'Otwell', 4'title'=>'Developer', 5]); 6 7$user->title='Painter'; 8 9$user->save();10 11$user->wasChanged();// true12$user->wasChanged('title');// true13$user->wasChanged(['title','slug']);// true14$user->wasChanged('first_name');// false15$user->wasChanged(['first_name','title']);// trueThegetOriginal method returns an array containing the original attributes of the model regardless of any changes to the model since it was retrieved. If needed, you may pass a specific attribute name to get the original value of a particular attribute:
1$user=User::find(1); 2 3$user->name;// John 5 6$user->name='Jack'; 7$user->name;// Jack 8 9$user->getOriginal('name');// John10$user->getOriginal();// Array of original attributes...ThegetChanges method returns an array containing the attributes that changed when the model was last saved:
1$user=User::find(1); 2 3$user->name;// John 5 6$user->update([ 7'name'=>'Jack', 9]);10 11$user->getChanges();12 13/*14 [15 'name' => 'Jack',16 'email' => '[email protected]',17 ]18*/You may use thecreate method to "save" a new model using a single PHP statement. The inserted model instance will be returned to you by the method:
1use App\Models\Flight;2 3$flight=Flight::create([4'name'=>'London to Paris',5]);However, before using thecreate method, you will need to specify either afillable orguarded property on your model class. These properties are required because all Eloquent models are protected against mass assignment vulnerabilities by default.
A mass assignment vulnerability occurs when a user passes an unexpected HTTP request field and that field changes a column in your database that you did not expect. For example, a malicious user might send anis_admin parameter through an HTTP request, which is then passed to your model'screate method, allowing the user to escalate themselves to an administrator.
So, to get started, you should define which model attributes you want to make mass assignable. You may do this using the$fillable property on the model. For example, let's make thename attribute of ourFlight model mass assignable:
1<?php 2 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Model; 6 7classFlightextendsModel 8{ 9/**10 * The attributes that are mass assignable.11 *12 *@vararray<int, string>13*/14protected$fillable= ['name'];15}Once you have specified which attributes are mass assignable, you may use thecreate method to insert a new record in the database. Thecreate method returns the newly created model instance:
1$flight=Flight::create(['name'=>'London to Paris']);If you already have a model instance, you may use thefill method to populate it with an array of attributes:
1$flight->fill(['name'=>'Amsterdam to Frankfurt']);When assigning JSON columns, each column's mass assignable key must be specified in your model's$fillable array. For security, Laravel does not support updating nested JSON attributes when using theguarded property:
1/**2 * The attributes that are mass assignable.3 *4 *@vararray<int, string>5*/6protected$fillable= [7'options->enabled',8];If you would like to make all of your attributes mass assignable, you may define your model's$guarded property as an empty array. If you choose to unguard your model, you should take special care to always hand-craft the arrays passed to Eloquent'sfill,create, andupdate methods:
1/**2 * The attributes that aren't mass assignable.3 *4 *@vararray<string>|bool5*/6protected$guarded= [];By default, attributes that are not included in the$fillable array are silently discarded when performing mass-assignment operations. In production, this is expected behavior; however, during local development it can lead to confusion as to why model changes are not taking effect.
If you wish, you may instruct Laravel to throw an exception when attempting to fill an unfillable attribute by invoking thepreventSilentlyDiscardingAttributes method. Typically, this method should be invoked in theboot method of your application'sAppServiceProvider class:
1use Illuminate\Database\Eloquent\Model;2 3/**4 * Bootstrap any application services.5*/6publicfunctionboot():void7{8Model::preventSilentlyDiscardingAttributes($this->app->isLocal());9}Eloquent'supsert method may be used to update or create records in a single, atomic operation. The method's first argument consists of the values to insert or update, while the second argument lists the column(s) that uniquely identify records within the associated table. The method's third and final argument is an array of the columns that should be updated if a matching record already exists in the database. Theupsert method will automatically set thecreated_at andupdated_at timestamps if timestamps are enabled on the model:
1Flight::upsert([2 ['departure'=>'Oakland','destination'=>'San Diego','price'=>99],3 ['departure'=>'Chicago','destination'=>'New York','price'=>150]4], uniqueBy: ['departure','destination'], update: ['price']);All databases except SQL Server require the columns in the second argument of theupsert method to have a "primary" or "unique" index. In addition, the MariaDB and MySQL database drivers ignore the second argument of theupsert method and always use the "primary" and "unique" indexes of the table to detect existing records.
To delete a model, you may call thedelete method on the model instance:
1use App\Models\Flight;2 3$flight=Flight::find(1);4 5$flight->delete();In the example above, we are retrieving the model from the database before calling thedelete method. However, if you know the primary key of the model, you may delete the model without explicitly retrieving it by calling thedestroy method. In addition to accepting the single primary key, thedestroy method will accept multiple primary keys, an array of primary keys, or acollection of primary keys:
1Flight::destroy(1);2 3Flight::destroy(1,2,3);4 5Flight::destroy([1,2,3]);6 7Flight::destroy(collect([1,2,3]));If you are utilizingsoft deleting models, you may permanently delete models via theforceDestroy method:
1Flight::forceDestroy(1);Thedestroy method loads each model individually and calls thedelete method so that thedeleting anddeleted events are properly dispatched for each model.
Of course, you may build an Eloquent query to delete all models matching your query's criteria. In this example, we will delete all flights that are marked as inactive. Like mass updates, mass deletes will not dispatch model events for the models that are deleted:
1$deleted=Flight::where('active',0)->delete();To delete all models in a table, you should execute a query without adding any conditions:
1$deleted=Flight::query()->delete();When executing a mass delete statement via Eloquent, thedeleting anddeleted model events will not be dispatched for the deleted models. This is because the models are never actually retrieved when executing the delete statement.
In addition to actually removing records from your database, Eloquent can also "soft delete" models. When models are soft deleted, they are not actually removed from your database. Instead, adeleted_at attribute is set on the model indicating the date and time at which the model was "deleted". To enable soft deletes for a model, add theIlluminate\Database\Eloquent\SoftDeletes trait to the model:
1<?php 2 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Model; 6use Illuminate\Database\Eloquent\SoftDeletes; 7 8classFlightextendsModel 9{10useSoftDeletes;11}TheSoftDeletes trait will automatically cast thedeleted_at attribute to aDateTime /Carbon instance for you.
You should also add thedeleted_at column to your database table. The Laravelschema builder contains a helper method to create this column:
1use Illuminate\Database\Schema\Blueprint; 2use Illuminate\Support\Facades\Schema; 3 4Schema::table('flights',function(Blueprint$table) { 5$table->softDeletes(); 6}); 7 8Schema::table('flights',function(Blueprint$table) { 9$table->dropSoftDeletes();10});Now, when you call thedelete method on the model, thedeleted_at column will be set to the current date and time. However, the model's database record will be left in the table. When querying a model that uses soft deletes, the soft deleted models will automatically be excluded from all query results.
To determine if a given model instance has been soft deleted, you may use thetrashed method:
1if ($flight->trashed()) {2// ...3}Sometimes you may wish to "un-delete" a soft deleted model. To restore a soft deleted model, you may call therestore method on a model instance. Therestore method will set the model'sdeleted_at column tonull:
1$flight->restore();You may also use therestore method in a query to restore multiple models. Again, like other "mass" operations, this will not dispatch any model events for the models that are restored:
1Flight::withTrashed()2->where('airline_id',1)3->restore();Therestore method may also be used when buildingrelationship queries:
1$flight->history()->restore();Sometimes you may need to truly remove a model from your database. You may use theforceDelete method to permanently remove a soft deleted model from the database table:
1$flight->forceDelete();You may also use theforceDelete method when building Eloquent relationship queries:
1$flight->history()->forceDelete();As noted above, soft deleted models will automatically be excluded from query results. However, you may force soft deleted models to be included in a query's results by calling thewithTrashed method on the query:
1use App\Models\Flight;2 3$flights=Flight::withTrashed()4->where('account_id',1)5->get();ThewithTrashed method may also be called when building arelationship query:
1$flight->history()->withTrashed()->get();TheonlyTrashed method will retrieveonly soft deleted models:
1$flights=Flight::onlyTrashed()2->where('airline_id',1)3->get();Sometimes you may want to periodically delete models that are no longer needed. To accomplish this, you may add theIlluminate\Database\Eloquent\Prunable orIlluminate\Database\Eloquent\MassPrunable trait to the models you would like to periodically prune. After adding one of the traits to the model, implement aprunable method which returns an Eloquent query builder that resolves the models that are no longer needed:
1<?php 2 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Builder; 6use Illuminate\Database\Eloquent\Model; 7use Illuminate\Database\Eloquent\Prunable; 8 9classFlightextendsModel10{11usePrunable;12 13/**14 * Get the prunable model query.15*/16publicfunctionprunable():Builder17 {18returnstatic::where('created_at','<=',now()->subMonth());19 }20}When marking models asPrunable, you may also define apruning method on the model. This method will be called before the model is deleted. This method can be useful for deleting any additional resources associated with the model, such as stored files, before the model is permanently removed from the database:
1/**2 * Prepare the model for pruning.3*/4protectedfunctionpruning():void5{6// ...7}After configuring your prunable model, you should schedule themodel:prune Artisan command in your application'sroutes/console.php file. You are free to choose the appropriate interval at which this command should be run:
1use Illuminate\Support\Facades\Schedule;2 3Schedule::command('model:prune')->daily();Behind the scenes, themodel:prune command will automatically detect "Prunable" models within your application'sapp/Models directory. If your models are in a different location, you may use the--model option to specify the model class names:
1Schedule::command('model:prune', [2'--model'=> [Address::class,Flight::class],3])->daily();If you wish to exclude certain models from being pruned while pruning all other detected models, you may use the--except option:
1Schedule::command('model:prune', [2'--except'=> [Address::class,Flight::class],3])->daily();You may test yourprunable query by executing themodel:prune command with the--pretend option. When pretending, themodel:prune command will simply report how many records would be pruned if the command were to actually run:
1phpartisanmodel:prune--pretendSoft deleting models will be permanently deleted (forceDelete) if they match the prunable query.
When models are marked with theIlluminate\Database\Eloquent\MassPrunable trait, models are deleted from the database using mass-deletion queries. Therefore, thepruning method will not be invoked, nor will thedeleting anddeleted model events be dispatched. This is because the models are never actually retrieved before deletion, thus making the pruning process much more efficient:
1<?php 2 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Builder; 6use Illuminate\Database\Eloquent\Model; 7use Illuminate\Database\Eloquent\MassPrunable; 8 9classFlightextendsModel10{11useMassPrunable;12 13/**14 * Get the prunable model query.15*/16publicfunctionprunable():Builder17 {18returnstatic::where('created_at','<=',now()->subMonth());19 }20}You may create an unsaved copy of an existing model instance using thereplicate method. This method is particularly useful when you have model instances that share many of the same attributes:
1use App\Models\Address; 2 3$shipping=Address::create([ 4'type'=>'shipping', 5'line_1'=>'123 Example Street', 6'city'=>'Victorville', 7'state'=>'CA', 8'postcode'=>'90001', 9]);10 11$billing=$shipping->replicate()->fill([12'type'=>'billing'13]);14 15$billing->save();To exclude one or more attributes from being replicated to the new model, you may pass an array to thereplicate method:
1$flight=Flight::create([ 2'destination'=>'LAX', 3'origin'=>'LHR', 4'last_flown'=>'2020-03-04 11:00:00', 5'last_pilot_id'=>747, 6]); 7 8$flight=$flight->replicate([ 9'last_flown',10'last_pilot_id'11]);Global scopes allow you to add constraints to all queries for a given model. Laravel's ownsoft delete functionality utilizes global scopes to only retrieve "non-deleted" models from the database. Writing your own global scopes can provide a convenient, easy way to make sure every query for a given model receives certain constraints.
To generate a new global scope, you may invoke themake:scope Artisan command, which will place the generated scope in your application'sapp/Models/Scopes directory:
1phpartisanmake:scopeAncientScopeWriting a global scope is simple. First, use themake:scope command to generate a class that implements theIlluminate\Database\Eloquent\Scope interface. TheScope interface requires you to implement one method:apply. Theapply method may addwhere constraints or other types of clauses to the query as needed:
1<?php 2 3namespace App\Models\Scopes; 4 5use Illuminate\Database\Eloquent\Builder; 6use Illuminate\Database\Eloquent\Model; 7use Illuminate\Database\Eloquent\Scope; 8 9classAncientScopeimplementsScope10{11/**12 * Apply the scope to a given Eloquent query builder.13*/14publicfunctionapply(Builder$builder,Model$model):void15 {16$builder->where('created_at','<',now()->subYears(2000));17 }18}If your global scope is adding columns to the select clause of the query, you should use theaddSelect method instead ofselect. This will prevent the unintentional replacement of the query's existing select clause.
To assign a global scope to a model, you may simply place theScopedBy attribute on the model:
1<?php 2 3namespace App\Models; 4 5use App\Models\Scopes\AncientScope; 6use Illuminate\Database\Eloquent\Attributes\ScopedBy; 7 8#[ScopedBy([AncientScope::class])] 9classUserextendsModel10{11//12}Or, you may manually register the global scope by overriding the model'sbooted method and invoke the model'saddGlobalScope method. TheaddGlobalScope method accepts an instance of your scope as its only argument:
1<?php 2 3namespace App\Models; 4 5use App\Models\Scopes\AncientScope; 6use Illuminate\Database\Eloquent\Model; 7 8classUserextendsModel 9{10/**11 * The "booted" method of the model.12*/13protectedstaticfunctionbooted():void14 {15static::addGlobalScope(newAncientScope);16 }17}After adding the scope in the example above to theApp\Models\User model, a call to theUser::all() method will execute the following SQL query:
1select*from`users`where`created_at`<0021-02-1800:00:00Eloquent also allows you to define global scopes using closures, which is particularly useful for simple scopes that do not warrant a separate class of their own. When defining a global scope using a closure, you should provide a scope name of your own choosing as the first argument to theaddGlobalScope method:
1<?php 2 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Builder; 6use Illuminate\Database\Eloquent\Model; 7 8classUserextendsModel 9{10/**11 * The "booted" method of the model.12*/13protectedstaticfunctionbooted():void14 {15static::addGlobalScope('ancient',function(Builder$builder) {16$builder->where('created_at','<',now()->subYears(2000));17 });18 }19}If you would like to remove a global scope for a given query, you may use thewithoutGlobalScope method. This method accepts the class name of the global scope as its only argument:
1User::withoutGlobalScope(AncientScope::class)->get();Or, if you defined the global scope using a closure, you should pass the string name that you assigned to the global scope:
1User::withoutGlobalScope('ancient')->get();If you would like to remove several or even all of the query's global scopes, you may use thewithoutGlobalScopes method:
1// Remove all of the global scopes...2User::withoutGlobalScopes()->get();3 4// Remove some of the global scopes...5User::withoutGlobalScopes([6FirstScope::class,SecondScope::class7])->get();Local scopes allow you to define common sets of query constraints that you may easily re-use throughout your application. For example, you may need to frequently retrieve all users that are considered "popular". To define a scope, prefix an Eloquent model method withscope.
Scopes should always return the same query builder instance orvoid:
1<?php 2 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Builder; 6use Illuminate\Database\Eloquent\Model; 7 8classUserextendsModel 9{10/**11 * Scope a query to only include popular users.12*/13publicfunctionscopePopular(Builder$query):void14 {15$query->where('votes','>',100);16 }17 18/**19 * Scope a query to only include active users.20*/21publicfunctionscopeActive(Builder$query):void22 {23$query->where('active',1);24 }25}Once the scope has been defined, you may call the scope methods when querying the model. However, you should not include thescope prefix when calling the method. You can even chain calls to various scopes:
1use App\Models\User;2 3$users=User::popular()->active()->orderBy('created_at')->get();Combining multiple Eloquent model scopes via anor query operator may require the use of closures to achieve the correctlogical grouping:
1$users=User::popular()->orWhere(function(Builder$query) {2$query->active();3})->get();However, since this can be cumbersome, Laravel provides a "higher order"orWhere method that allows you to fluently chain scopes together without the use of closures:
1$users=User::popular()->orWhere->active()->get();Sometimes you may wish to define a scope that accepts parameters. To get started, just add your additional parameters to your scope method's signature. Scope parameters should be defined after the$query parameter:
1<?php 2 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Builder; 6use Illuminate\Database\Eloquent\Model; 7 8classUserextendsModel 9{10/**11 * Scope a query to only include users of a given type.12*/13publicfunctionscopeOfType(Builder$query,string$type):void14 {15$query->where('type',$type);16 }17}Once the expected arguments have been added to your scope method's signature, you may pass the arguments when calling the scope:
1$users=User::ofType('admin')->get();If you would like to use scopes to create models that have the same attributes as those used to constrain the scope, you may use thewithAttributes method when building the scope query:
1<?php 2 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Builder; 6use Illuminate\Database\Eloquent\Model; 7 8classPostextendsModel 9{10/**11 * Scope the query to only include drafts.12*/13publicfunctionscopeDraft(Builder$query):void14 {15$query->withAttributes([16'hidden'=>true,17 ]);18 }19}ThewithAttributes method will addwhere clause constraints to the query using the given attributes, and it will also add the given attributes to any models created via the scope:
1$draft=Post::draft()->create(['title'=>'In Progress']);2 3$draft->hidden;// trueSometimes you may need to determine if two models are the "same" or not. Theis andisNot methods may be used to quickly verify two models have the same primary key, table, and database connection or not:
1if ($post->is($anotherPost)) {2// ...3}4 5if ($post->isNot($anotherPost)) {6// ...7}Theis andisNot methods are also available when using thebelongsTo,hasOne,morphTo, andmorphOnerelationships. This method is particularly helpful when you would like to compare a related model without issuing a query to retrieve that model:
1if ($post->author()->is($user)) {2// ...3}Want to broadcast your Eloquent events directly to your client-side application? Check out Laravel'smodel event broadcasting.
Eloquent models dispatch several events, allowing you to hook into the following moments in a model's lifecycle:retrieved,creating,created,updating,updated,saving,saved,deleting,deleted,trashed,forceDeleting,forceDeleted,restoring,restored, andreplicating.
Theretrieved event will dispatch when an existing model is retrieved from the database. When a new model is saved for the first time, thecreating andcreated events will dispatch. Theupdating /updated events will dispatch when an existing model is modified and thesave method is called. Thesaving /saved events will dispatch when a model is created or updated - even if the model's attributes have not been changed. Event names ending with-ing are dispatched before any changes to the model are persisted, while events ending with-ed are dispatched after the changes to the model are persisted.
To start listening to model events, define a$dispatchesEvents property on your Eloquent model. This property maps various points of the Eloquent model's lifecycle to your ownevent classes. Each model event class should expect to receive an instance of the affected model via its constructor:
1<?php 2 3namespace App\Models; 4 5use App\Events\UserDeleted; 6use App\Events\UserSaved; 7use Illuminate\Foundation\Auth\Useras Authenticatable; 8use Illuminate\Notifications\Notifiable; 9 10classUserextendsAuthenticatable11{12useNotifiable;13 14/**15 * The event map for the model.16 *17 *@vararray<string, string>18*/19protected$dispatchesEvents= [20'saved'=>UserSaved::class,21'deleted'=>UserDeleted::class,22 ];23}After defining and mapping your Eloquent events, you may useevent listeners to handle the events.
When issuing a mass update or delete query via Eloquent, thesaved,updated,deleting, anddeleted model events will not be dispatched for the affected models. This is because the models are never actually retrieved when performing mass updates or deletes.
Instead of using custom event classes, you may register closures that execute when various model events are dispatched. Typically, you should register these closures in thebooted method of your model:
1<?php 2 3namespace App\Models; 4 5use Illuminate\Database\Eloquent\Model; 6 7classUserextendsModel 8{ 9/**10 * The "booted" method of the model.11*/12protectedstaticfunctionbooted():void13 {14static::created(function(User$user) {15// ...16 });17 }18}If needed, you may utilizequeueable anonymous event listeners when registering model events. This will instruct Laravel to execute the model event listener in the background using your application'squeue:
1usefunction Illuminate\Events\queueable;2 3static::created(queueable(function(User$user){4 // ...5}));If you are listening for many events on a given model, you may use observers to group all of your listeners into a single class. Observer classes have method names which reflect the Eloquent events you wish to listen for. Each of these methods receives the affected model as their only argument. Themake:observer Artisan command is the easiest way to create a new observer class:
1phpartisanmake:observerUserObserver--model=UserThis command will place the new observer in yourapp/Observers directory. If this directory does not exist, Artisan will create it for you. Your fresh observer will look like the following:
1<?php 2 3namespace App\Observers; 4 5use App\Models\User; 6 7classUserObserver 8{ 9/**10 * Handle the User "created" event.11*/12publicfunctioncreated(User$user):void13 {14// ...15 }16 17/**18 * Handle the User "updated" event.19*/20publicfunctionupdated(User$user):void21 {22// ...23 }24 25/**26 * Handle the User "deleted" event.27*/28publicfunctiondeleted(User$user):void29 {30// ...31 }32 33/**34 * Handle the User "restored" event.35*/36publicfunctionrestored(User$user):void37 {38// ...39 }40 41/**42 * Handle the User "forceDeleted" event.43*/44publicfunctionforceDeleted(User$user):void45 {46// ...47 }48}To register an observer, you may place theObservedBy attribute on the corresponding model:
1use App\Observers\UserObserver;2use Illuminate\Database\Eloquent\Attributes\ObservedBy;3 4#[ObservedBy([UserObserver::class])]5classUserextendsAuthenticatable6{7//8}Or, you may manually register an observer by invoking theobserve method on the model you wish to observe. You may register observers in theboot method of your application'sAppServiceProvider class:
1use App\Models\User; 2use App\Observers\UserObserver; 3 4/** 5 * Bootstrap any application services. 6*/ 7publicfunctionboot():void 8{ 9User::observe(UserObserver::class);10}There are additional events an observer can listen to, such assaving andretrieved. These events are described within theevents documentation.
When models are being created within a database transaction, you may want to instruct an observer to only execute its event handlers after the database transaction is committed. You may accomplish this by implementing theShouldHandleEventsAfterCommit interface on your observer. If a database transaction is not in progress, the event handlers will execute immediately:
1<?php 2 3namespace App\Observers; 4 5use App\Models\User; 6use Illuminate\Contracts\Events\ShouldHandleEventsAfterCommit; 7 8classUserObserverimplementsShouldHandleEventsAfterCommit 9{10/**11 * Handle the User "created" event.12*/13publicfunctioncreated(User$user):void14 {15// ...16 }17}You may occasionally need to temporarily "mute" all events fired by a model. You may achieve this using thewithoutEvents method. ThewithoutEvents method accepts a closure as its only argument. Any code executed within this closure will not dispatch model events, and any value returned by the closure will be returned by thewithoutEvents method:
1use App\Models\User;2 3$user=User::withoutEvents(function() {4User::findOrFail(1)->delete();5 6returnUser::find(2);7});Sometimes you may wish to "save" a given model without dispatching any events. You may accomplish this using thesaveQuietly method:
1$user=User::findOrFail(1);2 3$user->name='Victoria Faith';4 5$user->saveQuietly();You may also "update", "delete", "soft delete", "restore", and "replicate" a given model without dispatching any events:
1$user->deleteQuietly();2$user->forceDeleteQuietly();3$user->restoreQuietly(); Laravel is the most productive way to
build, deploy, and monitor software.