GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( bd8707...a7f508 )
by De
07:21
created

Structure::getErrors()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
/**
4
 * This file is part of the PHPMongo package.
5
 *
6
 * (c) Dmytro Sokil <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Sokil\Mongo;
13
14
use Sokil\Mongo\Validator;
15
use Sokil\Mongo\Document\InvalidDocumentException;
16
17
class Structure implements
18
    ArrayableInterface,
19
    \JsonSerializable
20
{
21
    /**
22
     * @deprecated use self::$schema to define initial data and getters or setters to get or set field's values.
23
     * @var array
24
     */
25
    protected $_data = array();
26
27
    /**
28
     * Document's data
29
     * @var array
30
     */
31
    private $data = array();
32
33
    /**
34
     * Initial document's data
35
     * @var array
36
     */
37
    protected $schema = array();
38
39
    /**
40
     *
41
     * @var original data.
42
     */
43
    private $originalData = array();
44
45
    /**
46
     *
47
     * @var modified fields.
48
     */
49
    private $modifiedFields = array();
50
51
    /**
52
     * Name of scenario, used for validating fields
53
     * @var string
54
     */
55
    private $scenario;
56
57
    /**
58
     *
59
     * @var array list of namespaces
60
     */
61
    private $validatorNamespaces = array(
62
        '\Sokil\Mongo\Validator',
63
    );
64
65
66
    /**
67
     * @var array validator errors
68
     */
69
    private $errors = array();
70
71
    /**
72
     * @var array manually added validator errors
73
     */
74
    private $triggeredErrors = array();
75
76
    /**
77
     * @param array|null $data data to initialise structure
78
     * @param bool|true $notModified define if data set as modified or not
79
     */
80
    public function __construct(
81
        array $data = null,
82
        $notModified = true
83
    ) {
84
        // self::$data and self::$schema instead of deprecated self::$_data
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
85
        if ($this->_data) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->_data 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...
Deprecated Code introduced by
The property Sokil\Mongo\Structure::$_data has been deprecated with message: use self::$schema to define initial data and getters or setters to get or set field's values.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
86
            $this->schema = $this->_data;
0 ignored issues
show
Deprecated Code introduced by
The property Sokil\Mongo\Structure::$_data has been deprecated with message: use self::$schema to define initial data and getters or setters to get or set field's values.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
87
        }
88
89
        $this->_data = &$this->data;
0 ignored issues
show
Deprecated Code introduced by
The property Sokil\Mongo\Structure::$_data has been deprecated with message: use self::$schema to define initial data and getters or setters to get or set field's values.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
90
91
        // define initial data with schema
92
        $this->data = $this->schema;
93
        $this->originalData = $this->data;
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->data of type array is incompatible with the declared type object<Sokil\Mongo\original> of property $originalData.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
94
95
        // initialize with passed data
96
        if ($data) {
97
            if ($notModified) {
98
                // set as not modified
99
                $this->replace($data);
100
            } else {
101
                // set as modified
102
                $this->merge($data);
103
            }
104
        }
105
    }
106
107
    /**
108
     * Cloning not allowed because cloning of object not clone related aggregates of this object, so
109
     * cloned object has links to original aggregates. This is difficult to handle.
110
     */
111
    public final function __clone()
0 ignored issues
show
Coding Style introduced by
As per PSR2, final should precede the visibility keyword.
Loading history...
112
    {
113
        throw new \RuntimeException('Cloning not allowed');
114
    }
115
116
    /**
117
     * IMPORTANT! Do not use this method
118
     *
119
     * This method allow set data of document in external code.
120
     * e.g. link data of document to GridFS file matadata.
121
     * Modification of document's data will modify external data too.
122
     * Note that also the opposite case also right - modification of external data will
123
     * modify document's data directly, so document may be in unconsisted state.
124
     *
125
     * @param array $data reference to data in external code
126
     * @return Structure
127
     */
128
    protected function setDataReference(array &$data)
129
    {
130
        $this->data = &$data;
131
        return $this;
132
    }
133
134
    public function __get($name)
135
    {
136
        // get first-level value
137
        return isset($this->data[$name]) ? $this->data[$name] : null;
138
    }
139
140
    public function get($selector)
141
    {
142
        if(false === strpos($selector, '.')) {
143
            return isset($this->data[$selector]) ? $this->data[$selector] : null;
144
        }
145
146
        $value = $this->data;
147
        foreach(explode('.', $selector) as $field)
148
        {
149
            if(!isset($value[$field])) {
150
                return null;
151
            }
152
153
            $value = $value[$field];
154
        }
155
156
        return $value;
157
    }
