Complex classes like MetadataProvider 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 MetadataProvider, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
16 | class MetadataProvider extends MetadataBaseProvider |
||
17 | { |
||
18 | protected $multConstraints = [ '0..1' => ['1'], '1' => ['0..1', '*'], '*' => ['1', '*']]; |
||
19 | protected static $metaNAMESPACE = 'Data'; |
||
20 | 1 | ||
21 | /** |
||
22 | 1 | * Bootstrap the application services. Post-boot. |
|
23 | * |
||
24 | * @return void |
||
25 | 1 | */ |
|
26 | public function boot() |
||
27 | { |
||
28 | 1 | self::$metaNAMESPACE = env('ODataMetaNamespace', 'Data'); |
|
29 | 1 | // If we aren't migrated, there's no DB tables to pull metadata _from_, so bail out early |
|
30 | try { |
||
31 | if (!Schema::hasTable(config('database.migrations'))) { |
||
32 | return; |
||
33 | } |
||
34 | } catch (\Exception $e) { |
||
35 | return; |
||
36 | } |
||
37 | |||
38 | $isCaching = true === $this->getIsCaching(); |
||
39 | $meta = Cache::get('metadata'); |
||
40 | $hasCache = null != $meta; |
||
41 | |||
42 | if ($isCaching && $hasCache) { |
||
43 | App::instance('metadata', $meta); |
||
44 | return; |
||
45 | } |
||
46 | $meta = App::make('metadata'); |
||
47 | |||
48 | $stdRef = new \ReflectionClass(new \stdClass()); |
||
49 | $abstract = $meta->addEntityType($stdRef, 'polyMorphicPlaceholder', true, null); |
||
50 | |||
51 | $modelNames = $this->getCandidateModels(); |
||
52 | |||
53 | list($entityTypes) = $this->getEntityTypesAndResourceSets($meta, $modelNames); |
||
54 | $entityTypes['polyMorphicPlaceholder'] = $abstract; |
||
55 | |||
56 | // need to lift EntityTypes |
||
57 | $biDirect = $this->calculateRoundTripRelations(); |
||
58 | |||
59 | $groups = $this->getPolymorphicRelationGroups(); |
||
|
|||
60 | |||
61 | // now that endpoints are hooked up, tackle the relationships |
||
62 | // if we'd tried earlier, we'd be guaranteed to try to hook a relation up to null, which would be bad |
||
63 | foreach ($biDirect as $line) { |
||
64 | $this->processRelationLine($line, $entityTypes, $meta); |
||
65 | } |
||
66 | |||
67 | $key = 'metadata'; |
||
68 | $this->handlePostBoot($isCaching, $hasCache, $key, $meta); |
||
69 | } |
||
70 | |||
71 | /** |
||
72 | * Register the application services. Boot-time only. |
||
73 | * |
||
74 | * @return void |
||
75 | */ |
||
76 | public function register() |
||
77 | { |
||
78 | $this->app->singleton('metadata', function ($app) { |
||
79 | return new SimpleMetadataProvider('Data', self::$metaNAMESPACE); |
||
80 | }); |
||
81 | } |
||
82 | |||
83 | /** |
||
84 | * @return array |
||
85 | */ |
||
86 | protected function getCandidateModels() |
||
100 | |||
101 | /** |
||
102 | * @param $meta |
||
103 | * @param $ends |
||
104 | * @return array[] |
||
105 | */ |
||
106 | protected function getEntityTypesAndResourceSets($meta, $ends) |
||
134 | |||
135 | public function calculateRoundTripRelations() |
||
168 | |||
169 | public function getPolymorphicRelationGroups() |
||
170 | { |
||
171 | $modelNames = $this->getCandidateModels(); |
||
172 | |||
173 | $knownSide = []; |
||
174 | $unknownSide = []; |
||
175 | |||
176 | $hooks = []; |
||
177 | // fish out list of polymorphic-affected models for further processing |
||
178 | foreach ($modelNames as $name) { |
||
179 | $model = new $name(); |
||
180 | $isPoly = false; |
||
181 | if ($model->isKnownPolymorphSide()) { |
||
182 | $knownSide[$name] = []; |
||
183 | $isPoly = true; |
||
184 | } |
||
185 | if ($model->isUnknownPolymorphSide()) { |
||
186 | $unknownSide[$name] = []; |
||
187 | $isPoly = true; |
||
188 | } |
||
189 | if (false === $isPoly) { |
||
190 | continue; |
||
191 | } |
||
192 | |||
193 | $rels = $model->getRelationships(); |
||
194 | // it doesn't matter if a model has no relationships here, that lack will simply be skipped over |
||
195 | // during hookup processing |
||
196 | $hooks[$name] = $rels; |
||
197 | } |
||
198 | // ensure we've only loaded up polymorphic-affected models |
||
199 | $knownKeys = array_keys($knownSide); |
||
200 | $unknownKeys = array_keys($unknownSide); |
||
201 | $dualKeys = array_intersect($knownKeys, $unknownKeys); |
||
202 | assert(count($hooks) == (count($unknownKeys) + count($knownKeys) - count($dualKeys))); |
||
203 | // if either list is empty, bail out - there's nothing to do |
||
204 | if (0 === count($knownSide) || 0 === count($unknownSide)) { |
||
205 | return []; |
||
206 | } |
||
207 | |||
208 | // commence primary ignition |
||
209 | |||
210 | foreach ($unknownKeys as $key) { |
||
211 | assert(isset($hooks[$key])); |
||
212 | $hook = $hooks[$key]; |
||
213 | foreach ($hook as $barb) { |
||
214 | foreach ($barb as $knownType => $propData) { |
||
215 | if (in_array($knownType, $knownKeys)) { |
||
216 | if (!isset($knownSide[$knownType][$key])) { |
||
217 | $knownSide[$knownType][$key] = []; |
||
218 | } |
||
219 | assert(isset($knownSide[$knownType][$key])); |
||
220 | $knownSide[$knownType][$key][] = $propData['property']; |
||
221 | } |
||
222 | } |
||
223 | } |
||
224 | } |
||
225 | |||
226 | return $knownSide; |
||
227 | } |
||
228 | |||
229 | /** |
||
230 | * Get round-trip relations after inserting polymorphic-powered placeholders |
||
231 | * |
||
232 | * @return array |
||
233 | */ |
||
234 | public function getRepairedRoundTripRelations() |
||
278 | |||
279 | /** |
||
280 | * @param $remix |
||
281 | * @param $lines |
||
282 | * @return array |
||
283 | */ |
||
284 | private function calculateRoundTripRelationsSecondPass($remix, $lines) |
||
329 | |||
330 | /** |
||
331 | * @param $hooks |
||
332 | * @param $lines |
||
333 | * @param $remix |
||
334 | */ |
||
335 | private function calculateRoundTripRelationsFirstPass($hooks, &$lines, &$remix) |
||
391 | |||
392 | /** |
||
393 | * @param $principalType |
||
394 | * @param $principalMult |
||
395 | * @param $principalProperty |
||
396 | * @param $dependentType |
||
397 | * @param $dependentMult |
||
398 | * @param $dependentProperty |
||
399 | * @return array[] |
||
400 | */ |
||
401 | private function calculateRoundTripRelationsGenForwardReverse( |
||
427 | |||
428 | private function processRelationLine($line, $entityTypes, &$meta) |
||
482 | } |
||
483 |
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.
Both the
$myVar
assignment in line 1 and the$higher
assignment in line 2 are dead. The first because$myVar
is never used and the second because$higher
is always overwritten for every possible time line.