Laravel 从多对多关系创建一对一关系
Laravel create a 1-1 relationship from a many-many relationship
嗨,我在尝试 return 多对多关系中的单个记录时遇到困难。
所以在我的应用程序中我有 Clubs 和 Addresses 实体。
俱乐部有0、1或n个地址,其中一个可能是主要地址。
地址也可以被其他一些实体使用(如活动、会员等)
我的表格如下:
clubs: id, name
addresses: id, street, city, zip club
club_address: id, club_id, address_id, is_main
我现在可以像这样请求我俱乐部的所有地址:
class Club {
public function addresses()
{
return $this->belongsToMany('Address', 'club_address', 'club_id', 'address_id')->withPivot('is_main'); // club_address
}
}
现在我想要的是在请求俱乐部时获取主地址或空值。
我不能满足于简单地添加 ->wherePivot('is_main', '=', 1) 因为当我想要数组或 null.
我想要这样的东西
class Club {
// Get all the addresses in an array
public function addresses()
{
return $this->belongsToMany('Address', 'club_address', 'club_id', 'address_id')->withPivot('is_main'); // club_address
}
// Get the main address or null
public function address()
{
return $this->addresses()->wherePivot('is_main', '=', 1)->first();
}
}
但问题是我无法预先加载 address
因为它不是 return 关系模型 ...
first()
在 eloquent 模型上 returns 集合 - 即使该集合为零(这基本上就是您所说的)。
不过first()
上了一个合集returnsnull
就是没有第一个...
所以..
class Club {
public function addresses()
{
return $this->belongsToMany('Address', 'club_address', 'club_id', 'address_id')->withPivot('is_main');
}
public function address()
{
// First first is on the model, second first
// is on the collection
return $this->addresses()
->wherePivot('is_main', '=', 1)
->first()
->first();
}
}
注意 这本质上只是一个shorthand技巧。您的属性可以很容易地使用类似这样的东西,并且可能更具可读性:
class Club {
public function addresses()
{
return $this->belongsToMany('Address', 'club_address', 'club_id', 'address_id')->withPivot('is_main');
}
public function address()
{
$record = $this->addresses()
->wherePivot('is_main', '=', 1)
->first();
return count($record) === 0 ? null : $record;
}
}
我找到了一种方法,通过扩展 BelongsToMany 关系 class 并用它们的 BelongsTo 关系等效覆盖两个方法。
但我不会说使用它是谨慎的,但它似乎适合我的使用。
namespace App\Relations;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Query\Expression;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class BelongsToOneFromMany extends BelongsToMany {
/**
* Initialize the relation on a set of models.
*
* @param array $models
* @param string $relation
* @return array
*/
public function initRelation(array $models, $relation)
{
foreach ($models as $model)
{
$model->setRelation($relation, null);
}
return $models;
}
/**
* Match the eagerly loaded results to their parents.
*
* @param array $models
* @param \Illuminate\Database\Eloquent\Collection $results
* @param string $relation
* @return array
*/
public function match(array $models, Collection $results, $relation)
{
$foreign = $this->foreignKey;
$other = $this->otherKey;
// First we will get to build a dictionary of the child models by their primary
// key of the relationship, then we can easily match the children back onto
// the parents using that dictionary and the primary key of the children.
$dictionary = array();
foreach ($results as $result)
{
$dictionary[$result->getAttribute($other)] = $result;
}
// Once we have the dictionary constructed, we can loop through all the parents
// and match back onto their children using these keys of the dictionary and
// the primary key of the children to map them onto the correct instances.
foreach ($models as $model)
{
if (isset($dictionary[$model->$foreign]))
{
$model->setRelation($relation, $dictionary[$model->$foreign]);
}
}
return $models;
}
}
嗨,我在尝试 return 多对多关系中的单个记录时遇到困难。
所以在我的应用程序中我有 Clubs 和 Addresses 实体。
俱乐部有0、1或n个地址,其中一个可能是主要地址。
地址也可以被其他一些实体使用(如活动、会员等)
我的表格如下:
clubs: id, name
addresses: id, street, city, zip club
club_address: id, club_id, address_id, is_main
我现在可以像这样请求我俱乐部的所有地址:
class Club {
public function addresses()
{
return $this->belongsToMany('Address', 'club_address', 'club_id', 'address_id')->withPivot('is_main'); // club_address
}
}
现在我想要的是在请求俱乐部时获取主地址或空值。
我不能满足于简单地添加 ->wherePivot('is_main', '=', 1) 因为当我想要数组或 null.
我想要这样的东西
class Club {
// Get all the addresses in an array
public function addresses()
{
return $this->belongsToMany('Address', 'club_address', 'club_id', 'address_id')->withPivot('is_main'); // club_address
}
// Get the main address or null
public function address()
{
return $this->addresses()->wherePivot('is_main', '=', 1)->first();
}
}
但问题是我无法预先加载 address
因为它不是 return 关系模型 ...
first()
在 eloquent 模型上 returns 集合 - 即使该集合为零(这基本上就是您所说的)。
不过first()
上了一个合集returnsnull
就是没有第一个...
所以..
class Club {
public function addresses()
{
return $this->belongsToMany('Address', 'club_address', 'club_id', 'address_id')->withPivot('is_main');
}
public function address()
{
// First first is on the model, second first
// is on the collection
return $this->addresses()
->wherePivot('is_main', '=', 1)
->first()
->first();
}
}
注意 这本质上只是一个shorthand技巧。您的属性可以很容易地使用类似这样的东西,并且可能更具可读性:
class Club {
public function addresses()
{
return $this->belongsToMany('Address', 'club_address', 'club_id', 'address_id')->withPivot('is_main');
}
public function address()
{
$record = $this->addresses()
->wherePivot('is_main', '=', 1)
->first();
return count($record) === 0 ? null : $record;
}
}
我找到了一种方法,通过扩展 BelongsToMany 关系 class 并用它们的 BelongsTo 关系等效覆盖两个方法。
但我不会说使用它是谨慎的,但它似乎适合我的使用。
namespace App\Relations;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Query\Expression;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class BelongsToOneFromMany extends BelongsToMany {
/**
* Initialize the relation on a set of models.
*
* @param array $models
* @param string $relation
* @return array
*/
public function initRelation(array $models, $relation)
{
foreach ($models as $model)
{
$model->setRelation($relation, null);
}
return $models;
}
/**
* Match the eagerly loaded results to their parents.
*
* @param array $models
* @param \Illuminate\Database\Eloquent\Collection $results
* @param string $relation
* @return array
*/
public function match(array $models, Collection $results, $relation)
{
$foreign = $this->foreignKey;
$other = $this->otherKey;
// First we will get to build a dictionary of the child models by their primary
// key of the relationship, then we can easily match the children back onto
// the parents using that dictionary and the primary key of the children.
$dictionary = array();
foreach ($results as $result)
{
$dictionary[$result->getAttribute($other)] = $result;
}
// Once we have the dictionary constructed, we can loop through all the parents
// and match back onto their children using these keys of the dictionary and
// the primary key of the children to map them onto the correct instances.
foreach ($models as $model)
{
if (isset($dictionary[$model->$foreign]))
{
$model->setRelation($relation, $dictionary[$model->$foreign]);
}
}
return $models;
}
}