Completed
Push — master ( 4ac004...470d43 )
by Gabriel
06:41
created

RecordManager::exists()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 0
cts 12
cp 0
rs 9.568
c 0
b 0
f 0
cc 4
nc 5
nop 1
crap 20

1 Method

Rating   Name   Duplication   Size   Complexity  
A RecordManager::findOneByParams() 0 10 2
1
<?php
2
3
namespace Nip\Records\AbstractModels;
4
5
use Nip\Collections\Registry;
6
use Nip\Database\Query\Insert as InsertQuery;
7
use Nip\HelperBroker;
8
use Nip\Records\Collections\Collection as RecordCollection;
9
use Nip\Records\Traits\ActiveRecord\ActiveRecordsTrait;
10
use Nip\Utility\Traits\NameWorksTrait;
11
12
/**
13
 * Class Table
14
 * @package Nip\Records\_Abstract
15
 *
16
 * @method \Nip_Helper_Url Url()
17
 */
18
abstract class RecordManager
19
{
20
    use NameWorksTrait;
21
    use ActiveRecordsTrait;
22
23
    /**
24
     * Collection class for current record manager
25
     *
26
     * @var string
27
     */
28
    protected $collectionClass = null;
29
30
    protected $helpers = [];
31
32
    /**
33
     * @var null|string
34
     */
35
    protected $urlPK = null;
36
37
    /**
38
     * Model class name
39
     * @var null|string
40
     */
41
    protected $model = null;
42
43
    /**
44
     * @var null|string
45
     */
46
    protected $controller = null;
47
48
    /**
49
     * @var null|string
50
     */
51
    protected $modelNamespacePath = null;
52
53
    protected $registry = null;
54
55
    /**
56
     * Overloads findByRecord, findByField, deleteByRecord, deleteByField, countByRecord, countByField
57
     *
58
     * @example findByCategory(Category $item)
59
     * @example deleteByProduct(Product $item)
60
     * @example findByIdUser(2)
61
     * @example deleteByTitle(array('Lorem ipsum', 'like'))
62
     * @example countByIdCategory(1)
63
     *
64
     * @param string $name
65
     * @param array $arguments
66
     *
67
     * @return mixed
68
     */
69 1
    public function __call($name, $arguments)
70
    {
71 1
        $return = $this->isCallDatabaseOperation($name, $arguments);
72 1
        if ($return !== false) {
73
            return $return;
74
        }
75
76
        /** @noinspection PhpAssignmentInConditionInspection */
77 1
        if ($return = $this->isCallUrl($name, $arguments)) {
78
            return $return;
79
        }
80
81 1
        if ($name === ucfirst($name)) {
82 1
            return $this->getHelper($name);
83
        }
84
85
        trigger_error("Call to undefined method $name", E_USER_ERROR);
86
87
        return $this;
88
    }
89
90
    /**
91
     * @param string $name
92
     * @param $arguments
93
     * @return bool
94
     */
95 1
    protected function isCallUrl($name, $arguments)
96
    {
97 1
        if (substr($name, 0, 3) == "get" && substr($name, -3) == "URL") {
98
            $action = substr($name, 3, -3);
99
            $params = isset($arguments[0]) ? $arguments[0] : [];
100
            $module = isset($arguments[1]) ? $arguments[1] : null;
101
102
            return $this->compileURL($action, $params, $module);
103
        }
104
105 1
        return false;
106
    }
107
108
    /**
109
     * @param string $action
110
     * @param array $params
111
     * @param null $module
112
     * @return string|null
113
     */
114
    public function compileURL($action, $params = [], $module = null)
115
    {
116
        $controller = $this->getController();
117
118
        if (substr($action, 0, 5) == 'Async') {
119
            $controller = 'async-' . $controller;
120
            $action = substr($action, 5);
121
        }
122
123
        if (substr($action, 0, 5) == 'Modal') {
124
            $controller = 'modal-' . $controller;
125
            $action = substr($action, 5);
126
        }
127
128
        $params['action'] = (!empty($action)) ? $action : 'index';
129
        $params['controller'] = $controller;
130
131
        $params['action'] = inflector()->unclassify($params['action']);
132
        $params['action'] = ($params['action'] == 'index') ? false : $params['action'];
133
134
        $params['controller'] = $controller ? $controller : $this->getController();
135
        $params['module'] = $module ? $module : request()->getModuleName();
136
137
        $routeName = $params['module'] . '.' . $params['controller'] . '.' . $params['action'];
138
        if ($this->Url()->getRouter()->hasRoute($routeName)) {
139
            unset($params['module'], $params['controller'], $params['action']);
140
        } else {
141
            $routeName = $params['module'] . '.default';
142
        }
143
144
        return $this->Url()->assemble($routeName, $params);
0 ignored issues
show
Documentation introduced by
$params is of type array<string,?,{"module":"?"}>, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
145
    }
146
147
    /**
148
     * @return string
149
     */
150 13
    public function getController()
151
    {
152 13
        if ($this->controller === null) {
153 13
            $this->initController();
154
        }
155
156 13
        return $this->controller;
157
    }
158
159
    /**
160
     * @param null|string $controller
161
     */
162 13
    public function setController($controller)
163
    {
164 13
        $this->controller = $controller;
165 13
    }
166
167 13
    protected function initController()
168
    {
169 13
        if ($this->isNamespaced()) {
170 8
            $controller = $this->generateControllerNamespaced();
171
        } else {
172 5
            $controller = $this->generateControllerGeneric();
173
        }
174 13
        $this->setController($controller);
175 13
    }
176
177
    /**
178
     * @return string
179
     */
180 8
    protected function generateControllerNamespaced()
181
    {
182 8
        $class = $this->getModelNamespacePath();
183 8
        $class = trim($class, '\\');
184
185 8
        return inflector()->unclassify($class);
186
    }
187
188
    /**
189
     * @return string
190
     */
191 8
    public function getModelNamespacePath()
192
    {
193 8
        if ($this->modelNamespacePath == null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $this->modelNamespacePath of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
194 8
            $this->initModelNamespacePath();
195
        }
196
197 8
        return $this->modelNamespacePath;
198
    }
199
200 8
    public function initModelNamespacePath()
201
    {
202 8
        if ($this->isNamespaced()) {
203 8
            $path = $this->generateModelNamespacePathFromClassName() . '\\';
204
        } else {
205
            $controller = $this->generateControllerGeneric();
206
            $path = inflector()->classify($controller) . '\\';
207
        }
208 8
        $this->modelNamespacePath = $path;
209 8
    }
210
211
    /**
212
     * @return string
213
     */
214 8
    protected function generateModelNamespacePathFromClassName()
215
    {
216 8
        $className = $this->getClassName();
217 8
        $rootNamespace = $this->getRootNamespace();
218 8
        $path = str_replace($rootNamespace, '', $className);
219
220 8
        $nsParts = explode('\\', $path);
221 8
        array_pop($nsParts);
222
223 8
        return implode($nsParts, '\\');
224
    }
225
226
    /**
227
     * @return string
228
     */
229 8
    public function getRootNamespace()
230
    {
231 8
        if (function_exists('app')) {
232
            return app('app')->getRootNamespace() . 'Models\\';
233
        }
234 8
        return 'App\\Models\\';
235
    }
236
237
    /**
238
     * @return string
239
     */
240 5
    protected function generateControllerGeneric()
241
    {
242 5
        $class = $this->getClassName();
243
244 5
        return inflector()->unclassify($class);
245
    }
246
247
    /**
248
     * @param string $name
249
     * @return \Nip\Helpers\AbstractHelper
250
     */
251 1
    public function getHelper($name)
252
    {
253 1
        return HelperBroker::get($name);
254
    }
255
256
    /**
257
     * @return string
258
     */
259
    public function getModelNamespace()
260
    {
261
        return $this->getRootNamespace() . $this->getModelNamespacePath();
262
    }
263
264
    /**
265
     * When searching by primary key, look for items in current registry before
266
     * fetching them from the database
267
     *
268
     * @param array $pk_list
269
     * @return RecordCollection
270
     */
271
    public function findByPrimary($pk_list = [])
272
    {
273
        $pk = $this->getPrimaryKey();
274
        $return = $this->newCollection();
275
276
        if ($pk_list) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $pk_list of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
277
            $pk_list = array_unique($pk_list);
278
            foreach ($pk_list as $key => $value) {
279
                $item = $this->getRegistry()->get($value);
280
                if ($item) {
281
                    unset($pk_list[$key]);
282
                    $return[$item->{$pk}] = $item;
283
                }
284
            }
285
            if ($pk_list) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $pk_list of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
286
                $query = $this->paramsToQuery();
287
                $query->where("$pk IN ?", $pk_list);
288
                $items = $this->findByQuery($query);
289
290
                if (count($items)) {
291
                    foreach ($items as $item) {
292
                        $this->getRegistry()->set($item->{$pk}, $item);
293
                        $return[$item->{$pk}] = $item;
294
                    }
295
                }
296
            }
297
        }
