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 | } |