Laravel从许多关系中创建了一个1-1关系

时间:2015-04-16 10:38:41

标签: php laravel eloquent relationship

嗨,我正在努力尝试从多对多的关系中返回一条记录。

所以在我的应用程序中,我有俱乐部和地址实体。

分会有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时它仍然返回一个1或0元素的数组。

我喜欢这样的东西

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因为它没有返回一个关系模型......

2 个答案:

答案 0 :(得分:0)

eloquent模型上的

first()返回一个集合 - 即使该集合为零(这是你基本上所说的)。

但是集合上的first()返回null是没有第一个......

所以..

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(); 
    }
}

注意这实际上只是一个简写技巧。您的属性可以像以下一样轻松,可能更具可读性:

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;
    }
}

答案 1 :(得分:0)

我找到了一种方法来扩展BelongsToMany Relation类并使用它们的BelongsTo Relation等效覆盖两个方法。

但我不会说使用它是谨慎的,但对我的用途似乎没问题。

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;
    }

}