298
299
        return $return;
300
    }
301
302
    /**
303
     * @return RecordCollection
304
     */
305 1
    public function newCollection()
306
    {
307 1
        $class = $this->getCollectionClass();
308
        /** @var RecordCollection $collection */
309 1
        $collection = new $class();
310 1
        $collection->setManager($this);
311
312 1
        return $collection;
313
    }
314
315
    /**
316
     * @return string
317
     */
318 2
    public function getCollectionClass()
319
    {
320 2
        if ($this->collectionClass === null) {
321 2
            $this->initCollectionClass();
322
        }
323
324 2
        return $this->collectionClass;
325
    }
326
327
    /**
328
     * @param string $collectionClass
329
     */
330 2
    public function setCollectionClass($collectionClass)
331
    {
332 2
        $this->collectionClass = $collectionClass;
333 2
    }
334
335 2
    protected function initCollectionClass()
336
    {
337 2
        $this->setCollectionClass($this->generateCollectionClass());
338 2
    }
339
340
    /**
341
     * @return string
342
     */
343 2
    protected function generateCollectionClass()
344
    {
345 2
        return RecordCollection::class;
346
    }
347
348
    /**
349
     * @return \Nip\Collections\Registry
350
     */
351
    public function getRegistry()
352
    {
353
        if (!$this->registry) {
354
            $this->registry = new Registry();
355
        }
356
357
        return $this->registry;
358
    }
