Passed
Push — master ( 337d8e...76e5f0 )
by Gabriel
02:33
created

TypedCollectionTrait::validateItem()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 21
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 12
c 1
b 0
f 1
dl 0
loc 21
rs 9.8666
ccs 12
cts 12
cp 1
cc 3
nc 3
nop 1
crap 3
1
<?php
2
3
namespace Nip\Collections\Typed;
4
5
use Nip\Collections\Exceptions\InvalidTypeException;
6
use TypeError;
7
8
/**
9
 * Trait AbstractTypedCollectionTrait
10
 * @package Nip\Collections\Typed
11
 */
12
trait TypedCollectionTrait
13
{
14
    protected $type;
15
    protected $typeChecker;
16
17
    /**
18
     * @inheritDoc
19
     */
20 27
    public function offsetSet($offset, $value)
21
    {
22 27
        $this->validateItem($value);
23 13
        parent::offsetSet($offset, $value);
24 13
    }
25
26
    /**
27
     * @param mixed $type
28
     */
29
    public function setType($type): void
30
    {
31
        if (is_string($type)) {
32
            $this->type = $type;
33
            switch (strtolower($type)) {
34
                case 'string':
35
                case 'text':
36
                    $this->type = StringCollection::TYPE;
37
                    $this->typeChecker = StringCollection::CHECKER;
38
                    break;
39
                case 'double':
40
                case 'float':
41
                    $this->type = FloatCollection::TYPE;
42
                    $this->typeChecker = FloatCollection::CHECKER;
43
                    break;
44
                case 'array':
45
                    $this->type = ArrayCollection::TYPE;
46
                    $this->typeChecker = ArrayCollection::CHECKER;
47
                    break;
48
                case 'resource':
49
                case 'resource (closed)':
50
                    $this->type = ResourceCollection::TYPE;
51
                    $this->typeChecker = ResourceCollection::CHECKER;
52
                    break;
53
                case 'integer':
54
                case 'int':
55
                    $this->type = IntCollection::TYPE;
56
                    $this->typeChecker = IntCollection::CHECKER;
57
                    break;
58
                case 'number':
59
                    $this->type = NumberCollection::TYPE;
60
                    $this->typeChecker = NumberCollection::CHECKER;
61
                    break;
62
                case 'object':
63
                    $this->type = ObjectCollection::TYPE;
64
                    $this->typeChecker = ObjectCollection::CHECKER;
65
                    break;
66
                case 'callable':
67
                case 'closure':
68
                case 'callback':
69
                case 'function':
70
                    $this->type = CallableCollection::TYPE;
71
                    $this->typeChecker = CallableCollection::CHECKER;
72
                    break;
73
                case 'boolean':
74
                case 'bool':
75
                    $this->type = BooleanCollection::TYPE;
76
                    $this->typeChecker = BooleanCollection::CHECKER;
77
                    break;
78
                case 'json':
79
                    $this->typeChecker = function ($element) {
80
                        if (!is_string($element)) {
81
                            return false;
82
                        }
83
                        if (strcasecmp($element, 'null') == 0) {
84
                            return true;
85
                        }
86
                        return (json_decode($element) !== null);
87
                    };
88
                    break;
89
                default:
90
                    // Class name
91
                    $this->type = $type;
92
                    $this->typeChecker = function ($element) use ($type) {
93
                        return ($element instanceof $type);
94
                    };
95
            }
96
        } elseif (is_callable($type)) {
97
            $this->typeChecker = $type;
98
        } else {
99
            throw new TypeError('Invalid criteria to check elements of the collection.');
100
        }
101
    }
102
103
    /**
104
     * @param $sample
105
     */
106
    public function setTypeLike($sample)
107
    {
108
        if ($sample === null) {
109
            throw new \InvalidArgumentException('Sample element cannot be NULL');
110
        } elseif (is_object($sample)) {
111
            $this->setType(get_class($sample));
112
            return;
113
        }
114
        $this->setType(gettype($sample));
115
    }
116
117
    protected function validateItems(array $array): void
118
    {
119
        foreach ($array as $value) {
120
            $this->validateItem($value);
121
        }
122
    }
123
124
    /**
125
     * @param $value
126
     */
127 27
    protected function validateItem($value): void
128
    {
129 27
        if (!$this->validItem($value)) {
130 14
            $message = $this->getErrorMessage($value) ?? "%s not valid type. Expected [%s] for %s collection!";
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getErrorMessage($value) targeting Nip\Collections\Typed\Ty...rait::getErrorMessage() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
131
132 14
            $valueType = gettype($value);
133
134 14
            if ($valueType === 'object') {
135 2
                $valueType = get_class($value);
136
            }
137
138 14
            $message = sprintf(
139 14
                $message,
140
                $valueType,
141 14
                $this->type,
142 14
                get_called_class()
143
            );
144
145
146 14
            throw new InvalidTypeException(
147 14
                $message
148
            );
149
        }
150 13
    }
151
152
    /**
153
     * Is the item valid - overwrite if you need another check
154
     *
155
     * @param $item
156
     * @return bool
157
     */
158 27
    protected function validItem($item): bool
159
    {
160 27
        return ($this->typeChecker)($item);
161
    }
162
163
    /**
164
     * @param $value
165
     * @return string|null
166
     */
167 14
    protected function getErrorMessage($value): ?string
0 ignored issues
show
Unused Code introduced by
The parameter $value is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

167
    protected function getErrorMessage(/** @scrutinizer ignore-unused */ $value): ?string

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
168
    {
169 14
        return null;
170
    }
171
}
172