SmartEntity::isInternalType()   A
last analyzed

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 24
    protected function set(string $propertyName, array $arguments)
34
    {
35 24
        $value = $this->fetchValue($arguments, $propertyName);
36
37 24
        if (!$this->isPropertySet($propertyName)) {
38 3
            throw new \RuntimeException('Property [' . $propertyName . '] not set');
39
        }
40
41 21
        $type = $this->properties[$propertyName];
42
43 21
        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 18
        if ($this->isArrayOfObjects($type) && is_array($value)) {
56 3
            return parent::set($propertyName, [$this->processArrayOfObj($value, $type)]);
57
        }
58
59 15
        return parent::set($propertyName, [$this->processObjectType($value, $type)]);
60
    }
61
62
    /**
63
     * @param int|string $type
64
     * @return bool
65
     */
66 21
    private function isInternalType($type): bool
67
    {
68 21
        return is_numeric($type) && array_key_exists($type, self::INTERNAL_TYPES);
69
    }
70
71 24
    private function isPropertySet($propertyName): bool
72
    {
73 24
        return array_key_exists($propertyName, $this->properties);
74
    }
75
76
    /**
77
     * @param mixed $value
78
     * @param string $class
79
     * @return mixed
80
     * @throws Exception
81
     * @throws InvalidArgumentException
82
     */
83 24
    private function processObjectType($value, string $class)
84
    {
85 24
        $this->isClassOrInterface($class);
86
87 21
        if (is_array($value) && is_subclass_of($class, Makeable::class)) {
88 12
            return $class::make($value);
89
        }
90
91 12
        if (is_a($value, $class)) {
92 6
            return $value;
93
        }
94
95 6
        throw new InvalidArgumentException(
96 6
            'Expected value to be object of [' . $class . '] type different type was given'
97
        );
98
    }
99
100
    /**
101
     * @param string $class
102
     * @return bool
103
     * @throws Exception
104
     */
105 24
    private function isClassOrInterface(string $class): bool
106
    {
107 24
        if (class_exists($class) || interface_exists($class)) {
108 21
            return true;
109
        }
110
111 3
        throw new Exception('Non existing class or interface [' . $class . ']');
112
    }
113
114 27
    private function isArrayOfObjects($type): bool
115
    {
116 27
        return strpos($type, self::EXT_ARRAY) !== false;
117
    }
118
119
    /**
120
     * @param array $value
121
     * @param mixed $type
122
     * @return array
123
     * @throws Exception
124
     * @throws InvalidArgumentException
125
     */
126 3
    private function processArrayOfObj(array $value, $type): array
127
    {
128 3
        $ar = [];
129 3
        $class = $this->getClassNameFromType($type);
130
131 3
        foreach ($value as $key => $obj) {
132 3
            $ar[$key] = $this->processObjectType($obj, $class);
133
        }
134
135 3
        return $ar;
136
    }
137
138 9
    private function getClassNameFromType($type): string
139
    {
140 9
        return (string) str_replace(self::EXT_ARRAY, '', $type);
141
    }
142
143 6
    private function validateInternalType($value, $type): bool
144
    {
145
        switch ($type) {
146 6
            case self::TYPE_ARRAY:
147 3
                return is_array($value);
148 6
            case self::TYPE_INT:
149 3
                return is_int($value);
150 6
            case self::TYPE_STRING:
151 3
                return is_string($value);
152 6
            case self::TYPE_BOOL:
153 6
                return is_bool($value);
154 3
            case self::TYPE_FLOAT:
155 3
                return is_float($value);
156 3
            case self::TYPE_NUMERIC:
157 3
                return is_numeric($value);
158
        }
159
160
        return false;
161
    }
162
163
    /**
164
     * @param string $property
165
     * @param array $arguments
166
     * @return $this
167
     * @throws Exception
168
     * @throws InvalidArgumentException
169
     */
170 9
    protected function add(string $property, array $arguments)
171
    {
172 9
        $this->fetchValue($arguments, $property);
173
174 9
        if (!array_key_exists($property, $this->properties) ||
175 9
            !($this->isArrayOfObjects($this->properties[$property]) || $this->properties[$property] == self::TYPE_ARRAY)
176
        ) {
177 3
            throw new Exception('Can not use addProperty on non object array property');
178
        }
179
180 6
        if ($arguments[0] === null) {
181 3
            return $this;
182
        }
183
184 6
        if ($this->isArrayOfObjects($this->properties[$property])) {
185 6
            $arguments[0] = $this->processObjectType(
186 6
                $arguments[0],
187 6
                $this->getClassNameFromType($this->properties[$property])
188
            );
189
        }
190
191 3
        return parent::add($property, $arguments);
192
    }
193
}
194