Complex classes like AddonBuilder 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 AddonBuilder, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
10 | class AddonBuilder |
||
11 | { |
||
12 | |||
13 | const ADDONS_DIR = 'addon-downloads'; |
||
14 | |||
15 | const SCREENSHOTS_DIR = 'screenshots'; |
||
16 | |||
17 | private $packagist; |
||
18 | |||
19 | /** |
||
20 | * @var CheckSuite |
||
21 | */ |
||
22 | protected $checkSuite; |
||
23 | |||
24 | public function __construct(PackagistService $packagist) |
||
25 | { |
||
26 | $this->packagist = $packagist; |
||
27 | } |
||
28 | |||
29 | public function build(Addon $addon) |
||
30 | { |
||
31 | putenv("GIT_SSH_COMMAND=\"ssh -o StrictHostKeyChecking=no\""); |
||
32 | $this->setCheckSuite(new CheckSuite()); |
||
33 | |||
34 | $composer = $this->packagist->getComposer(); |
||
35 | $downloader = $composer->getDownloadManager(); |
||
|
|||
36 | $packageVersions = $this->packagist->getPackageVersions($addon->Name); |
||
37 | $time = time(); |
||
38 | |||
39 | if (!$packageVersions) { |
||
40 | throw new Exception('Could not find corresponding Packagist versions'); |
||
41 | } |
||
42 | |||
43 | // Get the latest local and packagist version pair. |
||
44 | $version = $addon->Versions()->filter('Development', true)->first(); |
||
45 | if (!$version) { |
||
46 | echo "No versions found for " . $addon->Name . "; deleting orphan record.\n"; |
||
47 | $addon->delete(); |
||
48 | return; |
||
49 | } |
||
50 | |||
51 | foreach ($packageVersions as $packageVersion) { |
||
52 | if ($packageVersion->getVersionNormalized() != $version->Version) { |
||
53 | continue; |
||
54 | } |
||
55 | |||
56 | if (defined('SS_ADDONS_DOWNLOAD_PATH')) { |
||
57 | $path = SS_ADDONS_DOWNLOAD_PATH . '/' . $addon->Name; |
||
58 | } else { |
||
59 | $path = implode('/', array( |
||
60 | TEMP_FOLDER, self::ADDONS_DIR, $addon->Name |
||
61 | )); |
||
62 | } |
||
63 | |||
64 | // Convert PackagistAPI result into class compatible with Composer logic |
||
65 | $package = new Package( |
||
66 | $addon->Name, |
||
67 | $packageVersion->getVersionNormalized(), |
||
68 | $packageVersion->getVersion() |
||
69 | ); |
||
70 | |||
71 | if ($extra = $packageVersion->getExtra()) { |
||
72 | $package->setExtra((array) $extra); |
||
73 | } |
||
74 | if ($source = $packageVersion->getSource()) { |
||
75 | $package->setSourceUrl($source->getUrl()); |
||
76 | $package->setSourceType($source->getType()); |
||
77 | $package->setSourceReference($source->getReference()); |
||
78 | } |
||
79 | if ($dist = $packageVersion->getDist()) { |
||
80 | $package->setDistUrl($dist->getUrl()); |
||
81 | $package->setDistType($dist->getType()); |
||
82 | $package->setDistReference($dist->getReference()); |
||
83 | } |
||
84 | |||
85 | try { |
||
86 | $this->download($package, $path); |
||
87 | |||
88 | // If there's an error, mark this version as bad |
||
89 | } catch (RuntimeException $e) { |
||
90 | echo "Add-on " . $addon->Name . " couldn't be downloaded; deleting from database.\n"; |
||
91 | echo "Error message: " . $e->getMessage() . "\n"; |
||
92 | $addon->delete(); |
||
93 | return; |
||
94 | } |
||
95 | |||
96 | $this->buildReadme($addon, $path); |
||
97 | $this->buildScreenshots($addon, $package, $path); |
||
98 | $this->rateModule($addon, $path); |
||
99 | } |
||
100 | |||
101 | $addon->LastBuilt = $time; |
||
102 | $addon->write(); |
||
103 | } |
||
104 | |||
105 | protected function download(PackageInterface $package, $path) |
||
112 | |||
113 | /** |
||
114 | * Parses a readme file from markdown to HTML, then purifies it |
||
115 | * @param Addon $addon |
||
116 | * @param string $path |
||
117 | */ |
||
118 | protected function buildReadme(Addon $addon, $path) |
||
159 | |||
160 | /** |
||
161 | * Determine if the repository is from GitHub, and if so then return the "context" (vendor/module) from the path |
||
162 | * |
||
163 | * @param Addon $addon |
||
164 | * @return string|false |
||
165 | */ |
||
166 | public function getGitHubContext(Addon $addon) |
||
181 | |||
182 | /** |
||
183 | * Given an addon and a parsed HTML readme string, find and replace relative links with absolute |
||
184 | * repository path links. This method applies to GitHub repositories only. |
||
185 | * |
||
186 | * @param Addon $addon |
||
187 | * @param string $readme |
||
188 | * @return string |
||
189 | */ |
||
190 | public function replaceRelativeLinks(Addon $addon, $readme) |
||
225 | |||
226 | /** |
||
227 | * Decide whether a URI path is relative or not. The regex pattern matches prefixes that start with |
||
228 | * a protocol, a slash or a hash. If they don't start with those things, then they are deemed to be |
||
229 | * relative paths. |
||
230 | * |
||
231 | * @param string $path |
||
232 | * @return bool |
||
233 | */ |
||
234 | public function isRelativeUri($path) |
||
238 | |||
239 | /** |
||
240 | * Determine whether an addon is hosted on GitHub |
||
241 | * |
||
242 | * @param Addon $addon |
||
243 | * @return bool |
||
244 | */ |
||
245 | public function hasGitHubRepository(Addon $addon) |
||
249 | |||
250 | private function buildScreenshots(Addon $addon, PackageInterface $package, $path) |
||
320 | |||
321 | /** |
||
322 | * Use the Rating check runner to generate an automated rating for this module |
||
323 | * |
||
324 | * @param Addon $addon |
||
325 | * @param string $modulePath |
||
326 | */ |
||
327 | protected function rateModule(Addon $addon, $modulePath) |
||
356 | |||
357 | /** |
||
358 | * @return CheckSuite |
||
359 | */ |
||
360 | public function getCheckSuite() |
||
364 | |||
365 | /** |
||
366 | * @param CheckSuite $checkSuite |
||
367 | * @return $this |
||
368 | */ |
||
369 | public function setCheckSuite($checkSuite) |
||
374 | } |
||
375 |
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.