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() { // } }

give the thumbs-up Cancel Like Collection Cancel Collection

<<Previous: Database filler: a good helper for initializing test data

>>Next: Advanced Chapter: Managing Association Relationship Using Eloquent Model