158
159
    /**
160
     * Get structure object from a document's value
161
     *
162
     * @param string $selector
163
     * @param string|callable $className string class name or closure, which accept data and return string class name
164
     * @return object representation of document with class, passed as argument
165
     * @throws \Sokil\Mongo\Exception
166
     */
167
    public function getObject($selector, $className = '\Sokil\Mongo\Structure')
168
    {
169
        $data = $this->get($selector);
170
        if(!$data) {
171
            return null;
172
        }
173
174
        // get class name from callable
175
        if(is_callable($className)) {
176
            $className = $className($data);
177
        }
178
179
        // prepare structure
180
        $structure =  new $className();
181
        if(!($structure instanceof Structure)) {
182
            throw new Exception('Wrong structure class specified');
183
        }
184
185
        return $structure->merge($data);
186
    }
187
188
    /**
189
     * Get list of structure objects from list of values in mongo document
190
     *
191
     * @param string $selector
192
     * @param string|callable $className Structure class name or closure, which accept data and return string class name of Structure
193
     * @return object representation of document with class, passed as argument
194
     * @throws \Sokil\Mongo\Exception
195
     */
196
    public function getObjectList($selector, $className = '\Sokil\Mongo\Structure')
197
    {
198
        $data = $this->get($selector);
199
        if(!$data || !is_array($data)) {
200
            return array();
201
        }
202
203
        // class name is string
204 View Code Duplication
        if(is_string($className)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
205
            $list = array_map(
206
                function($dataItem) use($className) {
207
                    $listItemStructure = new $className();
208
                    if(!($listItemStructure instanceof Structure)) {
209
                        throw new Exception('Wrong structure class specified');
210
                    }
211
                    $listItemStructure->mergeUnmodified($dataItem);
212
                    return $listItemStructure;
213
                },
214
                $data
215
            );
216
217
            return $list;
218
        }
219
220
        // class name id callable
221 View Code Duplication
        if(is_callable($className)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
222
            return array_map(function($dataItem) use( $className) {
223
                $classNameString = $className($dataItem);
224
                $listItemStructure = new $classNameString;
225
                if(!($listItemStructure instanceof Structure)) {
226
                    throw new Exception('Wrong structure class specified');
227
                }
228
229
                return $listItemStructure->merge($dataItem);
230
            }, $data);
231
        }
232
233
        throw new Exception('Wrong class name specified. Use string or closure');
234
    }
235
236
    /**
237
     * Handle setting params through public property
238
     *
239
     * @param string $name
240
     * @param mixed $value
241
     */
242
    public function __set($name, $value)
243
    {
244
        $this->set($name, $value);
245
    }
246
247
    /**
248
     * Store value to specified selector in local cache
249
     *
250
     * @param string $selector point-delimited field selector
251
     * @param mixed $value value
252
     * @return \Sokil\Mongo\Document
253
     * @throws Exception
254
     */
255
    public function set($selector, $value)
256
    {
257
        $value = self::prepareToStore($value);
258
259
        // modify
260
        $arraySelector = explode('.', $selector);
261
        $chunksNum = count($arraySelector);
262
263
        // optimize one-level selector search
264
        if(1 == $chunksNum) {
265
266
            // update only if new value different from current
267
            if(!isset($this->data[$selector]) || $this->data[$selector] !== $value) {
268
                // modify
269
                $this->data[$selector] = $value;
270
                // mark field as modified
271
                $this->modifiedFields[] = $selector;
272
            }
273
274
            return $this;
275
        }
276
277
        // selector is nested
278
        $section = &$this->data;
279
280
        for($i = 0; $i < $chunksNum - 1; $i++) {
281
282
            $field = $arraySelector[$i];
283
284
            if(!isset($section[$field])) {
285
                $section[$field] = array();
286
            } elseif(!is_array($section[$field])) {
287
                throw new Exception('Assigning sub-document to scalar value not allowed');
288
            }
289
290
            $section = &$section[$field];
291
        }
292
293
        // update only if new value different from current
294
        if(!isset($section[$arraySelector[$chunksNum - 1]]) || $section[$arraySelector[$chunksNum - 1]] !== $value) {
295
            // modify
296
            $section[$arraySelector[$chunksNum - 1]] = $value;
297
            // mark field as modified
298
            $this->modifiedFields[] = $selector;
299
        }
300
301
        return $this;
302
    }
303
304
    public function has($selector)
