Passed
Push — master ( 75ee84...60d2eb )
by Ronan
03:02
created

Model::__toString()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 4
ccs 0
cts 3
cp 0
crap 2
rs 10
1
<?php
2
3
namespace Ronanchilvers\Orm;
4
5
use Carbon\Carbon;
6
use DateTime;
7
use Exception;
8
use Ronanchilvers\Orm\Features\HasAttributes;
9
use Ronanchilvers\Orm\Features\HasHooks;
10
use Ronanchilvers\Orm\Features\HasRelationships;
11
use Ronanchilvers\Orm\Features\HasTimestamps;
12
use Ronanchilvers\Orm\Orm;
13
use Ronanchilvers\Utility\Str;
14
use RuntimeException;
15
use Serializable;
16
17
/**
18
 * Base model class for all models
19
 *
20
 * @property int id
21
 * @author Ronan Chilvers <[email protected]>
22
 */
23
abstract class Model implements Serializable
24
{
25
    use HasHooks,
26
        HasAttributes,
27
        HasTimestamps,
28
        HasRelationships;
29
30
    /**
31
     * @var string
32
     */
33
    static protected $finder = '';
34
35
    /**
36
     * @var string
37
     */
38
    static protected $table = '';
39
40
    /**
41
     * @var string
42
     */
43
    static protected $columnPrefix = '';
44
45
    /**
46
     * @var string
47
     */
48
    static protected $primaryKey = '';
49
50
    /**
51
     * Get the finder class for this model
52
     *
53
     * @return string
54
     * @author Ronan Chilvers <[email protected]>
55
     */
56
    static public function finder()
57
    {
58
        return static::$finder;
59
    }
60
61
    /**
62
     * Get the table name for this model
63
     *
64
     * @return string
65
     * @author Ronan Chilvers <[email protected]>
66
     */
67
    static public function table()
68
    {
69
        if ('' === static::$table) {
70
            $reflection = new \ReflectionClass(get_called_class());
71
            $table = Str::plural(Str::snake($reflection->getShortName()), 2);
72
73
            return $table;
74
        }
75
76
        return static::$table;
77
    }
78
79
    /**
80
     * Get the primary key fieldname for this model
81
     *
82
     * @return string
83
     * @author Ronan Chilvers <[email protected]>
84
     */
85
    static public function primaryKey()
86
    {
87
        if ('' === static::$primaryKey) {
88
            return static::prefix('id');
89
        }
90
91
        return static::$primaryKey;
92
    }
93
94
    /**
95
     * Prefix a string with the configured field prefix
96
     *
97
     * @param  string $string
98
     * @return string
99
     * @author Ronan Chilvers <[email protected]>
100
     */
101 1
    static public function prefix($string)
102
    {
103 1
        $prefix = static::$columnPrefix;
104 1
        if (!empty($prefix)) {
105
            $prefix = "{$prefix}_";
106
        }
107 1
        if (!empty($prefix) && 0 === strpos($string, $prefix)) {
108
            return $string;
109
        }
110
111 1
        return "{$prefix}{$string}";
112
    }
113
114
    /**
115
     * Un-prefix a string with the configured field prefix
116
     *
117
     * @param string $string
118
     * @return string
119
     * @author Ronan Chilvers <[email protected]>
120
     */
121 1
    static public function unprefix($string)
122
    {
123 1
        if (!empty(static::$columnPrefix) && 0 === strpos($string, static::$columnPrefix)) {
124
            return substr($string, strlen(static::$columnPrefix) + 1);
125
        }
126
127 1
        return $string;
128
    }
129
130
    /**
131
     * Transform a string into a fully qualified column with table and prefix
132
     *
133
     * @param string $string
134
     * @return string
135
     * @author Ronan Chilvers <[email protected]>
136
     */
137
    public static function qualify($string)
138
    {
139
        if ('*' != $string) {
140
            $string = static::prefix($string);
141
        }
142
        $table = static::table();
143
144
        return "{$table}.{$string}";
145
    }
146
147
    /**
148
     * Class constructor
149
     *
150
     * @author Ronan Chilvers <[email protected]>
151
     */
152 2
    public function __construct()
153
    {
154 2
        if ($this->useTimestamps()) {
155 2
            $this->bootHasTimestamps();
156
        }
157 2
        $this->boot();
158 2
    }
159
160
    /**
161
     * Magic clone method to ensure that cloned models are new
162
     *
163
     * @author Ronan Chilvers <[email protected]>
164
     */
165
    public function __clone()
166
    {
167
        $primaryKey = static::primaryKey();
168
        if (isset($this->data[$primaryKey])) {
169
            unset($this->data[$primaryKey]);
170
        }
171
        if ($this->useTimestamps()) {
172
            $this->clearTimestamps();
173
        }
174
        $this->clone();
175
    }
176
177
    /**
178
     * Clone function designed to be overriden by subclasses
179
     *
180
     *
181
     * @author Ronan Chilvers <[email protected]>
182
     */
183
    protected function clone()
184
    {}
185
186
    /**
187
     * Boot the model
188
     *
189
     * @author Ronan Chilvers <[email protected]>
190
     */
191 2
    protected function boot()
192 2
    {}
193
194
    /**
195
     * Magic property isset
196
     *
197
     * @param string $attribute
198
     * @return bool
199
     * @author Ronan Chilvers <[email protected]>
200
     */
201
    public function __isset($attribute)
202
    {
203
        return $this->hasAttribute($attribute);
204
    }
205
206
    /**
207
     * General property getter
208
     *
209
     * @param string $attribute
210
     * @return mixed
211
     * @author Ronan Chilvers <[email protected]>
212
     */
213 1
    public function get($attribute)
214
    {
215 1
        $result = $this->getRelation($attribute);
216 1
        if (!is_null($result)) {
217
            return $result;
218
        }
219 1
        return $this->getAttribute($attribute);
220
    }
221
222
    /**
223
     * Magic property getter
224
     *
225
     * @param string $attribute
226
     * @return mixed
227
     * @author Ronan Chilvers <[email protected]>
228
     */
229 1
    public function __get($attribute)
230
    {
231 1
        return $this->get($attribute);
232
    }
233
234
    /**
235
     * General property setter
236
     *
237
     * @param string $attribute
238
     * @param mixed $value
239
     * @author Ronan Chilvers <[email protected]>
240
     */
241
    public function set($attribute, $value)
242
    {
243
        return $this->setAttribute($attribute, $value);
244
    }
245
246
    /**
247
     * Magic property setter
248
     *
249
     * @param string $attribute
250
     * @param mixed $value
251
     * @author Ronan Chilvers <[email protected]>
252
     */
253
    public function __set($attribute, $value)
254
    {
255
        return $this->set($attribute, $value);
256
    }
257
258
    /**
259
     * Serialize the data array
260
     *
261
     * @return string
262
     * @author Ronan Chilvers <[email protected]>
263
     */
264
    public function serialize()
265
    {
266
        return serialize($this->toArray());
267
    }
268
269
    /**
270
     * Unserialize the data array
271
     *
272
     * @param string $serialized
273
     * @author Ronan Chilvers <[email protected]>
274
     */
275
    public function unserialize($serialized)
276
    {
277
        $this->fromArray(unserialize($serialized));
278
        $this->boot();
279
    }
280
281
    /**
282
     * Standard toString method returns id
283
     *
284
     * @return string
285
     * @author Ronan Chilvers <[email protected]>
286
     */
287
    public function __toString()
288
    {
289
        return (string) $this->getAttribute(
290
            static::primaryKey()
291
        );
292
    }
293
294
    /* Persistance methods **************/
295
    /************************************/
296
297
    /**
298
     * Is this model loaded?
299
     *
300
     * This simply means, do we have a primary key id?
301
     *
302
     * @return boolean
303
     * @author Ronan Chilvers <[email protected]>
304
     */
305
    public function isLoaded()
306
    {
307
        $key = static::primaryKey();
308
        return (
309
            $this->hasAttribute($key) &&
310
            is_numeric($this->getAttribute($key))
311
        );
312
    }
313
314
    /**
315
     * Save this model
316
     *
317
     * This method either inserts or updates the model row based on the presence
318
     * of an ID. It will return false if the save fails.
319
     *
320
     * @return boolean
321
     * @author Ronan Chilvers <[email protected]>
322
     */
323
    public function save()
324
    {
325
        if (false === $this->beforeSave()) {
326
            return false;
327
        }
328
        if (true === $this->isLoaded()) {
329
            if (false === $this->beforeUpdate()) {
330
                return false;
331
            }
332
            if ($this->useTimestamps()) {
333
                $this->updateTimestamps();
334
            }
335
            if (true !== $this->persistUpdate()) {
336
                return false;
337
            }
338
            $this->afterUpdate();
339
            $this->afterSave();
340
341
            return true;
342
        }
343
344
        if (false === $this->beforeCreate()) {
345
            return false;
346
        }
347
        if ($this->useTimestamps()) {
348
            $this->updateTimestamps();
349
        }
350
        if (true !== $this->persistInsert()) {
351
            return false;
352
        }
353
        $this->afterCreate();
354
        $this->afterSave();
355
356
        return true;
357
    }
358
359
    /**
360
     * Delete this model record
361
     *
362
     * @return boolean
363
     * @author Ronan Chilvers <[email protected]>
364
     */
365
    public function delete()
366
    {
367
        if (!$this->isLoaded()) {
368
            throw new RuntimeException(
369
                sprintf('Unable to delete model without primary key %s', static::primaryKey())
370
            );
371
        }
372
        if (false === $this->beforeDelete()) {
373
            return false;
374
        }
375
        if (false === $this->persistDelete()) {
376
            return false;
377
        }
378
        unset($this->data[static::primaryKey()]);
379
        $this->afterDelete();
380
381
        return true;
382
    }
383
384
    /**
385
     * Insert this model into the database
386
     *
387
     * @return boolean
388
     * @author Ronan Chilvers <[email protected]>
389
     */
390
    protected function persistInsert()
391
    {
392
        $this->beforePersist();
393
        $queryBuilder = $this->getQueryBuilderInstance();
394
        $query        = $queryBuilder->insert();
395
        $data         = $this->getAttributes();
396
        unset($data[static::primaryKey()]);
397
        $query->values(
398
            $data
399
        );
400
        if (true !== $query->execute()) {
401
            return false;
402
        }
403
        $this->data[static::primaryKey()] = $queryBuilder->getConnection()->lastInsertId();
404
        $this->oldData = [];
405
406
        return true;
407
    }
408
409
    /**
410
     * Update this model in the database
411
     *
412
     * @return boolean
413
     * @author Ronan Chilvers <[email protected]>
414
     */
415
    protected function persistUpdate()
416
    {
417
        $this->beforePersist();
418
        $queryBuilder = $this->getQueryBuilderInstance();
419
        $query        = $queryBuilder->update();
420
        $data         = $this->getAttributes();
421
        $id           = $data[static::primaryKey()];
422
        unset($data[static::primaryKey()]);
423
        $query
424
            ->set(
425
                $data
426
            )
427
            ->where(
428
                static::primaryKey(),
429
                '=',
430
                $id
431
            );
432
        $result = $query->execute();
433
        if (false == $result) {
434
            return false;
435
        }
436
        $this->oldData = [];
437
438
        return true;
439
    }
440
441
    /**
442
     * Delete this model from the database
443
     *
444
     * @return boolean
445
     * @author Ronan Chilvers <[email protected]>
446
     */
447
    protected function persistDelete()
448
    {
449
        $queryBuilder = $this->getQueryBuilderInstance();
450
        $query = $queryBuilder
451
            ->delete()
452
            ->where(
453
                static::primaryKey(),
454
                '=',
455
                $this->data[static::primaryKey()]
456
            )
457
            ;
458
        if (false === $query->execute()) {
459
            return false;
460
        }
461
        unset($this->data[static::primaryKey()]);
462
463
        return true;
464
    }
465
466
    /**
467
     * Get a query builder for this model
468
     *
469
     * @return \Ronanchilvers\Orm\QueryBuilder
470
     * @author Ronan Chilvers <[email protected]>
471
     */
472
    protected function getQueryBuilderInstance()
473
    {
474
        $connection = Orm::getConnection();
475
476
        return new QueryBuilder(
477
            $connection,
478
            get_called_class()
479
        );
480
    }
481
482
    /* Persistance methods **************/
483
    /************************************/
484
}
485