359
360
    /**
361
     * Factory
362
     *
363
     * @return Record
364
     * @param array $data [optional]
365
     */
366
    public function getNew($data = [])
367
    {
368
        $pk = $this->getPrimaryKey();
369
        if (is_string($pk) && isset($data[$pk]) && $this->getRegistry()->has($data[$pk])) {
370
            $return = $this->getRegistry()->get($data[$pk]);
371
            $return->writeData($data);
372
            $return->writeDBData($data);
373
374
            return $return;
375
        }
376
377
        $record = $this->getNewRecordFromDB($data);
378
379
        return $record;
380
    }
381
382
    /**
383
     * @param array $data
384
     * @return Record
385
     */
386
    public function getNewRecordFromDB($data = [])
387
    {
388
        $record = $this->getNewRecord($data);
389
        $record->writeDBData($data);
390
391
        return $record;
392
    }
393
394
    /**
395
     * @param array $data
396
     * @return Record
397
     */
398
    public function getNewRecord($data = [])
399
    {
400
        $model = $this->getModel();
401
        /** @var Record $record */
402
        $record = new $model();
403
        $record->setManager($this);
404
        $record->writeData($data);
405
406
        return $record;
407
    }
408
409
    /**
410
     * @return string
411
     */
412 1
    public function getModel()
413
    {
414 1
        if ($this->model == null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $this->model of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
415
            $this->inflectModel();
416
        }
417
418 1
        return $this->model;
419
    }
420
421
    /**
422
     * @param null $model
423
     */
424 1
    public function setModel($model)
425
    {
426 1
        $this->model = $model;
427 1
    }
428
429
    protected function inflectModel()
430
    {
431
        $class = $this->getClassName();
432
        if ($this->model == null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $this->model of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
433
            $this->model = $this->generateModelClass($class);
434
        }
435
    }
436
437
    /**
438
     * @param string $class
439
     * @return string
440
     */
441 1
    public function generateModelClass($class = null)
442
    {
443 1
        $class = $class ? $class : get_class($this);
444
445 1
        if (strpos($class, '\\')) {
446 1
            $nsParts = explode('\\', $class);
447 1
            $class = array_pop($nsParts);
448
449 1
            if ($class == 'Table') {
450 1
                $class = 'Row';
451
            } else {
452
                $class = ucfirst(inflector()->singularize($class));
453
            }
454
455 1
            return implode($nsParts, '\\') . '\\' . $class;
456
        }
457
458 1
        return ucfirst(inflector()->singularize($class));
459
    }
460
461
    /**
462
     * @return \Nip\Request
463
     */
464
    public function getRequest()
