1 <?php
2 /**
3 * Created by PhpStorm.
4 * User: Jean-fran�ois
5 * Date: 22/08/2015
6 * Time: 10:10.
7 */
8 namespace Skimia\ApiFusion\Domain;
9
10 use Skimia\ApiFusion\Domain\Users\SentinelServiceUserAdapter;
11 use Illuminate\Database\Eloquent\Collection;
12 use Skimia\ApiFusion\Domain\Contracts\InputValidatorContract;
13 use Skimia\ApiFusion\Domain\Contracts\ServiceUserContract;
14 use Skimia\ApiFusion\Domain\Contracts\ResourceServiceModelContract;
15 use Skimia\ApiFusion\Domain\Traits\CheckableTrait;
16 use Skimia\ApiFusion\Domain\Exceptions\DomainException;
17
18 abstract class ResourceService
19 {
20 use CheckableTrait;
21
22 /**
23 * The resource's model object that the service will use.
24 * @var ResourceServiceModelContract
25 */
26 protected $model;
27
28 /**
29 * User of the service.
30 * @var ServiceUserContract
31 */
32 protected $user;
33
34 /**
35 * Field to order results by.
36 * @var array
37 */
38 protected $orderBy = ['created_at'];
39
40 /**
41 * Related resources to eager load.
42 * @var array
43 */
44 protected $eagerLoad = [];
45
46 /**
47 * Set the resource's model and validator.
48 * @param ResourceServiceModelContract $model Resource's model
49 * @param InputValidatorContract $inputValidator Resource's input validator
50 */
51 public function __construct(
52 ResourceServiceModelContract $model,
53 InputValidatorContract $inputValidator = null
54 ) {
55 $this->model = $model;
56 $this->inputValidator = $inputValidator;
57 $this->user = new SentinelServiceUserAdapter(\Sentinel::getUser()); // TODO: extract out
58 }
59
60 /*
61 |--------------------------------------------------------------------------
62 | Easy Method to manipulate Query
63 |--------------------------------------------------------------------------
64 */
65
66 /**
67 * Apply order by property to query.
68 */
69 protected function order()
70 {
71 foreach ($this->orderBy as $orderBy) {
72 if (count($orderBy) == 1) {
73 $this->model = $this->model->orderBy($orderBy);
74 }
75
76 // field and direction
77 if (count($orderBy) == 2) {
78 $this->model = $this->model->orderBy($orderBy[0], $orderBy[1]);
79 }
80 }
81 }
82
83 /**
84 * Run query including eager load.
85 * @param int $id Item ID
86 * @return ResourceServiceModelContract|Collection Query results
87 */
88 protected function get($id = null)
89 {
90 $this->filter();
91
92 if ($this->eagerLoad) {
93 $this->model = $this->model->with($this->eagerLoad);
94 }
95
96 if ($id) {
97 return $this->model->where('id', $id)->firstOrFail();
98 }
99
100 return $this->model->get();
101 }
102
103 /*
104 |--------------------------------------------------------------------------
105 | Ressource Accessors
106 |--------------------------------------------------------------------------
107 */
108
109 /**
110 * Get all items of this resource.
111 * @return Collection Collection of items
112 */
113 public function all()
114 {
115 $this->runChecks('read');
116
117 $this->order();
118
119 return $this->get();
120 }
121
122 /**
123 * Get a single resource item by its ID.
124 * @param int $id Item ID
125 * @return BaseModel Model of the item
126 */
127 public function single($id)
128 {
129 $this->runChecks('read');
130
131 return $this->get($id);
132 }
133
134 /**
135 * Store a new resource item.
136 * @param array $input Raw user input
137 * @return bool
138 */
139 public function store($input)
140 {
141 $this->model = $this->model->fill($input);
142
143 $filteredInput = $this->runChecks('store', $this->model->toArray());
144
145 if ($filteredInput) {
146 $this->model->fill($filteredInput);
147 }
148
149 return $this->model->save();
150 }
151
152 /**
153 * Update an existing resource item by ID.
154 * @param int $id Item's ID
155 * @param array $input Raw user input
156 * @return bool
157 */
158 public function update($id, $input)
159 {
160 $this->model = $this->model->query()->findOrFail($id);
161
162 $this->model = $this->model->fill($input);
163
164 $filteredInput = $this->runChecks('update', $this->model->toArray(), $this->model->getOriginal());
165
166 if ($filteredInput) {
167 $this->model->fill($filteredInput);
168 }
169
170 return $this->model->save();
171 }
172
173 /**
174 * Destroy an existing resource item by ID.
175 * @param int $id Item's ID
176 * @return bool
177 */
178 public function destroy($id)
179 {
180 $this->model = $this->model->findOrFail($id);
181
182 $this->runChecks('destroy', $this->model->toArray());
183
184 return $this->model->delete();
185 }
186
187 /**
188 * Get id of resource.
189 * @return mixed
190 */
191 public function id()
192 {
193 // By default just return this resource's id
194 if (isset($this->model->id)) {
195 return $this->model->id;
196 }
197 }
198
199 /*
200 |--------------------------------------------------------------------------
201 | Default Methods
202 |--------------------------------------------------------------------------
203 */
204
205 /**
206 * Filters to enforce during resource read.
207 */
208 protected function filter()
209 {
210 }
211
212 /**
213 * Check if read operations are authorised on the service
214 * Typically redifined in subclasses.
215 * @return bool
216 */
217 protected function readAuthorised()
218 {
219 return false;
220 }
221
222 /**
223 * Check if store operations are authorised on the service
224 * Typically redifined in subclasses.
225 * @return bool
226 */
227 protected function storeAuthorised()
228 {
229 return false;
230 }
231
232 /**
233 * Check if update operations are authorised on the service
234 * Typically redifined in subclasses.
235 * @return bool
236 */
237 protected function updateAuthorised()
238 {
239 return false;
240 }
241
242 /**
243 * Check if destroy operations are authorised on the service
244 * Typically redifined in subclasses.
245 * @return bool
246 */
247 protected function destroyAuthorised()
248 {
249 return false;
250 }
251
252 /**
253 * Run rule checks that apply during resource read
254 * Typically redifined in subclasses.
255 * @param array $input Input data to be used when evaluating rules
256 * @throws DomainException when a rule is broken
257 */
258 protected function domainRulesOnRead($input)
259 {
260 }
261
262 /**
263 * Run rule checks that apply during resource store
264 * Typically redifined in subclasses.
265 * @param array $input Input data to be used when evaluating rules
266 * @throws DomainException when a rule is broken
267 */
268 protected function domainRulesOnStore($input)
269 {
270 }
271
272 /**
273 * Run rule checks that apply during resource update
274 * Typically redifined in subclasses.
275 * @param array $input Input data to be used when evaluating rules
276 * @param array $original Original item data to be used when evaluating rules
277 * @throws DomainException when a rule is broken
278 */
279 protected function domainRulesOnUpdate($input, $original)
280 {
281 }
282
283 /**
284 * Run rule checks that apply during resource destroy
285 * Typically redifined in subclasses.
286 * @param array $original original data to be used when evaluating rules
287 * @throws DomainException when a rule is broken
288 */
289 protected function domainRulesOnDestroy($original)
290 {
291 }
292 }
293