305
    {
306
        $pointer = &$this->data;
307
308
        foreach(explode('.', $selector) as $field) {
309
            if(!array_key_exists($field, $pointer)) {
310
                return false;
311
            }
312
313
            $pointer = &$pointer[$field];
314
        }
315
316
        return true;
317
    }
318
319
    public function __isset($name)
320
    {
321
        return isset($this->data[$name]);
322
    }
323
324
    public static function prepareToStore($value)
325
    {
326
        // if array - try to prepare every value
327
        if(is_array($value)) {
328
            foreach($value as $k => $v) {
329
                $value[$k] = self::prepareToStore($v);
330
            }
331
332
            return $value;
333
        }
334
335
        // if scalar - return it
336
        if(!is_object($value)) {
337
            return $value;
338
        }
339
340
        // if internal mongo types - pass it as is
341
        if(in_array(get_class($value), array('MongoId', 'MongoCode', 'MongoDate', 'MongoRegex', 'MongoBinData', 'MongoInt32', 'MongoInt64', 'MongoDBRef', 'MongoMinKey', 'MongoMaxKey', 'MongoTimestamp'))) {
342
            return $value;
343
        }
344
345
        // do not convert geo-json to array
346
        if($value instanceof \GeoJson\Geometry\Geometry) {
347
            return $value->jsonSerialize();
348
        }
349
350
        // structure
351
        if($value instanceof Structure) {
352
            // validate structure
353
            if (!$value->isValid()) {
354
                $exception = new InvalidDocumentException('Embedded document not valid');
355
                $exception->setDocument($value);
356
                throw $exception;
357
            }
358
359
            // get array from structure
360
            return $value->toArray();
361
        }
362
363
        // other objects convert to array
364
        return (array) $value;
365
    }
366
367
    public function unsetField($selector)
368
    {
369
        // modify
370
        $arraySelector = explode('.', $selector);
371
        $chunksNum = count($arraySelector);
372
373
        // optimize one-level selector search
374
        if(1 == $chunksNum) {
375
            // check if field exists
376
            if(isset($this->data[$selector])) {
377
                // unset field
378
                unset($this->data[$selector]);
379
                // mark field as modified
380
                $this->modifiedFields[] = $selector;
381
            }
382
383
            return $this;
384
        }
385
386
        // find section
387
        $section = &$this->data;
388
389
        for($i = 0; $i < $chunksNum - 1; $i++) {
390
391
            $field = $arraySelector[$i];
392
393
            if(!isset($section[$field])) {
394
                return $this;
395
            }
396
397
            $section = &$section[$field];
398
        }
399
400
        // check if field exists
401
        if(isset($section[$arraySelector[$chunksNum - 1]])) {
402
            // unset field
403
            unset($section[$arraySelector[$chunksNum - 1]]);
404
            // mark field as modified
405
            $this->modifiedFields[] = $selector;
406
        }
407
408
        return $this;
409
    }
410
411
    /**
412
     * If field not exist - set value.
413
     * If field exists and is not array - convert to array and append
414
     * If field -s array - append
415
     *
416
     * @param type $selector
417
     * @param type $value
418
     * @return \Sokil\Mongo\Structure
419
     */
420
    public function append($selector, $value)
421
    {
422
        $oldValue = $this->get($selector);
423
        if($oldValue) {
424
            if(!is_array($oldValue)) {
425
                $oldValue = (array) $oldValue;
426
            }
427
            $oldValue[] = $value;
428
            $value = $oldValue;
429
        }
430
431
        $this->set($selector, $value);
432
        return $this;
433
    }
434
435
    public function isModified($selector = null)
436
    {
437
        if(!$this->modifiedFields) {
438
            return false;
439
        }
440
441
        if(!$selector) {
442
            return (bool) $this->modifiedFields;
443
        }
444
445
        foreach($this->modifiedFields as $modifiedField) {
446
            if(preg_match('/^' . $selector . '($|.)/', $modifiedField)) {
447
                return true;
448
            }
449
        }
450
451
        return false;
452
    }
453
454
    public function getModifiedFields()
455
    {
456
        return $this->modifiedFields;
457
    }
458
459
    public function getOriginalData()
460
    {
461
        return $this->originalData;
462
    }
463
464
    public function toArray()
465
    {
466
        return $this->data;
467
    }
468
469
    public function jsonSerialize()
470
    {
471
        return $this->data;
472
    }
473
474
    /**
475
     * Recursive function to merge data for Structure::mergeUnmodified()
476
     *
477
     * @param array $target
478
     * @param array $source
479
     */
480
    private function mergeUnmodifiedPartial(array &$target, array $source)
