Passed
Push — master ( c5bd37...640ffc )
by
unknown
05:22
created

EloquentModelDataLayer::remove()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
c 0
b 0
f 0
dl 0
loc 8
rs 10
cc 2
nc 2
nop 3
1
<?php
2
3
namespace W2w\Laravel\Apie\Plugins\Illuminate\DataLayers;
4
5
use Illuminate\Database\Eloquent\ModelNotFoundException;
6
use RuntimeException;
7
use Illuminate\Database\Eloquent\Model;
8
use W2w\Laravel\Apie\Plugins\Illuminate\Eloquent\EloquentModelSerializer;
9
use W2w\Lib\Apie\Core\SearchFilters\SearchFilterFromMetadataTrait;
10
use W2w\Lib\Apie\Core\SearchFilters\SearchFilterRequest;
11
use W2w\Lib\Apie\Exceptions\ResourceNotFoundException;
12
use W2w\Lib\Apie\Interfaces\ApiResourcePersisterInterface;
13
use W2w\Lib\Apie\Interfaces\ApiResourceRetrieverInterface;
14
use W2w\Lib\Apie\Interfaces\SearchFilterProviderInterface;
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
        $class = str_replace('\\ApiResources\\', '\\Models\\', $resourceClass);
133
        if (class_exists($class)) {
134
            return $class;
135
        }
136
        return str_replace('\\ApiResources\\', '\\Entities\\', $resourceClass);
137
    }
138
139
    /**
140
     * Returns the name of the model class associated to a api resource class and a context.
141
     *
142
     * @param  string $resourceClass
143
     * @param  array  $context
144
     * @return string
145
     */
146
    private function getModelClass(string $resourceClass, array $context): string
147
    {
148
        $modelClass = $context[0] ?? $context['model'] ?? $this->determineModel($resourceClass);
149
        if (!class_exists($modelClass)) {
150
            throw new RuntimeException('Class "' . $modelClass . '" not found!');
151
        }
152
        if (!is_a($modelClass, Model::class, true)) {
153
            throw new RuntimeException('Class "' . $modelClass . '" exists, but is not a Eloquent model!');
154
        }
155
156
        return $modelClass;
157
    }
158
}
159