Quick start


Eloquent: Getting Started

##Introduction

Laravel's Eloquent ORM provides a beautiful, concise ActiveRecord implementation to interact with the database. Each database table has a corresponding "model" used to interact with the table. You can query data in the data table through the model and insert new records into the data table.

Before you begin, make sure you configure your database connection in

config/database.php

. For more information on database configuration, check out the documentation.

Model Definition

First, create an Eloquent model. Models are usually in the

app

directory, but you can place them anywhere where they can be automatically loaded based on the composer.json file. All Eloquent models inherit from the Illuminate\Database\Eloquent\Model class. The easiest way to create a model is to use

make:model

Artisan command:

php artisan make:model Flight
If you want to generate database migration when generating the model, you can use

- -migration

or -m Options:

php artisan make:model Flight --migration

php artisan make:model Flight -m

##Eloquent Model Convention
Now, let's look at an example of a

Flight

model that we will use to retrieve and store data information from the

flights database table:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class Flight extends Model{ 
       //
    }

Data table name

Please note that we do not tell Eloquent which data table to use for our Flight model. Unless another name is explicitly specified, the plural form of class, "snakes", will be used as the table name. Therefore, in this case, Eloquent will assume that the Flight model stores data from the flights data table. You can specify a custom data table by defining the table attribute on the model:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class Flight extends Model{ 
    /**
     * 与模型关联的表名
     *
     * @var string
     */  
   protected $table = 'my_flights';
 }

Primary key

Eloquent will also assume that each data table There is a primary key column named id. You can define a protected $primaryKey property to override the convention.

Additionally, Eloquent assumes that the primary key is an auto-incrementing integer value, which means that the primary key is automatically converted to the int type by default. If you wish to use a non-increasing or non-numeric primary key you need to set the public $incrementing property to false. If your primary key is not an integer, you need to set the protected $keyType property on the model to string.

Timestamp

By default, Eloquent expects created_at and updated_at to exist in your data table. If you do not want Eloquent to automatically manage these two columns, please set the $timestamps attribute in the model to false:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class Flight extends Model{    
    /**
     * 指示模型是否自动维护时间戳
     *
     * @var bool
     */    
   public $timestamps = false;
  }

If you need to customize the timestamps Format, set the $dateFormat property in your model. This attribute determines how the date attribute is stored in the database, and the format in which the model is serialized into an array or JSON:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class Flight extends Model{   
     /**
     * 模型日期列的存储格式。
     *
     * @var string
     */   
     protected $dateFormat = 'U';
    }

If you need to customize the field name for storing timestamps, you can set CREATED_AT in the model and UPDATED_AT constant values ​​to implement:

<?php
    class Flight extends Model{
        const CREATED_AT = 'creation_date';    
        const UPDATED_AT = 'last_update';
     }

Database Connection

By default, the Eloquent model will be used by your application Configured default database connection. If you want to specify a different connection for the model, set the $connection property:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class Flight extends Model{   
     /**
     * 模型的连接名称
     *
     * @var string
     */   
     protected $connection = 'connection-name';
   }

Default property value

If you want to define default values ​​for some attributes of the model, you can define $attributes attributes on the model:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class Flight extends Model{  
      /**
     * 模型的默认属性值。
     *
     * @var array
     */  
      protected $attributes = [      
        'delayed' => false,   
         ];
      }

Model Retrieval

After creating the model and its associated database table, you can query data from the database. Think of each Eloquent model as a powerful query builder that you can use to query its associated data table more quickly. For example:

<?php
    $flights = App\Flight::all();
    foreach ($flights as $flight) {   
     echo $flight->name;
    }

Additional constraints

Eloquent’s all method will return all results in the model. Since each Eloquent model acts as a query builder, you can also add query conditions and then use the get method to get the query results:

$flights = App\Flight::where('active', 1)         
      ->orderBy('name', 'desc')               
      ->take(10)               
      ->get();

{tip} Because the Eloquent model is also a query builder, so you should also read about all the methods available to the query builder. You can use these methods in Eloquent queries.

Reload the model

You can reload the model using the fresh and refresh methods. fresh The method will retrieve the model from the database again. Existing model instances are not affected: The

$flight = App\Flight::where('number', 'FR 900')->first();
$freshFlight = $flight->fresh();

refresh method reassigns an existing model with new data from the database. In addition, already loaded relationships will be reloaded:

$flight = App\Flight::where('number', 'FR 900')->first();
$flight->number = 'FR 456';$flight->refresh();
$flight->number;
 // "FR 900"

Collection

