|
1
|
|
|
<?php |
|
2
|
|
|
namespace Darya\ORM; |
|
3
|
|
|
|
|
4
|
|
|
use Exception; |
|
5
|
|
|
use Darya\ORM\Model; |
|
6
|
|
|
use Darya\ORM\Relation; |
|
7
|
|
|
use Darya\Storage\Query; |
|
8
|
|
|
use Darya\Storage\Readable; |
|
9
|
|
|
use Darya\Storage\Queryable; |
|
10
|
|
|
use Darya\Storage\Modifiable; |
|
11
|
|
|
use Darya\Storage\Searchable; |
|
12
|
|
|
use Darya\Storage\Aggregational; |
|
13
|
|
|
use Darya\Storage\Query\Builder; |
|
14
|
|
|
|
|
15
|
|
|
/** |
|
16
|
|
|
* Darya's active record implementation. |
|
17
|
|
|
* |
|
18
|
|
|
* @author Chris Andrew <[email protected]> |
|
19
|
|
|
*/ |
|
20
|
|
|
class Record extends Model { |
|
21
|
|
|
|
|
22
|
|
|
/** |
|
23
|
|
|
* Overrides the name of the database table that persists the model. The |
|
24
|
|
|
* model's lowercased class name is used if this is not set. |
|
25
|
|
|
* |
|
26
|
|
|
* @var string Database table name |
|
27
|
|
|
*/ |
|
28
|
|
|
protected $table; |
|
29
|
|
|
|
|
30
|
|
|
/** |
|
31
|
|
|
* @var \Darya\Storage\Readable Instance storage |
|
32
|
|
|
*/ |
|
33
|
|
|
protected $storage; |
|
34
|
|
|
|
|
35
|
|
|
/** |
|
36
|
|
|
* @var \Darya\Storage\Readable Shared storage |
|
37
|
|
|
*/ |
|
38
|
|
|
protected static $sharedStorage; |
|
39
|
|
|
|
|
40
|
|
|
/** |
|
41
|
|
|
* @var array Definitions of related models |
|
42
|
|
|
*/ |
|
43
|
|
|
protected $relations = array(); |
|
44
|
|
|
|
|
45
|
|
|
/** |
|
46
|
|
|
* @var array Default searchable attributes |
|
47
|
|
|
*/ |
|
48
|
|
|
protected $search = array(); |
|
49
|
|
|
|
|
50
|
|
|
/** |
|
51
|
|
|
* Instantiate a new record with the given data or load an instance from |
|
52
|
|
|
* storage if the given data is a valid primary key. |
|
53
|
|
|
* |
|
54
|
|
|
* @param mixed $data An array of key-value attributes to set or a primary key to load by |
|
55
|
|
|
*/ |
|
56
|
|
|
public function __construct($data = null) { |
|
57
|
|
|
if (is_numeric($data) || is_string($data)) { |
|
58
|
|
|
$this->data = static::load($data); |
|
59
|
|
|
} |
|
60
|
|
|
|
|
61
|
|
|
parent::__construct($data); |
|
62
|
|
|
} |
|
63
|
|
|
|
|
64
|
|
|
/** |
|
65
|
|
|
* Generate instances of the model with the given sets of attributes. |
|
66
|
|
|
* |
|
67
|
|
|
* @param array $rows |
|
68
|
|
|
* @return Record[] |
|
69
|
|
|
*/ |
|
70
|
|
View Code Duplication |
public static function generate(array $rows = array()) { |
|
|
|
|
|
|
71
|
|
|
$instances = array(); |
|
72
|
|
|
|
|
73
|
|
|
foreach ($rows as $key => $attributes) { |
|
74
|
|
|
$instances[$key] = new static; |
|
75
|
|
|
$instances[$key]->setMany($attributes); |
|
76
|
|
|
} |
|
77
|
|
|
|
|
78
|
|
|
return $instances; |
|
79
|
|
|
} |
|
80
|
|
|
|
|
81
|
|
|
/** |
|
82
|
|
|
* Determine whether the given attribute or relation is set on the record. |
|
83
|
|
|
* |
|
84
|
|
|
* @param string $attribute |
|
85
|
|
|
*/ |
|
86
|
|
|
public function has($attribute) { |
|
87
|
|
|
return $this->hasRelated($attribute) || parent::has($attribute); |
|
88
|
|
|
} |
|
89
|
|
|
|
|
90
|
|
|
/** |
|
91
|
|
|
* Retrieve the given attribute or relation from the record. |
|
92
|
|
|
* |
|
93
|
|
|
* @param string $attribute |
|
94
|
|
|
* @return mixed |
|
95
|
|
|
*/ |
|
96
|
|
|
public function get($attribute) { |
|
97
|
|
|
if ($this->hasRelation($attribute)) { |
|
98
|
|
|
return $this->related($attribute); |
|
99
|
|
|
} |
|
100
|
|
|
|
|
101
|
|
|
return parent::get($attribute); |
|
102
|
|
|
} |
|
103
|
|
|
|
|
104
|
|
|
/** |
|
105
|
|
|
* Set the value of an attribute or relation on the model. |
|
106
|
|
|
* |
|
107
|
|
|
* @param string $attribute |
|
108
|
|
|
* @param mixed $value |
|
109
|
|
|
*/ |
|
110
|
|
|
public function set($attribute, $value = null) { |
|
111
|
|
|
if (is_string($attribute) && $this->hasRelation($attribute)) { |
|
112
|
|
|
return $this->setRelated($attribute, $value); |
|
113
|
|
|
} |
|
114
|
|
|
|
|
115
|
|
|
parent::set($attribute, $value); |
|
116
|
|
|
} |
|
117
|
|
|
|
|
118
|
|
|
/** |
|
119
|
|
|
* Retrieve the name of the table this model belongs to. |
|
120
|
|
|
* |
|
121
|
|
|
* If none is set, it defaults to creating it from the class name. |
|
122
|
|
|
* |
|
123
|
|
|
* For example: |
|
124
|
|
|
* Page -> pages |
|
125
|
|
|
* PageSection -> page_sections |
|
126
|
|
|
* |
|
127
|
|
|
* @return string |
|
128
|
|
|
*/ |
|
129
|
|
|
public function table() { |
|
130
|
|
|
if ($this->table) { |
|
131
|
|
|
return $this->table; |
|
132
|
|
|
} |
|
133
|
|
|
|
|
134
|
|
|
return preg_replace_callback('/([A-Z])/', function($matches) { |
|
135
|
|
|
return '_' . strtolower($matches[1]); |
|
136
|
|
|
}, lcfirst(basename(get_class($this)))) . 's'; |
|
137
|
|
|
} |
|
138
|
|
|
|
|
139
|
|
|
/** |
|
140
|
|
|
* Get and optionally set the model's storage instance. |
|
141
|
|
|
* |
|
142
|
|
|
* @return \Darya\Storage\Readable |
|
143
|
|
|
*/ |
|
144
|
|
|
public function storage(Readable $storage = null) { |
|
145
|
|
|
$this->storage = $storage ?: $this->storage; |
|
146
|
|
|
|
|
147
|
|
|
return $this->storage ?: static::getSharedStorage(); |
|
148
|
|
|
} |
|
149
|
|
|
|
|
150
|
|
|
/** |
|
151
|
|
|
* Get the storage shared to all instances of this model. |
|
152
|
|
|
* |
|
153
|
|
|
* @return \Darya\Storage\Readable |
|
154
|
|
|
*/ |
|
155
|
|
|
public static function getSharedStorage() { |
|
156
|
|
|
return static::$sharedStorage; |
|
157
|
|
|
} |
|
158
|
|
|
|
|
159
|
|
|
/** |
|
160
|
|
|
* Share the given database connection to all instances of this model. |
|
161
|
|
|
* |
|
162
|
|
|
* @param \Darya\Storage\Readable $storage |
|
163
|
|
|
*/ |
|
164
|
|
|
public static function setSharedStorage(Readable $storage) { |
|
165
|
|
|
static::$sharedStorage = $storage; |
|
166
|
|
|
} |
|
167
|
|
|
|
|
168
|
|
|
/** |
|
169
|
|
|
* Prepare the record's data for storage. This is here until repositories |
|
170
|
|
|
* are implemented. |
|
171
|
|
|
* |
|
172
|
|
|
* @return array |
|
173
|
|
|
*/ |
|
174
|
|
|
protected function prepareData() { |
|
175
|
|
|
$types = $this->attributes; |
|
176
|
|
|
|
|
177
|
|
|
$changed = array_intersect_key($this->data, array_flip($this->changed)); |
|
178
|
|
|
|
|
179
|
|
|
$data = $this->id() && $changed ? $changed : $this->data; |
|
180
|
|
|
|
|
181
|
|
|
foreach ($data as $attribute => $value) { |
|
182
|
|
|
if (isset($types[$attribute])) { |
|
183
|
|
|
$type = $types[$attribute]; |
|
184
|
|
|
|
|
185
|
|
|
switch ($type) { |
|
186
|
|
|
case 'int': |
|
187
|
|
|
$value = (int) $value; |
|
188
|
|
|
break; |
|
189
|
|
|
case 'date': |
|
190
|
|
|
$value = date('Y-m-d', $value); |
|
191
|
|
|
break; |
|
192
|
|
|
case 'datetime': |
|
193
|
|
|
$value = date('Y-m-d H:i:s', $value); |
|
194
|
|
|
break; |
|
195
|
|
|
case 'time': |
|
196
|
|
|
$value = date('H:i:s', $value); |
|
197
|
|
|
break; |
|
198
|
|
|
} |
|
199
|
|
|
|
|
200
|
|
|
$data[$attribute] = $value; |
|
201
|
|
|
} |
|
202
|
|
|
} |
|
203
|
|
|
|
|
204
|
|
|
return $data; |
|
205
|
|
|
} |
|
206
|
|
|
|
|
207
|
|
|
/** |
|
208
|
|
|
* Prepare the given filter. |
|
209
|
|
|
* |
|
210
|
|
|
* Creates a filter for the record's key attribute if the given value is not |
|
211
|
|
|
* an array. |
|
212
|
|
|
* |
|
213
|
|
|
* @param mixed $filter |
|
214
|
|
|
* @return string |
|
215
|
|
|
*/ |
|
216
|
|
|
protected static function prepareFilter($filter) { |
|
217
|
|
|
if ($filter === null) { |
|
218
|
|
|
return array(); |
|
219
|
|
|
} |
|
220
|
|
|
|
|
221
|
|
|
if (!is_array($filter)) { |
|
222
|
|
|
$instance = new static; |
|
223
|
|
|
$filter = array($instance->key() => $filter); |
|
224
|
|
|
} |
|
225
|
|
|
|
|
226
|
|
|
return $filter; |
|
227
|
|
|
} |
|
228
|
|
|
|
|
229
|
|
|
/** |
|
230
|
|
|
* Prepare the given list data. |
|
231
|
|
|
* |
|
232
|
|
|
* @param array $data |
|
233
|
|
|
* @param string $attribute |
|
234
|
|
|
* @return array |
|
235
|
|
|
*/ |
|
236
|
|
|
protected static function prepareListing($data, $attribute) { |
|
237
|
|
|
$instance = new static; |
|
238
|
|
|
$key = $instance->key(); |
|
239
|
|
|
|
|
240
|
|
|
$list = array(); |
|
241
|
|
|
|
|
242
|
|
|
foreach ($data as $row) { |
|
243
|
|
|
if (isset($row[$attribute])) { |
|
244
|
|
|
$list[$row[$key]] = $row[$attribute]; |
|
245
|
|
|
} |
|
246
|
|
|
} |
|
247
|
|
|
|
|
248
|
|
|
return $list; |
|
249
|
|
|
} |
|
250
|
|
|
|
|
251
|
|
|
/** |
|
252
|
|
|
* Load record data from storage using the given criteria. |
|
253
|
|
|
* |
|
254
|
|
|
* @param array|string|int $filter [optional] |
|
255
|
|
|
* @param array|string $order [optional] |
|
256
|
|
|
* @param int $limit [optional] |
|
257
|
|
|
* @param int $offset [optional] |
|
258
|
|
|
* @return array |
|
259
|
|
|
*/ |
|
260
|
|
|
public static function load($filter = array(), $order = array(), $limit = null, $offset = 0) { |
|
261
|
|
|
$instance = new static; |
|
262
|
|
|
$storage = $instance->storage(); |
|
263
|
|
|
$filter = static::prepareFilter($filter); |
|
264
|
|
|
|
|
265
|
|
|
return $storage->read($instance->table(), $filter, $order, $limit, $offset); |
|
266
|
|
|
} |
|
267
|
|
|
|
|
268
|
|
|
/** |
|
269
|
|
|
* Load a record instance from storage using the given criteria. |
|
270
|
|
|
* |
|
271
|
|
|
* Returns false if the record cannot be found. |
|
272
|
|
|
* |
|
273
|
|
|
* @param array|string|int $filter [optional] |
|
274
|
|
|
* @param array|string $order [optional] |
|
275
|
|
|
* @return Record|bool |
|
276
|
|
|
*/ |
|
277
|
|
|
public static function find($filter = array(), $order = array()) { |
|
278
|
|
|
$data = static::load($filter, $order, 1); |
|
279
|
|
|
|
|
280
|
|
|
return !empty($data[0]) ? new static($data[0]) : false; |
|
281
|
|
|
} |
|
282
|
|
|
|
|
283
|
|
|
/** |
|
284
|
|
|
* Load a record instance from storage using the given criteria or create a |
|
285
|
|
|
* new instance if nothing is found. |
|
286
|
|
|
* |
|
287
|
|
|
* @param array|string|int $filter [optional] |
|
288
|
|
|
* @param array|string $order [optional] |
|
289
|
|
|
* @return Record |
|
290
|
|
|
*/ |
|
291
|
|
|
public static function findOrNew($filter = array(), $order = array()) { |
|
292
|
|
|
$instance = static::find($filter, $order); |
|
293
|
|
|
|
|
294
|
|
|
return $instance === false ? new static : $instance; |
|
295
|
|
|
} |
|
296
|
|
|
|
|
297
|
|
|
/** |
|
298
|
|
|
* Load multiple record instances from storage using the given criteria. |
|
299
|
|
|
* |
|
300
|
|
|
* @param array|string|int $filter [optional] |
|
301
|
|
|
* @param array|string $order [optional] |
|
302
|
|
|
* @param int $limit [optional] |
|
303
|
|
|
* @param int $offset [optional] |
|
304
|
|
|
* @return array |
|
305
|
|
|
*/ |
|
306
|
|
|
public static function all($filter = array(), $order = array(), $limit = null, $offset = 0) { |
|
307
|
|
|
return static::generate(static::load($filter, $order, $limit, $offset)); |
|
308
|
|
|
} |
|
309
|
|
|
|
|
310
|
|
|
/** |
|
311
|
|
|
* Eagerly load the given relations of multiple record instances. |
|
312
|
|
|
* |
|
313
|
|
|
* @param array|string $relations |
|
314
|
|
|
* @return array |
|
315
|
|
|
*/ |
|
316
|
|
|
public static function eager($relations) { |
|
317
|
|
|
$instance = new static; |
|
318
|
|
|
$instances = static::all(); |
|
319
|
|
|
|
|
320
|
|
|
foreach ((array) $relations as $relation) { |
|
321
|
|
|
if ($instance->relation($relation)) { |
|
322
|
|
|
$instances = $instance->relation($relation)->eager($instances, $relation); |
|
323
|
|
|
} |
|
324
|
|
|
} |
|
325
|
|
|
|
|
326
|
|
|
return $instances; |
|
327
|
|
|
} |
|
328
|
|
|
|
|
329
|
|
|
/** |
|
330
|
|
|
* Search for record instances in storage using the given criteria. |
|
331
|
|
|
* |
|
332
|
|
|
* @param string $query |
|
333
|
|
|
* @param array $attributes [optional] |
|
334
|
|
|
* @param array|string|int $filter [optional] |
|
335
|
|
|
* @param array|string $order [optional] |
|
336
|
|
|
* @param int $limit [optional] |
|
337
|
|
|
* @param int $offset [optional] |
|
338
|
|
|
* @return array |
|
339
|
|
|
*/ |
|
340
|
|
|
public static function search($query, $attributes = array(), $filter = array(), $order = array(), $limit = null, $offset = 0) { |
|
341
|
|
|
$instance = new static; |
|
342
|
|
|
$storage = $instance->storage(); |
|
343
|
|
|
|
|
344
|
|
|
if (!$storage instanceof Searchable) { |
|
345
|
|
|
throw new Exception(get_class($instance) . ' storage is not searchable'); |
|
346
|
|
|
} |
|
347
|
|
|
|
|
348
|
|
|
$attributes = $attributes ?: $instance->defaultSearchAttributes(); |
|
349
|
|
|
|
|
350
|
|
|
$data = $storage->search($instance->table(), $query, $attributes, $filter, $order, $limit, $offset); |
|
351
|
|
|
|
|
352
|
|
|
return static::generate($data); |
|
353
|
|
|
} |
|
354
|
|
|
|
|
355
|
|
|
/** |
|
356
|
|
|
* Retrieve key => value pairs using `id` for keys and the given attribute |
|
357
|
|
|
* for values. |
|
358
|
|
|
* |
|
359
|
|
|
* @param string $attribute |
|
360
|
|
|
* @param array $filter [optional] |
|
361
|
|
|
* @param array $order [optional] |
|
362
|
|
|
* @param int $limit [optional] |
|
363
|
|
|
* @param int $offset [optional] |
|
364
|
|
|
* @return array |
|
365
|
|
|
*/ |
|
366
|
|
|
public static function listing($attribute, $filter = array(), $order = array(), $limit = null, $offset = 0) { |
|
367
|
|
|
$instance = new static; |
|
368
|
|
|
$storage = $instance->storage(); |
|
369
|
|
|
|
|
370
|
|
|
$data = $storage->listing($instance->table(), array($instance->key(), $attribute), $filter, $order, $limit, $offset); |
|
371
|
|
|
|
|
372
|
|
|
return static::prepareListing($data, $attribute); |
|
373
|
|
|
} |
|
374
|
|
|
|
|
375
|
|
|
/** |
|
376
|
|
|
* Retrieve the distinct values of the given attribute. |
|
377
|
|
|
* |
|
378
|
|
|
* @param string $attribute |
|
379
|
|
|
* @param array $filter [optional] |
|
380
|
|
|
* @param array $order [optional] |
|
381
|
|
|
* @param int $limit [optional] |
|
382
|
|
|
* @param int $offset [optional] |
|
383
|
|
|
* @return array |
|
384
|
|
|
*/ |
|
385
|
|
|
public static function distinct($attribute, $filter = array(), $order = array(), $limit = null, $offset = 0) { |
|
386
|
|
|
$instance = new static; |
|
387
|
|
|
$storage = $instance->storage(); |
|
388
|
|
|
|
|
389
|
|
|
if (!$storage instanceof Aggregational) { |
|
390
|
|
|
return array_values(array_unique(static::listing($attribute, $filter, $order))); |
|
391
|
|
|
} |
|
392
|
|
|
|
|
393
|
|
|
return $storage->distinct($instance->table(), $attribute, $filter, $order, $limit, $offset); |
|
394
|
|
|
} |
|
395
|
|
|
|
|
396
|
|
|
/** |
|
397
|
|
|
* Create a query builder for the model. |
|
398
|
|
|
* |
|
399
|
|
|
* @return Builder |
|
400
|
|
|
*/ |
|
401
|
|
|
public static function query() { |
|
402
|
|
|
$instance = new static; |
|
403
|
|
|
$storage = $instance->storage(); |
|
404
|
|
|
|
|
405
|
|
|
if (!$storage instanceof Queryable) { |
|
406
|
|
|
throw new Exception(get_class($instance) . ' storage is not queryable'); |
|
407
|
|
|
} |
|
408
|
|
|
|
|
409
|
|
|
$query = new Query($instance->table()); |
|
410
|
|
|
$builder = new Builder($query, $instance->storage()); |
|
|
|
|
|
|
411
|
|
|
|
|
412
|
|
|
$builder->callback(function($result) use ($instance) { |
|
413
|
|
|
return $instance::generate($result->data); |
|
414
|
|
|
}); |
|
415
|
|
|
|
|
416
|
|
|
return $builder; |
|
417
|
|
|
} |
|
418
|
|
|
|
|
419
|
|
|
/** |
|
420
|
|
|
* Save the record to storage. |
|
421
|
|
|
* |
|
422
|
|
|
* @return bool |
|
423
|
|
|
*/ |
|
424
|
|
|
public function save() { |
|
425
|
|
|
if ($this->validate()) { |
|
426
|
|
|
$storage = $this->storage(); |
|
427
|
|
|
$class = get_class($this); |
|
428
|
|
|
|
|
429
|
|
|
if (!$storage instanceof Modifiable) { |
|
430
|
|
|
throw new Exception(basename($class) . ' storage is not modifiable'); |
|
431
|
|
|
} |
|
432
|
|
|
|
|
433
|
|
|
$data = $this->prepareData(); |
|
434
|
|
|
|
|
435
|
|
|
if (!$this->id()) { |
|
436
|
|
|
$id = $storage->create($this->table(), $data); |
|
437
|
|
|
|
|
438
|
|
|
if ($id) { |
|
439
|
|
|
$this->set($this->key(), $id); |
|
440
|
|
|
|
|
441
|
|
|
return true; |
|
442
|
|
|
} |
|
443
|
|
|
} else { |
|
444
|
|
|
$updated = $storage->update($this->table(), $data, array($this->key() => $this->id()), 1); |
|
445
|
|
|
|
|
446
|
|
|
if (!$updated) { |
|
447
|
|
|
$updated = $storage->create($this->table(), $data) > 0; |
|
448
|
|
|
} |
|
449
|
|
|
|
|
450
|
|
|
if ($updated) { |
|
451
|
|
|
return true; |
|
452
|
|
|
} |
|
453
|
|
|
} |
|
454
|
|
|
|
|
455
|
|
|
$entity = strtolower(basename($class)); |
|
456
|
|
|
$this->errors['save'] = "Failed to save $entity"; |
|
457
|
|
|
$this->errors['storage'] = $this->storage()->error(); |
|
458
|
|
|
} |
|
459
|
|
|
|
|
460
|
|
|
return false; |
|
461
|
|
|
} |
|
462
|
|
|
|
|
463
|
|
|
/** |
|
464
|
|
|
* Save multiple record instances to storage. |
|
465
|
|
|
* |
|
466
|
|
|
* Returns the number of instances that saved successfully. |
|
467
|
|
|
* |
|
468
|
|
|
* @param array $instances |
|
469
|
|
|
* @return int |
|
470
|
|
|
*/ |
|
471
|
|
|
public static function saveMany($instances) { |
|
472
|
|
|
$failed = 0; |
|
473
|
|
|
|
|
474
|
|
|
foreach ($instances as $instance) { |
|
475
|
|
|
if (!$instance->save()) { |
|
476
|
|
|
$failed++; |
|
477
|
|
|
} |
|
478
|
|
|
} |
|
479
|
|
|
|
|
480
|
|
|
return count($instances) - $failed; |
|
481
|
|
|
} |
|
482
|
|
|
|
|
483
|
|
|
/** |
|
484
|
|
|
* Delete the record from storage. |
|
485
|
|
|
* |
|
486
|
|
|
* @return bool |
|
487
|
|
|
*/ |
|
488
|
|
|
public function delete() { |
|
489
|
|
|
if ($this->id()) { |
|
490
|
|
|
$storage = $this->storage(); |
|
491
|
|
|
|
|
492
|
|
|
if ($storage instanceof Modifiable) { |
|
493
|
|
|
return (bool) $storage->delete($this->table(), array($this->key() => $this->id()), 1); |
|
494
|
|
|
} |
|
495
|
|
|
} |
|
496
|
|
|
|
|
497
|
|
|
return false; |
|
498
|
|
|
} |
|
499
|
|
|
|
|
500
|
|
|
/** |
|
501
|
|
|
* Determine whether the given attribute is a relation. |
|
502
|
|
|
* |
|
503
|
|
|
* @param string $attribute |
|
504
|
|
|
* @return bool |
|
505
|
|
|
*/ |
|
506
|
|
|
protected function hasRelation($attribute) { |
|
507
|
|
|
$attribute = $this->prepareAttribute($attribute); |
|
508
|
|
|
|
|
509
|
|
|
return isset($this->relations[$attribute]); |
|
510
|
|
|
} |
|
511
|
|
|
|
|
512
|
|
|
/** |
|
513
|
|
|
* Retrieve the given relation. |
|
514
|
|
|
* |
|
515
|
|
|
* @param string $attribute |
|
516
|
|
|
* @return \Darya\ORM\Relation |
|
517
|
|
|
*/ |
|
518
|
|
|
public function relation($attribute) { |
|
519
|
|
|
if (!$this->hasRelation($attribute)) { |
|
520
|
|
|
return null; |
|
521
|
|
|
} |
|
522
|
|
|
|
|
523
|
|
|
$attribute = $this->prepareAttribute($attribute); |
|
524
|
|
|
$relation = $this->relations[$attribute]; |
|
525
|
|
|
|
|
526
|
|
|
if (!$relation instanceof Relation) { |
|
527
|
|
|
$type = array_shift($relation); |
|
528
|
|
|
$arguments = array_merge(array($this), $relation); |
|
529
|
|
|
|
|
530
|
|
|
$relation = Relation::factory($type, $arguments); |
|
531
|
|
|
|
|
532
|
|
|
$this->relations[$attribute] = $relation; |
|
533
|
|
|
} |
|
534
|
|
|
|
|
535
|
|
|
return $relation; |
|
536
|
|
|
} |
|
537
|
|
|
|
|
538
|
|
|
/** |
|
539
|
|
|
* Determine whether the given relation has any set model(s). |
|
540
|
|
|
* |
|
541
|
|
|
* @param string $attribute |
|
542
|
|
|
* @return bool |
|
543
|
|
|
*/ |
|
544
|
|
|
protected function hasRelated($attribute) { |
|
545
|
|
|
$attribute = $this->prepareAttribute($attribute); |
|
546
|
|
|
|
|
547
|
|
|
return $this->hasRelation($attribute) && $this->relation($attribute)->count(); |
|
548
|
|
|
} |
|
549
|
|
|
|
|
550
|
|
|
/** |
|
551
|
|
|
* Retrieve the model(s) of the given relation. |
|
552
|
|
|
* |
|
553
|
|
|
* @param string $attribute |
|
554
|
|
|
* @return array |
|
555
|
|
|
*/ |
|
556
|
|
|
public function related($attribute) { |
|
557
|
|
|
if (!$this->hasRelation($attribute)) { |
|
558
|
|
|
return null; |
|
559
|
|
|
} |
|
560
|
|
|
|
|
561
|
|
|
$attribute = $this->prepareAttribute($attribute); |
|
562
|
|
|
|
|
563
|
|
|
$relation = $this->relation($attribute); |
|
564
|
|
|
|
|
565
|
|
|
return $relation->retrieve(); |
|
566
|
|
|
} |
|
567
|
|
|
|
|
568
|
|
|
/** |
|
569
|
|
|
* Set the given related model(s). |
|
570
|
|
|
* |
|
571
|
|
|
* @param string $attribute |
|
572
|
|
|
* @param mixed $value |
|
573
|
|
|
*/ |
|
574
|
|
|
protected function setRelated($attribute, $value) { |
|
575
|
|
|
if (!$this->hasRelation($attribute)) { |
|
576
|
|
|
return; |
|
577
|
|
|
} |
|
578
|
|
|
|
|
579
|
|
|
$relation = $this->relation($attribute); |
|
580
|
|
|
|
|
581
|
|
|
if ($value !== null && !$value instanceof $relation->target && !is_array($value)) { |
|
582
|
|
|
return; |
|
583
|
|
|
} |
|
584
|
|
|
|
|
585
|
|
|
$relation->associate($value); |
|
586
|
|
|
} |
|
587
|
|
|
|
|
588
|
|
|
/** |
|
589
|
|
|
* Retrieve the default search attributes for the model. |
|
590
|
|
|
* |
|
591
|
|
|
* @return array |
|
592
|
|
|
*/ |
|
593
|
|
|
public function defaultSearchAttributes() { |
|
594
|
|
|
return $this->search; |
|
595
|
|
|
} |
|
596
|
|
|
|
|
597
|
|
|
/** |
|
598
|
|
|
* Retrieve a relation. Shortcut for `relation()`. |
|
599
|
|
|
* |
|
600
|
|
|
* @param string $method |
|
601
|
|
|
* @param array $arguments |
|
602
|
|
|
* @return Relation |
|
603
|
|
|
*/ |
|
604
|
|
|
public function __call($method, $arguments) { |
|
605
|
|
|
return $this->relation($method); |
|
606
|
|
|
} |
|
607
|
|
|
|
|
608
|
|
|
} |
|
609
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.