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

nette / di / 6739042234

02 Nov 2023 10:31PM UTC coverage: 93.846% (+41.8%) from 52.037%
6739042234

push

github

dg
Option 'class' is allowed again

Partially reverts commit 046f89cc3.

1 of 1 new or added line in 1 file covered. (100.0%)

2257 of 2405 relevant lines covered (93.85%)

0.94 hits per line

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

97.18
/src/DI/Extensions/InjectExtension.php
1
<?php
2

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

8
declare(strict_types=1);
9

10
namespace Nette\DI\Extensions;
11

12
use Nette;
13
use Nette\DI;
14
use Nette\DI\Definitions;
15
use Nette\Utils\Reflection;
16

17

18
/**
19
 * Calls inject methods and fills @inject properties.
20
 */
21
final class InjectExtension extends DI\CompilerExtension
22
{
23
        public const TagInject = 'nette.inject';
24

25
        /** @deprecated use InjectExtension::TagInject */
26
        public const TAG_INJECT = self::TagInject;
27

28

29
        public function getConfigSchema(): Nette\Schema\Schema
30
        {
31
                return Nette\Schema\Expect::structure([]);
1✔
32
        }
33

34

35
        public function beforeCompile()
36
        {
37
                foreach ($this->getContainerBuilder()->getDefinitions() as $def) {
1✔
38
                        if ($def->getTag(self::TagInject)) {
1✔
39
                                $def = $def instanceof Definitions\FactoryDefinition
1✔
40
                                        ? $def->getResultDefinition()
1✔
41
                                        : $def;
1✔
42
                                if ($def instanceof Definitions\ServiceDefinition) {
1✔
43
                                        $this->updateDefinition($def);
1✔
44
                                }
45
                        }
46
                }
47
        }
1✔
48

49

50
        private function updateDefinition(Definitions\ServiceDefinition $def): void
1✔
51
        {
52
                $resolvedType = (new DI\Resolver($this->getContainerBuilder()))->resolveEntityType($def->getCreator());
1✔
53
                $class = is_subclass_of($resolvedType, $def->getType())
1✔
54
                        ? $resolvedType
1✔
55
                        : $def->getType();
1✔
56
                $setups = $def->getSetup();
1✔
57

58
                foreach (self::getInjectProperties($class) as $property => $type) {
1✔
59
                        $builder = $this->getContainerBuilder();
1✔
60
                        $inject = new Definitions\Statement('$' . $property, [Definitions\Reference::fromType((string) $type)]);
1✔
61
                        foreach ($setups as $key => $setup) {
1✔
62
                                if ($setup->getEntity() === $inject->getEntity()) {
1✔
63
                                        $inject = $setup;
1✔
64
                                        $builder = null;
1✔
65
                                        unset($setups[$key]);
1✔
66
                                }
67
                        }
68

69
                        array_unshift($setups, $inject);
1✔
70
                }
71

72
                foreach (array_reverse(self::getInjectMethods($class)) as $method) {
1✔
73
                        $inject = new Definitions\Statement($method);
1✔
74
                        foreach ($setups as $key => $setup) {
1✔
75
                                if ($setup->getEntity() === $inject->getEntity()) {
1✔
76
                                        $inject = $setup;
1✔
77
                                        unset($setups[$key]);
1✔
78
                                }
79
                        }
80

81
                        array_unshift($setups, $inject);
1✔
82
                }
83

84
                $def->setSetup($setups);
1✔
85
        }
1✔
86

87

88
        /**
89
         * Generates list of inject methods.
90
         * @internal
91
         */
92
        public static function getInjectMethods(string $class): array
1✔
93
        {
94
                $classes = [];
1✔
95
                foreach (get_class_methods($class) as $name) {
1✔
96
                        if (substr($name, 0, 6) === 'inject') {
1✔
97
                                $classes[$name] = (new \ReflectionMethod($class, $name))->getDeclaringClass()->name;
1✔
98
                        }
99
                }
100

101
                $methods = array_keys($classes);
1✔
102
                uksort($classes, function (string $a, string $b) use ($classes, $methods): int {
1✔
103
                        return $classes[$a] === $classes[$b]
1✔
104
                                ? array_search($a, $methods, true) <=> array_search($b, $methods, true)
1✔
105
                                : (is_a($classes[$a], $classes[$b], true) ? 1 : -1);
1✔
106
                });
1✔
107
                return array_keys($classes);
1✔
108
        }
109

110

111
        /**
112
         * Generates list of properties with annotation @inject.
113
         * @internal
114
         */
115
        public static function getInjectProperties(string $class): array
1✔
116
        {
117
                $res = [];
1✔
118
                foreach ((new \ReflectionClass($class))->getProperties() as $rp) {
1✔
119
                        $name = $rp->getName();
1✔
120
                        $hasAttr = PHP_VERSION_ID >= 80000 && $rp->getAttributes(DI\Attributes\Inject::class);
1✔
121
                        if ($hasAttr || DI\Helpers::parseAnnotation($rp, 'inject') !== null) {
1✔
122
                                if (!$rp->isPublic() || $rp->isStatic()) {
1✔
123
                                        trigger_error(sprintf('Property %s for injection must be public and non-static.', Reflection::toString($rp)), E_USER_WARNING);
1✔
124
                                        continue;
1✔
125
                                }
126

127
                                if (PHP_VERSION_ID >= 80100 && $rp->isReadOnly()) {
1✔
128
                                        throw new Nette\InvalidStateException(sprintf('Property %s for injection must not be readonly.', Reflection::toString($rp)));
×
129
                                }
130

131
                                $type = Nette\Utils\Type::fromReflection($rp);
1✔
132
                                if (!$type && !$hasAttr && ($annotation = DI\Helpers::parseAnnotation($rp, 'var'))) {
1✔
133
                                        $annotation = Reflection::expandClassName($annotation, Reflection::getPropertyDeclaringClass($rp));
1✔
134
                                        $type = Nette\Utils\Type::fromString($annotation);
1✔
135
                                }
136

137
                                $res[$rp->getName()] = DI\Helpers::ensureClassType($type, 'type of property ' . Reflection::toString($rp));
1✔
138
                        }
139
                }
140

141
                ksort($res);
1✔
142
                return $res;
1✔
143
        }
144

145

146
        /**
147
         * Calls all methods starting with with "inject" using autowiring.
148
         * @param  object  $service
149
         */
150
        public static function callInjects(DI\Container $container, $service): void
1✔
151
        {
152
                if (!is_object($service)) {
1✔
153
                        throw new Nette\InvalidArgumentException(sprintf('Service must be object, %s given.', gettype($service)));
×
154
                }
155

156
                foreach (self::getInjectMethods(get_class($service)) as $method) {
1✔
157
                        $container->callMethod([$service, $method]);
1✔
158
                }
159

160
                foreach (self::getInjectProperties(get_class($service)) as $property => $type) {
1✔
161
                        $service->$property = $container->getByType($type);
1✔
162
                }
163
        }
1✔
164
}
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