For in Eloquent The all and get methods can query multiple results and return an Illuminate\Database\Eloquent\Collection instance. The Collection class provides a number of helper functions to handle Eloquent results:

$flights = $flights->reject(function ($flight) { 
   return $flight->cancelled;
 });

You can iterate over the collection like an array:

foreach ($flights as $flight) {
    echo $flight->name;
  }

Chunking results

If you need to process thousands of Eloquent results, use the chunk command. The chunk method retrieves the "chunks" in the Eloquent model and provides them to the specified Closure for processing. When processing large result sets, use the chunk method to save memory:

Flight::chunk(200, function ($flights) { 
   foreach ($flights as $flight) {   
        //  
      }
  });

The first parameter passed to the method is the amount of data you want each "chunk" to receive. The closure is passed as the second parameter and is called each time a chunk is retrieved from the database. It will execute the database query and pass the retrieved chunked results to the closure method.

Using Cursors

cursor method allows you to traverse the database using a cursor, which only executes the query once. When processing large amounts of data, the cursor method can greatly reduce memory usage:

foreach (Flight::where('foo', 'bar')->cursor() as $flight) {
    //
 }

Retrieve a single model / Collection

In addition to retrieving all records from the specified data table, you can use the find or first method to retrieve a single record. These methods return a single model instance rather than a collection of models:

// 通过主键检索一个模型...
$flight = App\Flight::find(1);
// 检索符合查询限制的第一个模型...
$flight = App\Flight::where('active', 1)->first();

You can also call the find method with an array of primary keys as a parameter, which will return a collection of matching records:

$flights = App\Flight::find([1, 2, 3]);

『Not Found』Exception

Sometimes you want to throw an exception when the model is not found. This is very useful in controllers and routing. The findOrFail and firstOrFail methods will retrieve the first result of the query, if not found, will throw Illuminate\Database\Eloquent\ModelNotFoundException Exception:

$model = App\Flight::findOrFail(1);
$model = App\Flight::where('legs', '>', 100)->firstOrFail();

If the exception is not caught, a 404 response will be automatically returned to the user. That is, when using these methods, there is no need to write a check to return 404 Response: :

Route::get('/api/flights/{id}', function ($id) { 
   return App\Flight::findOrFail($id);
 });

Retrieve a collection

You can also use the count, sum, max, and other aggregate functions provided by the query builder. These methods will simply return the appropriate scalar value instead of a model instance:

$count = App\Flight::where('active', 1)->count();
$max = App\Flight::where('active', 1)->max('price');

##Insert & Update Model

Insert

To add a new record to the database, first create a new model instance, set properties for the instance, and then call

save Method:

<?php
    namespace App\Http\Controllers;
    use App\Flight;use Illuminate\Http\Request;
    use App\Http\Controllers\Controller;
    class FlightController extends Controller{   
     /**
     * 创建一个新的航班实例
     *
     * @param  Request  $request
     * @return Response
     */  
     public function store(Request $request)   
      {      
        // 校验请求...        
        $flight = new Flight;        
        $flight->name = $request->name;        
        $flight->save();  
        }
   }

In this example, we assign the HTTP request parameter

name to the name# of the App\Flight model instance ## Attributes. When the save method is called, a new record will be inserted. created_at and updated_at timestamps will be set automatically and no manual assignment is required.

Update

save

method can also be used to update an existing model in the database. To update the model, you need to retrieve it first, set the properties to be updated, and then call the save method. Similarly, the updated_at timestamp will be updated automatically, so there is no need to manually assign the value:

$flight = App\Flight::find(1);
$flight->name = 'New Flight Name';$flight->save();

Batch update

You can also update those that match the query conditions Multiple models. In this example, all

active

and destination flights to San Diego will be marked as delayed:

App\Flight::where('active', 1)    
      ->where('destination', 'San Diego')          
      ->update(['delayed' => 1]);

update

The method accepts an array whose keys are field names and data are values.

{note} When batch updating through Eloquent, the updated model will not trigger the
saved

and updated events. Because during batch updates, the model is never retrieved.

Batch assignment

You can also use the create method to save a new model, which will return a model instance. However, before using it, you need to specify the fillable or guarded attribute on the model, because all Eloquent models cannot be batch assigned by default.

When the user passes in an unexpected parameter via an HTTP request, and the parameter changes a field in the database that you don't need to change. For example: a malicious user may pass in the is_admin parameter through an HTTP request, and then pass it to the create method. This operation allows the user to upgrade himself to an administrator.

So, before you start, you should define which attributes on the model can be batch assigned. You can do this via the $fillable attribute on the model. For example: Let the name attribute of the Flight model be batch-assigned:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class Flight extends Model{  
      /**
     * 可以被批量赋值的属性。
     *
     * @var array
     */   
     protected $fillable = ['name'];
  }

