Passed
Push — master ( 92408f...e57c2f )
by
unknown
02:50
created

EloquentModelDataLayer::denormalize()   A

Complexity

Conditions 1
Paths 2

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 10
nc 2
nop 2
dl 0
loc 15
rs 9.9332
c 0
b 0
f 0
1
<?php
2
3
namespace W2w\Laravel\Apie\Services\Retrievers;
4
5
use Illuminate\Database\Eloquent\ModelNotFoundException;
6
use RuntimeException;
7
use Illuminate\Database\Eloquent\Model;
8
use W2w\Laravel\Apie\Services\Eloquent\EloquentModelSerializer;
9
use W2w\Lib\Apie\Exceptions\ResourceNotFoundException;
10
use W2w\Lib\Apie\Persisters\ApiResourcePersisterInterface;
11
use W2w\Lib\Apie\Retrievers\ApiResourceRetrieverInterface;
12
use W2w\Lib\Apie\Retrievers\SearchFilterFromMetadataTrait;
13
use W2w\Lib\Apie\Retrievers\SearchFilterProviderInterface;
14
use W2w\Lib\Apie\SearchFilters\SearchFilterRequest;
15
16
/**
17
 * Maps a domain object to an eloquent model. Remember that foreign key constraints can be confusing, so it might be
18
 * a good idea to make your own retriever and persister class if the model becomes more complex.
19
 *
20
 * It uses the fill and toArray method of the Eloquent model. Mass alignment is disabled to map the fields as we
21
 * assume the domain object does the protection.
22
 */
23
class EloquentModelDataLayer implements ApiResourceRetrieverInterface, ApiResourcePersisterInterface, SearchFilterProviderInterface
24
{
25
    use SearchFilterFromMetadataTrait;
26
27
    private $serializer;
28
29
    /**
30
     * @param EloquentModelSerializer $serializer
31
     */
32
    public function __construct(EloquentModelSerializer $serializer)
33
    {
34
        $this->serializer = $serializer;
35
    }
36
37
    /**
38
     * Retrieves all resources. Since the filtering whether you are allowed to see a model instance is done afterwards,
39
     * the pagination could show a less amount of records than indicated. This is only for performance reasons.
40
     *
41
     * @param  string              $resourceClass
42
     * @param  array               $context
43
     * @param  SearchFilterRequest $searchFilterRequest
44
     * @return array
45
     */
46
    public function retrieveAll(string $resourceClass, array $context, SearchFilterRequest $searchFilterRequest): iterable
47
    {
48
        $modelClass = $this->getModelClass($resourceClass, $context);
49
50
        $queryBuilder = $modelClass::query();
51
        return $this->serializer->toList($queryBuilder, $resourceClass, $searchFilterRequest);
52
    }
53
54
    /**
55
     * Retrieves a single instance.
56
     *
57
     * @param  string $resourceClass
58
     * @param  mixed  $id
59
     * @param  array  $context
60
     * @return mixed
61
     */
62
    public function retrieve(string $resourceClass, $id, array $context)
63
    {
64
        $modelClass = $this->getModelClass($resourceClass, $context);
65
        try {
66
            $modelInstance = $modelClass::where($context[1] ?? $context['id'] ?? 'id', $id)->firstOrFail();
67
        } catch (ModelNotFoundException $notFoundException) {
68
            throw new ResourceNotFoundException($id);
69
        }
70
        $result = $this->serializer->toResource($modelInstance, $resourceClass);
71
72
        return $result;
73
    }
74
75
    /**
76
     * Creates a new Eloquent model from an api resource.
77
     *
78
     * @param  mixed $resource
79
     * @param  array $context
80
     * @return mixed
81
     */
82
    public function persistNew($resource, array $context = [])
83
    {
84
        $resourceClass = get_class($resource);
85
        $modelInstance = $this->serializer->toModel($resource, $this->getModelClass($resourceClass, $context));
86
87
        return $this->serializer->toResource($modelInstance, $resourceClass);
88
    }
89
90
    /**
91
     * Stores an api resource to an existing Eloquent model instance.
92
     *
93
     * @param  mixed $resource
94
     * @param  mixed $id
95
     * @param  array $context
96
     * @return mixed
97
     */
98
    public function persistExisting($resource, $id, array $context = [])
99
    {
100
        $resourceClass = get_class($resource);
101
        $modelClass = $this->getModelClass($resourceClass, $context);
102
        $modelInstance = $this->serializer->toExistingModel($resource, $id, $modelClass);
103
104
        return $this->serializer->toResource($modelInstance, $resourceClass);
105
    }
106
107
    /**
108
     * Removes a resource from the database.
109
     *
110
     * @param string $resourceClass
111
     * @param mixed  $id
112
     * @param array  $context
113
     */
114
    public function remove(string $resourceClass, $id, array $context)
115
    {
116
        $modelClass = $this->getModelClass($resourceClass, $context);
117
        $modelInstance = $modelClass::where($context[1] ?? $context['id'] ?? 'id', $id)->first();
118
        if (!$modelInstance) {
119
            return;
120
        }
121
        $modelClass::destroy($id);
122
    }
123
124
    /**
125
     * Returns the name of the model class associated to a api resource class.
126
     *
127
     * @param  string $resourceClass
128
     * @return string
129
     */
130
    private function determineModel(string $resourceClass): string
131
    {
132
        return str_replace('\\ApiResources\\', '\\Models\\', $resourceClass);
133
    }
134
135
    /**
136
     * Returns the name of the model class associated to a api resource class and a context.
137
     *
138
     * @param  string $resourceClass
139
     * @param  array  $context
140
     * @return string
141
     */
142
    private function getModelClass(string $resourceClass, array $context): string
143
    {
144
        $modelClass = $context[0] ?? $context['model'] ?? $this->determineModel($resourceClass);
145
        if (!class_exists($modelClass)) {
146
            throw new RuntimeException('Class "' . $modelClass . '" not found!');
147
        }
148
        if (!is_a($modelClass, Model::class, true)) {
149
            throw new RuntimeException('Class "' . $modelClass . '" exists, but is not a Eloquent model!');
150
        }
151
152
        return $modelClass;
153
    }
154
}
155