我有两个模型资源,我希望将其合并到一个平面数组中,而不必明确定义其他资源的所有属性。
模型1:
id
name
created_at
模型2:
id
alternate_name
child_name
parent_name
sibling_name
created_at
Model1Resource
public function toArray($request)
{
return [
id => $this->id,
name => $this->name,
]
}
模型2资源
public function toArray($request)
{
return [
alternate_name => $this->alternate_name,
child_name => $this->child_name,
parent_name => $this->parent_name,
sibling_name => $this->sibling_name
]
}
我希望Model1Resource在平面结构中包含Model2Resource。通过向资源添加另一个属性,我可以轻松地在子数组中获取Model 2资源,如下所示:
Model2 => new Model2Resource($this->model2);
但这不是扁平结构。理想情况下,我希望返回这样的结构。
[id, name, alternate_name, child_name, parent_name, sibling_name]
我可以通过重新定义Model1Resource中Model2Resource的所有属性来做到这一点,但这似乎是不必要的。
澄清我指的是https://laravel.com/docs/5.5/eloquent-resources#writing-resources。在关系部分下,使用one to many
演示posts
关系。但是,如果结构是one to one
,我希望能够使它成为一个扁平数组,而不是在其中一个属性中有一个数组。
将这两种资源合并为一种扁平结构的简单方法是什么?
答案 0 :(得分:1)
因此,经过一番挖掘,这似乎并不容易。我决定最简单的方法是重新定义第一个模型中的输出,并使用mergeWhen()
函数仅在关系存在时合并。
return [
id => $this->id,
name => $this->name,
// Since a resource file is an extension
// we can use all the relationships we have defined.
$this->mergeWhen($this->Model2()->exists(), function() {
return [
// This code is only executed when the relationship exists.
alternate_name => $this->Model2->alternate_name,
child_name => $this->Model2->child_name,
parent_name => $this->Model2->parent_name,
sibling_name => $this->Model2->sibling_name
];
}
]
答案 1 :(得分:0)
为您的资源创建基类:
use Illuminate\Http\Resources\Json\JsonResource;
class BaseResource extends JsonResource {
/**
* @param bool $condition
* @param Request $request
* @param JsonResource|string $instanceOrClass
* @param mixed|null $model
* @return MergeValue|mixed
*/
public function mergeResourceWhen($condition, $request, $instanceOrClass, $model = null)
{
return $this->mergeResourcesWhen($condition, $request, [$instanceOrClass], $model);
}
/**
* @param Request $request
* @param JsonResource|string $instanceOrClass
* @param mixed|null $model
* @return MergeValue|mixed
*/
public function mergeResource($request, $instanceOrClass, $model = null)
{
return $this->mergeResourceWhen(true, $request, $instanceOrClass, $model);
}
/**
* @param bool $condition
* @param Request $request
* @param JsonResource[]|string[] $instancesOrClasses
* @param mixed|null $model
* @return MergeValue|mixed
*/
public function mergeResourcesWhen($condition, $request, $instancesOrClasses, $model = null)
{
return $this->mergeWhen($condition, function () use ($request, $instancesOrClasses, $model) {
return array_merge(...array_map(function ($instanceOrClass) use ($model, $request) {
if ($instanceOrClass instanceof JsonResource) {
if ($model) {
throw new RuntimeException('$model is specified but not used.');
}
} else {
$instanceOrClass = new $instanceOrClass($model ?? $this->resource);
}
return $instanceOrClass->toArray($request);
}, $instancesOrClasses));
});
}
/**
* @param Request $request
* @param JsonResource[]|string[] $instancesOrClasses
* @param mixed|null $model
* @return MergeValue|mixed
*/
public function mergeResources($request, $instancesOrClasses, $model = null)
{
return $this->mergeResourcesWhen(true, $request, $instancesOrClasses, $model);
}
}
Model1Resource
(这里不需要扩展BaseResource
,但我总是从我自己的自定义基类继承所有API资源类):
class Model1Resource extends JsonResource {
public function toArray($request)
{
return [
id => $this->id,
name => $this->name,
];
}
}
Model2Resource
:
class Model2Resource extends BaseResource {
public function toArray($request)
{
return [
$this->mergeResource($request, Model1Resource::class),
alternate_name => $this->alternate_name,
child_name => $this->child_name,
parent_name => $this->parent_name,
sibling_name => $this->sibling_name
];
}
}
如果要合并多个资源,则可以使用:
$this->mergeResources($request, [Model1Resource::class, SomeOtherResource::class]);
如果要按条件合并它:
$this->mergeResourceWhen($this->name !== 'John', $request, Model1Resource::class);
// or merge multiple resources
$this->mergeResourcesWhen($this->name !== 'John', $request, [Model1Resource::class, SomeOtherResource::class]);
默认情况下,合并的资源将使用$this->resource
可用的当前模型。
要将其他模型传递给合并的资源,请使用上述方法的最后一个参数:
$this->mergeResource($request, SomeModelResource::class, SomeModel::find(123));
$this->mergeResourcesWhen($this->name !== 'John', $request, [SomeModelResource::class, SomeOtherResource::class], SomeModel::find(123));
或传递JsonResource
实例而不是资源类:
$someModel = SomeModel::find(123);
$someOtherModel = SomeOtherModel::find(456);
$this->mergeResource($request, new SomeModelResource($someModel));
$this->mergeResourcesWhen($this->name !== 'John', $request, [new SomeModelResource($someModel), new SomeOtherModelResource($someOtherModel)]);