Once we have set up the attributes that can be batch-assigned, we can use create Method inserts new data into the database. The create method will return the saved model instance:

$flight = App\Flight::create(['name' => 'Flight 10']);

If you already have a model instance, you can pass an array to the fill method to assign values:

$flight->fill(['name' => 'Flight 22']);

Protected attributes

$fillable can be regarded as a "whitelist" for batch assignment. You can also use the $guarded attribute to fulfill. $guarded The attribute contains an array that does not allow batch assignment. In other words, $guarded will function more like a "blacklist". Note: You can only use one of $fillable or $guarded, not both at the same time. In the following example, Except for the price attribute, all other attributes can be assigned values ​​in batches:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class Flight extends Model{    
    /**
     * 不可批量赋值的属性。
     *
     * @var array
     */   
   protected $guarded = ['price'];
 }

If you want all attributes to be assigned values ​​in batches, you can $guarded Defined as an empty array:

/**
 * 不可以批量赋值的属性。
 *
 * @var array
 */
 protected $guarded = [];

##Other creation methods

firstOrCreate/ firstOrNew

Here are two methods you might use for batch assignment:

firstOrCreate and firstOrNew . firstOrCreate The method will match the data in the database through the given column/value. If the corresponding model cannot be found in the database, a record will be created from the attributes of the first parameter and even the attributes of the second parameter and inserted into the database. The

firstOrNew method like the firstOrCreate method attempts to find a record in the database by the given attribute. The difference is that if the firstOrNew method cannot find the corresponding model, it will return a new model instance. Note that firstOrNew the returned model instance has not yet been saved to the database, you need to manually call the save method to save:

// 通过 name 来查找航班,不存在则创建...
$flight = App\Flight::firstOrCreate(['name' => 'Flight 10']);
// 通过 name 查找航班,不存在则使用 name 和 delayed 属性创建...
$flight = App\Flight::firstOrCreate(['name' => 'Flight 10'], ['delayed' => 1]);
//  通过 name 查找航班,不存在则创建一个实例...
$flight = App\Flight::firstOrNew(['name' => 'Flight 10']);
// 通过 name 查找航班,不存在则使用 name 和 delayed 属性创建一个实例...
$flight = App\Flight::firstOrNew(['name' => 'Flight 10'], ['delayed' => 1]);

updateOrCreate

You may also encounter scenarios where you want to update an existing model or create a new model if it does not exist. Laravel provides the updateOrCreate method that can be implemented in just one step. Like the firstOrCreate method, updateOrCreate matches the corresponding model, so there is no need to call the save() method:

// 如果有从奥克兰到圣地亚哥的航班,则价格定为99美元。
// 如果没匹配到存在的模型,则创建一个。
$flight = App\Flight::updateOrCreate( 
   ['departure' => 'Oakland', 'destination' => 'San Diego'],    
   ['price' => 99]
 );

Delete model

You can call the delete method on the model instance to delete the instance:

$flight = App\Flight::find(1);
$flight->delete();

Delete model by primary key

In the above example, you need to find the corresponding model in the database before calling delete. In fact, if you know the primary key of the model, you can directly use the destroy method to delete the model without first searching it in the database. destroy In addition to accepting a single primary key as a parameter, the method also accepts multiple primary keys, or uses an array or collection to save multiple primary keys:

App\Flight::destroy(1);
App\Flight::destroy(1, 2, 3);
App\Flight::destroy([1, 2, 3]);
App\Flight::destroy(collect([1, 2, 3]));

Delete by query Model

You can also run delete statements on the model. In this example, we will delete all flights marked as inactive. Like batch update, batch deletion will not trigger any model events for the deleted model:

$deletedRows = App\Flight::where('active', 0)->delete();

{note} When executing a batch delete statement through Eloquent, deleting and deleted Model events. Therefore, when executing a delete statement, the model examples are never retrieved.

##Soft deletion

In addition to actually deleting database records, Eloquent can also "soft delete" models. A soft-deleted model is not actually deleted from the database. In fact, the

deleted_at attribute is set on the model and its value is written to the database. If the deleted_at value is non-empty, it means that the model has been soft deleted. If you want to enable the model soft deletion function, you need to use the Illuminate\Database\Eloquent\SoftDeletes trait on the model:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    use Illuminate\Database\Eloquent\SoftDeletes;
    class Flight extends Model{
        use SoftDeletes;
       }

{tip}

SoftDeletes trait Will automatically convert the deleted_at attribute into DateTime / Carbon instance

