Complex classes like ContainerFactory 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 ContainerFactory, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
13 | class ContainerFactory |
||
14 | { |
||
15 | |||
16 | private $configs; |
||
17 | |||
18 | /** @var Container[] */ |
||
19 | private $containersToMerge; |
||
20 | |||
21 | private $workingDirectory; |
||
22 | |||
23 | |||
24 | 7 | public function addConfig($file) |
|
28 | |||
29 | |||
30 | 1 | public function getConfigs() |
|
34 | |||
35 | |||
36 | 3 | public function addContainerToMerge(Container $container) |
|
40 | |||
41 | |||
42 | 1 | public function getContainersToMerge() |
|
46 | |||
47 | |||
48 | 1 | public function getWorkingDirectory() |
|
52 | |||
53 | |||
54 | 8 | public function setWorkingDirectory($workingDirectory) |
|
58 | |||
59 | |||
60 | 7 | public function create() |
|
61 | { |
||
62 | 7 | if (!class_exists('Nette\Neon\Decoder', TRUE)) { |
|
63 | throw new \RuntimeException("Neon is not loaded."); |
||
64 | } |
||
65 | 7 | if (empty($this->configs)) { |
|
66 | 1 | throw new \RuntimeException("No config added."); |
|
67 | } |
||
68 | $config = [ |
||
69 | 'parameters' => [ |
||
70 | 6 | 'workingDirectory' => $this->workingDirectory, |
|
71 | ] |
||
72 | 6 | ]; |
|
73 | 6 | if($this->containersToMerge !== NULL){ |
|
74 | 2 | foreach ($this->containersToMerge as $containerToMerge) { |
|
75 | 2 | foreach ($containerToMerge->getParameters() as $k => $v) { |
|
76 | 2 | $config['parameters'][$k] = $v; |
|
77 | 2 | } |
|
78 | 2 | foreach ($containerToMerge->getServices() as $k => $v) { |
|
79 | 1 | $config['services'][$k] = $v; |
|
80 | 2 | } |
|
81 | 2 | } |
|
82 | 2 | } |
|
83 | 6 | $configs = $this->resolveFiles($this->configs); |
|
84 | 4 | $config = $this->readConfigs($configs, $config); |
|
85 | 4 | $config = $this->parseValues($config); |
|
86 | |||
87 | // BC break check |
||
88 | 4 | $mainSections = ['includes', 'class', 'parameters', 'services']; |
|
89 | 4 | foreach($config as $key => $val){ |
|
90 | 4 | if(!in_array($key, $mainSections)) { |
|
91 | 1 | throw new \RuntimeException("Since version 2.0 are supported main only these sections: " . implode(", ", $mainSections) . ". Section '$key' found. Move your variables into parameters section."); |
|
92 | } |
||
93 | 4 | } |
|
94 | |||
95 | 3 | $container = new Container(); |
|
96 | 3 | $container->setClass($config['class']); |
|
97 | 3 | if(isset($config['parameters'])){ |
|
98 | 3 | $container->setParameters($config['parameters']); |
|
99 | 3 | } |
|
100 | 3 | if(isset($config['services'])){ |
|
101 | 3 | foreach($config['services'] as $name => $config){ |
|
102 | 3 | if(!is_array($config)){ |
|
103 | 1 | $container->addService($name, $config); // is directly service object from merged container |
|
104 | 1 | continue; |
|
105 | } |
||
106 | 3 | $class = $config['class']; |
|
107 | 3 | $arguments = []; |
|
108 | 3 | if($config['class'] instanceof \Nette\Neon\Entity){ |
|
109 | 3 | $class = $config['class']->value; |
|
110 | 3 | $arguments = $config['class']->attributes; |
|
111 | 3 | } |
|
112 | 3 | $reflectionClass = new \ReflectionClass($class); |
|
113 | 3 | $service = $reflectionClass->newInstanceArgs($arguments); |
|
114 | 3 | if(isset($config['setup'])){ |
|
115 | 3 | foreach($config['setup'] as $neonEntity){ |
|
116 | 3 | if(!method_exists($service, $neonEntity->value)){ |
|
117 | 1 | throw new \RuntimeException("Class $class does not have method $neonEntity->value()."); |
|
118 | } |
||
119 | 2 | call_user_func_array(array($service, $neonEntity->value), $neonEntity->attributes); |
|
120 | 2 | } |
|
121 | 2 | } |
|
122 | 2 | $container->addService($name, $service); |
|
123 | 2 | } |
|
124 | 2 | } |
|
125 | |||
126 | 2 | return $container; |
|
127 | } |
||
128 | |||
129 | |||
130 | 6 | private function resolveFiles(array $files) |
|
146 | |||
147 | |||
148 | 4 | private function readConfigs($files, $config) |
|
158 | |||
159 | |||
160 | 6 | private function readFile($file) |
|
171 | |||
172 | |||
173 | 4 | private function parseValues($config, & $allConfig = [], $keysPath = []) |
|
208 | |||
209 | |||
210 | 4 | private function parseValue($value, $config) |
|
232 | |||
233 | |||
234 | 4 | private function resolveUnmergables($config) |
|
245 | |||
246 | } |