Laravel管理不同的API响应

时间:2019-03-06 20:02:55

标签: php laravel eloquent eager-loading

说明

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

return new BarcodeResource($barcode);

条形码资源根据barcodable类解析barcodable资源。每个可编排模型都返回不同的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),
        ];
    }

1 个答案:

答案 0 :(得分: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);
    }

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

希望有帮助。