Of course, you need to

deleted_at Fields are added to the data table. Laravel's database migration has a method to create this field:

Schema::table('flights', function (Blueprint $table) 
{  
  $table->softDeletes();
});

Now, when you use the

delete method on the model instance, the current date and time will be written to deleted_at field. At the same time, the query results will automatically exclude records that have been soft deleted.

You can use the

trashed method to verify whether the current model is soft deleted:

if ($flight->trashed()) {
    //
 }

Query soft deletion model

Include soft-deleted models

As mentioned earlier, the query results will automatically exclude soft-deleted results. Of course, you can use the withTrashed method to get models including soft deleted models:

$flights = App\Flight::withTrashed()           
     ->where('account_id', 1)                
     ->get();

withTrashed The method can also be used in related queries:

$flight->history()->withTrashed()->get();

Retrieve soft deleted model

onlyTrashed Method Only Get the soft deleted model:

$flights = App\Flight::onlyTrashed()           
     ->where('airline_id', 1)                
     ->get();

Restore Soft-Deleted Model

Sometimes the soft-deleted model is "undone", and the restore method can be used on the soft-deleted data to restore it to the effective state:

$flight->restore();

You can also use the restore method in a query to quickly restore multiple models. Like other batch operations, this operation will not trigger any events in the model:

App\Flight::withTrashed()     
   ->where('airline_id', 1)        
   ->restore();

Similar to the withTrashed method, the restore method is also used on associations:

$flight->history()->restore();

Permanent deletion

To actually delete data, use the forceDelete method:

// 单个模型实例的永久删除...
$flight->forceDelete();
// 关联模型的永久删除...
$flight->history()->forceDelete();

Query scope

##Global scope

Global scope Domains can add constraints to model queries. Laravel's

Soft Delete function uses this feature to obtain "undeleted" models from the database. You can write your own global scope, which is very simple and convenient to add constraints to each model query:

Writing global scope

Writing global scope Scope is simple. Define a class that implements the

Illuminate\Database\Eloquent\Scope interface and implement the apply method. According to your needs, add the where conditions of the query in the apply method:

<?php
    namespace App\Scopes;
    use Illuminate\Database\Eloquent\Scope;
    use Illuminate\Database\Eloquent\Model;
    use Illuminate\Database\Eloquent\Builder;
    class AgeScope implements Scope{  
      /**
     * 把约束加到 Eloquent 查询构造中。
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $builder
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return void
     */  
      public function apply(Builder $builder, Model $model)  
        {       
         $builder->where('age', '>', 200);   
         }
      }

{tip} If you need to add fields to the select statement, you should Use the

addSelect method instead of the select method. This will effectively prevent existing select statements from being inadvertently replaced.

Apply global scope

To assign a global scope to a model, you need to override the model's

boot method and use addGlobalScope Method:

<?php
    namespace App;use App\Scopes\AgeScope;
    use Illuminate\Database\Eloquent\Model;
    class User extends Model{  
      /**
     *  模型的 「启动」 方法.
     *
     * @return void
     */  
     protected static function boot()  
       {     
          parent::boot();        
          static::addGlobalScope(new AgeScope);  
        }
   }

After adding the scope, the query for

User::all() will generate the following SQL query statement:

select * from `users` where `age` > 200

Anonymous global scope

Eloquent also allows the use of closures to define global scopes, so that there is no need to write a separate class for a simple scope:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    use Illuminate\Database\Eloquent\Builder;
    class User extends Model{  
      /**
     *模型的「启动」方法.
     *
     * @return void
     */  
     protected static function boot()   
      {      
        parent::boot();        
        static::addGlobalScope('age', function (Builder $builder) {  
                  $builder->where('age', '>', 200);       
                }); 
       }
   }

Cancel the global scope

If you need to cancel the global scope for the current query, you need to use the withoutGlobalScope method. This method only accepts the global scope class name as its only parameter:

User::withoutGlobalScope(AgeScope::class)->get();

Or, if a closure is used to define the global scope:

User::withoutGlobalScope('age')->get();

If you need to cancel part or all of the global For scope, you need to use the withoutGlobalScopes method:

// 取消所有的全局作用域...
User::withoutGlobalScopes()->get();
// 取消部分全局作用域...
User::withoutGlobalScopes([ 
   FirstScope::class, SecondScope::class
 ])->get();

##local scope

local Scopes allow the definition of common sets of constraints for reuse across applications. For example, you may often need to get all "popular" users. To define such a scope, just add the

scope prefix before the corresponding Eloquent model method:

