1 | <?php |
||||||
2 | |||||||
3 | declare(strict_types=1); |
||||||
4 | |||||||
5 | namespace Doctrine\ORM\Mapping\Factory; |
||||||
6 | |||||||
7 | use Doctrine\Common\Persistence\Mapping\ClassMetadataFactory; |
||||||
8 | use Doctrine\ORM\Configuration\MetadataConfiguration; |
||||||
9 | use Doctrine\ORM\Mapping\ClassMetadata; |
||||||
10 | use Doctrine\ORM\Mapping\ClassMetadataBuildingContext; |
||||||
11 | use Doctrine\ORM\Mapping\Driver\MappingDriver; |
||||||
12 | use Doctrine\ORM\Mapping\Factory\Strategy\ConditionalFileWriterClassMetadataGeneratorStrategy; |
||||||
13 | use Doctrine\ORM\Reflection\ReflectionService; |
||||||
14 | use Doctrine\ORM\Utility\StaticClassNameConverter; |
||||||
15 | use InvalidArgumentException; |
||||||
16 | use function array_reverse; |
||||||
17 | |||||||
18 | /** |
||||||
19 | * AbstractClassMetadataFactory is the base of ClassMetadata object creation that contain all the metadata mapping |
||||||
20 | * information of a class which describes how a class should be mapped to a relational database. |
||||||
21 | */ |
||||||
22 | abstract class AbstractClassMetadataFactory implements ClassMetadataFactory |
||||||
23 | { |
||||||
24 | /** |
||||||
25 | * Never autogenerate a class metadata and rely that it was generated by some process before deployment. |
||||||
26 | * |
||||||
27 | * @deprecated please use @see \Doctrine\ORM\Mapping\Factory\AbstractClassMetadataFactory::AUTOGENERATE_FILE_NOT_EXISTS |
||||||
28 | */ |
||||||
29 | public const AUTOGENERATE_NEVER = 0; |
||||||
30 | |||||||
31 | /** |
||||||
32 | * Always generates a new class metadata in every request. This is only sane during development. |
||||||
33 | * |
||||||
34 | * @deprecated please use @see \Doctrine\ORM\Mapping\Factory\AbstractClassMetadataFactory::AUTOGENERATE_FILE_NOT_EXISTS |
||||||
35 | */ |
||||||
36 | public const AUTOGENERATE_ALWAYS = 1; |
||||||
37 | |||||||
38 | /** |
||||||
39 | * Autogenerate the class metadata when the file does not exist. |
||||||
40 | * This strategy causes a file exists call whenever any metadata is used the first time in a request. |
||||||
41 | */ |
||||||
42 | public const AUTOGENERATE_FILE_NOT_EXISTS = 2; |
||||||
43 | |||||||
44 | /** @var ClassMetadataDefinitionFactory */ |
||||||
45 | protected $definitionFactory; |
||||||
46 | |||||||
47 | /** @var MappingDriver */ |
||||||
48 | protected $mappingDriver; |
||||||
49 | |||||||
50 | /** @var ClassMetadataDefinition[] */ |
||||||
51 | private $definitions = []; |
||||||
52 | |||||||
53 | /** @var ClassMetadata[] */ |
||||||
54 | private $loaded = []; |
||||||
55 | |||||||
56 | public function __construct(MetadataConfiguration $configuration) |
||||||
57 | { |
||||||
58 | $mappingDriver = $configuration->getMappingDriver(); |
||||||
59 | $resolver = $configuration->getResolver(); |
||||||
60 | //$autoGenerate = $configuration->getAutoGenerate(); |
||||||
61 | $generator = new ClassMetadataGenerator($mappingDriver); |
||||||
62 | $generatorStrategy = new ConditionalFileWriterClassMetadataGeneratorStrategy($generator); |
||||||
63 | $definitionFactory = new ClassMetadataDefinitionFactory($resolver, $generatorStrategy); |
||||||
64 | |||||||
65 | $this->mappingDriver = $mappingDriver; |
||||||
66 | $this->definitionFactory = $definitionFactory; |
||||||
67 | } |
||||||
68 | |||||||
69 | /** |
||||||
70 | * {@inheritdoc} |
||||||
71 | * |
||||||
72 | * @throws InvalidArgumentException |
||||||
73 | */ |
||||||
74 | public function getAllMetadata() : array |
||||||
75 | { |
||||||
76 | $metadata = []; |
||||||
77 | |||||||
78 | foreach ($this->mappingDriver->getAllClassNames() as $className) { |
||||||
79 | $metadata[] = $this->getMetadataFor($className); |
||||||
80 | } |
||||||
81 | |||||||
82 | return $metadata; |
||||||
83 | } |
||||||
84 | |||||||
85 | /** |
||||||
86 | * {@inheritdoc} |
||||||
87 | */ |
||||||
88 | public function getMetadataFor($className) |
||||||
89 | { |
||||||
90 | $entityClassName = StaticClassNameConverter::getRealClass($className); |
||||||
91 | |||||||
92 | if (isset($this->loaded[$entityClassName])) { |
||||||
93 | return $this->loaded[$entityClassName]; |
||||||
94 | } |
||||||
95 | |||||||
96 | $metadataBuildingContext = new ClassMetadataBuildingContext($this); |
||||||
0 ignored issues
–
show
$this of type Doctrine\ORM\Mapping\Fac...actClassMetadataFactory is incompatible with the type Doctrine\ORM\Mapping\AbstractClassMetadataFactory expected by parameter $classMetadataFactory of Doctrine\ORM\Mapping\Cla...gContext::__construct() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
97 | $parentClassNameList = $this->getParentClassNameList($entityClassName); |
||||||
98 | $parentClassNameList[] = $entityClassName; |
||||||
99 | $parent = null; |
||||||
100 | |||||||
101 | foreach ($parentClassNameList as $parentClassName) { |
||||||
102 | if (isset($this->loaded[$parentClassName])) { |
||||||
103 | $parent = $this->loaded[$parentClassName]; |
||||||
104 | |||||||
105 | continue; |
||||||
106 | } |
||||||
107 | |||||||
108 | $definition = $this->getOrCreateClassMetadataDefinition($parentClassName, $parent); |
||||||
0 ignored issues
–
show
The call to
Doctrine\ORM\Mapping\Fac...assMetadataDefinition() has too few arguments starting with metadataBuildingContext .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.
Loading history...
|
|||||||
109 | |||||||
110 | $parent = $this->loaded[$parentClassName] = $this->createClassMetadata($definition); |
||||||
111 | } |
||||||
112 | |||||||
113 | $metadataBuildingContext->validate(); |
||||||
114 | |||||||
115 | return $this->loaded[$entityClassName]; |
||||||
116 | } |
||||||
117 | |||||||
118 | /** |
||||||
119 | * {@inheritdoc} |
||||||
120 | */ |
||||||
121 | public function hasMetadataFor($className) : bool |
||||||
122 | { |
||||||
123 | return isset($this->loaded[$className]); |
||||||
124 | } |
||||||
125 | |||||||
126 | /** |
||||||
127 | * {@inheritdoc} |
||||||
128 | */ |
||||||
129 | public function setMetadataFor($className, $class) : void |
||||||
130 | { |
||||||
131 | $this->loaded[$className] = $class; |
||||||
132 | } |
||||||
133 | |||||||
134 | /** |
||||||
135 | * {@inheritdoc} |
||||||
136 | */ |
||||||
137 | public function isTransient($className) : bool |
||||||
138 | { |
||||||
139 | $entityClassName = StaticClassNameConverter::getRealClass($className); |
||||||
140 | |||||||
141 | return $this->mappingDriver->isTransient($entityClassName); |
||||||
142 | } |
||||||
143 | |||||||
144 | protected function createClassMetadata(ClassMetadataDefinition $definition) : ClassMetadata |
||||||
145 | { |
||||||
146 | /** @var ClassMetadata $classMetadata */ |
||||||
147 | $metadataFqcn = $definition->metadataClassName; |
||||||
148 | $classMetadata = new $metadataFqcn($definition->parentClassMetadata); |
||||||
149 | |||||||
150 | $classMetadata->wakeupReflection($this->getReflectionService()); |
||||||
151 | |||||||
152 | return $classMetadata; |
||||||
153 | } |
||||||
154 | |||||||
155 | /** |
||||||
156 | * Create a class metadata definition for the given class name. |
||||||
157 | */ |
||||||
158 | private function getOrCreateClassMetadataDefinition( |
||||||
159 | string $className, |
||||||
160 | ?ClassMetadata $parent, |
||||||
161 | ClassMetadataBuildingContext $metadataBuildingContext |
||||||
162 | ) : ClassMetadataDefinition { |
||||||
163 | if (! isset($this->definitions[$className])) { |
||||||
164 | $this->definitions[$className] = $this->definitionFactory->build($className, $parent, $metadataBuildingContext); |
||||||
165 | } |
||||||
166 | |||||||
167 | return $this->definitions[$className]; |
||||||
168 | } |
||||||
169 | |||||||
170 | /** |
||||||
171 | * @return string[] |
||||||
172 | * |
||||||
173 | * @throws InvalidArgumentException |
||||||
174 | */ |
||||||
175 | private function getParentClassNameList(string $className) : array |
||||||
176 | { |
||||||
177 | $reflectionService = $this->getReflectionService(); |
||||||
178 | $parentClassNameList = []; |
||||||
179 | |||||||
180 | foreach (array_reverse($reflectionService->getParentClasses($className)) as $parentClassName) { |
||||||
181 | if ($this->mappingDriver->isTransient($parentClassName)) { |
||||||
182 | continue; |
||||||
183 | } |
||||||
184 | |||||||
185 | $parentClassNameList[] = $parentClassName; |
||||||
186 | } |
||||||
187 | |||||||
188 | return $parentClassNameList; |
||||||
189 | } |
||||||
190 | |||||||
191 | abstract protected function getReflectionService() : ReflectionService; |
||||||
192 | } |
||||||
193 |
This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.