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

CPS-IT / handlebars / 23363698435

20 Mar 2026 09:40PM UTC coverage: 89.861% (-0.4%) from 90.285%
23363698435

Pull #543

github

web-flow
Merge 223a31852 into 86597a598
Pull Request #543: [TASK] Update codebase to match PHPStan max level

139 of 157 new or added lines in 43 files covered. (88.54%)

26 existing lines in 11 files now uncovered.

1356 of 1509 relevant lines covered (89.86%)

6.82 hits per line

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

92.45
/Classes/Renderer/Template/Path/ContentObjectPathProvider.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of the TYPO3 CMS extension "handlebars".
7
 *
8
 * It is free software; you can redistribute it and/or modify it under
9
 * the terms of the GNU General Public License, either version 2
10
 * of the License, or any later version.
11
 *
12
 * For the full copyright and license information, please read the
13
 * LICENSE.txt file that was distributed with this source code.
14
 *
15
 * The TYPO3 project - inspiring people to share!
16
 */
17

18
namespace CPSIT\Typo3Handlebars\Renderer\Template\Path;
19

20
use TYPO3\CMS\Core;
21

22
/**
23
 * ContentObjectPathProvider
24
 *
25
 * @author Elias Häußler <e.haeussler@familie-redlich.de>
26
 * @license GPL-2.0-or-later
27
 *
28
 * @phpstan-type RootPathStackItem array{
29
 *     current: array<int, string>,
30
 *     merged: array<int, string>|null,
31
 * }
32
 */
33
final class ContentObjectPathProvider implements PathProvider, Core\SingletonInterface
34
{
35
    /**
36
     * @var list<array<self::*, RootPathStackItem>>
37
     */
38
    private array $stack = [];
39

40
    private ?int $currentItem = null;
41

42
    /**
43
     * @param array{templateRootPath?: string, partialRootPath?: string, templateRootPaths?: array<int, string>, partialRootPaths?: array<int, string>} $configuration
44
     */
45
    public function push(array $configuration): void
4✔
46
    {
47
        $partialRootPaths = [];
4✔
48
        $templateRootPaths = [];
4✔
49

50
        if (is_array($configuration['templateRootPaths'] ?? null)) {
4✔
51
            $templateRootPaths = $configuration['templateRootPaths'];
4✔
52
        }
53
        if (is_array($configuration['partialRootPaths'] ?? null)) {
4✔
54
            $partialRootPaths = $configuration['partialRootPaths'];
4✔
55
        }
56

57
        // A single root path receives highest priority
58
        if (is_string($configuration['templateRootPath'] ?? null)) {
4✔
59
            $templateRootPaths[PHP_INT_MAX] = $configuration['templateRootPath'];
4✔
60
        }
61
        if (is_string($configuration['partialRootPath'] ?? null)) {
4✔
62
            $partialRootPaths[PHP_INT_MAX] = $configuration['partialRootPath'];
4✔
63
        }
64

65
        ksort($templateRootPaths);
4✔
66
        ksort($partialRootPaths);
4✔
67

68
        $this->stack[] = [
4✔
69
            'partialRootPaths' => [
4✔
70
                'current' => $partialRootPaths,
4✔
71
                'merged' => null,
4✔
72
            ],
4✔
73
            'templateRootPaths' => [
4✔
74
                'current' => $templateRootPaths,
4✔
75
                'merged' => null,
4✔
76
            ],
4✔
77
        ];
4✔
78

79
        if ($this->currentItem === null) {
4✔
80
            $this->currentItem = 0;
4✔
81
        } else {
82
            $this->currentItem++;
3✔
83
        }
84
    }
85

86
    public function pop(): void
2✔
87
    {
88
        if ($this->stack === []) {
2✔
89
            return;
1✔
90
        }
91

92
        array_pop($this->stack);
1✔
93

94
        if ($this->stack === []) {
1✔
95
            $this->currentItem = null;
1✔
96
        } else {
97
            $this->currentItem--;
1✔
98
        }
99
    }
100

101
    public function isEmpty(): bool
3✔
102
    {
103
        return $this->currentItem === null;
3✔
104
    }
105

106
    public function getPartialRootPaths(): array
3✔
107
    {
108
        return $this->getMergedRootPathsFromStack(self::PARTIALS);
3✔
109
    }
110

111
    public function getTemplateRootPaths(): array
3✔
112
    {
113
        return $this->getMergedRootPathsFromStack(self::TEMPLATES);
3✔
114
    }
115

UNCOV
116
    public function isCacheable(): bool
×
117
    {
118
        // Caching is done internally, based on the current stack
119
        return false;
×
120
    }
121

122
    /**
123
     * @param self::* $type
124
     * @return array<int, string>
125
     */
126
    private function getMergedRootPathsFromStack(string $type): array
5✔
127
    {
128
        if ($this->currentItem === null) {
5✔
129
            return [];
2✔
130
        }
131

132
        // Merge and cache root paths
133
        if ($this->stack[$this->currentItem][$type]['merged'] === null) {
3✔
134
            $merged = $this->stack[0][$type]['current'];
3✔
135

136
            for ($i = 1; $i <= $this->currentItem; $i++) {
3✔
137
                /** @noinspection SlowArrayOperationsInLoopInspection */
138
                $merged = array_replace($merged, $this->stack[$i][$type]['current']);
2✔
139
            }
140

141
            ksort($merged);
3✔
142

143
            $this->stack[$this->currentItem][$type]['merged'] = $merged;
3✔
144
        }
145

146
        return $this->stack[$this->currentItem][$type]['merged'];
3✔
147
    }
148

UNCOV
149
    public static function getPriority(): int
×
150
    {
UNCOV
151
        return 100;
×
152
    }
153
}
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