465
    {
466
        return request();
467
    }
468
469
    public function __wakeup()
470
    {
471
        $this->initDB();
472
    }
473
474
475
    /**
476
     * Finds one Record using params array
477
     *
478
     * @param array $params
479
     * @return Record|null
480
     */
481
    public function findOneByParams(array $params = [])
482
    {
483
        $params['limit'] = 1;
484
        $records = $this->findByParams($params);
485
        if (count($records) > 0) {
486
            return $records->rewind();
487
        }
488
489
        return null;
490
    }
491
492
    /**
493
     * Finds Records using params array
494
     *
495
     * @param array $params
496
     * @return RecordCollection
497
     */
498
    public function findByParams($params = [])
499
    {
500
        $query = $this->paramsToQuery($params);
501
502
        return $this->findByQuery($query, $params);
503
    }
504
505
    /**
506
     * @return RecordCollection
507
     */
508
    public function getAll()
509
    {
510
        if (!$this->getRegistry()->has("all")) {
511
            $this->getRegistry()->set("all", $this->findAll());
512
        }
513
514
        return $this->getRegistry()->get("all");
515
    }
516
517
    /**
518
     * @return RecordCollection
519
     */
520
    public function findAll()
521
    {
522
        return $this->findByParams();
523
    }
524
525
    /**
526
     * @param int $count
527
     * @return RecordCollection
528
     */
529
    public function findLast($count = 9)
530
    {
531
        return $this->findByParams([
532
            'limit' => $count,
533
        ]);
534
    }
535
536
    /**
537
     * Inserts a Record into the database
538
     * @param Record $model
539
     * @param array|bool $onDuplicate
540
     * @return integer
541
     */
542
    public function insert($model, $onDuplicate = false)
543
    {
544
        $query = $this->insertQuery($model, $onDuplicate);
545
        $query->execute();
546
547
        return $this->getDB()->lastInsertID();
548
    }
549
550
    /**
551
     * @param Record $model
552
     * @param $onDuplicate
553
     * @return InsertQuery
554
     */
555
    public function insertQuery($model, $onDuplicate)
556
    {
557
        $inserts = $this->getQueryModelData($model);
558
559
        $query = $this->newInsertQuery();
560
        $query->data($inserts);
0 ignored issues
show
Unused Code introduced by
The call to Insert::data() has too many arguments starting with $inserts.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
561
562
        if ($onDuplicate !== false) {
563
            $query->onDuplicate($onDuplicate);
564
        }
565
566
        return $query;
567
    }
568
569
    /**
570
     * @param Record $model
571
     * @return array
572
     */
573
    public function getQueryModelData($model)
574
    {
575
        $data = [];
576
577
        $fields = $this->getFields();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $fields is correct as $this->getFields() (which targets Nip\Records\Traits\Activ...cordsTrait::getFields()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
578
        foreach ($fields as $field) {
0 ignored issues
show
Bug introduced by
The expression $fields of type null is not traversable.
Loading history...
579
            if (isset($model->{$field})) {
580
                $data[$field] = $model->{$field};
581
            }
582
        }
583
584
        return $data;
585
    }
586
587
    /**
588
     * The name of the field used as a foreign key in other tables
589
     * @return string
590
     */
591
    public function getUrlPK()
592
    {
593
        if ($this->urlPK == null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $this->urlPK of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
594
            $this->urlPK = $this->getPrimaryKey();
595
        }
596
597
        return $this->urlPK;
598
    }
599
600
    /**
601
     * @param $name
602
     * @return bool
603
     */
604
    public function hasField($name)
605
    {
606
        $fields = $this->getFields();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $fields is correct as $this->getFields() (which targets Nip\Records\Traits\Activ...cordsTrait::getFields()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
607
        if (is_array($fields) && in_array($name, $fields)) {
608
            return true;
609
        }
610
611
        return false;
612
    }
613
614
    /**
615
     * @return array
616
     */
617
    public function getFullTextFields()
618
    {
619
        $return = [];
620
        $structure = $this->getTableStructure();
621
        foreach ($structure['indexes'] as $name => $index) {
622
            if ($index['fulltext']) {
623
                $return[$name] = $index['fields'];
624
            }
625
        }
626
627
        return $return;
628
    }
629
630
    /**
631
     * Sets model and database table from the class name
632
     */
633
    protected function inflect()
634
    {
635
        $this->initController();
636
    }
637
}
638