我一直在尝试在 Laravel 中对
ShapeContainer
实体和具有独特属性的不同形状之间的关系进行建模,但有一个通用的 Shape
接口(具有 getArea
和 getPerimeter
方法)。我已经阅读了 laravel 文档中的示例(posts
、videos
、comments
),但在该示例中,子实体 (Comment
) 可以属于不同类型的父实体。就我而言,我希望父实体(ShapeContainer
)能够处理不同类型的子实体(Circle,
Rectangle
等)。
我想要的最终结果是这样的:
$shapeContainer = ShapeContainer::find(1);
$shapes = $shapeContainer->shapes()
foreach($shapes as $shape) {
$area = $shape->getArea();
}
我现在设法实现这一目标的方法是在两者之间添加一个实体,比如枢轴
class Shape extends Model
{
public function shapeable()
{
return $this->morphTo('shapeable');
}
public function shapeConatiner()
{
return $this->belongsTo(ShapeContainer::class);
}
}
与相应的表字段
shape_container_id # Reference to the shape container
shapeable_type # square/circle
shapeble_id # Reference to the ID of the corresponding shape model.
所以在代码中我可以做到
$shapeContainer = ShapeContainer::find(1);
$shapes = $shapeContainer->shapes()
foreach($shapes as $shape) {
$area = $shape->shapable->getArea();
}
我想知道这是正确的方法,因为我没有在 laravel 文档中识别出与我的用例类似的任何内容,并且在两者之间建立一个完整的模型来解释这种关系似乎很笨拙。是否有可能保留该数据透视表,但简化界面,以便使用模型的开发人员不必担心或看到
shapeable()
数据透视表?
听起来您需要在创建模型时将模型转换为其即时类型,然后每个实例都可以有自己的版本
getArea
尝试在内部实现类似的东西
Shape
:
// Override the newFromBuilder method
public function newFromBuilder($attributes = [], $connection = null) {
$class = $attributes-> shapeable_type ?? self::class;
if (class_exists($class)) {
$model = (new $class)->newInstance((array) $attributes, true);
} else {
// If the class doesn't exist, fallback to the parent
$model = parent::newFromBuilder($attributes, $connection);
}
$model->setRawAttributes((array) $attributes);
return $model;
}