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

CPS-IT / handlebars / 25305815543

04 May 2026 07:07AM UTC coverage: 90.025% (+0.2%) from 89.817%
25305815543

push

github

web-flow
Merge pull request #563 from CPS-IT/fix/view-factory

[BUGFIX] Limit view factory override implementation to certain services

41 of 42 new or added lines in 1 file covered. (97.62%)

1417 of 1574 relevant lines covered (90.03%)

7.01 hits per line

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

97.62
/Classes/DependencyInjection/CompilerPass/HandlebarsViewFactoryPass.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\DependencyInjection\CompilerPass;
19

20
use CPSIT\Typo3Handlebars\View;
21
use Symfony\Component\DependencyInjection;
22

23
/**
24
 * HandlebarsViewFactoryPass
25
 *
26
 * @author Elias Häußler <e.haeussler@familie-redlich.de>
27
 * @license GPL-2.0-or-later
28
 *
29
 * @phpstan-type TargetService array{calls?: array<string, string>, properties?: list<string>}
30
 */
31
final class HandlebarsViewFactoryPass extends DependencyInjection\Compiler\AbstractRecursivePass
32
{
33
    private readonly DependencyInjection\Reference $viewFactory;
34

35
    /**
36
     * @var array<string, TargetService>
37
     */
38
    private array $targetServices = [];
39

40
    public function __construct(string $viewFactoryServiceId = View\HandlebarsViewFactory::class)
5✔
41
    {
42
        $this->viewFactory = new DependencyInjection\Reference($viewFactoryServiceId);
5✔
43
    }
44

45
    public function process(DependencyInjection\ContainerBuilder $container): void
5✔
46
    {
47
        if ($container->has((string)$this->viewFactory)) {
5✔
48
            parent::process($container);
4✔
49
        }
50
    }
51

52
    protected function processValue(mixed $value, bool $isRoot = false): mixed
4✔
53
    {
54
        $value = parent::processValue($value, $isRoot);
4✔
55

56
        if (!($value instanceof DependencyInjection\Definition)
4✔
57
            || $this->currentId === null
4✔
58
            || !$value->isAutowired()
4✔
59
            || $value->isAbstract()
4✔
60
            || $value->getClass() === null
4✔
61
        ) {
62
            return $value;
4✔
63
        }
64

65
        $configuration = $this->targetServices[$this->currentId] ?? $this->resolveBaseConfiguration($value->getClass());
4✔
66

67
        if ($configuration === null) {
4✔
68
            return $value;
4✔
69
        }
70

71
        foreach ($configuration['calls'] ?? [] as $methodName => $argumentName) {
3✔
72
            $value->removeMethodCall($methodName);
2✔
73
            $value->addMethodCall($methodName, [$argumentName => $this->viewFactory]);
2✔
74
        }
75

76
        foreach ($configuration['properties'] ?? [] as $propertyName) {
3✔
77
            $value->setArgument($propertyName, $this->viewFactory);
1✔
78
        }
79

80
        return $value;
3✔
81
    }
82

83
    /**
84
     * @return TargetService|null
85
     */
86
    private function resolveBaseConfiguration(string $className): ?array
4✔
87
    {
88
        $reflection = $this->container?->getReflectionClass($className, false);
4✔
89

90
        if ($reflection === null) {
4✔
NEW
91
            return null;
×
92
        }
93

94
        $current = $reflection;
4✔
95

96
        do {
97
            if (array_key_exists($current->getName(), $this->targetServices)) {
4✔
98
                return $this->targetServices[$current->getName()];
1✔
99
            }
100

101
            $current = $current->getParentClass();
4✔
102
        } while ($current !== false);
4✔
103

104
        return null;
4✔
105
    }
106

107
    public function addMethodCall(string $serviceId, string $methodName, string $argumentName = '$viewFactory'): self
2✔
108
    {
109
        $this->targetServices[$serviceId] ??= [];
2✔
110
        $this->targetServices[$serviceId]['calls'] ??= [];
2✔
111
        $this->targetServices[$serviceId]['calls'][$methodName] = $argumentName;
2✔
112

113
        return $this;
2✔
114
    }
115

116
    public function addProperty(string $serviceId, string $propertyName = '$viewFactory'): self
1✔
117
    {
118
        $this->targetServices[$serviceId] ??= [];
1✔
119
        $this->targetServices[$serviceId]['properties'] ??= [];
1✔
120
        $this->targetServices[$serviceId]['properties'][] = $propertyName;
1✔
121

122
        return $this;
1✔
123
    }
124
}
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