如何获得多对多关系的ID?

时间:2015-04-12 07:34:12

标签: php laravel laravel-4 eloquent

我有两个模型,FooBar

class Foo extends Eloquent {

    protected $table = 'foos';
    protected $fillable = array('name');
    public $timestamps = false;

    public function bars() {
       return $this->belongsToMany('bar','foos_bars');
    }
}
class Bar extends Eloquent {

    protected $table = 'bars';
    protected $fillable = array('name');
    public $timestamps = false;

    public function foos() {
        return $this->belongsToMany('foo','foos_bars');
    }
}

我试图让所有Foo模型及其相关的bars像这样,然后在json中输出:

class FooController extends \BaseController {

    /**
     * Display a listing of the resource.
     *
     * @return Response
     */
    public function index()
    {
       $foos = Foo:with('bars')->get();

       return Response::json(array(
          'foos' => $foos->toArray()
       ),200);
    }
}

我遇到的问题是输出。这将输出如下内容:

{
   "foos": [
      {
         "id": 1, 
         "name": "Foo 1", 
         "bars": [
            {
               "id": 1,
               "name": "Bar 1",
               "pivot": {
                  "foo_id": 1,
                  "bar_id": 1
               }
            },
            {
               "id": 2,
               "name": "Bar 2",
               "pivot": {
                  "foo_id": 1,
                  "bar_id": 2
               }
            },
            {
               "id": 3,
               "name": "Bar 3",
               "pivot": {
                  "foo_id": 1,
                  "bar_id": 3
               }
            }
         ]
      }
   ]
}

但我真正想要的是:

{
   "foos": 
        [{
            "id": 1, 
            "name": "Foo 1", 
            "bars": [1, 2, 3]
        }]
}

现在,我一直在迭代$foos,以获得正确的代码:

foreach($foos as &$foo) {

    $bar_ids = array();

    foreach($foo->bars as $bar) {
        $bar_ids[] = $bar->pivot->bar_id;                    
    }

    unset($foo->bars);
    $foo->bars = $bar_ids;                
}

但这似乎很复杂,增加了我试图摆脱的复杂性。是否有更简单的方法来获得所需的输出?

感谢您的帮助。

3 个答案:

答案 0 :(得分:2)

您可以使用lists方法。

$foo->bars->lists('id');

会给你一系列foo的bar id。

适用于:

  • 照亮\数据库\锋\生成器::列表
  • 照亮\数据库\查询\生成器::列表
  • 照亮\支持\收藏::列表

一些额外的建议:

要以您想要的格式返回数据,最好使用变换器,例如fractal package(或根据您的要求自行制作更简单的版本)。

我们的想法是在中间设置一些内容来格式化数据,而不是将模型转储到控制器中的响应中。它可以直接处理您的问题并添加诸如将属性转换为类型(如布尔和整数)以及使控制器与数据库更改隔离的好处。

变压器看起来像这样:

class FooTransformer extends TransformerAbstract
{
    /**
     * Transform this item object into a generic array.
     *
     * @param Foo $foo
     * @return array
     */
    public function transform(Foo $foo)
    {
        return [
            'id'   => (int) $foo->id,
            'name' => $foo->name,
            'bars' => $foo->bars->lists('id'),
        ];
    }
}

答案 1 :(得分:2)

使用变形金刚/演示者这样的东西,分形是你可以考虑的。但是,您可以使用Eloquent轻松完成相同的操作:

// Foo
protected $hidden  = ['bars']; // don't show the collection in json
protected $appends = ['barsIds']; // but show additional info you need via accessor

public function getBarsIdsAttribute()
{
   return $this->bars->lists('id');
}

现在您可以直接使用访问者:

$foo->barsIds; // [1,5,10]

并自动附加到toArray/toJson输出:

{
   "foos": [
      {
         "id": 1, 
         "name": "Foo 1", 
         "barsIds": [1,5,10]
      }
   ]
}

重要如果要输出foos的集合,请记住急切加载 bars关系,否则您将体验到N + 1查询问题。

答案 2 :(得分:1)

听起来你想要在foo查询中使用GROUP CONCAT,你需要使用DB :: raw()。

还有lists()方法,例如

public function barsIds() {
    return $this->belongsToMany('bar','foos_bars')
        ->lists('id');
}