This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | /** |
||
| 3 | * |
||
| 4 | * |
||
| 5 | * |
||
| 6 | * |
||
| 7 | */ |
||
| 8 | |||
| 9 | namespace MagentoHackathon\Composer\Magento; |
||
| 10 | |||
| 11 | use Composer\Config; |
||
| 12 | use Composer\DependencyResolver\Rule; |
||
| 13 | use Composer\Installer; |
||
| 14 | use Composer\Package\AliasPackage; |
||
| 15 | use Composer\Script\Event; |
||
| 16 | use Composer\Installer\PackageEvent; |
||
| 17 | use MagentoHackathon\Composer\Helper; |
||
| 18 | use MagentoHackathon\Composer\Magento\Event\EventManager; |
||
| 19 | use MagentoHackathon\Composer\Magento\Event\PackageDeployEvent; |
||
| 20 | use MagentoHackathon\Composer\Magento\Factory\DeploystrategyFactory; |
||
| 21 | use MagentoHackathon\Composer\Magento\Factory\EntryFactory; |
||
| 22 | use MagentoHackathon\Composer\Magento\Factory\ParserFactory; |
||
| 23 | use MagentoHackathon\Composer\Magento\Factory\PathTranslationParserFactory; |
||
| 24 | use MagentoHackathon\Composer\Magento\Patcher\Bootstrap; |
||
| 25 | use MagentoHackathon\Composer\Magento\Repository\InstalledPackageFileSystemRepository; |
||
| 26 | use MagentoHackathon\Composer\Magento\UnInstallStrategy\UnInstallStrategy; |
||
| 27 | use MagentoHackathon\Composer\Magento\Factory\InstallStrategyFactory; |
||
| 28 | use RecursiveDirectoryIterator; |
||
| 29 | use RecursiveIteratorIterator; |
||
| 30 | use Composer\Composer; |
||
| 31 | use Composer\IO\IOInterface; |
||
| 32 | use Composer\Package\PackageInterface; |
||
| 33 | use Composer\Plugin\PluginInterface; |
||
| 34 | use Composer\EventDispatcher\EventSubscriberInterface; |
||
| 35 | use Composer\Script\ScriptEvents; |
||
| 36 | use Composer\Util\Filesystem; |
||
| 37 | use Symfony\Component\Process\Process; |
||
| 38 | |||
| 39 | class Plugin implements PluginInterface, EventSubscriberInterface |
||
| 40 | { |
||
| 41 | /** |
||
| 42 | * The type of packages this plugin supports |
||
| 43 | */ |
||
| 44 | const PACKAGE_TYPE = 'magento-module'; |
||
| 45 | |||
| 46 | const VENDOR_DIR_KEY = 'vendor-dir'; |
||
| 47 | |||
| 48 | const BIN_DIR_KEY = 'bin-dir'; |
||
| 49 | |||
| 50 | const THESEER_AUTOLOAD_EXEC_BIN_PATH = '/phpab'; |
||
| 51 | |||
| 52 | const THESEER_AUTOLOAD_EXEC_REL_PATH = '/theseer/autoload/composer/bin/phpab'; |
||
| 53 | |||
| 54 | /** |
||
| 55 | * @var IOInterface |
||
| 56 | */ |
||
| 57 | protected $io; |
||
| 58 | |||
| 59 | /** |
||
| 60 | * @var ProjectConfig |
||
| 61 | */ |
||
| 62 | protected $config; |
||
| 63 | |||
| 64 | /** |
||
| 65 | * @var DeployManager |
||
| 66 | */ |
||
| 67 | protected $deployManager; |
||
| 68 | |||
| 69 | /** |
||
| 70 | * @var Composer |
||
| 71 | */ |
||
| 72 | protected $composer; |
||
| 73 | |||
| 74 | /** |
||
| 75 | * @var Filesystem |
||
| 76 | */ |
||
| 77 | protected $filesystem; |
||
| 78 | |||
| 79 | /** |
||
| 80 | * @var EntryFactory |
||
| 81 | */ |
||
| 82 | protected $entryFactory; |
||
| 83 | |||
| 84 | /** |
||
| 85 | * @var EventManager |
||
| 86 | */ |
||
| 87 | private $eventManager; |
||
| 88 | |||
| 89 | /** |
||
| 90 | * @var ModuleManager |
||
| 91 | */ |
||
| 92 | private $moduleManager; |
||
| 93 | |||
| 94 | /** |
||
| 95 | * init the DeployManager |
||
| 96 | * |
||
| 97 | * @param Composer $composer |
||
| 98 | * @param IOInterface $io |
||
| 99 | */ |
||
| 100 | 6 | protected function initDeployManager(Composer $composer, IOInterface $io, EventManager $eventManager) |
|
|
0 ignored issues
–
show
|
|||
| 101 | { |
||
| 102 | 6 | $this->deployManager = new DeployManager($eventManager); |
|
| 103 | 6 | $this->deployManager->setSortPriority($this->getSortPriority($composer)); |
|
| 104 | |||
| 105 | 6 | $this->applyEvents($eventManager); |
|
| 106 | 6 | } |
|
| 107 | |||
| 108 | 6 | protected function applyEvents(EventManager $eventManager) |
|
| 109 | { |
||
| 110 | |||
| 111 | 6 | if ($this->config->hasAutoAppendGitignore()) { |
|
| 112 | 1 | $gitIgnoreLocation = sprintf('%s/.gitignore', $this->config->getMagentoRootDir()); |
|
| 113 | 1 | $gitIgnore = new GitIgnoreListener(new GitIgnore($gitIgnoreLocation)); |
|
| 114 | |||
| 115 | 1 | $eventManager->listen('post-package-deploy', [$gitIgnore, 'addNewInstalledFiles']); |
|
| 116 | 1 | $eventManager->listen('post-package-uninstall', [$gitIgnore, 'removeUnInstalledFiles']); |
|
| 117 | } |
||
| 118 | |||
| 119 | 6 | $io = $this->io; |
|
| 120 | 6 | if ($this->io->isDebug()) { |
|
| 121 | $eventManager->listen('pre-package-deploy', function (PackageDeployEvent $event) use ($io) { |
||
| 122 | $io->write('Start magento deploy for ' . $event->getDeployEntry()->getPackageName()); |
||
| 123 | 1 | }); |
|
| 124 | } |
||
| 125 | 6 | } |
|
| 126 | |||
| 127 | /** |
||
| 128 | * get Sort Priority from extra Config |
||
| 129 | * |
||
| 130 | * @param \Composer\Composer $composer |
||
| 131 | * |
||
| 132 | * @return array |
||
| 133 | */ |
||
| 134 | 6 | private function getSortPriority(Composer $composer) |
|
| 135 | { |
||
| 136 | 6 | $extra = $composer->getPackage()->getExtra(); |
|
| 137 | |||
| 138 | 6 | return isset($extra[ProjectConfig::SORT_PRIORITY_KEY]) |
|
| 139 | ? $extra[ProjectConfig::SORT_PRIORITY_KEY] |
||
| 140 | 6 | : array(); |
|
| 141 | } |
||
| 142 | |||
| 143 | /** |
||
| 144 | * Apply plugin modifications to composer |
||
| 145 | * |
||
| 146 | * @param Composer $composer |
||
| 147 | * @param IOInterface $io |
||
| 148 | */ |
||
| 149 | 6 | public function activate(Composer $composer, IOInterface $io) |
|
| 150 | { |
||
| 151 | 6 | $this->io = $io; |
|
| 152 | 6 | $this->composer = $composer; |
|
| 153 | |||
| 154 | 6 | $this->filesystem = new Filesystem(); |
|
| 155 | 6 | $this->config = new ProjectConfig($composer->getPackage()->getExtra(), $composer->getConfig()->all()); |
|
| 156 | |||
| 157 | 6 | if (!$this->config->skipSuggestComposerRepositories()) { |
|
| 158 | 5 | $this->suggestComposerRepositories(); |
|
| 159 | } |
||
| 160 | |||
| 161 | 6 | $this->entryFactory = new EntryFactory( |
|
| 162 | 6 | $this->config, |
|
| 163 | 6 | new DeploystrategyFactory($this->config), |
|
| 164 | 6 | new PathTranslationParserFactory(new ParserFactory($this->config), $this->config) |
|
| 165 | ); |
||
| 166 | |||
| 167 | 6 | $this->initDeployManager($composer, $io, $this->getEventManager()); |
|
| 168 | 6 | $this->writeDebug('activate magento plugin'); |
|
| 169 | 6 | } |
|
| 170 | |||
| 171 | /** |
||
| 172 | * Returns an array of event names this subscriber wants to listen to. |
||
| 173 | * |
||
| 174 | * The array keys are event names and the value can be: |
||
| 175 | * |
||
| 176 | * * The method name to call (priority defaults to 0) |
||
| 177 | * * An array composed of the method name to call and the priority |
||
| 178 | * * An array of arrays composed of the method names to call and respective |
||
| 179 | * priorities, or 0 if unset |
||
| 180 | * |
||
| 181 | * For instance: |
||
| 182 | * |
||
| 183 | * * array('eventName' => 'methodName') |
||
| 184 | * * array('eventName' => array('methodName', $priority)) |
||
| 185 | * * array('eventName' => array(array('methodName1', $priority), array('methodName2')) |
||
| 186 | * |
||
| 187 | * @return array The event names to listen to |
||
| 188 | */ |
||
| 189 | public static function getSubscribedEvents() |
||
| 190 | { |
||
| 191 | return array( |
||
| 192 | Installer\PackageEvents::PRE_PACKAGE_UPDATE => array( |
||
| 193 | array('onPackageUpdate', 0), |
||
| 194 | ), |
||
| 195 | ScriptEvents::POST_INSTALL_CMD => array( |
||
| 196 | array('onNewCodeEvent', 0), |
||
| 197 | ), |
||
| 198 | ScriptEvents::POST_UPDATE_CMD => array( |
||
| 199 | array('onNewCodeEvent', 0), |
||
| 200 | ), |
||
| 201 | ); |
||
| 202 | } |
||
| 203 | |||
| 204 | /** |
||
| 205 | * event listener is named this way, as it listens for events leading to changed code files |
||
| 206 | * |
||
| 207 | * @param Event $event |
||
| 208 | */ |
||
| 209 | 3 | public function onNewCodeEvent(Event $event) |
|
| 210 | { |
||
| 211 | |||
| 212 | 3 | $packageTypeToMatch = static::PACKAGE_TYPE; |
|
| 213 | 3 | $magentoModules = array_filter( |
|
| 214 | 3 | $this->composer->getRepositoryManager()->getLocalRepository()->getPackages(), |
|
| 215 | 3 | function (PackageInterface $package) use ($packageTypeToMatch) { |
|
| 216 | 3 | if ($package instanceof AliasPackage) { |
|
| 217 | 1 | return false; |
|
| 218 | } |
||
| 219 | 3 | return $package->getType() === $packageTypeToMatch; |
|
| 220 | 3 | } |
|
| 221 | ); |
||
| 222 | |||
| 223 | 3 | if ($this->composer->getPackage()->getType() === static::PACKAGE_TYPE |
|
| 224 | 3 | && $this->config->getIncludeRootPackage() === true |
|
| 225 | ) { |
||
| 226 | 1 | $magentoModules[] = $this->composer->getPackage(); |
|
| 227 | } |
||
| 228 | |||
| 229 | 3 | $vendorDir = rtrim($this->composer->getConfig()->get(self::VENDOR_DIR_KEY), '/'); |
|
| 230 | |||
| 231 | 3 | Helper::initMagentoRootDir( |
|
| 232 | 3 | $this->config, |
|
| 233 | 3 | $this->io, |
|
| 234 | 3 | $this->filesystem, |
|
| 235 | $vendorDir |
||
| 236 | ); |
||
| 237 | |||
| 238 | 3 | $this->applyEvents($this->getEventManager()); |
|
| 239 | |||
| 240 | 3 | if (in_array('--redeploy', $event->getArguments())) { |
|
| 241 | $this->writeDebug('remove all deployed modules'); |
||
| 242 | $this->getModuleManager()->updateInstalledPackages(array()); |
||
| 243 | } |
||
| 244 | 3 | $this->writeDebug('start magento module deploy via moduleManager'); |
|
| 245 | 3 | $this->getModuleManager()->updateInstalledPackages($magentoModules); |
|
| 246 | 3 | $this->deployLibraries(); |
|
| 247 | |||
| 248 | 3 | $patcher = Bootstrap::fromConfig($this->config); |
|
| 249 | 3 | $patcher->setIo($this->io); |
|
| 250 | try { |
||
| 251 | 3 | $patcher->patch(); |
|
| 252 | 3 | } catch (\DomainException $e) { |
|
| 253 | 3 | $this->io->write('<comment>'.$e->getMessage().'</comment>'); |
|
| 254 | } |
||
| 255 | 3 | } |
|
| 256 | |||
| 257 | public function onPackageUpdate(PackageEvent $event) |
||
| 258 | { |
||
| 259 | /** @var Rule $rule */ |
||
| 260 | $rule = $event->getOperation()->getReason(); |
||
| 261 | if ($rule instanceof Rule) { |
||
| 262 | if ($event->getOperation()->getJobType() === 'update') { |
||
| 263 | if ($rule->getJob()['packageName'] === 'magento-hackathon/magento-composer-installer') { |
||
| 264 | throw new \Exception( |
||
| 265 | 'Dont update the "magento-hackathon/magento-composer-installer" with active plugins.' . PHP_EOL . |
||
| 266 | 'Consult the documentation on how to update the Installer' . PHP_EOL . |
||
| 267 | 'https://github.com/Cotya/magento-composer-installer#update-the-installer' . PHP_EOL |
||
| 268 | ); |
||
| 269 | } |
||
| 270 | } |
||
| 271 | } else { |
||
|
0 ignored issues
–
show
This
else statement is empty and can be removed.
This check looks for the These if (rand(1, 6) > 3) {
print "Check failed";
} else {
//print "Check succeeded";
}
could be turned into if (rand(1, 6) > 3) {
print "Check failed";
}
This is much more concise to read. Loading history...
|
|||
| 272 | |||
| 273 | } |
||
| 274 | |||
| 275 | } |
||
| 276 | |||
| 277 | /** |
||
| 278 | * test configured repositories and give message about adding recommended ones |
||
| 279 | */ |
||
| 280 | 5 | protected function suggestComposerRepositories() |
|
| 281 | { |
||
| 282 | 5 | $foundFiregento = false; |
|
| 283 | 5 | $foundMagento = false; |
|
|
0 ignored issues
–
show
$foundMagento is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the Loading history...
|
|||
| 284 | |||
| 285 | 5 | foreach ($this->config->getComposerRepositories() as $repository) { |
|
| 286 | if (!isset($repository["type"]) || $repository["type"] !== "composer") { |
||
| 287 | continue; |
||
| 288 | } |
||
| 289 | if (strpos($repository["url"], "packages.firegento.com") !== false) { |
||
| 290 | $foundFiregento = true; |
||
| 291 | } |
||
| 292 | }; |
||
| 293 | 5 | $message1 = "<comment>you may want to add the %s repository to composer.</comment>"; |
|
| 294 | 5 | $message2 = "<comment>add it with:</comment> composer.phar config -g repositories.%s composer %s"; |
|
| 295 | 5 | if (!$foundFiregento) { |
|
| 296 | 5 | $this->io->write(sprintf($message1, 'packages.firegento.com')); |
|
| 297 | 5 | $this->io->write(sprintf($message2, 'firegento', 'https://packages.firegento.com')); |
|
| 298 | } |
||
| 299 | 5 | } |
|
| 300 | |||
| 301 | /** |
||
| 302 | * deploy Libraries |
||
| 303 | */ |
||
| 304 | 3 | protected function deployLibraries() |
|
| 305 | { |
||
| 306 | 3 | $packages = $this->composer->getRepositoryManager()->getLocalRepository()->getPackages(); |
|
| 307 | 3 | $autoloadDirectories = array(); |
|
| 308 | |||
| 309 | 3 | $libraryPath = $this->config->getLibraryPath(); |
|
| 310 | |||
| 311 | 3 | if ($libraryPath === null) { |
|
| 312 | 3 | $this->writeDebug('jump over deployLibraries as no Magento libraryPath is set'); |
|
| 313 | |||
| 314 | 3 | return; |
|
| 315 | } |
||
| 316 | |||
| 317 | $vendorDir = rtrim($this->composer->getConfig()->get(self::VENDOR_DIR_KEY), '/'); |
||
| 318 | |||
| 319 | $this->filesystem->removeDirectory($libraryPath); |
||
| 320 | $this->filesystem->ensureDirectoryExists($libraryPath); |
||
| 321 | |||
| 322 | foreach ($packages as $package) { |
||
| 323 | /** @var PackageInterface $package */ |
||
| 324 | $packageConfig = $this->config->getLibraryConfigByPackagename($package->getName()); |
||
|
0 ignored issues
–
show
Are you sure the assignment to
$packageConfig is correct as $this->config->getLibrar...me($package->getName()) (which targets MagentoHackathon\Compose...ryConfigByPackagename()) seems to always return null.
This check looks for function or method calls that always return null and whose return value is assigned to a variable. class A
{
function getObject()
{
return null;
}
}
$a = new A();
$object = $a->getObject();
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. Loading history...
|
|||
| 325 | if ($packageConfig === null) { |
||
| 326 | continue; |
||
| 327 | } |
||
| 328 | if (!isset($packageConfig['autoload'])) { |
||
| 329 | $packageConfig['autoload'] = array('/'); |
||
| 330 | } |
||
| 331 | foreach ($packageConfig['autoload'] as $path) { |
||
| 332 | $autoloadDirectories[] = $libraryPath . '/' . $package->getName() . "/" . $path; |
||
| 333 | } |
||
| 334 | $this->writeDebug(sprintf('Magento deployLibraries executed for %s', $package->getName())); |
||
| 335 | |||
| 336 | $libraryTargetPath = $libraryPath . '/' . $package->getName(); |
||
| 337 | $this->filesystem->removeDirectory($libraryTargetPath); |
||
| 338 | $this->filesystem->ensureDirectoryExists($libraryTargetPath); |
||
| 339 | $this->copyRecursive($vendorDir . '/' . $package->getPrettyName(), $libraryTargetPath); |
||
| 340 | } |
||
| 341 | |||
| 342 | if (false !== ($executable = $this->getTheseerAutoloadExecutable())) { |
||
| 343 | $this->writeDebug('Magento deployLibraries executes autoload generator'); |
||
| 344 | |||
| 345 | $params = $this->getTheseerAutoloadParams($libraryPath, $autoloadDirectories); |
||
| 346 | |||
| 347 | $process = new Process($executable . $params); |
||
| 348 | $process->run(); |
||
| 349 | } |
||
| 350 | } |
||
| 351 | |||
| 352 | /** |
||
| 353 | * return the autoload generator binary path or false if not found |
||
| 354 | * |
||
| 355 | * @return bool|string |
||
| 356 | */ |
||
| 357 | protected function getTheseerAutoloadExecutable() |
||
| 358 | { |
||
| 359 | $executable = $this->composer->getConfig()->get(self::BIN_DIR_KEY) |
||
| 360 | . self::THESEER_AUTOLOAD_EXEC_BIN_PATH; |
||
| 361 | |||
| 362 | if (!file_exists($executable)) { |
||
| 363 | $executable = $this->composer->getConfig()->get(self::VENDOR_DIR_KEY) |
||
| 364 | . self::THESEER_AUTOLOAD_EXEC_REL_PATH; |
||
| 365 | } |
||
| 366 | |||
| 367 | if (!file_exists($executable)) { |
||
| 368 | $this->writeDebug( |
||
| 369 | 'Magento deployLibraries autoload generator not available, you should require "theseer/autoload"', |
||
| 370 | $executable |
||
| 371 | ); |
||
| 372 | |||
| 373 | return false; |
||
| 374 | } |
||
| 375 | |||
| 376 | return $executable; |
||
| 377 | } |
||
| 378 | |||
| 379 | /** |
||
| 380 | * get Theseer Autoload Generator Params |
||
| 381 | * |
||
| 382 | * @param string $libraryPath |
||
| 383 | * @param array $autoloadDirectories |
||
| 384 | * |
||
| 385 | * @return string |
||
| 386 | */ |
||
| 387 | protected function getTheseerAutoloadParams($libraryPath, $autoloadDirectories) |
||
| 388 | { |
||
| 389 | // @todo --blacklist 'test\\\\*' |
||
| 390 | return " -b {$libraryPath} -o {$libraryPath}/autoload.php " . implode(' ', $autoloadDirectories); |
||
| 391 | } |
||
| 392 | |||
| 393 | /** |
||
| 394 | * Copy then delete is a non-atomic version of {@link rename}. |
||
| 395 | * |
||
| 396 | * Some systems can't rename and also don't have proc_open, |
||
| 397 | * which requires this solution. |
||
| 398 | * |
||
| 399 | * copied from \Composer\Util\Filesystem::copyThenRemove and removed the remove part |
||
| 400 | * |
||
| 401 | * @param string $source |
||
| 402 | * @param string $target |
||
| 403 | */ |
||
| 404 | protected function copyRecursive($source, $target) |
||
| 405 | { |
||
| 406 | $it = new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS); |
||
| 407 | $ri = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::SELF_FIRST); |
||
| 408 | $this->filesystem->ensureDirectoryExists($target); |
||
| 409 | |||
| 410 | foreach ($ri as $file) { |
||
| 411 | $targetPath = $target . DIRECTORY_SEPARATOR . $ri->getSubPathName(); |
||
| 412 | if ($file->isDir()) { |
||
| 413 | $this->filesystem->ensureDirectoryExists($targetPath); |
||
| 414 | } else { |
||
| 415 | copy($file->getPathname(), $targetPath); |
||
| 416 | } |
||
| 417 | } |
||
| 418 | } |
||
| 419 | |||
| 420 | /** |
||
| 421 | * print Debug Message |
||
| 422 | * |
||
| 423 | * @param $message |
||
| 424 | */ |
||
| 425 | 6 | private function writeDebug($message, $varDump = null) |
|
| 426 | { |
||
| 427 | 6 | if ($this->io->isDebug()) { |
|
| 428 | 1 | $this->io->write($message); |
|
| 429 | |||
| 430 | 1 | if (!is_null($varDump)) { |
|
| 431 | var_dump($varDump); |
||
|
0 ignored issues
–
show
|
|||
| 432 | } |
||
| 433 | } |
||
| 434 | 6 | } |
|
| 435 | |||
| 436 | /** |
||
| 437 | * @param PackageInterface $package |
||
| 438 | * @return string |
||
| 439 | */ |
||
| 440 | public function getPackageInstallPath(PackageInterface $package) |
||
| 441 | { |
||
| 442 | $vendorDir = realpath(rtrim($this->composer->getConfig()->get('vendor-dir'), '/')); |
||
| 443 | return sprintf('%s/%s', $vendorDir, $package->getPrettyName()); |
||
| 444 | } |
||
| 445 | |||
| 446 | /** |
||
| 447 | * @return EventManager |
||
| 448 | */ |
||
| 449 | protected function getEventManager() |
||
| 450 | { |
||
| 451 | if (null === $this->eventManager) { |
||
| 452 | $this->eventManager = new EventManager; |
||
| 453 | } |
||
| 454 | |||
| 455 | return $this->eventManager; |
||
| 456 | } |
||
| 457 | |||
| 458 | /** |
||
| 459 | * @return ModuleManager |
||
| 460 | */ |
||
| 461 | protected function getModuleManager() |
||
| 462 | { |
||
| 463 | if (null === $this->moduleManager) { |
||
| 464 | $this->moduleManager = new ModuleManager( |
||
| 465 | new InstalledPackageFileSystemRepository( |
||
| 466 | rtrim($this->composer->getConfig()->get(self::VENDOR_DIR_KEY), '/') . '/installed.json', |
||
| 467 | new InstalledPackageDumper() |
||
| 468 | ), |
||
| 469 | $this->getEventManager(), |
||
| 470 | $this->config, |
||
| 471 | new UnInstallStrategy($this->filesystem, $this->config->getMagentoRootDir()), |
||
| 472 | new InstallStrategyFactory($this->config, new ParserFactory($this->config)) |
||
| 473 | ); |
||
| 474 | } |
||
| 475 | |||
| 476 | return $this->moduleManager; |
||
| 477 | } |
||
| 478 | } |
||
| 479 |
This check looks from parameters that have been defined for a function or method, but which are not used in the method body.