Introduction: database operation using Eloquent model
brief introduction
Larave's built-in Eloquent ORM provides a beautiful and simple ActiveRecord implementation for dealing with databases. Each data table corresponds to a model that interacts with the table. Through the model class, you can query, insert, update, delete and other operations on the data table.
Before you begin, make sure that you config/database.php
The database connection is configured in the file. For more information about database configuration, please View Document 。
Define model
We start by creating an Eloquent model. The model class is usually located in app
You can also place it in other directories composer.json
Where the file is automatically loaded. All Eloquent models inherit from Illuminate\Database\Eloquent\Model
Class.
The easiest way to create model instances is to use Artisan commands make:model
:
php artisan make:model User
If you want to generate Database migration , you can use --migration
or -m
Options:
php artisan make:model User --migration php artisan make:model User -m
Eloquent model convention
Now, let's look at a Flight
Model example, we will use this class to obtain and access data tables flights
Information in:
<? php namespace App; use Illuminate\Database\Eloquent\Model; class Flight extends Model { // }
Table name
Notice that we didn't tell Eloquent about our Flight
The default rule for which table the model uses is the lower case model class name plural format as its corresponding table name (unless other names are explicitly specified in the model class). So, in this example, Eloquent believes that Flight
The model is stored and recorded in flights
Table. You can also define in the model table
Property to specify a custom table name:
<? php namespace App; use Illuminate\Database\Eloquent\Model; class Flight extends Model { /** *Data table associated to model * * @var string */ protected $table = 'my_flights'; }
Primary key
Eloquent's default primary key name for each table is id
, you can define a $primaryKey
Property to override the convention.
In addition, Eloquent's default primary key field is self increasing integer data, which means that the primary key will be automatically converted to int
Type. If you want to use a non auto increment or non numeric primary key, you must set it in the corresponding model $incrementing
Property is false
If the primary key is not an integer, set it $keyType
The attribute value is string
。
time stamp
By default, Eloquent expects created_at
and updated_at
It already exists in the data table. If you don't want these data columns automatically managed by Larave, set them in the model class $timestamps
Property is false
:
<? php namespace App; use Illuminate\Database\Eloquent\Model; class Flight extends Model { /** *Indicates whether the model should be time stamped * * @var bool */ public $timestamps = false; }
If you need to customize the timestamp format, set the $dateFormat
Property. This attribute determines how the date is stored in the database and the format of the date when the model is serialized as an array or JSON:
<? php namespace App; use Illuminate\Database\Eloquent\Model; class Flight extends Model { /** *Storage format of model date column * * @var string */ protected $dateFormat = 'U'; }
If you need to customize the field name used to store the timestamp, you can set it in the model CREATED_AT
and UPDATED_AT
Constant:
<? php class Flight extends Model { const CREATED_AT = 'creation_date'; const UPDATED_AT = 'last_update'; }
Database connection
By default, all Eloquent models use the default database connection in the application configuration. If you want to specify a different connection for the model, you can use the $connection
Property to set:
<? php namespace App; use Illuminate\Database\Eloquent\Model; class Flight extends Model { /** * The connection name for the model. * * @var string */ protected $connection = 'connection-name'; }
Get model
After creating the model and Associated Data Table After that, you can get data from the database. Think of the Eloquent model as a powerful Query Builder , you can use it to smoothly query the data tables associated with it. For example:
<? php use App\Flight; $flights = App\Flight::all(); foreach ($flights as $flight) { echo $flight->name; }
Add additional constraints
Eloquent's all
Method returns all the results of the model table. Since every Eloquent model is a query builder, you can also add constraints to the query, and then use get
Method to obtain the corresponding results:
$flights = App\Flight::where('active', 1) ->orderBy('name', 'desc') ->take(10) ->get();
Note: Since the Eloquent model is essentially a query builder, you can use all the methods of the query builder in Eloquent queries.
aggregate
The method to obtain multiple results in Eloquent (such as all
and get
)The return value is Illuminate\Database\Eloquent\Collection
An instance of, Collection
Class provides Several useful functions To process the Eloquent result set:
$flights = $flights->reject(function ($flight) { return $flight->cancelled; });
Of course, you can also iterate over the collection like an array:
foreach ($flights as $flight) { echo $flight->name; }
Chunking result set
If you need to process Eloquent result sets with a large amount of data, you can use chunk
method. chunk
Method will obtain a specified number of Eloquent model "chunks" and fill them into the given closure for processing. use chunk
Method can effectively reduce memory consumption when processing a large number of data sets:
Flight::chunk(200, function ($flights) { foreach ($flights as $flight) { // } });
The first parameter passed to this method is the number of "chunks" you want to obtain. Closures are passed in as the second parameter to process each chunk data obtained from the database.
Use Cursor
cursor
The method allows you to use cursors to iteratively process database records, and only execute a single query at a time. When processing large quantities of data, cursor
Method can significantly reduce memory consumption:
foreach (Flight::where('foo', 'bar')->cursor() as $flight) { // }
Get single model/aggregate results
Of course, in addition to obtaining all records from the given table, you can also use find
and first
Get a single record. These methods return a single model instance instead of a model collection: //Get model through primary key $flight = App\Flight::find(1); //Get the first model matching the query criteria $flight = App\Flight::where('active', 1)->first();
You can also call the find
Method, which will return a set of matching records: $flights = App\Flight::find([1, 2, 3]);
Not Found exception
Sometimes you may want to throw an exception when the model cannot be found, which is very useful in routing or controllers, findOrFail
and firstOrFail
Method will get the first result queried. However, if there are no query results, Illuminate\Database\Eloquent\ModelNotFoundException
The exception will be thrown:
$model = App\Flight::findOrFail(1); $model = App\Flight::where('legs', '>', 100)->firstOrFail();
If the exception is not caught, then HTTP four hundred and four
The response will be sent to the user, so it is unnecessary to write additional checks on the returned 404 response when using these methods:
Route::get('/api/flights/{id}', function ($id) { return App\Flight::findOrFail($id); });
Get aggregate results
Of course, you can also use the aggregation method provided by the query builder, such as count
、 sum
、 max
, and other query builders Aggregate function 。 These methods return the calculated results rather than the whole model instance:
$count = App\Flight::where('active', 1)->count(); $max = App\Flight::where('active', 1)->max('price');
Insert/Update Model
insert
To insert a new record in the database, just create a new model instance, set the properties of the model, and call save
method:
<? php namespace App\Http\Controllers; use App\Flight; use Illuminate\Http\Request; use App\Http\Controllers\Controller; class FlightController extends Controller{ /** *Create a new flight instance * * @param Request $request * @return Response * @translator laravelacademy.org */ public function store(Request $request) { //Verify Request $flight = new Flight; $flight->name = $request->name; $flight->save(); } }
In this example, we simply allocate name
Parameter value App\Flight
Of the model instance name
Property, when we call save
Method, a record will be inserted into the database. created_at
and updated_at
Timestamp on save
Methods are automatically set when they are called, so there is no need to set them manually.
to update
save
Method can also be used to update existing models in the database. To update a model, you should first obtain it, set the properties you want to update, and then call save
method. Similarly, updated_at
The timestamp will be updated automatically, so it is unnecessary to set its value manually:
$flight = App\Flight::find(1); $flight->name = 'New Flight Name'; $flight->save();
Batch update
The update operation can also modify multiple model instances provided by a given query at the same time. In this case, all valid and destination=San Diego
's flights are marked as delayed:
App\Flight::where('active', 1) ->where('destination', 'San Diego') ->update(['delayed' => 1]);
update
The method requires that key value pair parameters be passed in an array, representing the columns in the data table that should be updated.
Note: When batch update is performed through Eloquent, saved
and updated
Model events will not be triggered when the model is updated. This is because the model is not obtained from the database during batch update.
Batch assignment
You can also use create
Method to save a new model. This method returns the inserted model instance. But before that, you need to specify the fillable
or guarded
Attribute, because all Eloquent models are protected by Mass Assignment, these two attributes are used to define which model fields are allowed to be assigned in batches and which model fields are protected, and cannot be explicitly assigned in batches.
When a user passes an unexpected parameter value through an HTTP request, a security risk will arise, and then the parameter will modify the field value in the database in an unexpected way. For example, a malicious user sends a is_admin
Parameter, which is then mapped to the create
Method to allow users to turn themselves into administrators.
Therefore, you should define which attributes can be assigned in the model $fillable
Property. For example, we set Flight
On model name
Attributes can be assigned:
<? php namespace App; use Illuminate\Database\Eloquent\Model; class Flight extends Model { /** *Attributes that can be assigned in batch * * @var array */ protected $fillable = ['name']; }
After setting the attributes that can be assigned, we can use create
Method to insert a new record in the database. create
Method returns the saved model instance:
$flight = App\Flight::create(['name' => 'Flight 10']);
If you already have a model instance, you can use fill
Method is filled with array properties:
$flight->fill(['name' => 'Flight 22']);
Blacklist attribute
$fillable
It is like a "white list" that can be assigned attributes. You can also choose to use $guarded
。 $guarded
Property contains an array of properties that you do not want to be assigned. Therefore, the attributes not included in it can be assigned. Therefore, $guarded
The function is like "blacklist". Of course, you can only use one of these two attributes at the same time, because they are mutually exclusive. In the following example, except price
All attributes other than can be assigned:
<? php namespace App; use Illuminate\Database\Eloquent\Model; class Flight extends Model { /** *Attributes that cannot be assigned in batch * * @var array */ protected $guarded = ['price']; }
If you want all attributes to be batch assignable, you can set $guarded
Property is set to an empty array:
/** * The attributes that aren't mass assignable. * * @var array */ protected $guarded = [];
Other creation methods
firstOrCreate/firstOrNew
There are two other ways to create models: firstOrCreate
and firstOrNew
。 firstOrCreate
Method first attempts to find a record in the database through the given column/value pair. If it is not found, a new record will be created through the given attribute.
firstOrNew
Methods and firstOrCreate
The same method is used to first try to find a matching record in the database. If it is not found, a new model instance will be returned. It should be noted that through firstOrNew
The model instance returned by the method is not persisted to the database. You need to call save
Method manual persistence:
//Get the flight through the attribute. If it does not exist, create it $flight = App\Flight::firstOrCreate(['name' => 'Flight 10']); //Get the flight by name. If it does not exist, create it by name and delayed attributes $flight = App\Flight::firstOrCreate( ['name' => 'Flight 10'], ['delayed' => 1] ); //Get the flight through the attribute. If it does not exist, initialize a new instance $flight = App\Flight::firstOrNew(['name' => 'Flight 10']); //Get it through name. If it does not exist, create a new instance through the name and delayed attributes $flight = App\Flight::firstOrNew( ['name' => 'Flight 10'], ['delayed' => 1] );
updateOrCreate
Similarly, you will also encounter the scene of updating if the model already exists, or creating a new model updateOrCreate
This can be done step by step. and firstOrCreate
In the same way, updateOrCreate
Method will persist the model, so there is no need to call save()
:
//If there are flights from Auckland to San Diego, set the price to $99 //If there is no matching model, create it $flight = App\Flight::updateOrCreate( ['departure' => 'Oakland', 'destination' => 'San Diego'], ['price' => 99] );
Delete Model
To delete a model, call the delete
method:
$flight = App\Flight::find(1); $flight->delete();
Delete model through primary key
In the above example, we call delete
Method to obtain the model from the database. However, if you know the primary key of the model, you can call destroy
Method to delete directly without obtaining it:
App\Flight::destroy(1); App\Flight::destroy([1, 2, 3]); App\Flight::destroy(1, 2, 3);
Delete model through query
Of course, you can also delete multiple models by querying. In this example, we delete all flights marked as invalid:
$deletedRows = App\Flight::where('active', 0)->delete();
Note: When batch deletion is performed through Eloquent, deleting
and deleted
The model event will not be triggered when the model is deleted, because the model will not be obtained when the model is deleted.
Soft Delete
In addition to physically deleting records from the database, Eloquent can also "soft delete" models. When models are soft deleted, they are not really deleted from the database, but set a deleted_at
Property and insert it into the database. If the model has a non empty deleted_at
Value, the model has been soft deleted. To enable soft deletion of a model, you can use the Illuminate\Database\Eloquent\SoftDeletes
Trait and add deleted_at
Column to $dates
Properties:
<? php namespace App; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; class Flight extends Model { use SoftDeletes; /** *The attribute should be adjusted to date * * @var array */ protected $dates = ['deleted_at']; }
Of course, you should add deleted_at
Column to the data table. The Larravel Schema builder contains an auxiliary function to create this data column:
Schema::table('flights', function ($table) { $table->softDeletes(); });
Now, when you call the delete
Method, deleted_at
The column will be set as the current date and time, and when a soft deleted model is queried, the soft deleted model will be automatically excluded from the query results.
To determine whether a given model instance has been soft deleted, you can use trashed
method:
if ($flight->trashed()) { // }
Query Soft Deleted Models
Include soft deleted models
As mentioned above, the soft deletion model will be automatically excluded from the query results. However, if you want the soft deletion model to appear in the query results, you can use withTrashed
method:
$flights = App\Flight::withTrashed() ->where('account_id', 1) ->get();
withTrashed
Methods can also be used in association queries:
$flight->history()->withTrashed()->get();
Get Soft Delete Models Only
onlyTrashed
Method only obtains the soft deletion model:
$flights = App\Flight::onlyTrashed() ->where('airline_id', 1) ->get();
Restore Soft Delete Model
Sometimes you want to restore a soft deleted model, you can use restore
method:
$flight->restore();
You can also use it in the query restore
Method to quickly restore multiple models. Similarly, this will not trigger any model events:
App\Flight::withTrashed() ->where('airline_id', 1) ->restore();
and withTrashed
In the same way, restore
Methods can also be used for association queries:
$flight->history()->restore();
Permanently delete model
Sometimes you really need to delete a model from the database. To permanently delete records from the database, you can use forceDelete
method:
//Force deletion of a single model instance $flight->forceDelete(); //Force deletion of all associated models $flight->history()->forceDelete();
Query Scope
global scope
Global scope allows us to add conditional constraints for all queries of a given model. Larave's built-in soft delete function uses the global scope to pull all the models that have not been deleted from the database. Writing a custom global scope can provide a convenient and simple way to ensure that each query of a given model has specific constraints.
Write Global Scope
Customizing the global scope is simple. First, define an implementation Illuminate\Database\Eloquent\Scope
Interface class, which requires you to implement a method: apply
。 If necessary, you can visit apply
Method where
Condition to query:
<? php namespace App\Scopes; use Illuminate\Database\Eloquent\Scope; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Builder; class AgeScope implements Scope { /** *Apply the scope to the given Eloquent query builder * * @param \Illuminate\Database\Eloquent\Builder $builder * @param \Illuminate\Database\Eloquent\Model $model * @return void * @translator laravelacademy.org */ public function apply(Builder $builder, Model $model) { return $builder->where('age', '>', 200); } }
The Larravel application does not predefine folders for the scope by default, so you can use the app
Create under directory Scopes
catalog.
Note: If your global scope needs to add columns to the select clause of the query, you need to use addSelect
Method to replace select
In this way, you can avoid the impact of the existing select query clause.
Apply Global Scope
To apply the global scope to the model, you need to override the boot
Method and use addGlobalScope
method:
<? php namespace App; use App\Scopes\AgeScope; use Illuminate\Database\Eloquent\Model; class User extends Model { /** *The "start" method of the model * * @return void */ protected static function boot() { parent::boot(); static::addGlobalScope(new AgeScope); } }
After adding a scope, if you use User::all()
The query will generate the following SQL statements:
select * from `users` where `age` > 200
Anonymous global scope
Eloquent also allows us to use closures to define global scopes, which is particularly useful when implementing simple scopes. In this way, we don't need to define a separate class:
<? php namespace App; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Builder; class User extends Model{ /** * The "booting" method of the model. * * @return void */ protected static function boot() { parent::boot(); static::addGlobalScope('age', function(Builder $builder) { $builder->where('age', '>', 200); }); } }
Remove Global Scope
If you want to remove the specified global scope from a given query, you can use the withoutGlobalScope
Method, which receives the class name of the global scope as its unique parameter:
User::withoutGlobalScope(AgeScope::class)->get();
If you want to remove some or all global scopes, you can use withoutGlobalScopes
method:
//Remove All Global Scopes User::withoutGlobalScopes()->get(); //Remove some global scopes User:: withoutGlobalScopes ([FirstScope:: class, SecondScope:: class]) ->get();
Local Scope
Local scope allows us to define a common set of constraints for reuse in applications. For example, you may often need to obtain the most popular users. To define such a scope, simply add a scope
Prefix. The scope always returns the query builder instance:
<? php namespace App; use Illuminate\Database\Eloquent\Model; class User extends Model { /** *Query scope containing only active users * * @return \Illuminate\Database\Eloquent\Builder */ public function scopePopular($query) { return $query->where('votes', '>', 100); } /** *Only include the query scope of the active user * * @return \Illuminate\Database\Eloquent\Builder */ public function scopeActive($query) { return $query->where('active', 1); } }
Use local scope
After the scope is defined, you can call the scope method when querying the model, but you do not need to add scope
Prefix, you can even call multiple scopes at the same time, for example:
$users = App\User::popular()->active()->orderBy('created_at')->get();
dynamic scope
Sometimes you may want to define a scope that can receive parameters. You just need to add additional parameters to your scope. Scope parameters should be defined in $query
After parameter:
<? php namespace App; use Illuminate\Database\Eloquent\Model; class User extends Model { /** *Let the query contain only users of a given type * * @param \Illuminate\Database\Eloquent\Builder $query * @param mixed $type * @return \Illuminate\Database\Eloquent\Builder */ public function scopeOfType($query, $type) { return $query->where('type', $type); } }
Now, you can pass parameters when calling the scope:
$users = App\User::ofType('admin')->get();
event
Eloquent model can trigger events, allowing you to call the following methods at multiple time points in the model life cycle: retrieved
, creating
, created
, updating
, updated
, saving
, saved
, deleting
, deleted
, restoring
, restored
。 Events allow you to execute code every time a specified model class is saved or updated.
retrieved
The event is triggered when the existing model is retrieved from the database. When a new model is saved for the first time, creating
and created
The event will be triggered. If a model already exists in the database and calls save
method, updating
/ updated
Events will be triggered, whether they are created or updated, saving
/ saved
Events will be triggered.
For example, define a $dispatchesEvents
Attribute to map multiple time points and corresponding event classes in the model life cycle:
<? php namespace App; use App\Events\UserSaved; use App\Events\UserDeleted; use Illuminate\Notifications\Notifiable; use Illuminate\Foundation\Auth\User as Authenticatable; class User extends Authenticatable { use Notifiable; /** * The event map for the model. * * @var array */ protected $dispatchesEvents = [ 'saved' => UserSaved::class, 'deleted' => UserDeleted::class, ]; }
Observer
If you listen to multiple events in a given model, you can use an observer to group all listeners. The observer class has a method name that reflects the Eloquent event you want to listen to. Each method receives the model as a unique parameter. Larave does not provide a default directory for observers, so you can create any directory to store observer classes:
<? php namespace App\Observers; use App\User; class UserObserver { /** *Listen to user creation events * * @param User $user * @return void */ public function created(User $user) { // } /** *Listen to user deletion events * * @param User $user * @return void */ public function deleting(User $user) { // } }
To register an observer, use the observe
Method, you can select a service provider's boot
Method. In this example, we register observers in the AppServiceProvider
Observers registered in:
<? php namespace App\Providers; use App\User; use App\Observers\UserObserver; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider { /** * Bootstrap any application services. * * @return void */ public function boot() { User::observe(UserObserver::class); } /** * Register the service provider. * * @return void */ public function register() { // } }