Completed
Pull Request — master (#3)
by Wojciech
01:27
created

SmartEntity::isInternalType()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 2
nc 2
nop 1
crap 2
1
<?php
2
3
/*
4
 * This file is part of the Bushido\Foundation package.
5
 *
6
 * (c) Wojciech Nowicki <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE.md
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Bushido\Foundation\SmartEntity;
13
14
use Bushido\Foundation\Contracts\Makeable;
15
use Bushido\Foundation\Exception;
16
use Bushido\Foundation\Exceptions\InvalidArgumentException;
17
18
/**
19
 * @todo support for some common classes
20
 * @todo limited internal type arrays
21
 */
22
abstract class SmartEntity extends FlexEntity
23
{
24
    protected $properties = [];
25
26
    /**
27
     * @param string $propertyName
28
     * @param array $arguments
29
     * @return $this
30
     * @throws Exception
31
     * @throws InvalidArgumentException
32
     */
33 18
    protected function set(string $propertyName, array $arguments)
34
    {
35 18
        $value = $this->fetchValue($arguments, $propertyName);
36
37 18
        if (!$this->isPropertySet($propertyName)) {
38 3
            throw new \RuntimeException('Property [' . $propertyName . '] not set');
39
        }
40
41 15
        $type = $this->properties[$propertyName];
42
43 15
        if ($this->isInternalType($type)) {
44 6
            if ($this->validateInternalType($value, $type)) {
45 3
                parent::set($propertyName, [$value]);
46
47 3
                return $this;
48
            }
49
50 3
            throw new InvalidArgumentException(
51 3
                'Expected value to be type of [' . self::INTERNAL_TYPES[$type] . '] different type was given'
52
            );
53
        }
54
55 12
        if ($this->isTypeArrayOfObjects($type) && is_array($value)) {
56
            $value = $this->processArrayOfObj($value, $type);
57
        }
58
59 12
        return parent::set($propertyName, [$this->processObjectType($value, $type)]);
60
    }
61
62 15
    private function isInternalType($type): bool
63
    {
64 15
        return is_numeric($type) && array_key_exists($type, self::INTERNAL_TYPES);
65
    }
66
67 18
    private function isPropertySet($propertyName): bool
68
    {
69 18
        return array_key_exists($propertyName, $this->properties);
70
    }
71
72
    /**
73
     * @param $value
74
     * @param $class
75
     * @return mixed
76
     * @throws Exception
77
     * @throws InvalidArgumentException
78
     */
79 18
    private function processObjectType($value, string $class)
80
    {
81 18
        $this->isClassOrInterface($class);
82
83 18
        if (is_array($value) && is_subclass_of($class, Makeable::class)) {
84 9
            return $class::make($value);
85
        }
86
87 12
        if (is_a($value, $class)) {
88 6
            return $value;
89
        }
90
91 6
        throw new InvalidArgumentException('Expected value to be object of [' . $class . '] type different type was given');
92
    }
93
94
    /**
95
     * @param string $class
96
     * @return bool
97
     * @throws Exception
98
     */
99 18
    private function isClassOrInterface(string $class): bool
100
    {
101 18
        if (class_exists($class) || interface_exists($class)) {
102 18
            return true;
103
        }
104
105
        throw new Exception('Non existing class or interface [' . $class . ']');
106
    }
107
108 12
    private function isTypeArrayOfObjects($type): bool
109
    {
110 12
        return strpos($type, '[]') !== false;
111
    }
112
113
    /**
114
     * @param array $value
115
     * @param $type
116
     * @return array
117
     * @throws Exception
118
     * @throws InvalidArgumentException
119
     */
120
    private function processArrayOfObj(array $value, $type): array
121
    {
122
        $ar = [];
123
        $class = $this->getClassNameFromType($type);
124
125
        foreach ($value as $obj) {
126
            $ar[] = $this->processObjectType($obj, $class);
127
        }
128
129
        return $ar;
130
    }
131
132 6
    private function getClassNameFromType($type): string
133
    {
134 6
        return (string) str_replace(self::EXT_ARRAY, '', $type);
135
    }
136
137 6
    private function validateInternalType($value, $type): bool
138
    {
139
        switch ($type) {
140 6
            case self::TYPE_ARRAY:
141 3
                return is_array($value);
142 6
            case self::TYPE_INT:
143 3
                return is_int($value);
144 6
            case self::TYPE_STRING:
145 3
                return is_string($value);
146 6
            case self::TYPE_BOOL:
147 6
                return is_bool($value);
148 3
            case self::TYPE_FLOAT:
149 3
                return is_float($value);
150 3
            case self::TYPE_NUMERIC:
151 3
                return is_numeric($value);
152
        }
153
154
        return false;
155
    }
156
157
    /**
158
     * @param string $property
159
     * @param array $arguments
160
     * @return $this
161
     * @throws Exception
162
     * @throws InvalidArgumentException
163
     */
164 6
    protected function add(string $property, array $arguments)
165
    {
166 6
        $this->fetchValue($arguments, $property);
167
168 6
        if (!array_key_exists($property, $this->properties) ||
169 6
            !($this->isArrayOfObjects($this->properties[$property]) || $this->properties[$property] == self::TYPE_ARRAY)
170
        ) {
171
            throw new Exception('Can not use addProperty on non object array property');
172
        }
173
174 6
        if ($arguments[0] === null) {
175
            return $this;
176
        }
177
178 6
        if ($this->isArrayOfObjects($this->properties[$property])) {
179 6
            $arguments[0] = $this->processObjectType(
180 6
                $arguments[0],
181 6
                $this->getClassNameFromType($this->properties[$property])
182
            );
183
        }
184
185 3
        return parent::add($property, $arguments);
186
    }
187
188 6
    private function isArrayOfObjects($type): bool
189
    {
190 6
        return strpos($type, '[]') !== false;
191
    }
192
}
193