Completed
Push — master ( 6174f1...fbfa48 )
by Freek
02:02
created

Valuestore::flushStartingWith()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 10
rs 9.4285
cc 2
eloc 5
nc 2
nop 1
1
<?php
2
3
namespace Spatie\Valuestore;
4
5
use ArrayAccess;
6
use Countable;
7
8
class Valuestore implements ArrayAccess, Countable
9
{
10
    /** @var string */
11
    protected $fileName;
12
13
    /**
14
     * @param string $fileName
15
     *
16
     * @return $this
17
     */
18
    public static function make(string $fileName)
19
    {
20
        return (new static())->setFileName($fileName);
21
    }
22
23
    protected function __construct()
24
    {
25
    }
26
27
    /**
28
     * Set the filename where all values will be stored.
29
     *
30
     * @param string $fileName
31
     *
32
     * @return $this
33
     */
34
    protected function setFileName(string $fileName)
35
    {
36
        $this->fileName = $fileName;
37
38
        return $this;
39
    }
40
41
    /**
42
     * Put a value in the store.
43
     *
44
     * @param string|array    $name
45
     * @param string|int|null $value
46
     *
47
     * @return $this
48
     */
49
    public function put($name, $value = null)
50
    {
51
        $newValues = $name;
52
53
        if (!is_array($name)) {
54
            $newValues = [$name => $value];
55
        }
56
57
        $newContent = array_merge($this->all(), $newValues);
58
59
        $this->setContent($newContent);
60
61
        return $this;
62
    }
63
64
    /**
65
     * Push a new value into an array.
66
     *
67
     * @param string $name
68
     * @param $pushValue
69
     *
70
     * @return $this
71
     */
72
    public function push(string $name, $pushValue)
73
    {
74
        if (!is_array($pushValue)) {
75
            $pushValue = [$pushValue];
76
        }
77
78
        if (!$this->has($name)) {
79
            $this->put($name, $pushValue);
0 ignored issues
show
Documentation introduced by
$pushValue is of type array, but the function expects a string|integer|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
80
81
            return $this;
82
        }
83
84
        $oldValue = $this->get($name);
85
86
        if (!is_array($oldValue)) {
87
            $oldValue = [$oldValue];
88
        }
89
90
        if (is_array($oldValue)) {
91
            $newValue = array_merge($oldValue, $pushValue);
92
        }
93
94
        $this->put($name, $newValue);
0 ignored issues
show
Bug introduced by
The variable $newValue does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Documentation introduced by
$newValue is of type array, but the function expects a string|integer|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
95
96
        return $this;
97
    }
98
99
    /**
100
     * Get a value from the store.
101
     *
102
     * @param string $name
103
     * @param $default
104
     *
105
     * @return null|string
106
     */
107
    public function get(string $name, $default = null)
108
    {
109
        if (!array_key_exists($name, $this->all())) {
110
            return $default;
111
        }
112
113
        return $this->all()[$name];
114
    }
115
116
    /*
117
     * Determine if the store has a value for the given name.
118
     */
119
    public function has(string $name) : bool
120
    {
121
        return array_key_exists($name, $this->all());
122
    }
123
124
    /**
125
     * Get all values from the store.
126
     *
127
     * @return array
128
     */
129
    public function all() : array
130
    {
131
        if (!file_exists($this->fileName)) {
132
            return [];
133
        }
134
135
        return json_decode(file_get_contents($this->fileName), true);
136
    }
137
138
    /**
139
     * Get all keys starting with a given string from the store.
140
     *
141
     * @param string $startingWith
142
     *
143
     * @return array
144
     */
145
    public function allStartingWith(string $startingWith = '') : array
146
    {
147
        $values = $this->all();
148
149
        if ($startingWith === '') {
150
            return $values;
151
        }
152
153
        return $this->filterKeysStartingWith($values, $startingWith);
154
    }
155
156
    /**
157
     * Forget a value from the store.
158
     *
159
     * @param string $key
160
     *
161
     * @return $this
162
     */
163
    public function forget(string $key)
164
    {
165
        $newContent = $this->all();
166
167
        unset($newContent[$key]);
168
169
        $this->setContent($newContent);
170
171
        return $this;
172
    }
173
174
    /**
175
     * Flush all values from the store.
176
     *
177
     * @return $this
178
     */
179
    public function flush()
180
    {
181
        return $this->setContent([]);
182
    }
183
184
    /**
185
     * Flush all values which keys start with a given string.
186
     *
187
     * @param string $startingWith
188
     *
189
     * @return $this
190
     */
191
    public function flushStartingWith(string $startingWith = '')
192
    {
193
        $newContent = [];
194
195
        if ($startingWith !== '') {
196
            $newContent = $this->filterKeysNotStartingWith($this->all(), $startingWith);
197
        }
198
199
        return $this->setContent($newContent);
200
    }
201
202
    /**
203
     * Get and forget a value from the store.
204
     *
205
     * @param string $name
206
     *
207
     * @return null|string
208
     */
209
    public function pull(string $name)
210
    {
211
        $value = $this->get($name);
212
213
        $this->forget($name);
214
215
        return $value;
216
    }
217
218
    /**
219
     * Increment a value from the store.
220
     *
221
     * @param string $name
222
     * @param int    $by
223
     *
224
     * @return int|null|string
225
     */
226
    public function increment(string $name, int $by = 1)
227
    {
228
        $currentValue = $this->get($name) ?? 0;
229
230
        $newValue = $currentValue + $by;
231
232
        $this->put($name, $newValue);
233
234
        return $newValue;
235
    }
236
237
    /**
238
     * Decrement a value from the store.
239
     *
240
     * @param string $name
241
     * @param int    $by
242
     *
243
     * @return int|null|string
244
     */
245
    public function decrement(string $name, int $by = 1)
246
    {
247
        return $this->increment($name, $by * -1);
248
    }
249
250
    /**
251
     * Whether a offset exists.
252
     *
253
     * @link http://php.net/manual/en/arrayaccess.offsetexists.php
254
     *
255
     * @param mixed $offset
256
     *
257
     * @return bool
258
     */
259
    public function offsetExists($offset)
260
    {
261
        return $this->has($offset);
262
    }
263
264
    /**
265
     * Offset to retrieve.
266
     *
267
     * @link http://php.net/manual/en/arrayaccess.offsetget.php
268
     *
269
     * @param mixed $offset
270
     *
271
     * @return mixed
272
     */
273
    public function offsetGet($offset)
274
    {
275
        return $this->get($offset);
276
    }
277
278
    /**
279
     * Offset to set.
280
     *
281
     * @link http://php.net/manual/en/arrayaccess.offsetset.php
282
     *
283
     * @param mixed $offset
284
     * @param mixed $value
285
     */
286
    public function offsetSet($offset, $value)
287
    {
288
        $this->put($offset, $value);
289
    }
290
291
    /**
292
     * Offset to unset.
293
     *
294
     * @link http://php.net/manual/en/arrayaccess.offsetunset.php
295
     *
296
     * @param mixed $offset
297
     */
298
    public function offsetUnset($offset)
299
    {
300
        $this->forget($offset);
301
    }
302
303
    protected function filterKeysStartingWith(array $values, string $startsWith) : array
304
    {
305
        return array_filter($values, function ($key) use ($startsWith) {
306
307
            return $this->startsWith($key, $startsWith);
308
309
        }, ARRAY_FILTER_USE_KEY);
310
    }
311
312
    protected function filterKeysNotStartingWith(array $values, string $startsWith) : array
313
    {
314
        return array_filter($values, function ($key) use ($startsWith) {
315
316
            return !$this->startsWith($key, $startsWith);
317
318
        }, ARRAY_FILTER_USE_KEY);
319
    }
320
321
    protected function startsWith(string $haystack, string $needle) : bool
322
    {
323
        return substr($haystack, 0, strlen($needle)) === $needle;
324
    }
325
326
    /**
327
     * @param array $values
328
     *
329
     * @return $this
330
     */
331
    protected function setContent(array $values)
332
    {
333
        file_put_contents($this->fileName, json_encode($values));
334
335
        if (!count($values)) {
336
            unlink($this->fileName);
337
        }
338
339
        return $this;
340
    }
341
342
    /**
343
     * Count elements of an object.
344
     *
345
     * @link http://php.net/manual/en/countable.count.php
346
     *
347
     * @return int The custom count as an integer.
348
     *             </p>
349
     *             <p>
350
     *             The return value is cast to an integer.
351
     *
352
     * @since 5.1.0
353
     */
354
    public function count()
355
    {
356
        return count($this->all());
357
    }
358
}
359