【问题标题】:Reading data from in vue/cli from Laravel ResourceCollection从 Laravel ResourceCollection 从 vue/cli 中读取数据
【发布时间】:2020-04-30 21:53:49
【问题描述】:

在 Laravel 6 后端 rest api 应用程序中,我使用 ResourceCollection 和 Resourcem 定义,例如:

<?php

namespace App\Http\Resources;
use App\Facades\MyFuncsClass;

use Illuminate\Http\Resources\Json\ResourceCollection;

class TaskCollection extends ResourceCollection
{
    public function toArray($task)
    {

        return [
            $this->collection->transform(function($task){
                return [
                    'id' => $task->id,
                    'name' => $task->name,
                    'slug' => $task->slug,
                    ...
                    'events' => !empty($task->events) ? $task->events : [],
                    'events_count' => !empty($task->events_count) ? $task->events_count : 0,
                    'created_at' => $task->created_at,
                    'updated_at' => $task->updated_at,
                ];
            }),
        ];

    }

    public function with($task)
    {
        return [
            'meta' => [
                'version'=>MyFuncsClass::getAppVersion()
            ]
        ];
    }

}

我发现这个决定是在 Laravel 5.5 API resources for collections (standalone data)

它对我有用,但我不喜欢我在客户端部分获取数据的方式,因此对于控件中定义的数据列表:

return (new TaskCollection($tasks));

我必须在 vue/cli app 中编写:

axios.post(this.apiUrl + '/adminarea/tasks-filter', filters, this.credentialsConfig)
    .then((response) => {
        this.tasks = response.data.data[0]
        this.tasks_total_count = response.data.meta.total
        this.tasks_per_page = response.data.meta.per_page

当我需要获得我在 laravel 控件中定义的 1 个项目时:

return (new TaskCollection([$task])); // I have to wrap it as array

我必须在 vue/cli app 中编写:

axios.get(this.apiUrl + '/adminarea/tasks/' + this.task_id, this.credentialsConfig)
    .then((response) => {
        // console.log('response::')
        // console.log(response)
        //
        this.taskRow = response.data.data[0][0]

我不喜欢 data.data[0] 和 data.data[0][0] 之类的语法,甚至对我有用

在我的 app/Providers/AppServiceProvider.php 我有几行:

<?php

namespace App\Providers;

use Auth;
use Validator;
use Illuminate\Http\Resources\Json\Resource;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {

        Resource::withoutWrapping(); // looks like that does not work for ResourceCollection!

<?php

namespace App\Providers;

use Auth;
use Validator;
use Illuminate\Http\Resources\Json\Resource;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Resource::withoutWrapping();
        ...

如果有办法摆脱 vue/cli 部分中的 data.data[0] 和 data.data[0][0] ?

修改 2: 我创建了几个列的新资源 app/Http/Resources/Skill.php :

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class Skill extends JsonResource
{
    public static $wrap = 'skills';
    public function toArray($request)
    {
        return [
            'id' => $request->id,
            'name' => $request->name,
            'user_id' => $request->user_id,
            'user_name' => $request->user_name,
            'skill_id' => $request->skill_id,
            'skill_name' => $request->skill_name,
            'rating' => $request->rating,
            'created_at' => $request->created_at,
        ];
    }
}

和 app/Http/Resources/SkillCollection.php :

<?php

namespace App\Http\Resources;

use App\Facades\MyFuncsClass;
use App\Http\Resources\Skill;
use Illuminate\Http\Resources\Json\ResourceCollection;

class SkillCollection extends ResourceCollection
{
    public static $wrap = 'skills';
    public function toArray($request)
    {

        return $this->collection->transform(function($request){
            parent::toArray($request);
            });
    }

结果我有空的“技能”:[null,null,null,null] 结果。怎么了?

谢谢!

【问题讨论】:

  • 您定义ResourceCollection 而不使用类来返回单一资源是否有原因,例如定义 TaskResource 扩展 JsonResource 然后返回 TaskResource::collection($tasks)?
  • 我认为无论您使用withoutWrapping(),您的资源都被包装在data 中,因为您的meta 函数返回一个非空对象。如果您有 with 数据,请在此处查看 source code,Laravel 会在其中包装您的回复。
  • 一开始我尝试了 JsonResource,但是由于我需要方法 public function with($task) ... 就像在我的代码中一样,我尝试了它,但它对我不起作用。我发现 JsonResource 无法访问这个“with”方法,而只能访问 ResourceCollection。是这样吗?
  • 我尝试了几种带有包装的变体,但都失败了。并且确定我需要 1 个 Collection 项目来列出元素和 1 个元素
  • 如果您希望它返回with 数据,您希望您的响应看起来如何?如果您有 with 数据,Laravel 会将您的响应包装在 data 数组中,否则它将与您的 with 数据混淆。例如,它会尝试返回一个类似[$task1, $task2, 'meta' =&gt; ['version' =&gt; 1]]]的数组。

标签: laravel laravel-resource


【解决方案1】:
  1. 您可以做的第一件事是使用 destructuring assignment 从您的 Axios 请求中获取 response data
axios.get(this.apiUrl + '/adminarea/tasks/' + this.task_id, this.credentialsConfig)
    .then(({ data }) => {
        this.taskRow = data.data[0][0]

所以现在response.data.data[0][0] 缩短为data.data[0][0]

  1. 您可以做的第二件事是,在 TaskCollection 类的 toArray 函数中,直接返回转换后的集合,而不是将其包装在数组中:
    public function toArray($task)
    {
            return $this->collection->transform(function($task){
                return [
                    'id' => $task->i
                    ...
                ];
            });
    }

现在您无需在任何地方使用[0]。因此,您可以使用 data.data[0] 访问单个任务,而不是 data.data[0][0]

  1. 为避免必须将[0] 用于单数响应,您应该返回JsonResource 而不是ResourceCollection。为此,您需要将代码从 $this-&gt;collection-&gt;transform 内部移动到新的 JsonResource 类。例如:

app/Http/Resources/TaskResource.php:

<?php

namespace App\Http\Resources;

use App\Facades\MyFuncsClass;
use Illuminate\Http\Resources\Json\JsonResource;

class TaskResource extends JsonResource
{
    public function toArray($task)
    {
         return [
                    'id' => $this->id,
                    'name' => $this->name,
                    'slug' => $this->slug,
                    ...
                ];
    }

    public function with($task)
    {
        return [
            'meta' => [
                'version'=>MyFuncsClass::getAppVersion()
            ]
        ];
    }

}

然后你可以返回单个资源

return new TaskResource($task);

在 Javascript 中,您现在可以使用 data.data 获得单个任务:

axios.get(this.apiUrl + '/adminarea/tasks/' + this.task_id, this.credentialsConfig)
    .then(({ data }) => {
        this.taskRow = data.data;

您可以重构您的 TaskCollection 类,以便为每个任务隐式使用您的新 TaskResource 类:

<?php

namespace App\Http\Resources;
use App\Facades\MyFuncsClass;

use Illuminate\Http\Resources\Json\ResourceCollection;

class TaskCollection extends ResourceCollection
{
    public function toArray($request)
    {
        return parent::toArray($request);
    }

    public function with($task)
    {
        return [
            'meta' => [
                'version'=>MyFuncsClass::getAppVersion()
            ]
        ];
    }
}
  1. 就像我试图在 cmets 中解释的那样,在从 with 函数返回非空值时,您将无法避免将结果包装在一个键中(如 'data')。如果您不相信我,请暂时删除您的 with 功能,您会发现只需使用 data 即可访问您的任务(如果您已禁用 Resource::withoutWrapping(); 包装)。

但是,您可以做的一件事是自定义“换行”键。例如,对于一组任务,您可能希望它是 tasks,而对于单个任务,您可能希望它是 task。您可以简单地将 $wrap 属性添加到您的 TaskCollectionTaskResource 类中:

class TaskCollection extends ResourceCollection
{
    public static $wrap = 'tasks';
    ...
class TaskResource extends JsonResource
{
    public static $wrap = 'task';

现在您可以使用data.tasks 访问来自Javascript 的任务列表,使用data.task 访问单个任务:

axios.post(this.apiUrl + '/adminarea/tasks-filter', filters, this.credentialsConfig)
    .then(({ data }) => {
        this.tasks = data.tasks;
axios.get(this.apiUrl + '/adminarea/tasks/' + this.task_id, this.credentialsConfig)
    .then(({ data }) => {
        this.taskRow = data.task;

【讨论】:

  • 太好了,谢谢!我唯一想问的是可以避免使用 2 个文件:基于 ResourceCollection 和 JsonResource 吗?或者也许其中一个作为第二个的包装?我的意思是字段列表可能会很长
  • 是的,如果您从TaskCollection 返回return parent::toArray($request);,它将自动为每个任务使用TaskResourcetoArray 函数。因此,您不必列出这两个类中的字段。
  • 请看 MODIFIED 2:
  • Skill 中的项目应该是'id' =&gt; $this-&gt;id, 而不是'id' =&gt; $request-&gt;id,
猜你喜欢
  • 2015-08-30
  • 1970-01-01
  • 1970-01-01
  • 2019-03-28
  • 2018-07-17
  • 2020-07-02
  • 1970-01-01
  • 2014-07-17
  • 2021-07-22
相关资源
最近更新 更多