【问题标题】:Laravel manage different API responsesLaravel 管理不同的 API 响应
【发布时间】:2019-03-06 20:02:54
【问题描述】:

说明

用户使用条形码模型(可以是商品、包裹或库存货架)扫描条形码和系统响应。

return new BarcodeResource($barcode);

条码资源根据条码类解析条码资源。每个条形码模型返回不同的 JSON 资源。

// BarcodeResource.php

$modelResource = app()->makeWith(__NAMESPACE__ . '\\' . class_basename($this->barcodable) . 'Resource', [
    'resource' => $this->barcodable
]);

return [
    'code' => $this->code,
    'model_type' => class_basename($this->barcodable),
    'model_data' => $modelResource
];

万一……

  • ...文章,我想打印包含此类文章的包裹
  • ...包裹,我要打印位置(库存货架),包含的物品和子包裹
  • ...库存货架,我想打印所有包裹

问题

我想用递归资源防止无限循环。

Article
  >> Package
      >> Article (infinity loop begins because package resource 
                  returns articles in spesific package)

Package
  >> Article
      >> Package (loop...)
  >> Inventory Shelf
      >> Package (loop...)
  >> Child package


Inventory Shelf
  >> Package
      >> Article
      >> Inventory Shelf (loop...)
      >> Child package

急切的加载和解除关系应该是一种解决方案,但我如何才能在正确的阶段解除这些关系呢?这甚至可以使用一个资源还是我应该制作多个资源(递归/正常)?


尝试

包含关系的额外属性

我尝试了这个解决方案,但神奇地$this->relations 属性在几次递归后变为整数 1...

class PackageResource extends JsonResource
{
    private $relations;

    public function __construct($resource, array $relations = [])
    {
        parent::__construct($resource);
        $this->relations = $relations;
    }

    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'articles' => $this->when(in_array('articles', $this->relations), ArticleResource::collection($this->articles, $this->relations)),
            'children' => PackageResource::collection($this->children, $this->relations),
        ];
    }

【问题讨论】:

  • 与尝试相关:失去关系,因为关系是通过构造函数预期的,但您通过集合方法传递它。
  • 你也应该覆盖收集方法。

标签: php laravel eloquent eager-loading


【解决方案1】:

我对类似情况的解决方案如下: 在资源文件中,我总是根据请求属性with 返回关系。这附在请求中,如下所示: 我需要UserOrdersProfile,但我还需要Area 来订购,而不是这样的请求:

http://example.com/api/v1/user/234?with=user.orders,user.profile,orders.area

在资源文件中有类似的东西:

    public function toArray($request)
    {
        $return = [
            'id' => $this->id,
            'name' => $this->name,
            'email' => $this->email,
            'location' => $this->location,
            'active' => $this->isActive(),
            'level' => $this->level,
        ];

        if($request->has('with')){

            $relationships = [
                'orders'=>[OrderCollection::class, 'orders'],
                'area'=>[Area::class, 'area', 'area.admin'],
                'profile'=>[UserProfile::class, 'profile'],
            ];

            $with = explode(',', $request->with);

            foreach($relationships as $key => $relationship){
                if( in_array("user.".$key, $with) ){
                    $return[$key] = new $relationship[0]($this->{$relationship[1]});
                }
            }
        }

        $return['created'] = $this->created_at->toDateTimeString();

        return $return;
    }

另一种解决方案是在资源类中添加一个额外的属性:

    protected $with = "";
    public function __construct(mixed $resource, $with="")
    {
        parent::__construct($resource);
    }

然后,当您调用该资源时,您可以按以前的方式对其进行过滤。我刚刚测试过,它对我有用。

希望对您有所帮助。

【讨论】:

  • 感谢您的回答。我不想在 URL 中提供任何额外的参数,因为无论返回的可条形码模型是什么,请求都应该完全相同。我试图从控制器向资源注入额外的属性,但我还没有让它工作。
  • 您无法插入额外的属性?
  • 是的,我是,但是当我将它转发给另一个资源时,它会更改为值整数 1(在包含关系的字符串之前)。所以原来的属性值不知何故消失了。
  • 由于某种原因,当我尝试向前传递参数时它不起作用:$return[$key] = new $relationship[0]($this->{$relationship[1]}, $with); 因为 with 属性更改为整数值 1。我不明白为什么它会那样...跨度>
  • 您应该使用命令php artisan make:resource UserCollection 创建资源控制器并将它们与new Resourcecontroller(Model) 样式一起使用。您失去了关系,因为您将它传递给集合静态方法而不是 ResourceController 的构造函数。
猜你喜欢
  • 2020-08-12
  • 1970-01-01
  • 2022-11-05
  • 2019-06-30
  • 2019-06-13
  • 2012-06-28
  • 2020-11-10
  • 1970-01-01
  • 2021-03-29
相关资源
最近更新 更多