481
    {
482
        foreach($source as $key => $value) {
483
            if(is_array($value) && isset($target[$key])) {
484
                $this->mergeUnmodifiedPartial($target[$key], $value);
485
            } else {
486
                $target[$key] = $value;
487
            }
488
        }
489
    }
490
491
    /**
492
     * Merge array to current structure without setting modification mark
493
     *
494
     * @param array $data
495
     * @return \Sokil\Mongo\Structure
496
     */
497
    public function mergeUnmodified(array $data)
498
    {
499
        $this->mergeUnmodifiedPartial($this->data, $data);
500
        $this->mergeUnmodifiedPartial($this->originalData, $data);
501
502
        return $this;
503
    }
504
505
    /**
506
     * Check if array is sequential list
507
     * @param array $array
508
     */
509
    private function isEmbeddedDocument($array)
510
    {
511
        return is_array($array) && (array_values($array) !== $array);
512
    }
513
514
    /**
515
     * Recursive function to merge data for Structure::merge()
516
     *
517
     * @param array $document
518
     * @param array $updatedDocument
519
     * @param string $prefix
520
     */
521
    private function mergePartial(array &$document, array $updatedDocument, $prefix = null)
522
    {
523
        foreach($updatedDocument as $key => $newValue) {
524
            // if original data is embedded document and value also - then merge
525
            if(is_array($newValue) && isset($document[$key]) && $this->isEmbeddedDocument($document[$key])) {
526
                $this->mergePartial($document[$key], $newValue, $prefix . $key . '.');
527
            }
528
            // in other cases just set new value
529
            else {
530
                $document[$key] = $newValue;
531
                $this->modifiedFields[] = $prefix . $key;
532
            }
533
        }
534
    }
535
536
    /**
537
     * Merge array to current structure with setting modification mark
538
     *
539
     * @param array $data
540
     * @return \Sokil\Mongo\Structure
541
     */
542
    public function merge(array $data)
543
    {
544
        $this->mergePartial($this->data, $data);
545
        return $this;
546
    }
547
548
    /**
549
     * Replace data of document with passed.
550
     * Document became unmodified
551
     *
552
     * @param array $data new document data
553
     */
554
    public function replace(array $data)
555
    {
556
        $this->data = $data;
557
        $this->apply();
558
559
        return $this;
560
    }
561
562
    /**
563
     * Replace modified fields with original
564
     * @return $this
565
     */
566
    public function reset()
567
    {
568
        $this->data = $this->originalData;
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->originalData of type object<Sokil\Mongo\original> is incompatible with the declared type array of property $data.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
569
        $this->modifiedFields = array();
0 ignored issues
show
Documentation Bug introduced by
It seems like array() of type array is incompatible with the declared type object<Sokil\Mongo\modified> of property $modifiedFields.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
570
571
        return $this;
572
    }
573
574
    /**
575
     * Apply modified document fields as original
576
     * @return $this
577
     */
578
    public function apply()
579
    {
580
        $this->originalData = $this->data;
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->data of type array is incompatible with the declared type object<Sokil\Mongo\original> of property $originalData.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
581
        $this->modifiedFields = array();
0 ignored issues
show
Documentation Bug introduced by
It seems like array() of type array is incompatible with the declared type object<Sokil\Mongo\modified> of property $modifiedFields.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
582
583
        return $this;
584
    }
585
586
    /**
587
     * Validation rules
588
     * @return array
589
     */
590
    public function rules()
591
    {
592
        return array();
593
    }
594
595
    public function setScenario($scenario)
596
    {
597
        $this->scenario = $scenario;
598
        return $this;
599
    }
600
601
    public function getScenario()
602
    {
603
        return $this->scenario;
604
    }
605
606
    public function setNoScenario()
607
    {
608
        $this->scenario = null;
609
        return $this;
610
    }
611
612
    public function isScenario($scenario)
613
    {
614
        return $scenario === $this->scenario;
615
    }
616
617
    public function hasErrors()
618
    {
619
        return ($this->errors || $this->triggeredErrors);
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->errors 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...
Bug Best Practice introduced by
The expression $this->triggeredErrors 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...
620
    }
621
622
    /**
623
     * get list of validation errors
624
     *
625
     * Format: $errors['fieldName']['rule'] = 'message';
626
     *
627
     * @return array list of validation errors
628
     */
629
    public function getErrors()
630
    {
631
        return array_merge_recursive($this->errors, $this->triggeredErrors);
632
    }
