phaza / single-table-inheritance
单表继承特性
Requires
- php: >=5.4.0
- illuminate/database: ~5.0
- illuminate/support: ~5.0
Requires (Dev)
- mockery/mockery: 0.9.*
- orchestra/testbench: ~3.0
- phpunit/phpunit: 4.5.*
README
信用
此代码是从Nanigans/single-table-inheritance分叉的。我已经更新了它,以便与Laravel 5兼容
单表继承是一个针对Laravel 5.0.6+ Eloquent模型的特性,允许多个模型存储在同一个数据库表中。我们支持一些关键特性
- 实现为一个特性,以便与其他特性如Laravel的
SoftDeletingTrait
或优秀的Validating兼容,而不需要复杂的Eloquent模型子类。 - 允许任意类层次结构,而不仅仅是两层父子关系。
- 可自定义用于存储模型类型的数据库列名。
- 可自定义存储在数据库中的模型类型字符串。(与强制使用完全限定模型类名相对)
- 允许数据库行不映射到已知的模型类型。它们永远不会在查询中返回。
安装
只需将包添加到您的composer.json
文件中,然后运行composer update
。
"phaza/single-table-inheritance": "1.0.*"
或者进入包含composer.json
文件的项目目录,并输入
composer require "phaza/single-table-inheritance:1.0.*"
概述
开始使用单表继承特性非常简单。添加约束,并在您的模型中添加一些属性。一个包含两个子类Truck
和Car
的Vehicle
超级类的完整示例如下
use Phaza\SingleTableInheritance\SingleTableInheritanceTrait; class Vehicle extends Eloquent { use SingleTableInheritanceTrait; protected $table = "vehicles"; protected static $singleTableTypeField = 'type'; protected static $singleTableSubclasses = ['Car', 'Truck']; } class Car extends Vehicle { protected static $singleTableType = 'car'; } class Truck extends Vehicle { protected static $singleTableType = 'truck'; }
在您的类中需要定义四个必需的属性
定义数据库表
在根模型中将protected
属性$table
设置为定义用于存储所有类的数据库表。
注意:即使您正在使用根类的默认值(即Vehicle
类的'vehicles'表),这也需要这样做,以便子类继承相同的设置,而不是默认为其自己的表名。
定义存储类类型的数据库列
在根模型中设置protected static
属性$singleTableTypeField
,以定义用于存储每个类类型的数据库列。
定义子类
在根模型和每个分支模型中定义protected static
属性$singleTableSubclasses
,以定义哪些子类属于类层次结构。
定义类类型的值
在每个具体类中设置protected static
属性$singleTableType
,以定义将存储在$singleTableTypeField
数据库列中的字符串值。
多层类层次结构
在类层次结构中有很多层并不罕见。通过在每个级别声明子类,很容易定义这种结构。例如,假设您有一个包含两个子类Bike和MotorVehicle的Vehicle超级类。MotorVehicle随后有两个子类Car和Truck。您将定义类如下
use Phaza\SingleTableInheritance\SingleTableInheritanceTrait; class Vehicle extends Eloquent { use SingleTableInheritanceTrait; protected $table = "vehicles"; protected static $singleTableTypeField = 'type'; protected static $singleTableSubclasses = ['MotorVehicle', 'Bike']; } class MotorVehicle extends Vehicle { protected static $singleTableSubclasses = ['Car', 'Truck']; } class Car extends MotorVehicle { protected static $singleTableType = 'car'; } class Truck extends MotorVehicle { protected static $singleTableType = 'truck'; } class Bike extends Vehicle { protected static $singleTableType = 'bike'; }
定义哪些属性是持久化的
在允许获取和设置属性方面,Eloquent 非常宽容。没有机制来声明模型支持的属性集合。如果你错误地使用了属性,通常会在尝试对不存在的列进行插入或更新操作时导致 SQL 错误。默认情况下,SingleTableInheritanceTrait 也以相同的方式操作。然而,当在单个表中存储类层次结构时,通常存在不适用于层次结构中所有类的数据库列。Eloquent 将值存储在这些列中,这使得编写错误变得容易得多。在这种情况下,SingleTableInheritanceTrait 允许你定义哪些属性是持久化的。持久化属性的集合也继承自父类。
class Vehicle extends Eloquent { protected static $persisted = ['color'] } class MotorVehicle extends Vehicle { protected static $persisted = ['fuel'] }
在上面的例子中,类 Vehicle
将持久化属性 color
,而类 MotorVehicle
将持久化 color
和 fuel
属性。
自动持久化属性
为了方便起见,模型主键和任何日期都会自动添加到持久化属性列表中。
BelongsTo 关联
如果你正在限制持久化属性,并且你的模型有 BelongsTo 关联,那么你必须包含 BelongsTo 关联的外键列。例如
class Vehicle extends Eloquent { protected static $persisted = ['color', 'owner_id']; public function owner() { return $this->belongsTo('User', 'owner_id'); } }
遗憾的是,没有有效的方法来自动检测 BelongsTo 外键。
对无效属性抛出异常
默认情况下,SingleTableINheritanceTrait 会静默处理无效属性。在保存模型时忽略非持久化属性,在从构建器查询中填充模型时忽略非持久化列。但是,你可以通过将 $throwInvalidAttributeExceptions
属性设置为 true,来强制在两种情况下遇到无效属性时抛出异常。
/** * Whether the model should throw an InvalidAttributesException if non-persisted * attributes are encoutered when saving or hydrating a model. * If not set, it will default to false. * * @var boolean */ protected static $throwInvalidAttributeExceptions = true;