Complex classes like FieldsConfigurationFactory often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use FieldsConfigurationFactory, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
25 | class FieldsConfigurationFactory |
||
26 | { |
||
27 | /** |
||
28 | * @var Types |
||
29 | */ |
||
30 | private $types; |
||
31 | |||
32 | /** |
||
33 | * @var EntityManager |
||
34 | */ |
||
35 | private $entityManager; |
||
36 | |||
37 | /** |
||
38 | * Doctrine metadata for the entity |
||
39 | * @var ClassMetadata |
||
40 | */ |
||
41 | private $metadata; |
||
42 | |||
43 | /** |
||
44 | * The identity field name, eg: "id" |
||
45 | * @var string |
||
46 | */ |
||
47 | private $identityField; |
||
48 | |||
49 | 9 | public function __construct(Types $types, EntityManager $entityManager) |
|
54 | |||
55 | /** |
||
56 | * Create a configuration for all fields of Doctrine entity |
||
57 | * @param string $className |
||
58 | * @return array |
||
59 | */ |
||
60 | 9 | public function create(string $className): array |
|
89 | |||
90 | /** |
||
91 | * Returns whether the getter is excluded |
||
92 | * @param ReflectionMethod $method |
||
93 | * @return bool |
||
94 | */ |
||
95 | 9 | private function isExcluded(ReflectionMethod $method): bool |
|
101 | |||
102 | /** |
||
103 | * Get annotation reader |
||
104 | * @return Reader |
||
105 | */ |
||
106 | 9 | private function getAnnotationReader(): Reader |
|
110 | |||
111 | /** |
||
112 | * Get a field from annotation, or an empty one |
||
113 | * All its types will be converted from string to real instance of Type |
||
114 | * |
||
115 | * @param ReflectionMethod $method |
||
116 | * @return Field |
||
117 | */ |
||
118 | 9 | private function getFieldFromAnnotation(ReflectionMethod $method): Field |
|
132 | |||
133 | /** |
||
134 | * Get instance of GraphQL type from a PHP class name |
||
135 | * |
||
136 | * Supported syntaxes are the following: |
||
137 | * |
||
138 | * - `?MyType` |
||
139 | * - `null|MyType` |
||
140 | * - `MyType|null` |
||
141 | * - `MyType[]` |
||
142 | * - `?MyType[]` |
||
143 | * - `null|MyType[]` |
||
144 | * - `MyType[]|null` |
||
145 | * |
||
146 | * @param string|null $typeDeclaration |
||
147 | * @return Type|null |
||
148 | */ |
||
149 | 9 | private function phpDeclarationToInstance(ReflectionMethod $method, ?string $typeDeclaration): ?Type |
|
173 | |||
174 | /** |
||
175 | * Prepend namespace of the method if the class actually exists |
||
176 | * @param ReflectionMethod $method |
||
177 | * @param string $type |
||
178 | * @return string |
||
179 | */ |
||
180 | 4 | private function adjustNamespace(ReflectionMethod $method, string $type): string |
|
190 | |||
191 | /** |
||
192 | * Get the entire configuration for a method |
||
193 | * @param ReflectionMethod $method |
||
194 | * @throws Exception |
||
195 | * @return array |
||
196 | */ |
||
197 | 9 | private function methodToConfiguration(ReflectionMethod $method): array |
|
236 | |||
237 | /** |
||
238 | * Get a GraphQL type instance from PHP type hinted type, possibly looking up the content of collections |
||
239 | * @param ReflectionMethod $method |
||
240 | * @param string $fieldName |
||
241 | * @throws Exception |
||
242 | * @return Type|null |
||
243 | */ |
||
244 | 6 | private function getTypeFromTypeHint(ReflectionMethod $method, string $fieldName): ?Type |
|
268 | |||
269 | /** |
||
270 | * Convert a reflected type to GraphQL Type |
||
271 | * @param ReflectionType $reflectionType |
||
272 | * @return Type |
||
273 | */ |
||
274 | 3 | private function refelectionTypeToType(ReflectionType $reflectionType): Type |
|
283 | |||
284 | /** |
||
285 | * Complete arguments configuration from existing type hints |
||
286 | * @param ReflectionMethod $method |
||
287 | * @param Argument[] $argsFromAnnotations |
||
288 | * @throws Exception |
||
289 | * @return array |
||
290 | */ |
||
291 | 8 | private function getArgumentsFromTypeHint(ReflectionMethod $method, array $argsFromAnnotations, DocBlockReader $docBlock): array |
|
309 | |||
310 | /** |
||
311 | * Complete a single argument from its type hint |
||
312 | * @param ReflectionMethod $method |
||
313 | * @param ReflectionParameter $param |
||
314 | * @param Argument $arg |
||
315 | * @throws Exception |
||
316 | */ |
||
317 | 6 | private function completeArgumentFromTypeHint(ReflectionMethod $method, ReflectionParameter $param, Argument $arg, DocBlockReader $docBlock) |
|
349 | |||
350 | /** |
||
351 | * Look up which field is the ID |
||
352 | * @param string $className |
||
353 | */ |
||
354 | 9 | private function findIdentityField(string $className) |
|
363 | |||
364 | /** |
||
365 | * Returns the fully qualified method name |
||
366 | * @param ReflectionMethod $method |
||
367 | * @return string |
||
368 | */ |
||
369 | 6 | private function getMethodFullName(ReflectionMethod $method): string |
|
373 | |||
374 | /** |
||
375 | * Get a GraphQL type instance from dock block return type |
||
376 | * @param ReflectionMethod $method |
||
377 | * @param \GraphQL\Doctrine\DocBlockReader $docBlock |
||
378 | * @return Type|null |
||
379 | */ |
||
380 | 8 | private function getTypeFromDocBock(ReflectionMethod $method, DocBlockReader $docBlock): ?Type |
|
394 | |||
395 | /** |
||
396 | * Throws exception if type is an array |
||
397 | * @param ReflectionParameter $param |
||
398 | * @param string|null $type |
||
399 | * @throws Exception |
||
400 | */ |
||
401 | 6 | private function throwIfArray(ReflectionParameter $param, ?string $type) |
|
407 | |||
408 | /** |
||
409 | * Throws exception if argument type is invalid |
||
410 | * @param ReflectionMethod $method |
||
411 | * @param Argument $arg |
||
412 | * @throws Exception |
||
413 | */ |
||
414 | 4 | private function throwIfNotInputType(ReflectionMethod $method, Argument $arg) |
|
425 | } |
||
426 |
The
EntityManager
might become unusable for example if a transaction is rolled back and it gets closed. Let’s assume that somewhere in your application, or in a third-party library, there is code such as the following:If that code throws an exception and the
EntityManager
is closed. Any other code which depends on the same instance of theEntityManager
during this request will fail.On the other hand, if you instead inject the
ManagerRegistry
, thegetManager()
method guarantees that you will always get a usable manager instance.