4299 lines
97 KiB
Markdown
4299 lines
97 KiB
Markdown
# Eloquent: Getting Started
|
||
|
||
* Introduction
|
||
* Generating Model Classes
|
||
* Eloquent Model Conventions
|
||
* Table Names
|
||
* Primary Keys
|
||
* UUID and ULID Keys
|
||
* Timestamps
|
||
* Database Connections
|
||
* Default Attribute Values
|
||
* Configuring Eloquent Strictness
|
||
* Retrieving Models
|
||
* Collections
|
||
* Chunking Results
|
||
* Chunk Using Lazy Collections
|
||
* Cursors
|
||
* Advanced Subqueries
|
||
* Retrieving Single Models / Aggregates
|
||
* Retrieving or Creating Models
|
||
* Retrieving Aggregates
|
||
* Inserting and Updating Models
|
||
* Inserts
|
||
* Updates
|
||
* Mass Assignment
|
||
* Upserts
|
||
* Deleting Models
|
||
* Soft Deleting
|
||
* Querying Soft Deleted Models
|
||
* Pruning Models
|
||
* Replicating Models
|
||
* Query Scopes
|
||
* Global Scopes
|
||
* Local Scopes
|
||
* Pending Attributes
|
||
* Comparing Models
|
||
* Events
|
||
* Using Closures
|
||
* Observers
|
||
* Muting Events
|
||
|
||
## Introduction
|
||
|
||
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's `config/database.php` configuration file. For more information
|
||
on configuring your database, check out [the database configuration
|
||
documentation](/docs/12.x/database#configuration).
|
||
|
||
## Generating Model Classes
|
||
|
||
To get started, let's create an Eloquent model. Models typically live in the
|
||
`app\Models` directory and extend the `Illuminate\Database\Eloquent\Model`
|
||
class. You may use the `make:model` [Artisan command](/docs/12.x/artisan) to
|
||
generate a new model:
|
||
|
||
|
||
|
||
1php artisan make:model Flight
|
||
|
||
|
||
php artisan make:model Flight
|
||
|
||
If you would like to generate a [database migration](/docs/12.x/migrations)
|
||
when you generate the model, you may use the `--migration` or `-m` option:
|
||
|
||
|
||
|
||
1php artisan make:model Flight --migration
|
||
|
||
|
||
php artisan make:model Flight --migration
|
||
|
||
You 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...
|
||
|
||
2php artisan make:model Flight --factory
|
||
|
||
3php artisan make:model Flight -f
|
||
|
||
4
|
||
|
||
5# Generate a model and a FlightSeeder class...
|
||
|
||
6php artisan make:model Flight --seed
|
||
|
||
7php artisan make:model Flight -s
|
||
|
||
8
|
||
|
||
9# Generate a model and a FlightController class...
|
||
|
||
10php artisan make:model Flight --controller
|
||
|
||
11php artisan make:model Flight -c
|
||
|
||
12
|
||
|
||
13# Generate a model, FlightController resource class, and form request classes...
|
||
|
||
14php artisan make:model Flight --controller --resource --requests
|
||
|
||
15php artisan make:model Flight -crR
|
||
|
||
16
|
||
|
||
17# Generate a model and a FlightPolicy class...
|
||
|
||
18php artisan make:model Flight --policy
|
||
|
||
19
|
||
|
||
20# Generate a model and a migration, factory, seeder, and controller...
|
||
|
||
21php artisan make:model Flight -mfsc
|
||
|
||
22
|
||
|
||
23# Shortcut to generate a model, migration, factory, seeder, policy, controller, and form requests...
|
||
|
||
24php artisan make:model Flight --all
|
||
|
||
25php artisan make:model Flight -a
|
||
|
||
26
|
||
|
||
27# Generate a pivot model...
|
||
|
||
28php artisan make:model Member --pivot
|
||
|
||
29php artisan make:model Member -p
|
||
|
||
|
||
# Generate a model and a FlightFactory class...
|
||
php artisan make:model Flight --factory
|
||
php artisan make:model Flight -f
|
||
|
||
# Generate a model and a FlightSeeder class...
|
||
php artisan make:model Flight --seed
|
||
php artisan make:model Flight -s
|
||
|
||
# Generate a model and a FlightController class...
|
||
php artisan make:model Flight --controller
|
||
php artisan make:model Flight -c
|
||
|
||
# Generate a model, FlightController resource class, and form request classes...
|
||
php artisan make:model Flight --controller --resource --requests
|
||
php artisan make:model Flight -crR
|
||
|
||
# Generate a model and a FlightPolicy class...
|
||
php artisan make:model Flight --policy
|
||
|
||
# Generate a model and a migration, factory, seeder, and controller...
|
||
php artisan make:model Flight -mfsc
|
||
|
||
# Shortcut to generate a model, migration, factory, seeder, policy, controller, and form requests...
|
||
php artisan make:model Flight --all
|
||
php artisan make:model Flight -a
|
||
|
||
# Generate a pivot model...
|
||
php artisan make:model Member --pivot
|
||
php artisan make:model Member -p
|
||
|
||
#### Inspecting Models
|
||
|
||
Sometimes it can be difficult to determine all of a model's available
|
||
attributes and relationships just by skimming its code. Instead, try the
|
||
`model:show` Artisan command, which provides a convenient overview of all the
|
||
model's attributes and relations:
|
||
|
||
|
||
|
||
1php artisan model:show Flight
|
||
|
||
|
||
php artisan model:show Flight
|
||
|
||
## Eloquent Model Conventions
|
||
|
||
Models generated by the `make:model` command will be placed in the
|
||
`app/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
|
||
|
||
7class Flight extends Model
|
||
|
||
8{
|
||
|
||
9 // ...
|
||
|
||
10}
|
||
|
||
|
||
<?php
|
||
|
||
namespace App\Models;
|
||
|
||
use Illuminate\Database\Eloquent\Model;
|
||
|
||
class Flight extends Model
|
||
{
|
||
// ...
|
||
}
|
||
|
||
### Table Names
|
||
|
||
After glancing at the example above, you may have noticed that we did not tell
|
||
Eloquent which database table corresponds to our `Flight` 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 the `Flight` model stores records in the `flights` table,
|
||
while an `AirTrafficController` model would store records in an
|
||
`air_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 a `table` property on
|
||
the model:
|
||
|
||
|
||
|
||
1<?php
|
||
|
||
2
|
||
|
||
3namespace App\Models;
|
||
|
||
4
|
||
|
||
5use Illuminate\Database\Eloquent\Model;
|
||
|
||
6
|
||
|
||
7class Flight extends Model
|
||
|
||
8{
|
||
|
||
9 /**
|
||
|
||
10 * The table associated with the model.
|
||
|
||
11 *
|
||
|
||
12 * @var string
|
||
|
||
13 */
|
||
|
||
14 protected $table = 'my_flights';
|
||
|
||
15}
|
||
|
||
|
||
<?php
|
||
|
||
namespace App\Models;
|
||
|
||
use Illuminate\Database\Eloquent\Model;
|
||
|
||
class Flight extends Model
|
||
{
|
||
/**
|
||
* The table associated with the model.
|
||
*
|
||
* @var string
|
||
*/
|
||
protected $table = 'my_flights';
|
||
}
|
||
|
||
### Primary Keys
|
||
|
||
Eloquent will also assume that each model's corresponding database table has a
|
||
primary key column named `id`. 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
|
||
|
||
7class Flight extends Model
|
||
|
||
8{
|
||
|
||
9 /**
|
||
|
||
10 * The primary key associated with the table.
|
||
|
||
11 *
|
||
|
||
12 * @var string
|
||
|
||
13 */
|
||
|
||
14 protected $primaryKey = 'flight_id';
|
||
|
||
15}
|
||
|
||
|
||
<?php
|
||
|
||
namespace App\Models;
|
||
|
||
use Illuminate\Database\Eloquent\Model;
|
||
|
||
class Flight extends Model
|
||
{
|
||
/**
|
||
* The primary key associated with the table.
|
||
*
|
||
* @var string
|
||
*/
|
||
protected $primaryKey = 'flight_id';
|
||
}
|
||
|
||
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 to
|
||
`false`:
|
||
|
||
|
||
|
||
1<?php
|
||
|
||
2
|
||
|
||
3class Flight extends Model
|
||
|
||
4{
|
||
|
||
5 /**
|
||
|
||
6 * Indicates if the model's ID is auto-incrementing.
|
||
|
||
7 *
|
||
|
||
8 * @var bool
|
||
|
||
9 */
|
||
|
||
10 public $incrementing = false;
|
||
|
||
11}
|
||
|
||
|
||
<?php
|
||
|
||
class Flight extends Model
|
||
{
|
||
/**
|
||
* Indicates if the model's ID is auto-incrementing.
|
||
*
|
||
* @var bool
|
||
*/
|
||
public $incrementing = false;
|
||
}
|
||
|
||
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 of
|
||
`string`:
|
||
|
||
|
||
|
||
1<?php
|
||
|
||
2
|
||
|
||
3class Flight extends Model
|
||
|
||
4{
|
||
|
||
5 /**
|
||
|
||
6 * The data type of the primary key ID.
|
||
|
||
7 *
|
||
|
||
8 * @var string
|
||
|
||
9 */
|
||
|
||
10 protected $keyType = 'string';
|
||
|
||
11}
|
||
|
||
|
||
<?php
|
||
|
||
class Flight extends Model
|
||
{
|
||
/**
|
||
* The data type of the primary key ID.
|
||
*
|
||
* @var string
|
||
*/
|
||
protected $keyType = 'string';
|
||
}
|
||
|
||
#### "Composite" Primary Keys
|
||
|
||
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.
|
||
|
||
### UUID and ULID Keys
|
||
|
||
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 the `Illuminate\Database\Eloquent\Concerns\HasUuids`
|
||
trait on the model. Of course, you should ensure that the model has a [UUID
|
||
equivalent primary key column](/docs/12.x/migrations#column-method-uuid):
|
||
|
||
|
||
|
||
1use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||
|
||
2use Illuminate\Database\Eloquent\Model;
|
||
|
||
3
|
||
|
||
4class Article extends Model
|
||
|
||
5{
|
||
|
||
6 use HasUuids;
|
||
|
||
7
|
||
|
||
8 // ...
|
||
|
||
9}
|
||
|
||
10
|
||
|
||
11$article = Article::create(['title' => 'Traveling to Europe']);
|
||
|
||
12
|
||
|
||
13$article->id; // "8f8e8478-9035-4d23-b9a7-62f4d2612ce5"
|
||
|
||
|
||
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||
use Illuminate\Database\Eloquent\Model;
|
||
|
||
class Article extends Model
|
||
{
|
||
use HasUuids;
|
||
|
||
// ...
|
||
}
|
||
|
||
$article = Article::create(['title' => 'Traveling to Europe']);
|
||
|
||
$article->id; // "8f8e8478-9035-4d23-b9a7-62f4d2612ce5"
|
||
|
||
By default, The `HasUuids` trait will generate ["ordered"
|
||
UUIDs](/docs/12.x/strings#method-str-ordered-uuid) 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 a
|
||
`newUniqueId` method on the model. In addition, you may specify which columns
|
||
should receive UUIDs by defining a `uniqueIds` method on the model:
|
||
|
||
|
||
|
||
1use Ramsey\Uuid\Uuid;
|
||
|
||
2
|
||
|
||
3/**
|
||
|
||
4 * Generate a new UUID for the model.
|
||
|
||
5 */
|
||
|
||
6public function newUniqueId(): string
|
||
|
||
7{
|
||
|
||
8 return (string) Uuid::uuid4();
|
||
|
||
9}
|
||
|
||
10
|
||
|
||
11/**
|
||
|
||
12 * Get the columns that should receive a unique identifier.
|
||
|
||
13 *
|
||
|
||
14 * @return array<int, string>
|
||
|
||
15 */
|
||
|
||
16public function uniqueIds(): array
|
||
|
||
17{
|
||
|
||
18 return ['id', 'discount_code'];
|
||
|
||
19}
|
||
|
||
|
||
use Ramsey\Uuid\Uuid;
|
||
|
||
/**
|
||
* Generate a new UUID for the model.
|
||
*/
|
||
public function newUniqueId(): string
|
||
{
|
||
return (string) Uuid::uuid4();
|
||
}
|
||
|
||
/**
|
||
* Get the columns that should receive a unique identifier.
|
||
*
|
||
* @return array<int, string>
|
||
*/
|
||
public function uniqueIds(): array
|
||
{
|
||
return ['id', 'discount_code'];
|
||
}
|
||
|
||
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 the
|
||
`Illuminate\Database\Eloquent\Concerns\HasUlids` trait on your model. You
|
||
should also ensure that the model has a [ULID equivalent primary key
|
||
column](/docs/12.x/migrations#column-method-ulid):
|
||
|
||
|
||
|
||
1use Illuminate\Database\Eloquent\Concerns\HasUlids;
|
||
|
||
2use Illuminate\Database\Eloquent\Model;
|
||
|
||
3
|
||
|
||
4class Article extends Model
|
||
|
||
5{
|
||
|
||
6 use HasUlids;
|
||
|
||
7
|
||
|
||
8 // ...
|
||
|
||
9}
|
||
|
||
10
|
||
|
||
11$article = Article::create(['title' => 'Traveling to Asia']);
|
||
|
||
12
|
||
|
||
13$article->id; // "01gd4d3tgrrfqeda94gdbtdk5c"
|
||
|
||
|
||
use Illuminate\Database\Eloquent\Concerns\HasUlids;
|
||
use Illuminate\Database\Eloquent\Model;
|
||
|
||
class Article extends Model
|
||
{
|
||
use HasUlids;
|
||
|
||
// ...
|
||
}
|
||
|
||
$article = Article::create(['title' => 'Traveling to Asia']);
|
||
|
||
$article->id; // "01gd4d3tgrrfqeda94gdbtdk5c"
|
||
|
||
### Timestamps
|
||
|
||
By default, Eloquent expects `created_at` and `updated_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 of `false`:
|
||
|
||
|
||
|
||
1<?php
|
||
|
||
2
|
||
|
||
3namespace App\Models;
|
||
|
||
4
|
||
|
||
5use Illuminate\Database\Eloquent\Model;
|
||
|
||
6
|
||
|
||
7class Flight extends Model
|
||
|
||
8{
|
||
|
||
9 /**
|
||
|
||
10 * Indicates if the model should be timestamped.
|
||
|
||
11 *
|
||
|
||
12 * @var bool
|
||
|
||
13 */
|
||
|
||
14 public $timestamps = false;
|
||
|
||
15}
|
||
|
||
|
||
<?php
|
||
|
||
namespace App\Models;
|
||
|
||
use Illuminate\Database\Eloquent\Model;
|
||
|
||
class Flight extends Model
|
||
{
|
||
/**
|
||
* Indicates if the model should be timestamped.
|
||
*
|
||
* @var bool
|
||
*/
|
||
public $timestamps = false;
|
||
}
|
||
|
||
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
|
||
|
||
7class Flight extends Model
|
||
|
||
8{
|
||
|
||
9 /**
|
||
|
||
10 * The storage format of the model's date columns.
|
||
|
||
11 *
|
||
|
||
12 * @var string
|
||
|
||
13 */
|
||
|
||
14 protected $dateFormat = 'U';
|
||
|
||
15}
|
||
|
||
|
||
<?php
|
||
|
||
namespace App\Models;
|
||
|
||
use Illuminate\Database\Eloquent\Model;
|
||
|
||
class Flight extends Model
|
||
{
|
||
/**
|
||
* The storage format of the model's date columns.
|
||
*
|
||
* @var string
|
||
*/
|
||
protected $dateFormat = 'U';
|
||
}
|
||
|
||
If you need to customize the names of the columns used to store the
|
||
timestamps, you may define `CREATED_AT` and `UPDATED_AT` constants on your
|
||
model:
|
||
|
||
|
||
|
||
1<?php
|
||
|
||
2
|
||
|
||
3class Flight extends Model
|
||
|
||
4{
|
||
|
||
5 const CREATED_AT = 'creation_date';
|
||
|
||
6 const UPDATED_AT = 'updated_date';
|
||
|
||
7}
|
||
|
||
|
||
<?php
|
||
|
||
class Flight extends Model
|
||
{
|
||
const CREATED_AT = 'creation_date';
|
||
const UPDATED_AT = 'updated_date';
|
||
}
|
||
|
||
If you would like to perform model operations without the model having its
|
||
`updated_at` timestamp modified, you may operate on the model within a closure
|
||
given to the `withoutTimestamps` method:
|
||
|
||
|
||
|
||
1Model::withoutTimestamps(fn () => $post->increment('reads'));
|
||
|
||
|
||
Model::withoutTimestamps(fn () => $post->increment('reads'));
|
||
|
||
### Database Connections
|
||
|
||
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
|
||
|
||
7class Flight extends Model
|
||
|
||
8{
|
||
|
||
9 /**
|
||
|
||
10 * The database connection that should be used by the model.
|
||
|
||
11 *
|
||
|
||
12 * @var string
|
||
|
||
13 */
|
||
|
||
14 protected $connection = 'mysql';
|
||
|
||
15}
|
||
|
||
|
||
<?php
|
||
|
||
namespace App\Models;
|
||
|
||
use Illuminate\Database\Eloquent\Model;
|
||
|
||
class Flight extends Model
|
||
{
|
||
/**
|
||
* The database connection that should be used by the model.
|
||
*
|
||
* @var string
|
||
*/
|
||
protected $connection = 'mysql';
|
||
}
|
||
|
||
### Default Attribute Values
|
||
|
||
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
|
||
|
||
7class Flight extends Model
|
||
|
||
8{
|
||
|
||
9 /**
|
||
|
||
10 * The model's default values for attributes.
|
||
|
||
11 *
|
||
|
||
12 * @var array
|
||
|
||
13 */
|
||
|
||
14 protected $attributes = [
|
||
|
||
15 'options' => '[]',
|
||
|
||
16 'delayed' => false,
|
||
|
||
17 ];
|
||
|
||
18}
|
||
|
||
|
||
<?php
|
||
|
||
namespace App\Models;
|
||
|
||
use Illuminate\Database\Eloquent\Model;
|
||
|
||
class Flight extends Model
|
||
{
|
||
/**
|
||
* The model's default values for attributes.
|
||
*
|
||
* @var array
|
||
*/
|
||
protected $attributes = [
|
||
'options' => '[]',
|
||
'delayed' => false,
|
||
];
|
||
}
|
||
|
||
### Configuring Eloquent Strictness
|
||
|
||
Laravel offers several methods that allow you to configure Eloquent's behavior
|
||
and "strictness" in a variety of situations.
|
||
|
||
First, the `preventLazyLoading` 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 the `boot` method of your application's
|
||
`AppServiceProvider`:
|
||
|
||
|
||
|
||
1use Illuminate\Database\Eloquent\Model;
|
||
|
||
2
|
||
|
||
3/**
|
||
|
||
4 * Bootstrap any application services.
|
||
|
||
5 */
|
||
|
||
6public function boot(): void
|
||
|
||
7{
|
||
|
||
8 Model::preventLazyLoading(! $this->app->isProduction());
|
||
|
||
9}
|
||
|
||
|
||
use Illuminate\Database\Eloquent\Model;
|
||
|
||
/**
|
||
* Bootstrap any application services.
|
||
*/
|
||
public function boot(): void
|
||
{
|
||
Model::preventLazyLoading(! $this->app->isProduction());
|
||
}
|
||
|
||
Also, you may instruct Laravel to throw an exception when attempting to fill
|
||
an unfillable attribute by invoking the `preventSilentlyDiscardingAttributes`
|
||
method. This can help prevent unexpected errors during local development when
|
||
attempting to set an attribute that has not been added to the model's
|
||
`fillable` array:
|
||
|
||
|
||
|
||
1Model::preventSilentlyDiscardingAttributes(! $this->app->isProduction());
|
||
|
||
|
||
Model::preventSilentlyDiscardingAttributes(! $this->app->isProduction());
|
||
|
||
## Retrieving Models
|
||
|
||
Once you have created a model and [its associated database
|
||
table](/docs/12.x/migrations#generating-migrations), you are ready to start
|
||
retrieving data from your database. You can think of each Eloquent model as a
|
||
powerful [query builder](/docs/12.x/queries) allowing you to fluently query
|
||
the database table associated with the model. The model's `all` method will
|
||
retrieve all of the records from the model's associated database table:
|
||
|
||
|
||
|
||
1use App\Models\Flight;
|
||
|
||
2
|
||
|
||
3foreach (Flight::all() as $flight) {
|
||
|
||
4 echo $flight->name;
|
||
|
||
5}
|
||
|
||
|
||
use App\Models\Flight;
|
||
|
||
foreach (Flight::all() as $flight) {
|
||
echo $flight->name;
|
||
}
|
||
|
||
#### Building Queries
|
||
|
||
The Eloquent `all` method will return all of the results in the model's table.
|
||
However, since each Eloquent model serves as a [query
|
||
builder](/docs/12.x/queries), you may add additional constraints to queries
|
||
and then invoke the `get` method to retrieve the results:
|
||
|
||
|
||
|
||
1$flights = Flight::where('active', 1)
|
||
|
||
2 ->orderBy('name')
|
||
|
||
3 ->limit(10)
|
||
|
||
4 ->get();
|
||
|
||
|
||
$flights = Flight::where('active', 1)
|
||
->orderBy('name')
|
||
->limit(10)
|
||
->get();
|
||
|
||
Since Eloquent models are query builders, you should review all of the methods
|
||
provided by Laravel's [query builder](/docs/12.x/queries). You may use any of
|
||
these methods when writing your Eloquent queries.
|
||
|
||
#### Refreshing Models
|
||
|
||
If you already have an instance of an Eloquent model that was retrieved from
|
||
the database, you can "refresh" the model using the `fresh` and `refresh`
|
||
methods. The `fresh` 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();
|
||
|
||
|
||
$flight = Flight::where('number', 'FR 900')->first();
|
||
|
||
$freshFlight = $flight->fresh();
|
||
|
||
The `refresh` 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"
|
||
|
||
|
||
$flight = Flight::where('number', 'FR 900')->first();
|
||
|
||
$flight->number = 'FR 456';
|
||
|
||
$flight->refresh();
|
||
|
||
$flight->number; // "FR 900"
|
||
|
||
### Collections
|
||
|
||
As we have seen, Eloquent methods like `all` and `get` retrieve multiple
|
||
records from the database. However, these methods don't return a plain PHP
|
||
array. Instead, an instance of `Illuminate\Database\Eloquent\Collection` is
|
||
returned.
|
||
|
||
The Eloquent `Collection` class extends Laravel's base
|
||
`Illuminate\Support\Collection` class, which provides a [variety of helpful
|
||
methods](/docs/12.x/collections#available-methods) for interacting with data
|
||
collections. For example, the `reject` 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) {
|
||
|
||
4 return $flight->cancelled;
|
||
|
||
5});
|
||
|
||
|
||
$flights = Flight::where('destination', 'Paris')->get();
|
||
|
||
$flights = $flights->reject(function (Flight $flight) {
|
||
return $flight->cancelled;
|
||
});
|
||
|
||
In addition to the methods provided by Laravel's base collection class, the
|
||
Eloquent collection class provides [a few extra methods](/docs/12.x/eloquent-
|
||
collections#available-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 ($flights as $flight) {
|
||
|
||
2 echo $flight->name;
|
||
|
||
3}
|
||
|
||
|
||
foreach ($flights as $flight) {
|
||
echo $flight->name;
|
||
}
|
||
|
||
### Chunking Results
|
||
|
||
Your application may run out of memory if you attempt to load tens of
|
||
thousands of Eloquent records via the `all` or `get` methods. Instead of using
|
||
these methods, the `chunk` method may be used to process large numbers of
|
||
models more efficiently.
|
||
|
||
The `chunk` 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, the `chunk` 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) {
|
||
|
||
5 foreach ($flights as $flight) {
|
||
|
||
6 // ...
|
||
|
||
7 }
|
||
|
||
8});
|
||
|
||
|
||
use App\Models\Flight;
|
||
use Illuminate\Database\Eloquent\Collection;
|
||
|
||
Flight::chunk(200, function (Collection $flights) {
|
||
foreach ($flights as $flight) {
|
||
// ...
|
||
}
|
||
});
|
||
|
||
The first argument passed to the `chunk` 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 the `chunk` method based on a column that
|
||
you will also be updating while iterating over the results, you should use the
|
||
`chunkById` method. Using the `chunk` method in these scenarios could lead to
|
||
unexpected and inconsistent results. Internally, the `chunkById` method will
|
||
always retrieve models with an `id` 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');
|
||
|
||
|
||
Flight::where('departed', true)
|
||
->chunkById(200, function (Collection $flights) {
|
||
$flights->each->update(['departed' => false]);
|
||
}, column: 'id');
|
||
|
||
Since the `chunkById` and `lazyById` methods add their own "where" conditions
|
||
to the query being executed, you should typically [logically
|
||
group](/docs/12.x/queries#logical-grouping) 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' => true
|
||
|
||
7 ]);
|
||
|
||
8}, column: 'id');
|
||
|
||
|
||
Flight::where(function ($query) {
|
||
$query->where('delayed', true)->orWhere('cancelled', true);
|
||
})->chunkById(200, function (Collection $flights) {
|
||
$flights->each->update([
|
||
'departed' => false,
|
||
'cancelled' => true
|
||
]);
|
||
}, column: 'id');
|
||
|
||
### Chunking Using Lazy Collections
|
||
|
||
The `lazy` method works similarly to the `chunk` 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, the `lazy` method returns a
|
||
flattened [LazyCollection](/docs/12.x/collections#lazy-collections) 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}
|
||
|
||
|
||
use App\Models\Flight;
|
||
|
||
foreach (Flight::lazy() as $flight) {
|
||
// ...
|
||
}
|
||
|
||
If you are filtering the results of the `lazy` method based on a column that
|
||
you will also be updating while iterating over the results, you should use the
|
||
`lazyById` method. Internally, the `lazyById` method will always retrieve
|
||
models with an `id` column greater than the last model in the previous chunk:
|
||
|
||
|
||
|
||
1Flight::where('departed', true)
|
||
|
||
2 ->lazyById(200, column: 'id')
|
||
|
||
3 ->each->update(['departed' => false]);
|
||
|
||
|
||
Flight::where('departed', true)
|
||
->lazyById(200, column: 'id')
|
||
->each->update(['departed' => false]);
|
||
|
||
You may filter the results based on the descending order of the `id` using the
|
||
`lazyByIdDesc` method.
|
||
|
||
### Cursors
|
||
|
||
Similar to the `lazy` method, the `cursor` method may be used to significantly
|
||
reduce your application's memory consumption when iterating through tens of
|
||
thousands of Eloquent model records.
|
||
|
||
The `cursor` 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 the `cursor` 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 using the `lazy` method instead.
|
||
|
||
Internally, the `cursor` method uses PHP
|
||
[generators](https://www.php.net/manual/en/language.generators.overview.php)
|
||
to implement this functionality:
|
||
|
||
|
||
|
||
1use App\Models\Flight;
|
||
|
||
2
|
||
|
||
3foreach (Flight::where('destination', 'Zurich')->cursor() as $flight) {
|
||
|
||
4 // ...
|
||
|
||
5}
|
||
|
||
|
||
use App\Models\Flight;
|
||
|
||
foreach (Flight::where('destination', 'Zurich')->cursor() as $flight) {
|
||
// ...
|
||
}
|
||
|
||
The `cursor` returns an `Illuminate\Support\LazyCollection` instance. [Lazy
|
||
collections](/docs/12.x/collections#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) {
|
||
|
||
4 return $user->id > 500;
|
||
|
||
5});
|
||
|
||
6
|
||
|
||
7foreach ($users as $user) {
|
||
|
||
8 echo $user->id;
|
||
|
||
9}
|
||
|
||
|
||
use App\Models\User;
|
||
|
||
$users = User::cursor()->filter(function (User $user) {
|
||
return $user->id > 500;
|
||
});
|
||
|
||
foreach ($users as $user) {
|
||
echo $user->id;
|
||
}
|
||
|
||
Although the `cursor` 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 is [due to PHP's PDO driver internally
|
||
caching all raw query results in its
|
||
buffer](https://www.php.net/manual/en/mysqlinfo.concepts.buffering.php). If
|
||
you're dealing with a very large number of Eloquent records, consider using
|
||
the `lazy` method instead.
|
||
|
||
### Advanced Subqueries
|
||
|
||
#### Subquery Selects
|
||
|
||
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 flight `destinations` and a table of `flights` to
|
||
destinations. The `flights` table contains an `arrived_at` column which
|
||
indicates when the flight arrived at the destination.
|
||
|
||
Using the subquery functionality available to the query builder's `select` and
|
||
`addSelect` methods, we can select all of the `destinations` 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
|
||
|
||
4return Destination::addSelect(['last_flight' => Flight::select('name')
|
||
|
||
5 ->whereColumn('destination_id', 'destinations.id')
|
||
|
||
6 ->orderByDesc('arrived_at')
|
||
|
||
7 ->limit(1)
|
||
|
||
8])->get();
|
||
|
||
|
||
use App\Models\Destination;
|
||
use App\Models\Flight;
|
||
|
||
return Destination::addSelect(['last_flight' => Flight::select('name')
|
||
->whereColumn('destination_id', 'destinations.id')
|
||
->orderByDesc('arrived_at')
|
||
->limit(1)
|
||
])->get();
|
||
|
||
#### Subquery Ordering
|
||
|
||
In addition, the query builder's `orderBy` 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:
|
||
|
||
|
||
|
||
1return Destination::orderByDesc(
|
||
|
||
2 Flight::select('arrived_at')
|
||
|
||
3 ->whereColumn('destination_id', 'destinations.id')
|
||
|
||
4 ->orderByDesc('arrived_at')
|
||
|
||
5 ->limit(1)
|
||
|
||
6)->get();
|
||
|
||
|
||
return Destination::orderByDesc(
|
||
Flight::select('arrived_at')
|
||
->whereColumn('destination_id', 'destinations.id')
|
||
->orderByDesc('arrived_at')
|
||
->limit(1)
|
||
)->get();
|
||
|
||
## Retrieving Single Models / Aggregates
|
||
|
||
In addition to retrieving all of the records matching a given query, you may
|
||
also retrieve single records using the `find`, `first`, or `firstWhere`
|
||
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);
|
||
|
||
|
||
use App\Models\Flight;
|
||
|
||
// Retrieve a model by its primary key...
|
||
$flight = Flight::find(1);
|
||
|
||
// Retrieve the first model matching the query constraints...
|
||
$flight = Flight::where('active', 1)->first();
|
||
|
||
// Alternative to retrieving the first model matching the query constraints...
|
||
$flight = Flight::firstWhere('active', 1);
|
||
|
||
Sometimes you may wish to perform some other action if no results are found.
|
||
The `findOr` and `firstOr` 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});
|
||
|
||
|
||
$flight = Flight::findOr(1, function () {
|
||
// ...
|
||
});
|
||
|
||
$flight = Flight::where('legs', '>', 3)->firstOr(function () {
|
||
// ...
|
||
});
|
||
|
||
#### Not Found Exceptions
|
||
|
||
Sometimes you may wish to throw an exception if a model is not found. This is
|
||
particularly useful in routes or controllers. The `findOrFail` and
|
||
`firstOrFail` methods will retrieve the first result of the query; however, if
|
||
no result is found, an `Illuminate\Database\Eloquent\ModelNotFoundException`
|
||
will be thrown:
|
||
|
||
|
||
|
||
1$flight = Flight::findOrFail(1);
|
||
|
||
2
|
||
|
||
3$flight = Flight::where('legs', '>', 3)->firstOrFail();
|
||
|
||
|
||
$flight = Flight::findOrFail(1);
|
||
|
||
$flight = Flight::where('legs', '>', 3)->firstOrFail();
|
||
|
||
If the `ModelNotFoundException` 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) {
|
||
|
||
4 return Flight::findOrFail($id);
|
||
|
||
5});
|
||
|
||
|
||
use App\Models\Flight;
|
||
|
||
Route::get('/api/flights/{id}', function (string $id) {
|
||
return Flight::findOrFail($id);
|
||
});
|
||
|
||
### Retrieving or Creating Models
|
||
|
||
The `firstOrCreate` 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.
|
||
|
||
The `firstOrNew` method, like `firstOrCreate`, 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 by
|
||
`firstOrNew` has not yet been persisted to the database. You will need to
|
||
manually call the `save` 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);
|
||
|
||
|
||
use App\Models\Flight;
|
||
|
||
// Retrieve flight by name or create it if it doesn't exist...
|
||
$flight = Flight::firstOrCreate([
|
||
'name' => 'London to Paris'
|
||
]);
|
||
|
||
// Retrieve flight by name or create it with the name, delayed, and arrival_time attributes...
|
||
$flight = Flight::firstOrCreate(
|
||
['name' => 'London to Paris'],
|
||
['delayed' => 1, 'arrival_time' => '11:30']
|
||
);
|
||
|
||
// Retrieve flight by name or instantiate a new Flight instance...
|
||
$flight = Flight::firstOrNew([
|
||
'name' => 'London to Paris'
|
||
]);
|
||
|
||
// Retrieve flight by name or instantiate with the name, delayed, and arrival_time attributes...
|
||
$flight = Flight::firstOrNew(
|
||
['name' => 'Tokyo to Sydney'],
|
||
['delayed' => 1, 'arrival_time' => '11:30']
|
||
);
|
||
|
||
### Retrieving Aggregates
|
||
|
||
When interacting with Eloquent models, you may also use the `count`, `sum`,
|
||
`max`, and other [aggregate methods](/docs/12.x/queries#aggregates) provided
|
||
by the Laravel [query builder](/docs/12.x/queries). 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');
|
||
|
||
|
||
$count = Flight::where('active', 1)->count();
|
||
|
||
$max = Flight::where('active', 1)->max('price');
|
||
|
||
## Inserting and Updating Models
|
||
|
||
### Inserts
|
||
|
||
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 the `save` 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
|
||
|
||
9class FlightController extends Controller
|
||
|
||
10{
|
||
|
||
11 /**
|
||
|
||
12 * Store a new flight in the database.
|
||
|
||
13 */
|
||
|
||
14 public function store(Request $request): RedirectResponse
|
||
|
||
15 {
|
||
|
||
16 // Validate the request...
|
||
|
||
17
|
||
|
||
18 $flight = new Flight;
|
||
|
||
19
|
||
|
||
20 $flight->name = $request->name;
|
||
|
||
21
|
||
|
||
22 $flight->save();
|
||
|
||
23
|
||
|
||
24 return redirect('/flights');
|
||
|
||
25 }
|
||
|
||
26}
|
||
|
||
|
||
<?php
|
||
|
||
namespace App\Http\Controllers;
|
||
|
||
use App\Models\Flight;
|
||
use Illuminate\Http\RedirectResponse;
|
||
use Illuminate\Http\Request;
|
||
|
||
class FlightController extends Controller
|
||
{
|
||
/**
|
||
* Store a new flight in the database.
|
||
*/
|
||
public function store(Request $request): RedirectResponse
|
||
{
|
||
// Validate the request...
|
||
|
||
$flight = new Flight;
|
||
|
||
$flight->name = $request->name;
|
||
|
||
$flight->save();
|
||
|
||
return redirect('/flights');
|
||
}
|
||
}
|
||
|
||
In this example, we assign the `name` field from the incoming HTTP request to
|
||
the `name` attribute of the `App\Models\Flight` model instance. When we call
|
||
the `save` method, a record will be inserted into the database. The model's
|
||
`created_at` and `updated_at` timestamps will automatically be set when the
|
||
`save` method is called, so there is no need to set them manually.
|
||
|
||
Alternatively, you may use the `create` method to "save" a new model using a
|
||
single PHP statement. The inserted model instance will be returned to you by
|
||
the `create` method:
|
||
|
||
|
||
|
||
1use App\Models\Flight;
|
||
|
||
2
|
||
|
||
3$flight = Flight::create([
|
||
|
||
4 'name' => 'London to Paris',
|
||
|
||
5]);
|
||
|
||
|
||
use App\Models\Flight;
|
||
|
||
$flight = Flight::create([
|
||
'name' => 'London to Paris',
|
||
]);
|
||
|
||
However, before using the `create` method, you will need to specify either a
|
||
`fillable` or `guarded` 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 the mass assignment documentation.
|
||
|
||
### Updates
|
||
|
||
The `save` 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's `save` method. Again, the
|
||
`updated_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();
|
||
|
||
|
||
use App\Models\Flight;
|
||
|
||
$flight = Flight::find(1);
|
||
|
||
$flight->name = 'Paris to London';
|
||
|
||
$flight->save();
|
||
|
||
Occasionally, you may need to update an existing model or create a new model
|
||
if no matching model exists. Like the `firstOrCreate` method, the
|
||
`updateOrCreate` method persists the model, so there's no need to manually
|
||
call the `save` method.
|
||
|
||
In the example below, if a flight exists with a `departure` location of
|
||
`Oakland` and a `destination` location of `San Diego`, its `price` and
|
||
`discounted` 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);
|
||
|
||
|
||
$flight = Flight::updateOrCreate(
|
||
['departure' => 'Oakland', 'destination' => 'San Diego'],
|
||
['price' => 99, 'discounted' => 1]
|
||
);
|
||
|
||
#### Mass Updates
|
||
|
||
Updates can also be performed against models that match a given query. In this
|
||
example, all flights that are `active` and have a `destination` of `San Diego`
|
||
will be marked as delayed:
|
||
|
||
|
||
|
||
1Flight::where('active', 1)
|
||
|
||
2 ->where('destination', 'San Diego')
|
||
|
||
3 ->update(['delayed' => 1]);
|
||
|
||
|
||
Flight::where('active', 1)
|
||
->where('destination', 'San Diego')
|
||
->update(['delayed' => 1]);
|
||
|
||
The `update` method expects an array of column and value pairs representing
|
||
the columns that should be updated. The `update` method returns the number of
|
||
affected rows.
|
||
|
||
When issuing a mass update via Eloquent, the `saving`, `saved`, `updating`,
|
||
and `updated` model events will not be fired for the updated models. This is
|
||
because the models are never actually retrieved when issuing a mass update.
|
||
|
||
#### Examining Attribute Changes
|
||
|
||
Eloquent provides the `isDirty`, `isClean`, and `wasChanged` methods to
|
||
examine the internal state of your model and determine how its attributes have
|
||
changed from when the model was originally retrieved.
|
||
|
||
The `isDirty` 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 the `isDirty` method to determine if any of the
|
||
attributes are "dirty". The `isClean` 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(); // true
|
||
|
||
12$user->isDirty('title'); // true
|
||
|
||
13$user->isDirty('first_name'); // false
|
||
|
||
14$user->isDirty(['first_name', 'title']); // true
|
||
|
||
15
|
||
|
||
16$user->isClean(); // false
|
||
|
||
17$user->isClean('title'); // false
|
||
|
||
18$user->isClean('first_name'); // true
|
||
|
||
19$user->isClean(['first_name', 'title']); // false
|
||
|
||
20
|
||
|
||
21$user->save();
|
||
|
||
22
|
||
|
||
23$user->isDirty(); // false
|
||
|
||
24$user->isClean(); // true
|
||
|
||
|
||
use App\Models\User;
|
||
|
||
$user = User::create([
|
||
'first_name' => 'Taylor',
|
||
'last_name' => 'Otwell',
|
||
'title' => 'Developer',
|
||
]);
|
||
|
||
$user->title = 'Painter';
|
||
|
||
$user->isDirty(); // true
|
||
$user->isDirty('title'); // true
|
||
$user->isDirty('first_name'); // false
|
||
$user->isDirty(['first_name', 'title']); // true
|
||
|
||
$user->isClean(); // false
|
||
$user->isClean('title'); // false
|
||
$user->isClean('first_name'); // true
|
||
$user->isClean(['first_name', 'title']); // false
|
||
|
||
$user->save();
|
||
|
||
$user->isDirty(); // false
|
||
$user->isClean(); // true
|
||
|
||
The `wasChanged` 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(); // true
|
||
|
||
12$user->wasChanged('title'); // true
|
||
|
||
13$user->wasChanged(['title', 'slug']); // true
|
||
|
||
14$user->wasChanged('first_name'); // false
|
||
|
||
15$user->wasChanged(['first_name', 'title']); // true
|
||
|
||
|
||
$user = User::create([
|
||
'first_name' => 'Taylor',
|
||
'last_name' => 'Otwell',
|
||
'title' => 'Developer',
|
||
]);
|
||
|
||
$user->title = 'Painter';
|
||
|
||
$user->save();
|
||
|
||
$user->wasChanged(); // true
|
||
$user->wasChanged('title'); // true
|
||
$user->wasChanged(['title', 'slug']); // true
|
||
$user->wasChanged('first_name'); // false
|
||
$user->wasChanged(['first_name', 'title']); // true
|
||
|
||
The `getOriginal` 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
|
||
|
||
4$user->email; // [[email protected]](/cdn-cgi/l/email-protection)
|
||
|
||
5
|
||
|
||
6$user->name = 'Jack';
|
||
|
||
7$user->name; // Jack
|
||
|
||
8
|
||
|
||
9$user->getOriginal('name'); // John
|
||
|
||
10$user->getOriginal(); // Array of original attributes...
|
||
|
||
|
||
$user = User::find(1);
|
||
|
||
$user->name; // John
|
||
$user->email; // [[email protected]](/cdn-cgi/l/email-protection)
|
||
|
||
$user->name = 'Jack';
|
||
$user->name; // Jack
|
||
|
||
$user->getOriginal('name'); // John
|
||
$user->getOriginal(); // Array of original attributes...
|
||
|
||
The `getChanges` method returns an array containing the attributes that
|
||
changed when the model was last saved, while the `getPrevious` method returns
|
||
an array containing the original attribute values before the model was last
|
||
saved:
|
||
|
||
|
||
|
||
1$user = User::find(1);
|
||
|
||
2
|
||
|
||
3$user->name; // John
|
||
|
||
4$user->email; // [[email protected]](/cdn-cgi/l/email-protection)
|
||
|
||
5
|
||
|
||
6$user->update([
|
||
|
||
7 'name' => 'Jack',
|
||
|
||
8 'email' => '[[email protected]](/cdn-cgi/l/email-protection)',
|
||
|
||
9]);
|
||
|
||
10
|
||
|
||
11$user->getChanges();
|
||
|
||
12
|
||
|
||
13/*
|
||
|
||
14 [
|
||
|
||
15 'name' => 'Jack',
|
||
|
||
16 'email' => '[[email protected]](/cdn-cgi/l/email-protection)',
|
||
|
||
17 ]
|
||
|
||
18*/
|
||
|
||
19
|
||
|
||
20$user->getPrevious();
|
||
|
||
21
|
||
|
||
22/*
|
||
|
||
23 [
|
||
|
||
24 'name' => 'John',
|
||
|
||
25 'email' => '[[email protected]](/cdn-cgi/l/email-protection)',
|
||
|
||
26 ]
|
||
|
||
27*/
|
||
|
||
|
||
$user = User::find(1);
|
||
|
||
$user->name; // John
|
||
$user->email; // [[email protected]](/cdn-cgi/l/email-protection)
|
||
|
||
$user->update([
|
||
'name' => 'Jack',
|
||
'email' => '[[email protected]](/cdn-cgi/l/email-protection)',
|
||
]);
|
||
|
||
$user->getChanges();
|
||
|
||
/*
|
||
[
|
||
'name' => 'Jack',
|
||
'email' => '[[email protected]](/cdn-cgi/l/email-protection)',
|
||
]
|
||
*/
|
||
|
||
$user->getPrevious();
|
||
|
||
/*
|
||
[
|
||
'name' => 'John',
|
||
'email' => '[[email protected]](/cdn-cgi/l/email-protection)',
|
||
]
|
||
*/
|
||
|
||
### Mass Assignment
|
||
|
||
You may use the `create` 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]);
|
||
|
||
|
||
use App\Models\Flight;
|
||
|
||
$flight = Flight::create([
|
||
'name' => 'London to Paris',
|
||
]);
|
||
|
||
However, before using the `create` method, you will need to specify either a
|
||
`fillable` or `guarded` 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 an `is_admin` parameter
|
||
through an HTTP request, which is then passed to your model's `create` 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 the `name` attribute of our `Flight` model mass
|
||
assignable:
|
||
|
||
|
||
|
||
1<?php
|
||
|
||
2
|
||
|
||
3namespace App\Models;
|
||
|
||
4
|
||
|
||
5use Illuminate\Database\Eloquent\Model;
|
||
|
||
6
|
||
|
||
7class Flight extends Model
|
||
|
||
8{
|
||
|
||
9 /**
|
||
|
||
10 * The attributes that are mass assignable.
|
||
|
||
11 *
|
||
|
||
12 * @var array<int, string>
|
||
|
||
13 */
|
||
|
||
14 protected $fillable = ['name'];
|
||
|
||
15}
|
||
|
||
|
||
<?php
|
||
|
||
namespace App\Models;
|
||
|
||
use Illuminate\Database\Eloquent\Model;
|
||
|
||
class Flight extends Model
|
||
{
|
||
/**
|
||
* The attributes that are mass assignable.
|
||
*
|
||
* @var array<int, string>
|
||
*/
|
||
protected $fillable = ['name'];
|
||
}
|
||
|
||
Once you have specified which attributes are mass assignable, you may use the
|
||
`create` method to insert a new record in the database. The `create` method
|
||
returns the newly created model instance:
|
||
|
||
|
||
|
||
1$flight = Flight::create(['name' => 'London to Paris']);
|
||
|
||
|
||
$flight = Flight::create(['name' => 'London to Paris']);
|
||
|
||
If you already have a model instance, you may use the `fill` method to
|
||
populate it with an array of attributes:
|
||
|
||
|
||
|
||
1$flight->fill(['name' => 'Amsterdam to Frankfurt']);
|
||
|
||
|
||
$flight->fill(['name' => 'Amsterdam to Frankfurt']);
|
||
|
||
#### Mass Assignment and JSON Columns
|
||
|
||
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 the `guarded` property:
|
||
|
||
|
||
|
||
1/**
|
||
|
||
2 * The attributes that are mass assignable.
|
||
|
||
3 *
|
||
|
||
4 * @var array<int, string>
|
||
|
||
5 */
|
||
|
||
6protected $fillable = [
|
||
|
||
7 'options->enabled',
|
||
|
||
8];
|
||
|
||
|
||
/**
|
||
* The attributes that are mass assignable.
|
||
*
|
||
* @var array<int, string>
|
||
*/
|
||
protected $fillable = [
|
||
'options->enabled',
|
||
];
|
||
|
||
#### Allowing Mass Assignment
|
||
|
||
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's `fill`, `create`, and `update` methods:
|
||
|
||
|
||
|
||
1/**
|
||
|
||
2 * The attributes that aren't mass assignable.
|
||
|
||
3 *
|
||
|
||
4 * @var array<string>|bool
|
||
|
||
5 */
|
||
|
||
6protected $guarded = [];
|
||
|
||
|
||
/**
|
||
* The attributes that aren't mass assignable.
|
||
*
|
||
* @var array<string>|bool
|
||
*/
|
||
protected $guarded = [];
|
||
|
||
#### Mass Assignment Exceptions
|
||
|
||
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 the
|
||
`preventSilentlyDiscardingAttributes` method. Typically, this method should be
|
||
invoked in the `boot` method of your application's `AppServiceProvider` class:
|
||
|
||
|
||
|
||
1use Illuminate\Database\Eloquent\Model;
|
||
|
||
2
|
||
|
||
3/**
|
||
|
||
4 * Bootstrap any application services.
|
||
|
||
5 */
|
||
|
||
6public function boot(): void
|
||
|
||
7{
|
||
|
||
8 Model::preventSilentlyDiscardingAttributes($this->app->isLocal());
|
||
|
||
9}
|
||
|
||
|
||
use Illuminate\Database\Eloquent\Model;
|
||
|
||
/**
|
||
* Bootstrap any application services.
|
||
*/
|
||
public function boot(): void
|
||
{
|
||
Model::preventSilentlyDiscardingAttributes($this->app->isLocal());
|
||
}
|
||
|
||
### Upserts
|
||
|
||
Eloquent's `upsert` 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. The `upsert` method will automatically
|
||
set the `created_at` and `updated_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']);
|
||
|
||
|
||
Flight::upsert([
|
||
['departure' => 'Oakland', 'destination' => 'San Diego', 'price' => 99],
|
||
['departure' => 'Chicago', 'destination' => 'New York', 'price' => 150]
|
||
], uniqueBy: ['departure', 'destination'], update: ['price']);
|
||
|
||
All databases except SQL Server require the columns in the second argument of
|
||
the `upsert` method to have a "primary" or "unique" index. In addition, the
|
||
MariaDB and MySQL database drivers ignore the second argument of the `upsert`
|
||
method and always use the "primary" and "unique" indexes of the table to
|
||
detect existing records.
|
||
|
||
## Deleting Models
|
||
|
||
To delete a model, you may call the `delete` method on the model instance:
|
||
|
||
|
||
|
||
1use App\Models\Flight;
|
||
|
||
2
|
||
|
||
3$flight = Flight::find(1);
|
||
|
||
4
|
||
|
||
5$flight->delete();
|
||
|
||
|
||
use App\Models\Flight;
|
||
|
||
$flight = Flight::find(1);
|
||
|
||
$flight->delete();
|
||
|
||
#### Deleting an Existing Model by its Primary Key
|
||
|
||
In the example above, we are retrieving the model from the database before
|
||
calling the `delete` method. However, if you know the primary key of the
|
||
model, you may delete the model without explicitly retrieving it by calling
|
||
the `destroy` method. In addition to accepting the single primary key, the
|
||
`destroy` method will accept multiple primary keys, an array of primary keys,
|
||
or a [collection](/docs/12.x/collections) 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]));
|
||
|
||
|
||
Flight::destroy(1);
|
||
|
||
Flight::destroy(1, 2, 3);
|
||
|
||
Flight::destroy([1, 2, 3]);
|
||
|
||
Flight::destroy(collect([1, 2, 3]));
|
||
|
||
If you are utilizing soft deleting models, you may permanently delete models
|
||
via the `forceDestroy` method:
|
||
|
||
|
||
|
||
1Flight::forceDestroy(1);
|
||
|
||
|
||
Flight::forceDestroy(1);
|
||
|
||
The `destroy` method loads each model individually and calls the `delete`
|
||
method so that the `deleting` and `deleted` events are properly dispatched for
|
||
each model.
|
||
|
||
#### Deleting Models Using Queries
|
||
|
||
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();
|
||
|
||
|
||
$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();
|
||
|
||
|
||
$deleted = Flight::query()->delete();
|
||
|
||
When executing a mass delete statement via Eloquent, the `deleting` and
|
||
`deleted` model events will not be dispatched for the deleted models. This is
|
||
because the models are never actually retrieved when executing the delete
|
||
statement.
|
||
|
||
### Soft Deleting
|
||
|
||
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, a `deleted_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 the `Illuminate\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
|
||
|
||
8class Flight extends Model
|
||
|
||
9{
|
||
|
||
10 use SoftDeletes;
|
||
|
||
11}
|
||
|
||
|
||
<?php
|
||
|
||
namespace App\Models;
|
||
|
||
use Illuminate\Database\Eloquent\Model;
|
||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||
|
||
class Flight extends Model
|
||
{
|
||
use SoftDeletes;
|
||
}
|
||
|
||
The `SoftDeletes` trait will automatically cast the `deleted_at` attribute to
|
||
a `DateTime` / `Carbon` instance for you.
|
||
|
||
You should also add the `deleted_at` column to your database table. The
|
||
Laravel [schema builder](/docs/12.x/migrations) 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});
|
||
|
||
|
||
use Illuminate\Database\Schema\Blueprint;
|
||
use Illuminate\Support\Facades\Schema;
|
||
|
||
Schema::table('flights', function (Blueprint $table) {
|
||
$table->softDeletes();
|
||
});
|
||
|
||
Schema::table('flights', function (Blueprint $table) {
|
||
$table->dropSoftDeletes();
|
||
});
|
||
|
||
Now, when you call the `delete` method on the model, the `deleted_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 the
|
||
`trashed` method:
|
||
|
||
|
||
|
||
1if ($flight->trashed()) {
|
||
|
||
2 // ...
|
||
|
||
3}
|
||
|
||
|
||
if ($flight->trashed()) {
|
||
// ...
|
||
}
|
||
|
||
#### Restoring Soft Deleted Models
|
||
|
||
Sometimes you may wish to "un-delete" a soft deleted model. To restore a soft
|
||
deleted model, you may call the `restore` method on a model instance. The
|
||
`restore` method will set the model's `deleted_at` column to `null`:
|
||
|
||
|
||
|
||
1$flight->restore();
|
||
|
||
|
||
$flight->restore();
|
||
|
||
You may also use the `restore` 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();
|
||
|
||
|
||
Flight::withTrashed()
|
||
->where('airline_id', 1)
|
||
->restore();
|
||
|
||
The `restore` method may also be used when building
|
||
[relationship](/docs/12.x/eloquent-relationships) queries:
|
||
|
||
|
||
|
||
1$flight->history()->restore();
|
||
|
||
|
||
$flight->history()->restore();
|
||
|
||
#### Permanently Deleting Models
|
||
|
||
Sometimes you may need to truly remove a model from your database. You may use
|
||
the `forceDelete` method to permanently remove a soft deleted model from the
|
||
database table:
|
||
|
||
|
||
|
||
1$flight->forceDelete();
|
||
|
||
|
||
$flight->forceDelete();
|
||
|
||
You may also use the `forceDelete` method when building Eloquent relationship
|
||
queries:
|
||
|
||
|
||
|
||
1$flight->history()->forceDelete();
|
||
|
||
|
||
$flight->history()->forceDelete();
|
||
|
||
### Querying Soft Deleted Models
|
||
|
||
#### Including Soft Deleted Models
|
||
|
||
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 the `withTrashed` method on the query:
|
||
|
||
|
||
|
||
1use App\Models\Flight;
|
||
|
||
2
|
||
|
||
3$flights = Flight::withTrashed()
|
||
|
||
4 ->where('account_id', 1)
|
||
|
||
5 ->get();
|
||
|
||
|
||
use App\Models\Flight;
|
||
|
||
$flights = Flight::withTrashed()
|
||
->where('account_id', 1)
|
||
->get();
|
||
|
||
The `withTrashed` method may also be called when building a
|
||
[relationship](/docs/12.x/eloquent-relationships) query:
|
||
|
||
|
||
|
||
1$flight->history()->withTrashed()->get();
|
||
|
||
|
||
$flight->history()->withTrashed()->get();
|
||
|
||
#### Retrieving Only Soft Deleted Models
|
||
|
||
The `onlyTrashed` method will retrieve **only** soft deleted models:
|
||
|
||
|
||
|
||
1$flights = Flight::onlyTrashed()
|
||
|
||
2 ->where('airline_id', 1)
|
||
|
||
3 ->get();
|
||
|
||
|
||
$flights = Flight::onlyTrashed()
|
||
->where('airline_id', 1)
|
||
->get();
|
||
|
||
## Pruning Models
|
||
|
||
Sometimes you may want to periodically delete models that are no longer
|
||
needed. To accomplish this, you may add the
|
||
`Illuminate\Database\Eloquent\Prunable` or
|
||
`Illuminate\Database\Eloquent\MassPrunable` trait to the models you would like
|
||
to periodically prune. After adding one of the traits to the model, implement
|
||
a `prunable` 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
|
||
|
||
9class Flight extends Model
|
||
|
||
10{
|
||
|
||
11 use Prunable;
|
||
|
||
12
|
||
|
||
13 /**
|
||
|
||
14 * Get the prunable model query.
|
||
|
||
15 */
|
||
|
||
16 public function prunable(): Builder
|
||
|
||
17 {
|
||
|
||
18 return static::where('created_at', '<=', now()->subMonth());
|
||
|
||
19 }
|
||
|
||
20}
|
||
|
||
|
||
<?php
|
||
|
||
namespace App\Models;
|
||
|
||
use Illuminate\Database\Eloquent\Builder;
|
||
use Illuminate\Database\Eloquent\Model;
|
||
use Illuminate\Database\Eloquent\Prunable;
|
||
|
||
class Flight extends Model
|
||
{
|
||
use Prunable;
|
||
|
||
/**
|
||
* Get the prunable model query.
|
||
*/
|
||
public function prunable(): Builder
|
||
{
|
||
return static::where('created_at', '<=', now()->subMonth());
|
||
}
|
||
}
|
||
|
||
When marking models as `Prunable`, you may also define a `pruning` 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 */
|
||
|
||
4protected function pruning(): void
|
||
|
||
5{
|
||
|
||
6 // ...
|
||
|
||
7}
|
||
|
||
|
||
/**
|
||
* Prepare the model for pruning.
|
||
*/
|
||
protected function pruning(): void
|
||
{
|
||
// ...
|
||
}
|
||
|
||
After configuring your prunable model, you should schedule the `model:prune`
|
||
Artisan command in your application's `routes/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();
|
||
|
||
|
||
use Illuminate\Support\Facades\Schedule;
|
||
|
||
Schedule::command('model:prune')->daily();
|
||
|
||
Behind the scenes, the `model:prune` command will automatically detect
|
||
"Prunable" models within your application's `app/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();
|
||
|
||
|
||
Schedule::command('model:prune', [
|
||
'--model' => [Address::class, Flight::class],
|
||
])->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();
|
||
|
||
|
||
Schedule::command('model:prune', [
|
||
'--except' => [Address::class, Flight::class],
|
||
])->daily();
|
||
|
||
You may test your `prunable` query by executing the `model:prune` command with
|
||
the `--pretend` option. When pretending, the `model:prune` command will simply
|
||
report how many records would be pruned if the command were to actually run:
|
||
|
||
|
||
|
||
1php artisan model:prune --pretend
|
||
|
||
|
||
php artisan model:prune --pretend
|
||
|
||
Soft deleting models will be permanently deleted (`forceDelete`) if they match
|
||
the prunable query.
|
||
|
||
#### Mass Pruning
|
||
|
||
When models are marked with the `Illuminate\Database\Eloquent\MassPrunable`
|
||
trait, models are deleted from the database using mass-deletion queries.
|
||
Therefore, the `pruning` method will not be invoked, nor will the `deleting`
|
||
and `deleted` 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
|
||
|
||
9class Flight extends Model
|
||
|
||
10{
|
||
|
||
11 use MassPrunable;
|
||
|
||
12
|
||
|
||
13 /**
|
||
|
||
14 * Get the prunable model query.
|
||
|
||
15 */
|
||
|
||
16 public function prunable(): Builder
|
||
|
||
17 {
|
||
|
||
18 return static::where('created_at', '<=', now()->subMonth());
|
||
|
||
19 }
|
||
|
||
20}
|
||
|
||
|
||
<?php
|
||
|
||
namespace App\Models;
|
||
|
||
use Illuminate\Database\Eloquent\Builder;
|
||
use Illuminate\Database\Eloquent\Model;
|
||
use Illuminate\Database\Eloquent\MassPrunable;
|
||
|
||
class Flight extends Model
|
||
{
|
||
use MassPrunable;
|
||
|
||
/**
|
||
* Get the prunable model query.
|
||
*/
|
||
public function prunable(): Builder
|
||
{
|
||
return static::where('created_at', '<=', now()->subMonth());
|
||
}
|
||
}
|
||
|
||
## Replicating Models
|
||
|
||
You may create an unsaved copy of an existing model instance using the
|
||
`replicate` 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();
|
||
|
||
|
||
use App\Models\Address;
|
||
|
||
$shipping = Address::create([
|
||
'type' => 'shipping',
|
||
'line_1' => '123 Example Street',
|
||
'city' => 'Victorville',
|
||
'state' => 'CA',
|
||
'postcode' => '90001',
|
||
]);
|
||
|
||
$billing = $shipping->replicate()->fill([
|
||
'type' => 'billing'
|
||
]);
|
||
|
||
$billing->save();
|
||
|
||
To exclude one or more attributes from being replicated to the new model, you
|
||
may pass an array to the `replicate` 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]);
|
||
|
||
|
||
$flight = Flight::create([
|
||
'destination' => 'LAX',
|
||
'origin' => 'LHR',
|
||
'last_flown' => '2020-03-04 11:00:00',
|
||
'last_pilot_id' => 747,
|
||
]);
|
||
|
||
$flight = $flight->replicate([
|
||
'last_flown',
|
||
'last_pilot_id'
|
||
]);
|
||
|
||
## Query Scopes
|
||
|
||
### Global Scopes
|
||
|
||
Global scopes allow you to add constraints to all queries for a given model.
|
||
Laravel's own soft 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.
|
||
|
||
#### Generating Scopes
|
||
|
||
To generate a new global scope, you may invoke the `make:scope` Artisan
|
||
command, which will place the generated scope in your application's
|
||
`app/Models/Scopes` directory:
|
||
|
||
|
||
|
||
1php artisan make:scope AncientScope
|
||
|
||
|
||
php artisan make:scope AncientScope
|
||
|
||
#### Writing Global Scopes
|
||
|
||
Writing a global scope is simple. First, use the `make:scope` command to
|
||
generate a class that implements the `Illuminate\Database\Eloquent\Scope`
|
||
interface. The `Scope` interface requires you to implement one method:
|
||
`apply`. The `apply` method may add `where` 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
|
||
|
||
9class AncientScope implements Scope
|
||
|
||
10{
|
||
|
||
11 /**
|
||
|
||
12 * Apply the scope to a given Eloquent query builder.
|
||
|
||
13 */
|
||
|
||
14 public function apply(Builder $builder, Model $model): void
|
||
|
||
15 {
|
||
|
||
16 $builder->where('created_at', '<', now()->subYears(2000));
|
||
|
||
17 }
|
||
|
||
18}
|
||
|
||
|
||
<?php
|
||
|
||
namespace App\Models\Scopes;
|
||
|
||
use Illuminate\Database\Eloquent\Builder;
|
||
use Illuminate\Database\Eloquent\Model;
|
||
use Illuminate\Database\Eloquent\Scope;
|
||
|
||
class AncientScope implements Scope
|
||
{
|
||
/**
|
||
* Apply the scope to a given Eloquent query builder.
|
||
*/
|
||
public function apply(Builder $builder, Model $model): void
|
||
{
|
||
$builder->where('created_at', '<', now()->subYears(2000));
|
||
}
|
||
}
|
||
|
||
If your global scope is adding columns to the select clause of the query, you
|
||
should use the `addSelect` method instead of `select`. This will prevent the
|
||
unintentional replacement of the query's existing select clause.
|
||
|
||
#### Applying Global Scopes
|
||
|
||
To assign a global scope to a model, you may simply place the `ScopedBy`
|
||
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])]
|
||
|
||
9class User extends Model
|
||
|
||
10{
|
||
|
||
11 //
|
||
|
||
12}
|
||
|
||
|
||
<?php
|
||
|
||
namespace App\Models;
|
||
|
||
use App\Models\Scopes\AncientScope;
|
||
use Illuminate\Database\Eloquent\Attributes\ScopedBy;
|
||
|
||
#[ScopedBy([AncientScope::class])]
|
||
class User extends Model
|
||
{
|
||
//
|
||
}
|
||
|
||
Or, you may manually register the global scope by overriding the model's
|
||
`booted` method and invoke the model's `addGlobalScope` method. The
|
||
`addGlobalScope` 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
|
||
|
||
8class User extends Model
|
||
|
||
9{
|
||
|
||
10 /**
|
||
|
||
11 * The "booted" method of the model.
|
||
|
||
12 */
|
||
|
||
13 protected static function booted(): void
|
||
|
||
14 {
|
||
|
||
15 static::addGlobalScope(new AncientScope);
|
||
|
||
16 }
|
||
|
||
17}
|
||
|
||
|
||
<?php
|
||
|
||
namespace App\Models;
|
||
|
||
use App\Models\Scopes\AncientScope;
|
||
use Illuminate\Database\Eloquent\Model;
|
||
|
||
class User extends Model
|
||
{
|
||
/**
|
||
* The "booted" method of the model.
|
||
*/
|
||
protected static function booted(): void
|
||
{
|
||
static::addGlobalScope(new AncientScope);
|
||
}
|
||
}
|
||
|
||
After adding the scope in the example above to the `App\Models\User` model, a
|
||
call to the `User::all()` method will execute the following SQL query:
|
||
|
||
|
||
|
||
1select * from `users` where `created_at` < 0021-02-18 00:00:00
|
||
|
||
|
||
select * from `users` where `created_at` < 0021-02-18 00:00:00
|
||
|
||
#### Anonymous Global Scopes
|
||
|
||
Eloquent 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 the `addGlobalScope`
|
||
method:
|
||
|
||
|
||
|
||
1<?php
|
||
|
||
2
|
||
|
||
3namespace App\Models;
|
||
|
||
4
|
||
|
||
5use Illuminate\Database\Eloquent\Builder;
|
||
|
||
6use Illuminate\Database\Eloquent\Model;
|
||
|
||
7
|
||
|
||
8class User extends Model
|
||
|
||
9{
|
||
|
||
10 /**
|
||
|
||
11 * The "booted" method of the model.
|
||
|
||
12 */
|
||
|
||
13 protected static function booted(): void
|
||
|
||
14 {
|
||
|
||
15 static::addGlobalScope('ancient', function (Builder $builder) {
|
||
|
||
16 $builder->where('created_at', '<', now()->subYears(2000));
|
||
|
||
17 });
|
||
|
||
18 }
|
||
|
||
19}
|
||
|
||
|
||
<?php
|
||
|
||
namespace App\Models;
|
||
|
||
use Illuminate\Database\Eloquent\Builder;
|
||
use Illuminate\Database\Eloquent\Model;
|
||
|
||
class User extends Model
|
||
{
|
||
/**
|
||
* The "booted" method of the model.
|
||
*/
|
||
protected static function booted(): void
|
||
{
|
||
static::addGlobalScope('ancient', function (Builder $builder) {
|
||
$builder->where('created_at', '<', now()->subYears(2000));
|
||
});
|
||
}
|
||
}
|
||
|
||
#### Removing Global Scopes
|
||
|
||
If you would like to remove a global scope for a given query, you may use the
|
||
`withoutGlobalScope` method. This method accepts the class name of the global
|
||
scope as its only argument:
|
||
|
||
|
||
|
||
1User::withoutGlobalScope(AncientScope::class)->get();
|
||
|
||
|
||
User::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();
|
||
|
||
|
||
User::withoutGlobalScope('ancient')->get();
|
||
|
||
If you would like to remove several or even all of the query's global scopes,
|
||
you may use the `withoutGlobalScopes` method:
|
||
|
||
|
||
|
||
1// Remove all of the global scopes...
|
||
|
||
2User::withoutGlobalScopes()->get();
|
||
|
||
3
|
||
|
||
4// Remove some of the global scopes...
|
||
|
||
5User::withoutGlobalScopes([
|
||
|
||
6 FirstScope::class, SecondScope::class
|
||
|
||
7])->get();
|
||
|
||
|
||
// Remove all of the global scopes...
|
||
User::withoutGlobalScopes()->get();
|
||
|
||
// Remove some of the global scopes...
|
||
User::withoutGlobalScopes([
|
||
FirstScope::class, SecondScope::class
|
||
])->get();
|
||
|
||
### Local Scopes
|
||
|
||
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, add the `Scope` attribute to an Eloquent method.
|
||
|
||
Scopes should always return the same query builder instance or `void`:
|
||
|
||
|
||
|
||
1<?php
|
||
|
||
2
|
||
|
||
3namespace App\Models;
|
||
|
||
4
|
||
|
||
5use Illuminate\Database\Eloquent\Attributes\Scope;
|
||
|
||
6use Illuminate\Database\Eloquent\Builder;
|
||
|
||
7use Illuminate\Database\Eloquent\Model;
|
||
|
||
8
|
||
|
||
9class User extends Model
|
||
|
||
10{
|
||
|
||
11 /**
|
||
|
||
12 * Scope a query to only include popular users.
|
||
|
||
13 */
|
||
|
||
14 #[Scope]
|
||
|
||
15 protected function popular(Builder $query): void
|
||
|
||
16 {
|
||
|
||
17 $query->where('votes', '>', 100);
|
||
|
||
18 }
|
||
|
||
19
|
||
|
||
20 /**
|
||
|
||
21 * Scope a query to only include active users.
|
||
|
||
22 */
|
||
|
||
23 #[Scope]
|
||
|
||
24 protected function active(Builder $query): void
|
||
|
||
25 {
|
||
|
||
26 $query->where('active', 1);
|
||
|
||
27 }
|
||
|
||
28}
|
||
|
||
|
||
<?php
|
||
|
||
namespace App\Models;
|
||
|
||
use Illuminate\Database\Eloquent\Attributes\Scope;
|
||
use Illuminate\Database\Eloquent\Builder;
|
||
use Illuminate\Database\Eloquent\Model;
|
||
|
||
class User extends Model
|
||
{
|
||
/**
|
||
* Scope a query to only include popular users.
|
||
*/
|
||
#[Scope]
|
||
protected function popular(Builder $query): void
|
||
{
|
||
$query->where('votes', '>', 100);
|
||
}
|
||
|
||
/**
|
||
* Scope a query to only include active users.
|
||
*/
|
||
#[Scope]
|
||
protected function active(Builder $query): void
|
||
{
|
||
$query->where('active', 1);
|
||
}
|
||
}
|
||
|
||
#### Utilizing a Local Scope
|
||
|
||
Once the scope has been defined, you may call the scope methods when querying
|
||
the model. You can even chain calls to various scopes:
|
||
|
||
|
||
|
||
1use App\Models\User;
|
||
|
||
2
|
||
|
||
3$users = User::popular()->active()->orderBy('created_at')->get();
|
||
|
||
|
||
use App\Models\User;
|
||
|
||
$users = User::popular()->active()->orderBy('created_at')->get();
|
||
|
||
Combining multiple Eloquent model scopes via an `or` query operator may
|
||
require the use of closures to achieve the correct [logical
|
||
grouping](/docs/12.x/queries#logical-grouping):
|
||
|
||
|
||
|
||
1$users = User::popular()->orWhere(function (Builder $query) {
|
||
|
||
2 $query->active();
|
||
|
||
3})->get();
|
||
|
||
|
||
$users = User::popular()->orWhere(function (Builder $query) {
|
||
$query->active();
|
||
})->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();
|
||
|
||
|
||
$users = User::popular()->orWhere->active()->get();
|
||
|
||
#### Dynamic Scopes
|
||
|
||
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\Attributes\Scope;
|
||
|
||
6use Illuminate\Database\Eloquent\Builder;
|
||
|
||
7use Illuminate\Database\Eloquent\Model;
|
||
|
||
8
|
||
|
||
9class User extends Model
|
||
|
||
10{
|
||
|
||
11 /**
|
||
|
||
12 * Scope a query to only include users of a given type.
|
||
|
||
13 */
|
||
|
||
14 #[Scope]
|
||
|
||
15 protected function ofType(Builder $query, string $type): void
|
||
|
||
16 {
|
||
|
||
17 $query->where('type', $type);
|
||
|
||
18 }
|
||
|
||
19}
|
||
|
||
|
||
<?php
|
||
|
||
namespace App\Models;
|
||
|
||
use Illuminate\Database\Eloquent\Attributes\Scope;
|
||
use Illuminate\Database\Eloquent\Builder;
|
||
use Illuminate\Database\Eloquent\Model;
|
||
|
||
class User extends Model
|
||
{
|
||
/**
|
||
* Scope a query to only include users of a given type.
|
||
*/
|
||
#[Scope]
|
||
protected function ofType(Builder $query, string $type): void
|
||
{
|
||
$query->where('type', $type);
|
||
}
|
||
}
|
||
|
||
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();
|
||
|
||
|
||
$users = User::ofType('admin')->get();
|
||
|
||
### Pending Attributes
|
||
|
||
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 the `withAttributes` method
|
||
when building the scope query:
|
||
|
||
|
||
|
||
1<?php
|
||
|
||
2
|
||
|
||
3namespace App\Models;
|
||
|
||
4
|
||
|
||
5use Illuminate\Database\Eloquent\Attributes\Scope;
|
||
|
||
6use Illuminate\Database\Eloquent\Builder;
|
||
|
||
7use Illuminate\Database\Eloquent\Model;
|
||
|
||
8
|
||
|
||
9class Post extends Model
|
||
|
||
10{
|
||
|
||
11 /**
|
||
|
||
12 * Scope the query to only include drafts.
|
||
|
||
13 */
|
||
|
||
14 #[Scope]
|
||
|
||
15 protected function draft(Builder $query): void
|
||
|
||
16 {
|
||
|
||
17 $query->withAttributes([
|
||
|
||
18 'hidden' => true,
|
||
|
||
19 ]);
|
||
|
||
20 }
|
||
|
||
21}
|
||
|
||
|
||
<?php
|
||
|
||
namespace App\Models;
|
||
|
||
use Illuminate\Database\Eloquent\Attributes\Scope;
|
||
use Illuminate\Database\Eloquent\Builder;
|
||
use Illuminate\Database\Eloquent\Model;
|
||
|
||
class Post extends Model
|
||
{
|
||
/**
|
||
* Scope the query to only include drafts.
|
||
*/
|
||
#[Scope]
|
||
protected function draft(Builder $query): void
|
||
{
|
||
$query->withAttributes([
|
||
'hidden' => true,
|
||
]);
|
||
}
|
||
}
|
||
|
||
The `withAttributes` method will add `where` conditions 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; // true
|
||
|
||
|
||
$draft = Post::draft()->create(['title' => 'In Progress']);
|
||
|
||
$draft->hidden; // true
|
||
|
||
To instruct the `withAttributes` method to not add `where` conditions to the
|
||
query, you may set the `asConditions` argument to `false`:
|
||
|
||
|
||
|
||
1$query->withAttributes([
|
||
|
||
2 'hidden' => true,
|
||
|
||
3], asConditions: false);
|
||
|
||
|
||
$query->withAttributes([
|
||
'hidden' => true,
|
||
], asConditions: false);
|
||
|
||
## Comparing Models
|
||
|
||
Sometimes you may need to determine if two models are the "same" or not. The
|
||
`is` and `isNot` 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}
|
||
|
||
|
||
if ($post->is($anotherPost)) {
|
||
// ...
|
||
}
|
||
|
||
if ($post->isNot($anotherPost)) {
|
||
// ...
|
||
}
|
||
|
||
The `is` and `isNot` methods are also available when using the `belongsTo`,
|
||
`hasOne`, `morphTo`, and `morphOne` [relationships](/docs/12.x/eloquent-
|
||
relationships). 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}
|
||
|
||
|
||
if ($post->author()->is($user)) {
|
||
// ...
|
||
}
|
||
|
||
## Events
|
||
|
||
Want to broadcast your Eloquent events directly to your client-side
|
||
application? Check out Laravel's [model event
|
||
broadcasting](/docs/12.x/broadcasting#model-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`, and `replicating`.
|
||
|
||
The `retrieved` event will dispatch when an existing model is retrieved from
|
||
the database. When a new model is saved for the first time, the `creating` and
|
||
`created` events will dispatch. The `updating` / `updated` events will
|
||
dispatch when an existing model is modified and the `save` method is called.
|
||
The `saving` / `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 own [event classes](/docs/12.x/events). 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\User as Authenticatable;
|
||
|
||
8use Illuminate\Notifications\Notifiable;
|
||
|
||
9
|
||
|
||
10class User extends Authenticatable
|
||
|
||
11{
|
||
|
||
12 use Notifiable;
|
||
|
||
13
|
||
|
||
14 /**
|
||
|
||
15 * The event map for the model.
|
||
|
||
16 *
|
||
|
||
17 * @var array<string, string>
|
||
|
||
18 */
|
||
|
||
19 protected $dispatchesEvents = [
|
||
|
||
20 'saved' => UserSaved::class,
|
||
|
||
21 'deleted' => UserDeleted::class,
|
||
|
||
22 ];
|
||
|
||
23}
|
||
|
||
|
||
<?php
|
||
|
||
namespace App\Models;
|
||
|
||
use App\Events\UserDeleted;
|
||
use App\Events\UserSaved;
|
||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||
use Illuminate\Notifications\Notifiable;
|
||
|
||
class User extends Authenticatable
|
||
{
|
||
use Notifiable;
|
||
|
||
/**
|
||
* The event map for the model.
|
||
*
|
||
* @var array<string, string>
|
||
*/
|
||
protected $dispatchesEvents = [
|
||
'saved' => UserSaved::class,
|
||
'deleted' => UserDeleted::class,
|
||
];
|
||
}
|
||
|
||
After defining and mapping your Eloquent events, you may use [event
|
||
listeners](/docs/12.x/events#defining-listeners) to handle the events.
|
||
|
||
When issuing a mass update or delete query via Eloquent, the `saved`,
|
||
`updated`, `deleting`, and `deleted` 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.
|
||
|
||
### Using Closures
|
||
|
||
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 the `booted` method of your model:
|
||
|
||
|
||
|
||
1<?php
|
||
|
||
2
|
||
|
||
3namespace App\Models;
|
||
|
||
4
|
||
|
||
5use Illuminate\Database\Eloquent\Model;
|
||
|
||
6
|
||
|
||
7class User extends Model
|
||
|
||
8{
|
||
|
||
9 /**
|
||
|
||
10 * The "booted" method of the model.
|
||
|
||
11 */
|
||
|
||
12 protected static function booted(): void
|
||
|
||
13 {
|
||
|
||
14 static::created(function (User $user) {
|
||
|
||
15 // ...
|
||
|
||
16 });
|
||
|
||
17 }
|
||
|
||
18}
|
||
|
||
|
||
<?php
|
||
|
||
namespace App\Models;
|
||
|
||
use Illuminate\Database\Eloquent\Model;
|
||
|
||
class User extends Model
|
||
{
|
||
/**
|
||
* The "booted" method of the model.
|
||
*/
|
||
protected static function booted(): void
|
||
{
|
||
static::created(function (User $user) {
|
||
// ...
|
||
});
|
||
}
|
||
}
|
||
|
||
If needed, you may utilize [queueable anonymous event
|
||
listeners](/docs/12.x/events#queuable-anonymous-event-listeners) when
|
||
registering model events. This will instruct Laravel to execute the model
|
||
event listener in the background using your application's
|
||
[queue](/docs/12.x/queues):
|
||
|
||
|
||
|
||
1use function Illuminate\Events\queueable;
|
||
|
||
2
|
||
|
||
3static::created(queueable(function (User $user) {
|
||
|
||
4 // ...
|
||
|
||
5}));
|
||
|
||
|
||
use function Illuminate\Events\queueable;
|
||
|
||
static::created(queueable(function (User $user) {
|
||
// ...
|
||
}));
|
||
|
||
### Observers
|
||
|
||
#### Defining Observers
|
||
|
||
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. The
|
||
`make:observer` Artisan command is the easiest way to create a new observer
|
||
class:
|
||
|
||
|
||
|
||
1php artisan make:observer UserObserver --model=User
|
||
|
||
|
||
php artisan make:observer UserObserver --model=User
|
||
|
||
This command will place the new observer in your `app/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
|
||
|
||
7class UserObserver
|
||
|
||
8{
|
||
|
||
9 /**
|
||
|
||
10 * Handle the User "created" event.
|
||
|
||
11 */
|
||
|
||
12 public function created(User $user): void
|
||
|
||
13 {
|
||
|
||
14 // ...
|
||
|
||
15 }
|
||
|
||
16
|
||
|
||
17 /**
|
||
|
||
18 * Handle the User "updated" event.
|
||
|
||
19 */
|
||
|
||
20 public function updated(User $user): void
|
||
|
||
21 {
|
||
|
||
22 // ...
|
||
|
||
23 }
|
||
|
||
24
|
||
|
||
25 /**
|
||
|
||
26 * Handle the User "deleted" event.
|
||
|
||
27 */
|
||
|
||
28 public function deleted(User $user): void
|
||
|
||
29 {
|
||
|
||
30 // ...
|
||
|
||
31 }
|
||
|
||
32
|
||
|
||
33 /**
|
||
|
||
34 * Handle the User "restored" event.
|
||
|
||
35 */
|
||
|
||
36 public function restored(User $user): void
|
||
|
||
37 {
|
||
|
||
38 // ...
|
||
|
||
39 }
|
||
|
||
40
|
||
|
||
41 /**
|
||
|
||
42 * Handle the User "forceDeleted" event.
|
||
|
||
43 */
|
||
|
||
44 public function forceDeleted(User $user): void
|
||
|
||
45 {
|
||
|
||
46 // ...
|
||
|
||
47 }
|
||
|
||
48}
|
||
|
||
|
||
<?php
|
||
|
||
namespace App\Observers;
|
||
|
||
use App\Models\User;
|
||
|
||
class UserObserver
|
||
{
|
||
/**
|
||
* Handle the User "created" event.
|
||
*/
|
||
public function created(User $user): void
|
||
{
|
||
// ...
|
||
}
|
||
|
||
/**
|
||
* Handle the User "updated" event.
|
||
*/
|
||
public function updated(User $user): void
|
||
{
|
||
// ...
|
||
}
|
||
|
||
/**
|
||
* Handle the User "deleted" event.
|
||
*/
|
||
public function deleted(User $user): void
|
||
{
|
||
// ...
|
||
}
|
||
|
||
/**
|
||
* Handle the User "restored" event.
|
||
*/
|
||
public function restored(User $user): void
|
||
{
|
||
// ...
|
||
}
|
||
|
||
/**
|
||
* Handle the User "forceDeleted" event.
|
||
*/
|
||
public function forceDeleted(User $user): void
|
||
{
|
||
// ...
|
||
}
|
||
}
|
||
|
||
To register an observer, you may place the `ObservedBy` attribute on the
|
||
corresponding model:
|
||
|
||
|
||
|
||
1use App\Observers\UserObserver;
|
||
|
||
2use Illuminate\Database\Eloquent\Attributes\ObservedBy;
|
||
|
||
3
|
||
|
||
4#[ObservedBy([UserObserver::class])]
|
||
|
||
5class User extends Authenticatable
|
||
|
||
6{
|
||
|
||
7 //
|
||
|
||
8}
|
||
|
||
|
||
use App\Observers\UserObserver;
|
||
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
|
||
|
||
#[ObservedBy([UserObserver::class])]
|
||
class User extends Authenticatable
|
||
{
|
||
//
|
||
}
|
||
|
||
Or, you may manually register an observer by invoking the `observe` method on
|
||
the model you wish to observe. You may register observers in the `boot` method
|
||
of your application's `AppServiceProvider` class:
|
||
|
||
|
||
|
||
1use App\Models\User;
|
||
|
||
2use App\Observers\UserObserver;
|
||
|
||
3
|
||
|
||
4/**
|
||
|
||
5 * Bootstrap any application services.
|
||
|
||
6 */
|
||
|
||
7public function boot(): void
|
||
|
||
8{
|
||
|
||
9 User::observe(UserObserver::class);
|
||
|
||
10}
|
||
|
||
|
||
use App\Models\User;
|
||
use App\Observers\UserObserver;
|
||
|
||
/**
|
||
* Bootstrap any application services.
|
||
*/
|
||
public function boot(): void
|
||
{
|
||
User::observe(UserObserver::class);
|
||
}
|
||
|
||
There are additional events an observer can listen to, such as `saving` and
|
||
`retrieved`. These events are described within the events documentation.
|
||
|
||
#### Observers and Database Transactions
|
||
|
||
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 the
|
||
`ShouldHandleEventsAfterCommit` 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
|
||
|
||
8class UserObserver implements ShouldHandleEventsAfterCommit
|
||
|
||
9{
|
||
|
||
10 /**
|
||
|
||
11 * Handle the User "created" event.
|
||
|
||
12 */
|
||
|
||
13 public function created(User $user): void
|
||
|
||
14 {
|
||
|
||
15 // ...
|
||
|
||
16 }
|
||
|
||
17}
|
||
|
||
|
||
<?php
|
||
|
||
namespace App\Observers;
|
||
|
||
use App\Models\User;
|
||
use Illuminate\Contracts\Events\ShouldHandleEventsAfterCommit;
|
||
|
||
class UserObserver implements ShouldHandleEventsAfterCommit
|
||
{
|
||
/**
|
||
* Handle the User "created" event.
|
||
*/
|
||
public function created(User $user): void
|
||
{
|
||
// ...
|
||
}
|
||
}
|
||
|
||
### Muting Events
|
||
|
||
You may occasionally need to temporarily "mute" all events fired by a model.
|
||
You may achieve this using the `withoutEvents` method. The `withoutEvents`
|
||
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 the `withoutEvents` method:
|
||
|
||
|
||
|
||
1use App\Models\User;
|
||
|
||
2
|
||
|
||
3$user = User::withoutEvents(function () {
|
||
|
||
4 User::findOrFail(1)->delete();
|
||
|
||
5
|
||
|
||
6 return User::find(2);
|
||
|
||
7});
|
||
|
||
|
||
use App\Models\User;
|
||
|
||
$user = User::withoutEvents(function () {
|
||
User::findOrFail(1)->delete();
|
||
|
||
return User::find(2);
|
||
});
|
||
|
||
#### Saving a Single Model Without Events
|
||
|
||
Sometimes you may wish to "save" a given model without dispatching any events.
|
||
You may accomplish this using the `saveQuietly` method:
|
||
|
||
|
||
|
||
1$user = User::findOrFail(1);
|
||
|
||
2
|
||
|
||
3$user->name = 'Victoria Faith';
|
||
|
||
4
|
||
|
||
5$user->saveQuietly();
|
||
|
||
|
||
$user = User::findOrFail(1);
|
||
|
||
$user->name = 'Victoria Faith';
|
||
|
||
$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();
|
||
|
||
|
||
$user->deleteQuietly();
|
||
$user->forceDeleteQuietly();
|
||
$user->restoreQuietly();
|
||
|