使用 Laravel Lift 提升 Eloquent 模型
发布日期 作者 Wendell Adriel
Lift 是一个用于提升 Laravel 中 Eloquent 模型的包。
它允许你在 Eloquent 模型 中创建与你的表模式匹配的公共属性。这使得你的模型在任何 IDE 中都更容易阅读和使用。
它提供了一种简单的方法来设置你的模型,通过使用 PHP 8 的属性,重点关注简单性和易用性。
该包依赖于 Eloquent Events 才能正常工作。这意味着该包可以轻松地集成到你的项目中,而无需任何重大更改(除非你已关闭事件触发)。
在本篇文章中,让我们深入研究 Lift 并了解它提供的所有功能。
安装 Laravel Lift
你可以通过 Composer 安装该包
composer require wendelladriel/laravel-lift
要开始使用 Lift,你需要将 Lift
特性添加到你的 Eloquent 模型 中,然后你就可以开始使用了。
use Illuminate\Database\Eloquent\Model;use WendellAdriel\Lift\Lift; final class Product extends Model{ use Lift;}
功能
默认情况下,当你将 Lift
特性添加到你的 Eloquent 模型 中时,你可以在模型上创建公共属性,使它们更容易理解并在任何 IDE 中使用。
use Illuminate\Database\Eloquent\Model;use WendellAdriel\Lift\Lift; final class Product extends Model{ use Lift; public $id; public $name; public $price;}
当你开始使用该包提供的属性时,魔法就会发生。
类属性
DB 属性
Lift 提供了一个 DB
属性,你可以使用它来定义模型的连接、表和时间戳。
没有 Lift
use Illuminate\Database\Eloquent\Model; final class Product extends Model{ public $timestamps = false; protected $connection = 'mysql'; protected $table = 'custom_products_table'; // ...}
使用 Lift
use Illuminate\Database\Eloquent\Model;use WendellAdriel\Lift\Attributes\DB;use WendellAdriel\Lift\Lift; #[DB(connection: 'mysql', table: 'custom_products_table', timestamps: false)]final class Product extends Model{ use Lift; // ...}
关系属性
Lift 提供属性来定义模型之间的关系,因此,你无需使用方法来定义它们,而是可以使用属性来定义它们。所有关系属性都接受与方法相同的参数。
没有 Lift
// Post.php use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\HasMany; final class Post extends Model{ public function comments(): HasMany { return $this->hasMany(Comment::class); } // ...} // Comment.php use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\BelongsTo; final class Comment extends Model{ public function post(): BelongsTo { return $this->belongsTo(Post::class); } // ...}
使用 Lift
// Post.php use Illuminate\Database\Eloquent\Model;use WendellAdriel\Lift\Attributes\Relations\HasMany;use WendellAdriel\Lift\Lift; #[HasMany(Comment::class)]final class Post extends Model{ use Lift; // ...} // Comment.php use Illuminate\Database\Eloquent\Model;use WendellAdriel\Lift\Attributes\Relations\BelongsTo;use WendellAdriel\Lift\Lift; #[BelongsTo(Post::class)]final class Comment extends Model{ use Lift; // ...}
你可以查看 文档中 所有可用的关系属性。
这些关系的工作方式与使用方法定义它们的方式相同。
属性属性
Cast 属性
Lift 提供了一个 Cast
属性,你可以使用它来定义模型属性的类型转换。除了类型转换值之外,它还允许你为你的属性进行类型声明。
没有 Lift
use Illuminate\Database\Eloquent\Model; final class Product extends Model{ protected $casts = [ 'id' => 'int', 'name' => 'string', 'price' => 'float', 'active' => 'boolean', 'expires_at' => 'immutable_datetime', ];}
使用 Lift
use Carbon\CarbonImmutable;use Illuminate\Database\Eloquent\Model;use WendellAdriel\Lift\Attributes\Cast;use WendellAdriel\Lift\Lift; final class Product extends Model{ use Lift; #[Cast('int')] public int $id; #[Cast('string')] public string $name; #[Cast('float')] public float $price; #[Cast('boolean')] public bool $active; #[Cast('immutable_datetime')] public CarbonImmutable $expires_at;}
Column 属性
Lift 提供了一个 Column
属性,你可以使用它来定制模型属性的列名并为它们定义默认值。
use Illuminate\Database\Eloquent\Model;use WendellAdriel\Lift\Attributes\Cast;use WendellAdriel\Lift\Attributes\Column;use WendellAdriel\Lift\Lift; final class Product extends Model{ use Lift; #[Cast('int')] public int $id; #[Cast('string')] #[Column('product_name')] public string $name; #[Cast('float')] #[Column(name: 'product_price', default: 0.0] public float $price;}
在上面的示例中,name
属性将映射到 product_name
列,而 price
属性将映射到 product_price
列,默认值为 0.0
。
你甚至可以将函数名传递给默认值,该函数将在属性保存到数据库时被调用。
use Illuminate\Database\Eloquent\Model;use WendellAdriel\Lift\Attributes\Cast;use WendellAdriel\Lift\Attributes\Column;use WendellAdriel\Lift\Lift; final class Product extends Model{ use Lift; #[Cast('int')] public int $id; #[Cast('string')] #[Column('product_name')] public string $name; #[Cast('float')] #[Column(name: 'product_price', default: 0.0] public float $price; #[Cast('float')] #[Column(default: 'generatePromotionalPrice')] public float $promotional_price; public function generatePromotionalPrice(): float { return $this->price * 0.8; }}
Fillable 属性
当使用 Lift
特性时,模型的所有属性都将被设置为 guarded。你可以使用 Fillable
属性来定义哪些属性可以进行批量赋值。
没有 Lift
use Illuminate\Database\Eloquent\Model; final class Product extends Model{ protected $fillable = [ 'name', 'price', ]; protected $casts = [ 'id' => 'int', 'name' => 'string', 'price' => 'float', ];}
使用 Lift
use Illuminate\Database\Eloquent\Model;use WendellAdriel\Lift\Attributes\Cast;use WendellAdriel\Lift\Attributes\Fillable;use WendellAdriel\Lift\Lift; final class Product extends Model{ use Lift; #[Cast('int')] public int $id; #[Fillable] #[Cast('string')] public string $name; #[Fillable] #[Cast('float')] public float $price;}
Hidden 属性
Lift 提供了一个 Hidden
属性,你可以使用它来隐藏模型转换为数组或 JSON 时不希望显示的属性。
没有 Lift
use Illuminate\Database\Eloquent\Model; final class Product extends Model{ protected $fillable = [ 'name', 'price', 'active', ]; protected $casts = [ 'id' => 'int', 'name' => 'string', 'price' => 'float', 'active' => 'boolean', ]; protected $hidden = [ 'active', ];}
使用 Lift
use Illuminate\Database\Eloquent\Model;use WendellAdriel\Lift\Attributes\Cast;use WendellAdriel\Lift\Attributes\Fillable;use WendellAdriel\Lift\Attributes\Hidden;use WendellAdriel\Lift\Lift; final class Product extends Model{ use Lift; #[Cast('int')] public int $id; #[Fillable] #[Cast('string')] public string $name; #[Fillable] #[Cast('float')] public float $price; #[Hidden] #[Fillable] #[Cast('boolean')] public bool $active;}
Immutable 属性
Lift 提供了一个 Immutable
属性,你可以使用它来使属性不可变。这意味着,一旦模型被创建,该属性就无法更改。如果你尝试更改它,将会抛出一个 WendellAdriel\Lift\Exceptions\ImmutablePropertyException
异常。
use Illuminate\Database\Eloquent\Model;use WendellAdriel\Lift\Attributes\Cast;use WendellAdriel\Lift\Attributes\Fillable;use WendellAdriel\Lift\Attributes\Immutable;use WendellAdriel\Lift\Lift; final class Product extends Model{ use Lift; #[Cast('int')] public int $id; #[Immutable] #[Fillable] #[Cast('string')] public string $name;} $product = Product::query()->create([ 'name' => 'Product 1',]); $product->name = 'Product 2';$product->save(); // Throws an WendellAdriel\Lift\Exceptions\ImmutablePropertyException
PrimaryKey 属性
Lift 提供了一个 PrimaryKey
属性,你可以使用它来定制模型的主键。
没有 Lift
use Illuminate\Database\Eloquent\Model; final class Product extends Model{ public $incrementing = false; protected $primaryKey = 'uuid'; protected $keyType = 'string'; // ...}
使用 Lift
use Illuminate\Database\Eloquent\Model;use WendellAdriel\Lift\Attributes\Cast;use WendellAdriel\Lift\Attributes\PrimaryKey;use WendellAdriel\Lift\Lift; final class Product extends Model{ use Lift; #[PrimaryKey(type: 'string', incrementing: false)] #[Cast('string')] public string $uuid; // ...}
Rules 属性
Lift 提供了一个 Rules
属性,你可以使用它来定义模型属性的验证规则。
验证规则的设置方式与你在 Laravel Form Request 中设置的方式相同,你甚至可以为每个规则设置自定义消息。
⚠️ 仅在保存模型(创建或更新)时才会验证规则
use Illuminate\Database\Eloquent\Model;use WendellAdriel\Lift\Attributes\Cast;use WendellAdriel\Lift\Attributes\Fillable;use WendellAdriel\Lift\Attributes\Rules;use WendellAdriel\Lift\Lift; final class Product extends Model{ use Lift; #[Cast('int')] public int $id; #[Fillable] #[Cast('string')] #[Rules(['required', 'string', 'max:255'])] public string $name; #[Fillable] #[Cast('float')] #[Rules(['required', 'numeric', 'min:0.0'])] public float $price; #[Fillable] #[Cast('boolean')] #[Rules(rules: ['required', 'boolean'], messages: ['required' => 'You must set the active status for the product'])] public bool $active;}
Watch 属性
默认情况下,Eloquent 已经在创建、更新、删除等操作时触发了事件。但那是一个通用的事件,有时,你需要在属性更改时触发一个特定的事件。这就是 Watch
属性发挥作用的地方。
你可以定义一个自定义事件,当属性更改时会触发该事件。该事件将接收更新后的模型实例作为参数。
// Product.php use Illuminate\Database\Eloquent\Model;use WendellAdriel\Lift\Attributes\Cast;use WendellAdriel\Lift\Attributes\Fillable;use WendellAdriel\Lift\Attributes\Watch;use WendellAdriel\Lift\Lift; final class Product extends Model{ use Lift; #[Cast('int')] public int $id; #[Fillable] #[Cast('string')] public string $name; #[Fillable] #[Cast('float')] #[Watch(PriceChangedEvent::class)] public float $price; #[Fillable] #[Cast('boolean')] public bool $active;} // PriceChangedEvent.php final class PriceChangedEvent{ use Dispatchable, InteractsWithSockets, SerializesModels; public function __construct( public Product $product, ) { }}
方法
除了该包提供的所有属性之外,它还提供了一些方法,你可以使用这些方法来获取有关模型的更多信息。
customColumns()
它将返回一个包含你在模型中定义的所有自定义列的数组。
use Illuminate\Database\Eloquent\Model;use WendellAdriel\Lift\Attributes\Cast;use WendellAdriel\Lift\Attributes\Column;use WendellAdriel\Lift\Lift; final class Product extends Model{ use Lift; #[Cast('int')] public int $id; #[Cast('string')] #[Column('product_name')] public string $name; #[Cast('float')] #[Column(name: 'product_price', default: 0.0] public float $price;} Product::customColumns(); // WILL RETURN[ 'name' => 'product_name', 'price' => 'product_price',]
defaultValues()
它将返回一个包含所有定义了默认值的属性的数组。如果默认值是一个函数,则将返回函数名,而不是函数结果,因为这是一个静态调用。
use Illuminate\Database\Eloquent\Model;use WendellAdriel\Lift\Attributes\Cast;use WendellAdriel\Lift\Attributes\Column;use WendellAdriel\Lift\Lift; final class Product extends Model{ use Lift; #[Cast('int')] public int $id; #[Cast('string')] #[Column('product_name')] public string $name; #[Cast('float')] #[Column(name: 'product_price', default: 0.0] public float $price; #[Cast('float')] #[Column(default: 'generatePromotionalPrice')] public float $promotional_price; public function generatePromotionalPrice(): float { return $this->price * 0.8; }} Product::defaultValues(); // WILL RETURN[ 'price' => 0.0, 'promotional_price' => 'generatePromotionalPrice',]
immutableProperties()
它将返回一个包含所有不可变属性的数组。
use Illuminate\Database\Eloquent\Model;use WendellAdriel\Lift\Attributes\Cast;use WendellAdriel\Lift\Attributes\Fillable;use WendellAdriel\Lift\Attributes\Immutable;use WendellAdriel\Lift\Lift; final class Product extends Model{ use Lift; #[Cast('int')] public int $id; #[Immutable] #[Fillable] #[Cast('string')] public string $name;} Product::immutableProperties(); // WILL RETURN[ 'name',]
validationMessages()
它将返回一个包含你在模型中定义的所有验证消息的数组。
use Illuminate\Database\Eloquent\Model;use WendellAdriel\Lift\Attributes\Cast;use WendellAdriel\Lift\Attributes\Fillable;use WendellAdriel\Lift\Attributes\Rules;use WendellAdriel\Lift\Lift; final class Product extends Model{ use Lift; #[Cast('int')] public int $id; #[Fillable] #[Cast('string')] #[Rules(['required', 'string', 'max:255'])] public string $name; #[Fillable] #[Cast('float')] #[Rules(['required', 'numeric', 'min:0.0'])] public float $price; #[Fillable] #[Cast('boolean')] #[Rules(rules: ['required', 'boolean'], messages: ['required' => 'You must set the active status for the product'])] public bool $active;} Product::validationMessages(); // WILL RETURN[ 'name' => [], 'price' => [], 'active' => [ 'required' => 'You must set the active status for the product', ],]
validationRules()
它将返回一个数组,其中包含您在模型中定义的所有验证规则。
use Illuminate\Database\Eloquent\Model;use WendellAdriel\Lift\Attributes\Cast;use WendellAdriel\Lift\Attributes\Fillable;use WendellAdriel\Lift\Attributes\Rules;use WendellAdriel\Lift\Lift; final class Product extends Model{ use Lift; #[Cast('int')] public int $id; #[Fillable] #[Cast('string')] #[Rules(['required', 'string', 'max:255'])] public string $name; #[Fillable] #[Cast('float')] #[Rules(['required', 'numeric', 'min:0.0'])] public float $price; #[Fillable] #[Cast('boolean')] #[Rules(rules: ['required', 'boolean'], messages: ['required' => 'You must set the active status for the product'])] public bool $active;} Product::validationRules(); // WILL RETURN[ 'name' => ['required', 'string', 'max:255'], 'price' => ['required', 'numeric', 'min:0.0'], 'active' => ['required', 'boolean'],]
watchedProperties()
它将返回一个数组,其中包含所有定义了自定义事件的属性。
use Illuminate\Database\Eloquent\Model;use WendellAdriel\Lift\Attributes\Cast;use WendellAdriel\Lift\Attributes\Fillable;use WendellAdriel\Lift\Attributes\Watch;use WendellAdriel\Lift\Lift; final class Product extends Model{ use Lift; #[Cast('int')] public int $id; #[Fillable] #[Cast('string')] public string $name; #[Fillable] #[Cast('float')] #[Watch(PriceChangedEvent::class)] public float $price; #[Fillable] #[Cast('boolean')] public bool $active;} Product::watchedProperties(); // WILL RETURN[ 'price' => PriceChangedEvent::class,]
结论
Lift 是一个将Doctrine、Spring 和Entity Framework 等工具的一些功能引入Eloquent 的软件包。
它通过利用 PHP 8 的属性,使您的模型更易于阅读和理解,并具有更简洁的外观。