Passed
Push — master ( b556a2...2820ae )
by Gabriel
01:39
created

TypedCollectionTrait::unshift()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 2
c 0
b 0
f 0
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
cc 1
nc 1
nop 2
crap 1
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
     * @inheritDoc
28
     */
29 27
    public function unshift($value, $key = null)
30
    {
31 27
        $this->validateItem($value);
32 13
        parent::unshift($value, $key);
33 13
    }
34
35
    /**
36
     * @param mixed $type
37
     */
38
    public function setType($type): void
39
    {
40
        if (is_string($type)) {
41
            $this->type = $type;
42
            switch (strtolower($type)) {
43
                case 'string':
44
                case 'text':
45
                    $this->type = StringCollection::TYPE;
46
                    $this->typeChecker = StringCollection::CHECKER;
47
                    break;
48
                case 'double':
49
                case 'float':
50
                    $this->type = FloatCollection::TYPE;
51
                    $this->typeChecker = FloatCollection::CHECKER;
52
                    break;
53
                case 'array':
54
                    $this->type = ArrayCollection::TYPE;
55
                    $this->typeChecker = ArrayCollection::CHECKER;
56
                    break;
57
                case 'resource':
58
                case 'resource (closed)':
59
                    $this->type = ResourceCollection::TYPE;
60
                    $this->typeChecker = ResourceCollection::CHECKER;
61
                    break;
62
                case 'integer':
63
                case 'int':
64
                    $this->type = IntCollection::TYPE;
65
                    $this->typeChecker = IntCollection::CHECKER;
66
                    break;
67
                case 'number':
68
                    $this->type = NumberCollection::TYPE;
69
                    $this->typeChecker = NumberCollection::CHECKER;
70
                    break;
71
                case 'object':
72
                    $this->type = ObjectCollection::TYPE;
73
                    $this->typeChecker = ObjectCollection::CHECKER;
74
                    break;
75
                case 'callable':
76
                case 'closure':
77
                case 'callback':
78
                case 'function':
79
                    $this->type = CallableCollection::TYPE;
80
                    $this->typeChecker = CallableCollection::CHECKER;
81
                    break;
82
                case 'boolean':
83
                case 'bool':
84
                    $this->type = BooleanCollection::TYPE;
85
                    $this->typeChecker = BooleanCollection::CHECKER;
86
                    break;
87
                case 'json':
88
                    $this->typeChecker = function ($element) {
89
                        if (!is_string($element)) {
90
                            return false;
91
                        }
92
                        if (strcasecmp($element, 'null') == 0) {
93
                            return true;
94
                        }
95
                        return (json_decode($element) !== null);
96
                    };
97
                    break;
98
                default:
99
                    // Class name
100
                    $this->type = $type;
101
                    $this->typeChecker = function ($element) use ($type) {
102
                        return ($element instanceof $type);
103
                    };
104
            }
105
        } elseif (is_callable($type)) {
106
            $this->typeChecker = $type;
107
        } else {
108
            throw new TypeError('Invalid criteria to check elements of the collection.');
109
        }
110
    }
111
112
    /**
113
     * @param $sample
114
     */
115
    public function setTypeLike($sample)
116
    {
117
        if ($sample === null) {
118
            throw new \InvalidArgumentException('Sample element cannot be NULL');
119
        } elseif (is_object($sample)) {
120
            $this->setType(get_class($sample));
121
            return;
122
        }
123
        $this->setType(gettype($sample));
124
    }
125
126
    protected function validateItems(array $array): void
127
    {
128
        foreach ($array as $value) {
129
            $this->validateItem($value);
130
        }
131
    }
132
133
    /**
134
     * @param $value
135
     */
136 27
    protected function validateItem($value): void
137
    {
138 27
        if (!$this->validItem($value)) {
139 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...
140
141 14
            $valueType = gettype($value);
142
143 14
            if ($valueType === 'object') {
144 2
                $valueType = get_class($value);
145
            }
146
147 14
            $message = sprintf(
148 14
                $message,
149
                $valueType,
150 14
                $this->type,
151 14
                get_called_class()
152
            );
153
154
155 14
            throw new InvalidTypeException(
156 14
                $message
157
            );
158
        }
159 13
    }
160
161
    /**
162
     * Is the item valid - overwrite if you need another check
163
     *
164
     * @param $item
165
     * @return bool
166
     */
167 27
    protected function validItem($item): bool
168
    {
169 27
        return ($this->typeChecker)($item);
170
    }
171
172
    /**
173
     * @param $value
174
     * @return string|null
175
     */
176 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

176
    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...
177
    {
178 14
        return null;
179
    }
180
}
181