Passed
Push — master ( 13b148...e0ea5e )
by Maxim
02:03
created

ConditionsSuit::count()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 16
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 13
nc 4
nop 1
1
<?php
2
/**
3
 * This file is a part of "Axessors" library.
4
 *
5
 * @author <[email protected]>
6
 * @license GPL
7
 */
8
9
namespace NoOne4rever\Axessors;
10
11
use NoOne4rever\Axessors\Exceptions\TypeError;
12
13
/**
14
 * Class ConditionsSuit.
15
 * 
16
 * Processes Axessors conditions.
17
 * 
18
 * @package NoOne4rever\Axessors
19
 */
20
class ConditionsSuit
21
{
22
    public const SETTER_MODE = 4;
23
    public const GETTER_MODE = 8;
24
    
25
    /** @var object|null object */
26
    private $object;
27
    /** @var PropertyData property data */
28
    private $propertyData;
29
    /** @var int mode of execution */
30
    private $runningMode;
31
    /** @var string class */
32
    private $class;
33
    /** @var string method name */
34
    private $method;
35
36
    /**
37
     * ConditionsSuit constructor.
38
     * 
39
     * @param int $mode mode of execution
40
     * @param PropertyData $data property data
41
     * @param string $class class
42
     * @param string $method method name
43
     * @param object|null $object object
44
     */
45
    public function __construct(int $mode, PropertyData $data, string $class, string $method, $object = null)
46
    {
47
        $this->runningMode = $mode;
48
        $this->propertyData = $data;
49
        $this->object = $object;
50
        $this->class = $class;
51
        $this->method = $method;
52
    }
53
54
    /**
55
     * Checks the conditions defined in the Axessors comment.
56
     *
57
     * Creates logical tree of the conditions and then checks if the general result is true.
58
     *
59
     * @param $value mixed value of the property
60
     * @return bool result of checking of the conditions
61
     */
62
    public function processConditions($value): bool
63
    {
64
        $conditions = $this->calculateConditions($value);
65
        if (empty($conditions)) {
66
            return true;
67
        }
68
        foreach ($conditions as $condition) {
69
            if (is_array($condition)) {
70
                foreach ($condition as $subCondition) {
71
                    if (!$subCondition) {
72
                        continue 2;
73
                    }
74
                }
75
                return true;
76
            }
77
            if ($condition) {
78
                return true;
79
            }
80
        }
81
        return false;
82
    }
83
84
    /**
85
     * Calculates every condition defined in the Axessors comment.
86
     *
87
     * @param $value mixed value of the property
88
     * @return bool[] results of the conditions
89
     */
90
    private function calculateConditions($value): array
91
    {
92
        $calculatedConditions = [];
93
        $conditions = $this->runningMode == self::GETTER_MODE ? $this->propertyData->getOutputConditions() : $this->propertyData->getInputConditions();
94
        foreach ($conditions as $number => $complexCondition) {
95
            if (is_array($complexCondition)) {
96
                foreach ($complexCondition as $condition) {
97
                    $calculatedConditions[$number][] = $this->executeCondition($condition, $value);
98
                }
99
            } else {
100
                $calculatedConditions[$number] = $this->executeCondition($complexCondition, $value);
101
            }
102
        }
103
        return $calculatedConditions;
104
    }
105
106
    /**
107
     * Calculates a condition defined in the Axessors comment.
108
     *
109
     * @param $condition string the condition
110
     * @param $value mixed value of the property
111
     * @return bool result of the condition
112
     */
113
    private function executeCondition(string $condition, $value): bool
114
    {
115
        if (strpos($condition, '`') !== false) {
116
            $condition = str_replace('\\`', '`', substr($condition, 1, strlen($condition) - 2));
117
            if (is_null($this->object)) {
118
                return call_user_func("{$this->class}::__axessorsExecute", $condition, $value, true);
119
            } else {
120
                return $this->object->__axessorsExecute($condition, $value, true);
121
            }
122
        } else {
123
            $value = $this->count($value);
124
            if (strpos($condition, '..') !== false) {
125
                $condition = explode('..', $condition);
126
                $condition = "<= {$condition[1]} && $value >= {$condition[0]}";
127
            }
128
            return eval("return $value $condition;");
129
        }
130
    }
131
132
    /**
133
     * Casts the property to integer.
134
     *
135
     * If the property is string or array returns it's length.
136
     * If the property is integer of float returns the property itself.
137
     *
138
     * @param $value mixed value of the property
139
     * @return int integer value of the property
140
     * @throws TypeError if the property can't be turned into integer
141
     */
142
    private function count($value): int
143
    {
144
        switch (gettype($value)) {
145
            case 'integer':
146
            case 'float':
147
                break;
148
            case 'string':
149
                $value = strlen($value);
150
                break;
151
            case 'array':
152
                $value = count($value);
153
                break;
154
            default:
155
                throw new TypeError('value "' . var_export($value, true) . "\" passed to {$this->class}::{$this->method}() is not countable");
156
        }
157
        return $value;
158
    }
159
}