633
634
    /**
635
     * Add validator error from validator classes and methods. This error
636
     * reset on every re-validation
637
     *
638
     * @param string $fieldName dot-notated field name
639
     * @param string $ruleName name of validation rule
640
     * @param string $message error message
641
     * @return \Sokil\Mongo\Document
642
     */
643
    public function addError($fieldName, $ruleName, $message)
644
    {
645
        $this->errors[$fieldName][$ruleName] = $message;
646
647
        return $this;
648
    }
649
650
    /**
651
     * Add errors
652
     *
653
     * @param array $errors
654
     * @return \Sokil\Mongo\Document
655
     */
656
    public function addErrors(array $errors)
657
    {
658
        $this->errors = array_merge_recursive($this->errors, $errors);
659
        return $this;
660
    }
661
662
    /**
663
     * Add custom error which not reset after validation
664
     *
665
     * @param type $fieldName
666
     * @param type $ruleName
667
     * @param type $message
668
     * @return \Sokil\Mongo\Document
669
     */
670
    public function triggerError($fieldName, $ruleName, $message)
671
    {
672
        $this->triggeredErrors[$fieldName][$ruleName] = $message;
673
        return $this;
674
    }
675
676
    /**
677
     * Add custom errors
678
     *
679
     * @param array $errors
680
     * @return \Sokil\Mongo\Document
681
     */
682
    public function triggerErrors(array $errors)
683
    {
684
        $this->triggeredErrors = array_merge_recursive($this->triggeredErrors, $errors);
685
        return $this;
686
    }
687
688
    /**
689
     * Clear triggered and validation errors
690
     * @return $this
691
     */
692
    public function clearErrors()
693
    {
694
        $this->errors = array();
695
        $this->triggeredErrors = array();
696
        return $this;
697
    }
698
699
    /**
700
     * Remove custom errors
701
     *
702
     * @return \Sokil\Mongo\Document
703
     */
704
    public function clearTriggeredErrors()
705
    {
706
        $this->triggeredErrors = array();
707
        return $this;
708
    }
709
710
    /**
711
     * Add own namespace of validators
712
     *
713
     * @param type $namespace
714
     * @return \Sokil\Mongo\Document
715
     */
716
    public function addValidatorNamespace($namespace)
717
    {
718
        $this->validatorNamespaces[] = rtrim($namespace, '\\');
719
        return $this;
720
    }
721
722
    private function getValidatorClassNameByRuleName($ruleName)
723
    {
724
        if(false !== strpos($ruleName, '_')) {
725
            $className = implode('', array_map('ucfirst', explode('_', strtolower($ruleName))));
726
        } else {
727
            $className = ucfirst(strtolower($ruleName));
728
        }
729
730
        foreach ($this->validatorNamespaces as $namespace) {
731
            $fullyQualifiedClassName = $namespace . '\\' . $className . 'Validator';
732
            if (class_exists($fullyQualifiedClassName)) {
733
                return $fullyQualifiedClassName;
734
            }
735
        }
736
737
        throw new Exception('Validator with name ' . $ruleName . ' not found');
738
    }
739
740
    /**
741
     * check if filled model params is valid
742
     * @return boolean
743
     */
744
    public function isValid()
745
    {
746
        $this->errors = array();
747
748
        foreach ($this->rules() as $rule) {
749
            $fields = array_map('trim', explode(',', $rule[0]));
750
            $ruleName = $rule[1];
751
            $params = array_slice($rule, 2);
752
753
            // check scenario
754 View Code Duplication
            if (!empty($rule['on'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
755
                $onScenarios = explode(',', $rule['on']);
756
                if (!in_array($this->getScenario(), $onScenarios)) {
757
                    continue;
758
                }
759
            }
760
761 View Code Duplication
            if (!empty($rule['except'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
762
                $exceptScenarios = explode(',', $rule['except']);
763
                if (in_array($this->getScenario(), $exceptScenarios)) {
764
                    continue;
765
                }
766
            }
767
768
            if (method_exists($this, $ruleName)) {
769
                // method
770
                foreach ($fields as $field) {
771
                    $this->{$ruleName}($field, $params);
772
                }
773
            } else {
774
                // validator class
775
                $validatorClassName = $this->getValidatorClassNameByRuleName($ruleName);
776
777
                /* @var $validator \Sokil\Mongo\Validator */
778
                $validator = new $validatorClassName;
779
                if (!$validator instanceof Validator) {
780
                    throw new Exception('Validator class must implement \Sokil\Mongo\Validator class');
781
                }
782
783
                $validator->validate($this, $fields, $params);
784
            }
785
        }
786
787
        return !$this->hasErrors();
788
    }
789
790
}
791