Scope always returns a query builder instance:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class User extends Model{  
      /**
     * 只查询受欢迎的用户的作用域.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */   
      public function scopePopular($query)  
        {      
          return $query->where('votes', '>', 100);   
        }    
     /**
     * 只查询 active 用户的作用域.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */  
      public function scopeActive($query)  
        {      
          return $query->where('active', 1);  
         }
      }

Using local scopes

Once a scope is defined, scope methods can be called when querying the model. However, it is not necessary to include the

scope prefix when calling these methods. You can even chain calls to multiple scopes, for example:

$users = App\User::popular()->active()->orderBy('created_at')->get();

Integrate multiple Eloquent models with the

or query runner, you may need to use closure callbacks:

$users = App\User::popular()->orWhere(function (Builder $query) {
    $query->active();
   })->get();

Because this can be a bit cumbersome, Laravel provides the "higher-order"

orWhere method, which allows you to chain call scopes without using closures:

$users = App\User::popular()->orWhere->active()->get();

Dynamic Scope

Sometimes you may want to define a scope that accepts parameters. This can be achieved by passing additional parameters to the scope. The scope parameters should be placed after the

$query parameters:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class User extends Model{   
     /**
     * 将查询作用域限制为仅包含给定类型的用户。
     *
     * @param  \Illuminate\Database\Eloquent\Builder $query
     * @param  mixed $type
     * @return \Illuminate\Database\Eloquent\Builder
     */   
    public function scopeOfType($query, $type)  
      {      
        return $query->where('type', $type);   
       }
      }

so that the parameters can be passed when calling the scope:

$users = App\User::ofType('admin')->get();

Model comparison

Sometimes it may be necessary to determine whether two models are "the same". The

is method can be used to quickly verify whether two models have the same primary keys, tables, and database connections:

if ($post->is($anotherPost)) { 
   //
 }

Events

The Eloquent model triggers several events, allowing you to hook into the following nodes of the model life cycle: retrieved, creating, created, updating, updated, saving, saved, deleting, deleted , restoring and restored. Events allow you to execute code whenever a specific model is saved or updated in the database. Each event accepts a model instance through its constructor.

retrieved Event is fired when an existing model looks up data from the database. Each time a new model is saved, the creating and created events are fired. If the model already exists in the database and the save method is called, the updating / updated events are triggered. In these cases, saving / saved events are also triggered.

{note} When performing batch updates through Eloquent, the saved and updated events of the updated model will not be triggered. This is because the model is not actually obtained during batch update.

First, define a $dispatchesEvents attribute on the Eloquent model to map several nodes of the Eloquent model life cycle to your own event class:

<?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;   
       /**
     * 为模型事件。
     *
     * @var array
     */ 
      protected $dispatchesEvents = [    
          'saved' => UserSaved::class,        
          'deleted' => UserDeleted::class,   
           ];
       }

After defining and mapping Eloquent events, you can use event listeners to process these events.

##Observer

Define Observer

If in a There are multiple events listened to on the model, and observers can be used to organize these listeners into a separate class. The method names of the observer class map to the Eloquent events you wish to listen to. These methods all take the model as their only parameter.

make:observer The Artisan command can quickly create a new observer class:

php artisan make:observer UserObserver --model=User

This command will place a new observer class in the

App/Observers folder. If this directory does not exist, Artisan will create it for you. Use the following method to enable an observer:

<?php
    namespace App\Observers;
    use App\User;
    class UserObserver{   
     /**
     * 处理 User 「新建」事件。
     *
     * @param  \App\User  $user
     * @return void
     */   
      public function created(User $user) 
         {      
           //  
          }   
     /**
     * 处理 User 「更新」 事件。
     *
     * @param  \App\User  $user
     * @return void
     */   
      public function updated(User $user)  
        {      
          //   
         }   
     /**
     * 处理 User 「删除」 事件。
     *
     * @param  \App\User  $user
     * @return void
     */   
     public function deleted(User $user) 
        {   
             //   
         }
   }

Use the

observe method to register an observer on the model you wish to observe. Observers can also be registered in the boot method of the service provider. The following is an example of registering an observer in AppServiceProvider:

<?php
    namespace App\Providers;
    use App\User;use App\Observers\UserObserver;
    use Illuminate\Support\ServiceProvider;
    class AppServiceProvider extends ServiceProvider{  
      /**
     * 启动应用服务。
     *
     * @return void
     */   
      public function boot()  
       {       
         User::observe(UserObserver::class);   
       }  
    /**
     * 注册服务提供者。
     *
     * @return void
     */  
     public function register() 
        {      
          //   
         }
      }

This article first appeared on the
LearnKu.com website.