oxyaction / yii2-polymorphic-relation-behavior
建立多态关系
Requires
- php: >=5.4.0
Requires (Dev)
- phpunit/phpunit: *
- yiisoft/yii2: ^2.0.0
Suggests
- yiisoft/yii2: ^2.0.0
This package is not auto-updated.
Last update: 2024-09-14 20:04:20 UTC
README
此行为有助于轻松建立多态行为。忘掉你在存储中无尽的字典表。
问题
通常,你的系统中有些实体与多个实体相关联。例如,Comment
实体可以属于 Article
、Photo
、Post
等。你可以为每个实体创建一个评论表(ArticleComment
、PhotoComment
、PostComment
),但这种方法并不好,并且完全不遵循DRY原则。
最佳解决方案是创建单个 Comment
实体表并建立多态关系。comment
表需要有一个 type
列,用于指示评论属于哪个实体类型,以及一个 external_id
列,用作外键列。
class Article extends ActiveRecord { const ARTICLE = 1; public function behaviors() { return [ 'polymorphic' => [ 'class' => RelatedPolymorphicBehavior::className(), 'polyRelations' => [ 'comments' => Comment::className() ], 'polymorphicType' => self::TYPE_ARTICLE ] ]; } } class Photo extends ActiveRecord { const PHOTO = 2; public function behaviors() { return [ 'polymorphic' => [ 'class' => RelatedPolymorphicBehavior::className(), 'polyRelations' => [ 'comments' => Comment::className() ], 'polymorphicType' => self::TYPE_PHOTO ] ]; } }
然后你可以像往常一样查询关系
$article->comments;
$photo->comments;
选项
拥有多个
简写
... public function behaviors() { return [ 'polymorphic' => [ 'class' => RelatedPolymorphicBehavior::className(), 'polyRelations' => [ 'comments' => Comment::className() ], 'polymorphicType' => 'article' ] ]; } ...
相同于
public function behaviors() { return [ 'polymorphic' => [ 'class' => RelatedPolymorphicBehavior::className(), 'polyRelations' => [ 'comments' => [ 'type' => RelatedPolymorphicBehavior::HAS_MANY, 'class' => Comment::className(), 'pkColumnName' => 'id', 'foreignKeyColumnName' => 'external_id', 'typeColumnName' => 'type', 'deleteRelated' => false, ] ], 'polymorphicType' => 'article' ] ] }
多对多
我们通常需要以多对多的方式建立多态关系。在这种情况下,type
和 external_id
列将位于连接表中。
public function behaviors() { return [ 'polymorphic' => [ 'class' => RelatedPolymorphicBehavior::className(), 'polyRelations' => [ 'tags' => [ 'type' => RelatedPolymorphicBehavior::MANY_MANY, 'class' => Tag::className(), 'viaTable' => 'taggable_tag', ] ], 'polymorphicType' => 'article' ] ] }
所有可用选项
public function behaviors() { return [ 'polymorphic' => [ 'class' => RelatedPolymorphicBehavior::className(), 'polyRelations' => [ 'tags' => [ 'type' => RelatedPolymorphicBehavior::MANY_MANY, 'class' => Tag::className(), 'viaTable' => 'taggable_tag', 'pkColumnName' => 'id', 'foreignKeyColumnName' => 'external_id', 'otherKeyColumnName' => 'tag_id', 'typeColumnName' => 'type', 'relatedPkColumnName' => 'id', ] ], 'polymorphicType' => 'photo' ] ] }
某些选项可以设置在每个行为或每个关系级别。例如,上面的示例中设置的 polymorphicType
是在行为级别设置的,而 typeColumnName
是在关系级别设置的。如果在行为级别设置了选项,则不需要为多个关系重复设置它,而关系选项将具有优先权。
最终示例
class Article extends ActiveRecord { public function behaviors() { return [ 'polymorphic' => [ 'class' => RelatedPolymorphicBehavior::className(), 'polyRelations' => [ 'tags' => [ 'type' => RelatedPolymorphicBehavior::MANY_MANY, 'class' => Tag::className(), 'viaTable' => 'taggable_tag', ], 'images' => [ 'type' => RelatedPolymorphicBehavior::HAS_MANY, 'class' => Image::className(), ], 'comments' => [ 'type' => RelatedPolymorphicBehavior::HAS_MANY, 'class' => Comment::className(), ], ], 'polymorphicType' => 'article', 'pkColumnName' => 'ID', 'foreignKeyColumnName' => 'some_external_id', 'typeColumnName' => 'entity_type', ] ] } }
这假设 taggable_tag
、image
和 comment
表都有 some_external_id
和 entity_type
列,对于 Article
实体,它将填充 article
值,而 Article
的主键列名为 ID
。
警告
由于多态目标实体的 external_id
链接到多个实体,因此不能使用外键约束,需要在应用程序级别检查数据一致性。