EloquentModelSerializer::toList()   A
last analyzed

Complexity

Conditions 5
Paths 6

Size

Total Lines 23
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 15
nc 6
nop 4
dl 0
loc 23
rs 9.4555
c 0
b 0
f 0
1
<?php
2
namespace W2w\Laravel\Apie\Plugins\Illuminate\Eloquent;
3
4
use Illuminate\Database\Eloquent\Builder;
5
use Illuminate\Database\Eloquent\Model;
6
use UnexpectedValueException;
7
use W2w\Lib\Apie\Core\SearchFilters\SearchFilterRequest;
8
use W2w\Lib\Apie\Interfaces\ResourceSerializerInterface;
9
10
/**
11
 * Contains logic to serialize from/to Eloquent models. This is placed in a different class for reusability.
12
 */
13
class EloquentModelSerializer
14
{
15
    private $serializer;
16
17
    public function __construct(ResourceSerializerInterface $serializer)
18
    {
19
        $this->serializer = $serializer;
20
    }
21
22
    /**
23
     * Converts a Query builder into a list of resources.
24
     *
25
     * @param Builder                  $builder
26
     * @param string                   $resourceClass
27
     * @param SearchFilterRequest|null $searchFilterRequest
28
     * @param array|null               $mapping
29
     * @return Model[]
30
     */
31
    public function toList(Builder $builder, string $resourceClass, ?SearchFilterRequest $searchFilterRequest, array $mapping = null): array
32
    {
33
        if (empty($builder->getQuery()->orders) && empty($builder->getQuery()->unionOrders)) {
34
            $builder = $builder->orderBy('id', 'ASC');
35
        }
36
        if ($searchFilterRequest) {
37
            $searches = $searchFilterRequest->getSearches();
38
            if ($mapping !== null) {
39
                $searches = ArrayRemapper::remap($mapping, $searches);
40
            }
41
            $builder = $builder
42
                ->where($searches)
43
                ->skip($searchFilterRequest->getOffset())
44
                ->take($searchFilterRequest->getNumberOfItems());
45
        }
46
47
        $modelInstances = $builder->get();
48
49
        return array_map(
50
            function ($modelInstance) use (&$resourceClass, &$mapping) {
51
                return $this->toResource($modelInstance, $resourceClass, $mapping);
52
            },
53
            iterator_to_array($modelInstances)
54
        );
55
    }
56
57
    /**
58
     * Converts resource into a eloquent model. The instance returns is always a new entity.
59
     *
60
     * @param mixed      $resource
61
     * @param string     $modelClass
62
     * @param array|null $mapping
63
     * @return Model
64
     */
65
    public function toModel($resource, string $modelClass, array $mapping = null): Model
66
    {
67
        $array = $this->serializer->normalize($resource, 'application/json');
68
        if (!is_array($array)) {
69
            throw new UnexpectedValueException('Resource ' . get_class($resource) . ' was normalized to a non array field');
70
        }
71
        if ($mapping !== null) {
72
            $array = ArrayRemapper::remap($mapping, $array);
73
        }
74
        $modelClass::unguard();
75
        try {
76
            $modelInstance = $modelClass::create($array);
77
        } finally {
78
            $modelClass::reguard();
79
        }
80
        return $modelInstance;
81
    }
82
83
    /**
84
     * Maps Eloquent model to a class of $resoureClass
85
     *
86
     * @param Model      $eloquentModel
87
     * @param string     $resourceClass
88
     * @param array|null $mapping
89
     * @return mixed
90
     */
91
    public function toResource(Model $eloquentModel, string $resourceClass, array $mapping = null)
92
    {
93
        $array = $eloquentModel->toArray();
94
        if ($mapping !== null) {
95
            $array = ArrayRemapper::reverseRemap($mapping, $array);
96
        }
97
        return $this->serializer->hydrateWithReflection($array, $resourceClass);
98
    }
99
100
    /**
101
     * Converts existing resource into a eloquent model. The instance returns is always a new entity.
102
     *
103
     * @param mixed $resource
104
     * @param mixed $id
105
     * @param string $modelClass
106
     * @return Model
107
     */
108
    public function toExistingModel($resource, $id, string $modelClass, array $mapping = null): Model
109
    {
110
        $resourceClass = get_class($resource);
111
        $modelInstance = $modelClass::where(['id' => $id])->firstOrFail();
112
        $array = $this->serializer->normalize($resource, 'application/json');
113
        if (!is_array($array)) {
114
            throw new UnexpectedValueException('Resource ' . $resourceClass . ' was normalized to a non array field');
115
        }
116
        if ($mapping !== null) {
117
            $array = ArrayRemapper::remap($mapping, $array);
118
        }
119
        unset($array['id']);
120
        $modelInstance->unguard();
121
        try {
122
            $modelInstance->fill($array);
123
        } finally {
124
            $modelInstance->reguard();
125
        }
126
        $modelInstance->save();
127
        return $modelInstance;
128
    }
129
}
130