Passed
Push — develop ( cfc1cb...98f18c )
by Csaba
37s
created

Schema::setNestedFieldDefaults()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 13
c 0
b 0
f 0
ccs 9
cts 9
cp 1
rs 8.8571
cc 5
eloc 8
nc 5
nop 1
crap 5
1
<?php
2
namespace Fathomminds\Rest;
3
4
use Fathomminds\Rest\Contracts\ISchema;
5
use Fathomminds\Rest\Schema\SchemaValidator;
6
use Fathomminds\Rest\Schema\TypeValidators\ValidatorFactory;
7
use Fathomminds\Rest\Exceptions\RestException;
8
9
abstract class Schema implements ISchema
10
{
11
    const REPLACE_MODE = 'replace';
12
    const UPDATE_MODE = 'update';
13
14 18
    public static function cast($object)
15
    {
16 18
        return new static($object);
17
    }
18
19 86
    public function __construct($object = null)
20
    {
21 86
        if ($object === null) {
22 73
            return;
23
        }
24 35
        if (gettype($object) !== 'object') {
25 1
            throw new RestException('Schema constructor expects object or null as parameter', [
26 1
                'parameter' => $object,
27
            ]);
28
        }
29 34
        $schema = $this->schema();
30 34
        foreach (get_object_vars($object) as $name => $value) {
31 29
            $this->{$name} = $this->castProperty($schema, $name, $value);
32
        }
33 34
    }
34
35 29
    private function castProperty($schema, $name, $value)
36
    {
37 29
        if (!array_key_exists($name, $schema)) {
38 1
            return $value;
39
        }
40 29
        if (isset($schema[$name]['type']) && $schema[$name]['type'] === 'schema') {
41 10
            return $schema[$name]['validator']['class']::cast($value);
42
        }
43 29
        $params = empty($schema[$name]['validator']['params'])
44 29
            ? null
45 29
            : $schema[$name]['validator']['params'];
46 29
        return $schema[$name]['validator']['class']::cast($value, $params);
47
    }
48
49 2
    public function __get($name)
50
    {
51 2
        if (!isset($this->{$name})) {
52 1
            throw new RestException(
53 1
                'Trying to access undefined property ' . $name,
54 1
                []
55
            );
56
        }
57 1
        return $this->{$name};
58
    }
59
60
    abstract public function schema();
61
62 4
    public function toArray()
63
    {
64 4
        return json_decode(json_encode($this), true);
65
    }
66
67 3
    public function setFieldDefaults()
68
    {
69 3
        $schemaValidator = new SchemaValidator(static::class);
70 3
        $schemaFields = $schemaValidator->getSchemaFieldsWithDetails($this);
71 3
        $defaultFields = $schemaValidator->getFieldsWithDefaults($this);
72 3
        $this->setNestedFieldDefaults($schemaFields);
73 3
        $this->setRemainingFieldDefaults($defaultFields);
74 3
        return $this;
75
    }
76
77 3
    protected function setNestedFieldDefaults($schemaFields)
78
    {
79 3
        foreach ($schemaFields as $schemaFieldName => $schemaFieldDetails) {
80 3
            $propertyExists = property_exists($this, $schemaFieldName);
81 3
            if (isset($schemaFieldDetails['default']) && !$propertyExists) {
82 3
                $this->setFieldDefaultValue($schemaFieldName, $schemaFieldDetails['default']);
83 3
                $propertyExists = true;
84
            }
85 3
            if ($propertyExists) {
86 3
                $this->{$schemaFieldName}->setFieldDefaults();
87
            }
88
        }
89 3
    }
90
91 3
    protected function setRemainingFieldDefaults($defaultFields)
92
    {
93 3
        $properties = array_diff_key(
94 3
            $defaultFields,
95 3
            get_object_vars($this)
96
        );
97 3
        foreach ($properties as $fieldName => $field) {
98 3
            $this->setFieldDefaultValue($fieldName, $field['default']);
99
        }
100 3
    }
101
102 3
    protected function setFieldDefaultValue($fieldName, $value)
103
    {
104 3
        if (gettype($value) === 'object' && is_callable($value)) {
105 3
            $this->{$fieldName} = $value();
106 3
            return;
107
        }
108 3
        $this->{$fieldName} = $value;
109 3
    }
110
111 5
    public function validate($mode = null)
112
    {
113 5
        $schemaValidator = new SchemaValidator(static::class);
114
        switch ($mode) {
115 5
            case self::REPLACE_MODE:
116 2
                $schemaValidator->replaceMode(true);
117 2
                $schemaValidator->updateMode(false);
118 2
                break;
119 3
            case self::UPDATE_MODE:
120 1
                $schemaValidator->replaceMode(false);
121 1
                $schemaValidator->updateMode(true);
122 1
                break;
123
            default:
124 2
                break;
125
        }
126 5
        $schemaValidator->validate($this);
127 3
        return $this;
128
    }
129
}
130