Circular   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 123
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 7
Bugs 0 Features 0
Metric Value
eloc 36
c 7
b 0
f 0
dl 0
loc 123
ccs 44
cts 44
cp 1
rs 10
wmc 18

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __invoke() 0 3 1
A rewind() 0 3 1
A current() 0 3 1
A valid() 0 4 1
A next() 0 3 1
A key() 0 3 1
A convert() 0 18 4
A refineData() 0 13 4
A value() 0 11 3
A __construct() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace AlecRabbit\Accessories;
6
7
use function AlecRabbit\typeOf;
8
9
/**
10
 * Class Circular
11
 */
12
class Circular implements \Iterator
13
{
14
    /** @var mixed|Rewindable */
15
    protected $data;
16
17
    /** @var bool */
18
    protected $oneElement = false;
19
20
    /**
21
     * Circular constructor.
22
     * @param array|callable|Rewindable $data accepts array, callable which returns \Generator or Rewindable
23
     */
24 11
    public function __construct($data)
25
    {
26 11
        $this->data = $this->refineData($data);
27 9
    }
28
29
    /**
30
     * @param mixed $data
31
     * @return mixed
32
     */
33 11
    protected function refineData($data)
34
    {
35 11
        if (\is_array($data)) {
36 7
            if (1 === $count = count($data)) {
37 2
                $this->oneElement = true;
38 2
                return reset($data);
39
            }
40 5
            if (0 === $count) {
41 1
                $this->oneElement = true;
42 1
                return null;
43
            }
44
        }
45 8
        return $this->convert($data);
46
    }
47
48
    /**
49
     * @param mixed $arg
50
     * @return Rewindable
51
     */
52 8
    protected function convert(&$arg): Rewindable
53
    {
54 8
        if (\is_array($arg)) {
55
            return
56 4
                new Rewindable(
57
                    static function () use (&$arg): \Generator {
58 4
                        yield from $arg;
59 4
                    }
60
                );
61
        }
62 4
        if (\is_callable($arg)) {
63
            return
64 2
                new Rewindable($arg);
65
        }
66 2
        if ($arg instanceof Rewindable) {
67 1
            return $arg;
68
        }
69 1
        throw new \InvalidArgumentException('Unexpected argument type: ' . typeOf($arg) . ' for ' . Caller::get());
70
    }
71
72
    /**
73
     * @return mixed
74
     */
75 2
    public function __invoke()
76
    {
77 2
        return $this->value();
78
    }
79
80
    /**
81
     * @return mixed
82
     */
83 5
    public function value()
84
    {
85 5
        if ($this->oneElement) {
86 3
            return $this->data;
87
        }
88 2
        if (null === $value = $this->current()) {
89 2
            $this->rewind();
90 2
            $value = $this->current();
91
        }
92 2
        $this->next();
93 2
        return $value;
94
    }
95
96
    /**
97
     * {@inheritdoc}
98
     */
99 6
    public function current()
100
    {
101 6
        return $this->data->current();
102
    }
103
104
    /**
105
     * {@inheritdoc}
106
     */
107 6
    public function rewind(): void
108
    {
109 6
        $this->data->rewind();
110 6
    }
111
112
    /**
113
     * {@inheritdoc}
114
     */
115 6
    public function next(): void
116
    {
117 6
        $this->data->next();
118 6
    }
119
120
    /**
121
     * {@inheritdoc}
122
     */
123 4
    public function valid(): bool
124
    {
125
        return
126 4
            $this->data->valid();
127
    }
128
129
    /**
130
     * {@inheritdoc}
131
     */
132 4
    public function key()
133
    {
134 4
        return $this->data->key();
135
    }
136
}
137