Completed
Pull Request — master (#3)
by Wojciech
02:38
created

SmartEntity::processArrayOfObj()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 5
c 1
b 0
f 0
dl 0
loc 10
ccs 0
cts 6
cp 0
rs 10
cc 2
nc 2
nop 2
crap 6
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 clone implementation
20
 * @todo add method
21
 * @todo support for some common classes
22
 * @todo limited internal type arrays
23
 */
24
abstract class SmartEntity extends FlexEntity
25
{
26
    protected $properties = [];
27
28 14
    protected function set(string $propertyName, array $arguments)
29
    {
30 14
        $value = $this->fetchValue($arguments, $propertyName);
31
32 14
        if (!$this->isPropertySet($propertyName)) {
33 3
            throw new \RuntimeException('Property [' . $propertyName . '] not set');
34
        }
35
36 11
        $type = $this->properties[$propertyName];
37
38 11
        if ($this->isInternalType($type)) {
39 5
            if ($this->validateInternalType($value, $type)) {
40 2
                parent::set($propertyName, [$value]);
41
42 2
                return $this;
43
            }
44
45 3
            throw new InvalidArgumentException(
46 3
                'Expected value to be type of [' . $this->propertyInternalTypes()[$type] . '] different type was given'
47
            );
48
        }
49
50 8
        if ($this->isTypeArrayOfObjects($type) && is_array($value)) {
51
            return $this->processArrayOfObj($value, $type);
52
        }
53
54 8
        return parent::set($propertyName, [$this->processObjectType($value, $type)]);
55
    }
56
57 11
    private function isInternalType($type)
58
    {
59 11
        return is_numeric($type) && array_key_exists($type, $this->propertyInternalTypes());
60
    }
61
62 14
    private function isPropertySet($propertyName): bool
63
    {
64 14
        return array_key_exists($propertyName, $this->properties);
65
    }
66
67 8
    private function processObjectType($value, $class)
68
    {
69 8
        $this->isClassOrInterface($class);
70
71 8
        if (is_array($value) && is_subclass_of($class, Makeable::class)) {
72 5
            return $class::make($value);
73
        }
74
75 6
        if (is_a($value, $class)) {
76 3
            return $value;
77
        }
78
79 3
        throw new InvalidArgumentException(
80 3
            'Expected value to be object of [' . $class . '] type different type was given'
81
        );
82
    }
83
84 8
    private function isClassOrInterface($class): bool
85
    {
86 8
        if (class_exists($class) || interface_exists($class)) {
87 8
            return true;
88
        }
89
        throw new Exception('Non existing class or interface [' . $class . ']');
90
    }
91
92 8
    private function isTypeArrayOfObjects($type): bool
93
    {
94 8
        return strpos($type, '[]') !== false;
95
    }
96
97
    private function processArrayOfObj(array $value, $type)
98
    {
99
        $ar = [];
100
        $class = $this->getClassNameFromType($type);
101
102
        foreach ($value as $obj) {
103
            $ar[] = $this->processObjectType($obj, $class);
104
        }
105
106
        return $ar;
107
    }
108
109
    private function getClassNameFromType($type)
110
    {
111
        return (string) str_replace('[]', '', $type);
112
    }
113
114 5
    private function validateInternalType($value, $type): bool
115
    {
116
        switch ($type) {
117 5
            case self::TYPE_ARRAY:
118 2
                return is_array($value);
119 5
            case self::TYPE_INT:
120 2
                return is_int($value);
121 5
            case self::TYPE_STRING:
122 2
                return is_string($value);
123 5
            case self::TYPE_BOOL:
124 5
                return is_bool($value);
125 2
            case self::TYPE_FLOAT:
126 2
                return is_float($value);
127 2
            case self::TYPE_NUMERIC:
128 2
                return is_numeric($value);
129
        }
130
131
        return false;
132
    }
133
134 5
    private function propertyInternalTypes()
135
    {
136
        return [
137 5
            self::TYPE_ARRAY => 'array',
138 5
            self::TYPE_INT => 'int',
139 5
            self::TYPE_STRING => 'string',
140 5
            self::TYPE_BOOL => 'bool',
141 5
            self::TYPE_FLOAT => 'float',
142 5
            self::TYPE_NUMERIC => 'numeric',
143
        ];
144
    }
145
}
146