Completed
Push — master ( 56127f...c3d14e )
by Travis
03:10
created

SingleIterableInput::isWithinCountSize()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 14
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 6
nc 6
nop 1
dl 0
loc 14
ccs 7
cts 7
cp 1
crap 5
rs 9.6111
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace InputGuard\Guards\Bases;
5
6
use ArrayAccess;
7
use Traversable;
8
9
trait SingleIterableInput
10
{
11
    use SingleInput;
12
13
    /**
14
     * @var int
15
     */
16
    private $minCount = 0;
17
18
    /**
19
     * @var int|null;
20
     */
21
    private $maxCount;
22
23
    /**
24
     * @var bool
25
     */
26
    private $allowNullElement = false;
27
28
    /**
29
     * A method to allow extra validation to be done for each element of an iterable.
30
     *
31
     * @param mixed $element
32
     * @param mixed $value
33
     *
34
     * @return bool
35
     */
36
    abstract protected function validateIterableElement($element, &$value): bool;
37
38 2
    public function maxCount(int $max): self
39
    {
40 2
        $this->maxCount = $max;
41
42 2
        return $this;
43
    }
44
45 2
    public function minCount(int $min): self
46
    {
47 2
        $this->minCount = $min;
48
49 2
        return $this;
50
    }
51
52 11
    public function betweenCount(int $min, int $max): self
53
    {
54 11
        $this->minCount = $min;
55 11
        $this->maxCount = $max;
56
57 11
        return $this;
58
    }
59
60 1
    public function allowNullElement(): self
61
    {
62 1
        $this->allowNullElement = true;
63
64 1
        return $this;
65
    }
66
67 40
    public function value(): ?iterable
68
    {
69 40
        $this->success();
70
71 40
        return $this->value;
72
    }
73
74 3
    public function valueAsArray(): array
75
    {
76 3
        $this->success();
77
78 3
        return $this->value instanceof Traversable ? iterator_to_array($this->value) : (array)$this->value;
79
    }
80
81
    /**
82
     * @param $input
83
     * @param $value
84
     *
85
     * @return bool
86
     */
87 44
    protected function validation($input, &$value): bool
88
    {
89 44
        if (is_iterable($input) === false) {
90 3
            return false;
91
        }
92
93
        /** @var iterable $input */
94 41
        if ($this->isWithinCountSize($input) === false) {
95 8
            return false;
96
        }
97
98 33
        $can_be_updated = $this->elementsCanBeUpdated($input);
99
100 33
        foreach ($input as $key => $element) {
101 29
            if ($element === null) {
102 2
                if ($this->allowNullElement) {
103 1
                    continue;
104
                }
105
106 1
                return false;
107
            }
108
109 29
            $element_value = null;
110 29
            if ($this->validateIterableElement($element, $element_value) === false) {
111 7
                return false;
112
            }
113
114 24
            if ($can_be_updated) {
115
                /** @noinspection OffsetOperationsInspection */
116 24
                $input[$key] = $element_value;
117
            }
118
119
            // @todo Make the method return false if strict validation is disabled and the iterable cannot be updated.
120
        }
121
122 25
        $value = $input;
123
124 25
        return true;
125
    }
126
127 41
    private function isWithinCountSize(iterable $input): bool
128
    {
129
        /** @noinspection PhpParamsInspection */
130 41
        $iterableSize = \is_array($input) ? count($input) : iterator_count($input);
131
132 41
        if ($iterableSize < $this->minCount) {
133 4
            return false;
134
        }
135
136 37
        if ($this->maxCount !== null && $iterableSize > $this->maxCount) {
137 4
            return false;
138
        }
139
140 33
        return true;
141
    }
142
143 33
    protected function elementsCanBeUpdated(iterable $input): bool
144
    {
145
        // At this time only iterable that are arrays or implement array access can be modified.
146
        // I need to look into using http://www.php.net/manual/en/closure.bind.php or Refection to see if it's
147
        // possible to modify the elements of an object that only implements the Iterator interface.
148 33
        return \is_array($input) || $input instanceof ArrayAccess;
149
    }
150
}
151