Laravel API resourceCollection 使用数组而不是模型

Posted

技术标签:

【中文标题】Laravel API resourceCollection 使用数组而不是模型【英文标题】:Laravel API resourceCollection using array rather than model 【发布时间】:2018-07-14 11:14:25 【问题描述】:

我有一个 API,它使用 API 资源和资源集合来正确格式化 JSON 响应。为了将我的控制器与我的模型分离,我使用适配器来查询底层模型。我想将适配器返回值作为数组而不是 Eloquent 模型传递,以确保任何未来的适配器在返回数据结构方面都更容易正确。为了创建数组返回值,我使用 ->toArray() 序列化我的适配器 Eloquent 结果。

对于我拥有的单个资源,我有 2 个 API 资源来正确格式化这些结果:

使用 Illuminate\Http\Resources\Json\Resource;

class Todo extends Resource

    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    public function toArray($request)
    
        return $this->resource;
    

对于我拥有的资源集合:

使用 Illuminate\Http\Resources\Json\ResourceCollection;

class TodoCollection extends ResourceCollection

    /**
     * Transform the resource collection into an array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    public function toArray($request)
    
        return [
            'data' => $this->collection
                          ->map
                          ->toArray($request)
                          ->all()
        ];
    

当我从控制器返回单个资源时:

use App\Http\Resources\Todo;

public function show($id)

    return new Todo($this->todoAdapter->findById($id));

适配器查询为:

public function findById(int $id)
        return TodoModel::findOrFail($id)
                ->toArray();

这按预期工作。当我尝试传递模型集合的数组时,问题就出现了,即

public function index(Request $request)

    $todos = $this->todoAdapter->getAllForUserId(Auth::id(), 'created_by', 'desc', self::DEFAULT_PAGINATE);
    return new TodoCollection($todos);

适配器查询为:

public function getAllForUserId(int $userId, string $sortField, string $sortDir, int $pageSize = self::DEFAULT_PAGINATE)

        return Todo::BelongsUser($userId)
                                    ->orderBy($sortField, $sortDir)
                                    ->paginate($pageSize)
                                    ->toArray();

我收到以下错误:

"message": "Call to a member function first() on array",
    "exception": "Symfony\\Component\\Debug\\Exception\\FatalThrowableError",
    "file": "/home/vagrant/code/public/umotif/vendor/laravel/framework/src/Illuminate/Http/Resources/CollectsResources.php",
    "line": 24,

我猜我不能执行 'new TodoCollection($todos)' 其中 $todos 是一个结果数组。如何让我的 todoCollection 与数组一起使用?任何建议将不胜感激!

【问题讨论】:

你可以做的比这更简单 你是什么意思? 你可以在你的资源中传递集合对象,并像 laravel 文档所说的那样把它变成一个数组 如何在资源中做到这一点?从适配器返回一个数组不是为了更容易实现其他适配器吗?例如,如果我通过 API 适配器获取数据,那么如果资源需要一个数组,我就不需要将其转换为集合? 请看laravel.com/docs/5.5/eloquent-resources#introduction,上面写着`Laravel 的资源类允许你以富有表现力的方式轻松地将模型和模型集合转换为 JSON。` 【参考方案1】:

您的 toArray 集合试图做的太多了:

$this->collection
         ->map
         ->toArray($request)
         ->all()

直接拨打$this->collection->toArray()即可。

【讨论】:

尝试将集合 toArray() 替换为 return $this->collection->toArray();但得到同样的错误 - 谢谢你的建议。【参考方案2】:

只是为了更新这个。最后,我发现从结果数组创建一个集合并将其传递给资源集合构造函数是可行的,尽管我确实必须在资源集合中为链接和元等添加显式映射。

【讨论】:

嗨,你能告诉我如何在 TodoResource 文件的响应对象中检索多数组项吗?我的 $this->response 就像 array(25) [0]=> array(9) ["ID"]=> int(3160) ["UserID"]=> int(3302) ["ItemName"] => 字符串(1) "2" ["描述"]=> 字符串(1) "2" 在资源中,我刚刚在 toArray() 方法中添加了以下内容 - return $this->resource;如果您使用集合(即 ResourceCollection),则首先转换为数组($collectionArray = $this->collection->toArray();),然后获取您需要的位,例如return ['data' => $this->collection->get('data')];

以上是关于Laravel API resourceCollection 使用数组而不是模型的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 8 中的 API

Laravel + React,使用 Laravel 身份验证的 api

从控制器调用外部 API 函数,LARAVEL 4

如何将 Laravel 项目转换为 laravel api?

Laravel 5 野狗 API 控制器

Laravel 5.3 中以 API 为中心的应用程序