【问题标题】:Eager Load lists() in Laravel 4Laravel 4 中的急切加载列表()
【发布时间】:2013-08-10 17:35:31
【问题描述】:

在 Laravel 4 中,我使用 Eager Loading 实现多对多关系:

public function categories()
{

    return $this->belongsToMany('Category');

}

它返回这样的类别:

    "categories": [
        {
            "id": 1,
            "priority": 1,
            "title": "My category 1",
            "created_at": "2013-08-10 18:45:08",
            "updated_at": "2013-08-10 18:45:08"
        },
        {
            "id": 2,
            "priority": 2,
            "title": "My category 2",
            "created_at": "2013-08-10 18:45:08",
            "updated_at": "2013-08-10 18:45:08"
        }
    ],

但我只需要这个:

    "categories": [1,2] // References category id's only

查询生成器有一个名为“lists”的方法,它应该可以解决问题。但它在急切负载的情况下不起作用???

public function categories()
{

    return $this->belongsToMany('Category')->lists('category_id');

}

【问题讨论】:

    标签: php laravel laravel-4 eager-loading


    【解决方案1】:

    它不起作用的原因是因为在使用 with 方法进行预加载时,Laravel 期望一个关系方法返回一个 Illuminate\Database\Eloquent\Relations\Relation 对象,以便它可以在其上调用 get。当您调用lists 时,查询已经运行,而是返回的是一个数组。

    为了减少数据传输,您可以做的是在查询上使用select 方法,然后在类别集合上运行lists。示例:

    Model.php

    function categories() {
        return $this->belongsToMany('Category')->select('id');
    }
    

    Whatever.php

    $posts = Post::with('Category')->get();
    $categories = $posts->categories;
    
    // List only the ids
    $categoriesIds = $categories->lists('id');
    

    【讨论】:

    • 在伪中我使用这样的东西:return Response::json(Post::with('Category'));所以我可以参考 $json['categories'] 之类的类别。是否可以更改 $posts->categories 对象,而不是先将其转换为数组然后进行 JSON 编码?
    【解决方案2】:

    将以下代码添加到您的模型/基础模型中:

    /**
     * Set additional attributes as hidden on the current Model
     *
     * @return instanceof Model
     */
    public function addHidden($attribute)
    {
        $hidden = $this->getHidden();
    
        array_push($hidden, $attribute);
    
        $this->setHidden($hidden);
    
        // Make method chainable
        return $this;
    }
    
    /**
     * Convert appended collections into a list of attributes
     *
     * @param  object       $data       Model OR Collection
     * @param  string|array $levels     Levels to iterate over
     * @param  string       $attribute  The attribute we want to get listified
     * @param  boolean      $hideOrigin Hide the original relationship data from the result set
     * @return Model
     */
    public function listAttributes($data, $levels, $attribute = 'id', $hideOrigin = true)
    {
    
        // Set some defaults on first call of this function (because this function is recursive)
        if (! is_array($levels))
            $levels = explode('.', $levels);
    
        if ($data instanceof Illuminate\Database\Eloquent\Collection) // Collection of Model objects
        {
            // We are dealing with an array here, so iterate over its contents and use recursion to look deeper:
            foreach ($data as $row)
            {
                $this->listAttributes($row, $levels, $attribute, $hideOrigin);
            }
        }
        else
        {
            // Fetch the name of the current level we are looking at
            $curLevel = array_shift($levels);
    
            if (is_object($data->{$curLevel}))
            {
                if (! empty($levels))
                {
                    // We are traversing the right section, but are not at the level of the list yet... Let's use recursion to look deeper:
                    $this->listAttributes($data->{$curLevel}, $levels, $attribute, $hideOrigin);
                }
                else
                {
                    // Hide the appended collection itself from the result set, if the user didn't request it
                    if ($hideOrigin)
                        $data->addHidden($curLevel);
    
                    // Convert Collection to Eloquent lists()
                    if (is_array($attribute)) // Use specific attributes as key and value
                        $data->{$curLevel . '_' . $attribute[0]} = $data->{$curLevel}->lists($attribute[0], $attribute[1]);
                    else // Use specific attribute as value (= numeric keys)
                        $data->{$curLevel . '_' . $attribute} = $data->{$curLevel}->lists($attribute);
                }
            }
        }
    
        return $data;
    }
    

    您可以像这样在模型/集合对象上使用它:

    // Fetch posts data
    $data = Post::with('tags')->get(); // or use ->first()
    
    // Convert relationship data to list of id's
    $data->listAttributes($data, 'tags');
    

    $data 现在将包含以下对象存储:

    {
        "posts": [
            {
                "title": "Laravel is awesome",
                "body": "Lorem Ipsum...",
                "tags_id": [ 1, 2, 3 ]
            },
            {
                "title": "Did I mention how awesome Laravel is?",
                "body": "Lorem Ipsum...",
                "tags_id": [ 1, 2, 4 ]
            }
        ]
    }
    

    它还支持嵌套关系:

    // Fetch posts data
    $data = Post::with('comments', 'comments.tags')->get(); // or use ->first()
    
    // Convert relationship data to list of id's
    $data->listAttributes($data, 'comments.tags');
    

    【讨论】:

      【解决方案3】:

      如果所有请求category模型都是这种情况,您可以设置visible array

      点赞protected $visible = array('category_id');

      现在对类别模型的每个请求都将仅检索category_id

      在你的情况下-

      Class Category extends Eloquent{
      
          protected $visible=array('category_id');
          ...
      }
      

      注意- 它将category_id 的集合作为对象返回,但如果您需要一个数组,则必须使用查询构建器的toArray() 方法来获取category_id 的数组

      为了得到你所需要的,你可以试试这个

      $cat_id=Category::all()->toArray();
      $arrid=array();
      array_walk_recursive($cat_id,function($value,$key) use (&$arrid){
        array_push($arrid,$value);
      })
      //$arrid will contain only category_id's like
      //$arrid=[1,2,3];
      

      【讨论】:

      • 这仅在调用toArray() 方法时有效。
      • @Raphael_ 是的,如果你需要一个数组,否则你会得到一个对象
      • 应该把它写在答案上。
      • @Raphael_ 编辑了答案
      猜你喜欢
      • 1970-01-01
      • 2014-08-13
      • 1970-01-01
      • 2015-03-19
      • 1970-01-01
      • 2013-03-27
      • 1970-01-01
      • 1970-01-01
      • 2014-11-12
      相关资源
      最近更新 更多