• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nette / latte / 15809643126

22 Jun 2025 06:35PM UTC coverage: 93.67% (+0.09%) from 93.583%
15809643126

push

github

dg
added {include?} {import?} {embed?} {sandbox?}

34 of 36 new or added lines in 7 files covered. (94.44%)

164 existing lines in 43 files now uncovered.

5164 of 5513 relevant lines covered (93.67%)

0.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.78
/src/Latte/Essential/CachingIterator.php
1
<?php
2

3
/**
4
 * This file is part of the Latte (https://latte.nette.org)
5
 * Copyright (c) 2008 David Grudl (https://davidgrudl.com)
6
 */
7

8
declare(strict_types=1);
9

10
namespace Latte\Essential;
11

12
use function get_debug_type, is_array, max, method_exists, sprintf;
13

14

15
/**
16
 * Smarter caching iterator.
17
 *
18
 * @property-read bool $first
19
 * @property-read bool $last
20
 * @property-read bool $empty
21
 * @property-read bool $odd
22
 * @property-read bool $even
23
 * @property-read int $counter
24
 * @property-read int $counter0
25
 * @property-read mixed $nextKey
26
 * @property-read mixed $nextValue
27
 * @property-read ?self $parent
28
 * @internal
29
 */
30
class CachingIterator extends \CachingIterator implements \Countable
31
{
32
        private int $counter = 0;
33
        private ?self $parent = null;
34

35

36
        public function __construct(mixed $iterator, ?self $parent = null)
1✔
37
        {
38
                if (is_array($iterator) || $iterator instanceof \stdClass) {
1✔
39
                        $iterator = new \ArrayIterator($iterator);
1✔
40

41
                } elseif ($iterator instanceof \IteratorAggregate) {
1✔
42
                        do {
43
                                $iterator = $iterator->getIterator();
1✔
44
                        } while (!$iterator instanceof \Iterator);
1✔
45
                } elseif ($iterator instanceof \Traversable) {
1✔
46
                        if (!$iterator instanceof \Iterator) {
1✔
UNCOV
47
                                $iterator = new \IteratorIterator($iterator);
×
48
                        }
49
                } else {
50
                        throw new \InvalidArgumentException(sprintf('Invalid argument passed to foreach; array or Traversable expected, %s given.', get_debug_type($iterator)));
1✔
51
                }
52

53
                parent::__construct($iterator, 0);
1✔
54
                $this->parent = $parent;
1✔
55
        }
1✔
56

57

58
        /**
59
         * Is the current element the first one?
60
         */
61
        public function isFirst(?int $width = null): bool
1✔
62
        {
63
                return $this->counter === 1 || ($width && $this->counter !== 0 && (($this->counter - 1) % $width) === 0);
1✔
64
        }
65

66

67
        /**
68
         * Is the current element the last one?
69
         */
70
        public function isLast(?int $width = null): bool
1✔
71
        {
72
                return !$this->hasNext() || ($width && ($this->counter % $width) === 0);
1✔
73
        }
74

75

76
        /**
77
         * Is the iterator empty?
78
         */
79
        public function isEmpty(): bool
80
        {
81
                return $this->counter === 0;
1✔
82
        }
83

84

85
        /**
86
         * Is the counter odd?
87
         */
88
        public function isOdd(): bool
89
        {
90
                return $this->counter % 2 === 1;
1✔
91
        }
92

93

94
        /**
95
         * Is the counter even?
96
         */
97
        public function isEven(): bool
98
        {
99
                return $this->counter % 2 === 0;
1✔
100
        }
101

102

103
        /**
104
         * Returns the 1-indexed counter.
105
         */
106
        public function getCounter(): int
107
        {
108
                return $this->counter;
1✔
109
        }
110

111

112
        /**
113
         * Returns the 0-indexed counter.
114
         */
115
        public function getCounter0(): int
116
        {
117
                return max(0, $this->counter - 1);
1✔
118
        }
119

120

121
        /**
122
         * Decrements counter.
123
         */
124
        public function skipRound(): void
125
        {
126
                $this->counter = max($this->counter - 1, 0);
1✔
127
        }
1✔
128

129

130
        /**
131
         * Returns the counter as string
132
         */
133
        public function __toString(): string
134
        {
135
                return (string) $this->counter;
1✔
136
        }
137

138

139
        /**
140
         * Returns the count of elements.
141
         */
142
        public function count(): int
143
        {
144
                $inner = $this->getInnerIterator();
×
UNCOV
145
                if ($inner instanceof \Countable) {
×
UNCOV
146
                        return $inner->count();
×
147

148
                } else {
UNCOV
149
                        throw new \LogicException('Iterator is not countable.');
×
150
                }
151
        }
152

153

154
        /**
155
         * Forwards to the next element.
156
         */
157
        public function next(): void
158
        {
159
                parent::next();
1✔
160
                if (parent::valid()) {
1✔
161
                        $this->counter++;
1✔
162
                }
163
        }
1✔
164

165

166
        /**
167
         * Rewinds the Iterator.
168
         */
169
        public function rewind(): void
170
        {
171
                parent::rewind();
1✔
172
                $this->counter = parent::valid() ? 1 : 0;
1✔
173
        }
1✔
174

175

176
        /**
177
         * Returns the next key or null if position is not valid.
178
         */
179
        public function getNextKey(): mixed
180
        {
181
                $iterator = $this->getInnerIterator();
1✔
182
                return $iterator->valid() ? $iterator->key() : null;
1✔
183
        }
184

185

186
        /**
187
         * Returns the next element or null if position is not valid.
188
         */
189
        public function getNextValue(): mixed
190
        {
191
                $iterator = $this->getInnerIterator();
1✔
192
                return $iterator->valid() ? $iterator->current() : null;
1✔
193
        }
194

195

196
        /**
197
         * Returns the iterator surrounding the current one.
198
         */
199
        public function getParent(): ?self
200
        {
201
                return $this->parent;
1✔
202
        }
203

204

205
        /********************* property accessor ****************d*g**/
206

207

208
        /**
209
         * Returns property value.
210
         * @throws \LogicException if the property is not defined.
211
         */
212
        public function __get(string $name): mixed
1✔
213
        {
214
                if (method_exists($this, $m = 'get' . $name) || method_exists($this, $m = 'is' . $name)) {
1✔
215
                        return $this->$m();
1✔
216
                }
217

UNCOV
218
                throw new \LogicException('Attempt to read undeclared property ' . static::class . "::\$$name.");
×
219
        }
220

221

222
        /**
223
         * Is property defined?
224
         */
225
        public function __isset(string $name): bool
226
        {
UNCOV
227
                return method_exists($this, 'get' . $name) || method_exists($this, 'is' . $name);
×
228
        }
229
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc