hamid09430 / direct-nested-relation-object
Laravel Eloquent HasManyThrough 关系,支持无限层级
Requires
- php: >=7.0
- illuminate/database: ^5.5.25
Requires (Dev)
- phpunit/phpunit: ~6.0
This package is not auto-updated.
Last update: 2024-09-29 05:55:20 UTC
README
简介
这个 HasManyThrough
扩展版本允许与无限中间模型建立关系。
它支持 多对多 和 多态 关系以及所有可能的组合。
支持 Laravel 5.5.29+。
安装
composer require hamid09430/direct-nested-relation-object:1.1
用法
HasMany
使用 文档示例 并增加一个层级
Country
→ has many → User
→ has many → Post
→ has many → Comment
class Country extends Model { use \Staudenmeir\EloquentHasManyDeep\HasRelationships; public function comments() { return $this->hasManyDeep('App\Comment', ['App\User', 'App\Post']); } }
与 hasManyThrough()
一样,hasManyDeep()
的第一个参数是相关模型。第二个参数是一个数组,包含从远端父模型(定义关系的模型)到相关模型的中间模型。
默认情况下,hasManyDeep()
使用 Eloquent 的外键和本地键约定。您还可以指定自定义外键作为第三个参数,并指定自定义本地键作为第四个参数
class Country extends Model { use \Staudenmeir\EloquentHasManyDeep\HasRelationships; public function comments() { return $this->hasManyDeep( 'App\Comment', ['App\User', 'App\Post'], // Intermediate models, beginning at the far parent (Country). [ 'country_id', // Foreign key on the "users" table. 'user_id', // Foreign key on the "posts" table. 'post_id' // Foreign key on the "comments" table. ], [ 'id', // Local key on the "countries" table. 'id', // Local key on the "users" table. 'id' // Local key on the "posts" table. ] ); } }
您可以使用 null
代替默认键
class Country extends Model { use \Staudenmeir\EloquentHasManyDeep\HasRelationships; public function comments() { return $this->hasManyDeep('App\Comment', ['App\User', 'App\Post'], [null, 'custom_user_id']); } }
BelongsToMany
您可以在中间路径中包含 BelongsToMany
关系。
使用 文档示例 并增加一个层级
User
→ belongs to many → Role
→ has many → Permission
将连接表添加到中间模型中
class User extends Model { use \Staudenmeir\EloquentHasManyDeep\HasRelationships; public function permissions() { return $this->hasManyDeep('App\Permission', ['role_user', 'App\Role']); } }
如果您指定了自定义键,请记住在连接表的“右侧”交换外键和本地键
class User extends Model { use \Staudenmeir\EloquentHasManyDeep\HasRelationships; public function permissions() { return $this->hasManyDeep( 'App\Permission', ['role_user', 'App\Role'], // Intermediate models and tables, beginning at the far parent (User). [ 'user_id', // Foreign key on the "role_user" table. 'id', // Foreign key on the "roles" table (local key). 'role_id' // Foreign key on the "permissions" table. ], [ 'id', // Local key on the "users" table. 'role_id', // Local key on the "role_user" table (foreign key). 'id' // Local key on the "roles" table. ] ); } }
MorphMany
您可以在中间路径中包含 MorphMany
关系。
使用 文档示例 并增加一个层级
User
→ has many → Post
→ morph many → Comment
将多态外键指定为数组,从 *_type
列开始
class User extends Model { use \Staudenmeir\EloquentHasManyDeep\HasRelationships; public function postComments() { return $this->hasManyDeep( 'App\Comment', ['App\Post'], [null, ['commentable_type', 'commentable_id']] ); } }
MorphToMany
您可以在中间路径中包含 MorphToMany
关系。
使用 文档示例 并增加一个层级
User
→ has many → Post
→ morph to many → Tag
将连接表添加到中间模型中,并将多态外键指定为数组,从 *_type
列开始
class User extends Model { use \Staudenmeir\EloquentHasManyDeep\HasRelationships; public function postTags() { return $this->hasManyDeep( 'App\Tag', ['App\Post', 'taggables'], [null, ['taggable_type', 'taggable_id'], 'id'], [null, null, 'tag_id'] ); } }
请记住在连接表的“右侧”交换外键和本地键
MorphedByMany
您可以在中间路径中包含 MorphedByMany
关系。
使用 文档示例 并增加一个层级
Tag
→ morphed by many → Post
→ has many → Comment
将连接表添加到中间模型中,并将多态本地键指定为数组,从 *_type
列开始
class Tag extends Model { use \Staudenmeir\EloquentHasManyDeep\HasRelationships; public function postComments() { return $this->hasManyDeep( 'App\Comment', ['taggables', 'App\Post'], [null, 'id'], [null, ['taggable_type', 'taggable_id']] ); } }
BelongsTo
您可以在中间路径中包含 BelongsTo
关系
Tag
→ morphed by many → Post
→ belongs to → User
交换外键和本地键
class Tag extends Model { use \Staudenmeir\EloquentHasManyDeep\HasRelationships; public function postAuthors() { return $this->hasManyDeep( 'App\User', ['taggables', 'App\Post'], [null, 'id', 'id'], [null, ['taggable_type', 'taggable_id'], 'user_id'] ); } }
现有关系
在复杂情况下,您可以通过链式调用现有关系来定义 HasManyDeep
关系
class Country extends Model { use \Staudenmeir\EloquentHasManyDeep\HasRelationships; public function comments() { return $this->hasManyDeepFromRelations($this->posts(), (new Post)->comments()); } public function posts() { return $this->hasManyThrough('App\Post', 'App\User'); } } class Post extends Model { public function comments() { return $this->hasMany('App\Comment'); } }
HasOneDeep
如果只想检索一个相关实例,请使用 HasOneDeep
关系
class Country extends Model { use \Staudenmeir\EloquentHasManyDeep\HasRelationships; public function latestComment() { return $this->hasOneDeep('App\Comment', ['App\User', 'App\Post']) ->latest('comments.created_at'); } }
中间和关联数据
使用 withIntermediate()
来检索中间表的属性
public function comments() { return $this->hasManyDeep('App\Comment', ['App\User', 'App\Post']) ->withIntermediate('App\Post'); } foreach ($country->comments as $comment) { // $comment->post->title }
默认情况下,这将检索表的所有列。请注意,这将执行一个单独的查询来获取列列表。
您可以将选择的列作为第二个参数指定
public function comments() { return $this->hasManyDeep('App\Comment', ['App\User', 'App\Post']) ->withIntermediate('App\Post', ['id', 'title']); }
作为第三个参数,您可以指定一个自定义访问器
public function comments() { return $this->hasManyDeep('App\Comment', ['App\User', 'App\Post']) ->withIntermediate('App\Post', ['id', 'title'], 'accessor'); } foreach ($country->comments as $comment) { // $comment->accessor->title }
如果您从多个表中检索数据,您可以使用嵌套访问器
public function comments() { return $this->hasManyDeep('App\Comment', ['App\User', 'App\Post']) ->withIntermediate('App\Post') ->withIntermediate('App\User', ['*'], 'post.user'); } foreach ($country->comments as $comment) { // $comment->post->title // $comment->post->user->name }
对于 BelongsToMany
和 MorphToMany
/MorphedByMany
关系的交叉表,请使用 withPivot()
public function permissions() { return $this->hasManyDeep('App\Permission', ['role_user', 'App\Role']) ->withPivot('role_user', ['expires_at']); } foreach ($user->permissions as $permission) { // $permission->role_user->expires_at }
您可以将自定义交叉模型作为第三个参数,并将自定义访问器作为第四个参数指定
public function permissions() { return $this->hasManyDeep('App\Permission', ['role_user', 'App\Role']) ->withPivot('role_user', ['expires_at'], 'App\RoleUserPivot', 'pivot'); } foreach ($user->permissions as $permission) { // $permission->pivot->expires_at }
表别名
如果您的关联路径包含相同的模型多次,您可以指定一个表别名
class Post extends Model { use \Staudenmeir\EloquentHasManyDeep\HasRelationships; public function childComments() { return $this->hasManyDeep('App\Comment', ['App\Comment as alias'], [null, 'parent_id']); } }
在使用别名的模型中,请使用 HasTableAlias
特性
class Comment extends Model { use \Staudenmeir\EloquentHasManyDeep\HasTableAlias; }
软删除
默认情况下,软删除的中间模型将不包括在结果中。使用 withTrashed()
来包含它们
class Country extends Model { use \Staudenmeir\EloquentHasManyDeep\HasRelationships; public function comments() { return $this->hasManyDeep('App\Comment', ['App\User', 'App\Post']) ->withTrashed('users.deleted_at'); } } class User extends Model { use SoftDeletes; }