/** * The callback function of the event `ScriptEvents::PRE_AUTOLOAD_DUMP` * * @param Event $event The Composer event * * @return void * * @throws \InvalidArgumentException with Symfony\Component\Finder\Finder * @throws \RuntimeException with Composer\Config */ public function findRewrite(Event $event) { $toRewrite = array(); $composer = $event->getComposer(); $config = $this->config; $allPath = array(); $packages = $composer->getRepositoryManager()->getLocalRepository()->getPackages(); $autoloads = $composer->getAutoloadGenerator()->parseAutoloads($composer->getAutoloadGenerator()->buildPackageMap($composer->getInstallationManager(), $composer->getPackage(), $packages), $composer->getPackage()); $worker = new Worker(); $worker->setCacheDir($config->has('rewrite-dir') ? $config->get('rewrite-dir') : $config->get('vendor-dir') . DIRECTORY_SEPARATOR . '_rewrite'); $this->output('very-verbose', 'Clear rewriters cache'); $worker->clearCache(); foreach ($autoloads as $loaderType => $package) { if (!in_array($loaderType, array('psr-4', 'psr-0'), true)) { continue; } foreach ($package as $packageName => $paths) { $this->output('very-verbose', 'Analysing namespace "%s" (%s)', array($packageName, $loaderType)); if (in_array($packageName, $this->getIgnoreNamespace($composer), true)) { $this->output('very-verbose', ' <info>(skipped)</info>'); continue; } /** * The file in reading * * @var SplFileInfo $file */ foreach (Finder::create()->in(array_values($paths))->exclude($worker->getCacheDir())->name('*.php')->ignoreDotFiles(true)->ignoreVCS(true)->ignoreUnreadableDirs(true)->files() as $file) { $this->output('debug', '- On file "%s"', array($file->getRealPath())); if (in_array(Rewriter::class, Getter::readFromFile($file->getRealPath(), Getter::TYPE_INTERFACES), true)) { $this->output('very-verbose', ' - Find "<info>%s</info>" rewriting "<comment>%s</comment>"', array(Getter::getFQCN($file->getRealPath()), Getter::readFromFile($file->getRealPath(), Getter::TYPE_PARENT_NAME))); /** * The FQCN of the parent class (the rewritten FQCN) * * @var string $parentFQCN */ $parentFQCN = Getter::readFromFile($file->getRealPath(), Getter::TYPE_PARENT_NAME); $toRewrite[$parentFQCN] = $file->getRealPath(); continue; } $allPath[$file->getRealPath()] = Getter::getFQCN($file->getRealPath()); } } } $allPath = array_filter($allPath, function ($value) use($toRewrite) { return array_key_exists($value, $toRewrite); }); $this->output('verbose', 'Build rewrite class cache'); $allPath = array_flip($allPath); foreach ($toRewrite as $parentClassName => $rewriteFile) { $this->output('very-verbose', ' - For class "<info>%s</info>" (rewriting "<comment>%s</comment>")', array(Getter::getFQCN($rewriteFile), $parentClassName)); $worker->rewriteClass($allPath[$parentClassName], $rewriteFile); } $this->output('verbose', 'Add rewrite class in Composer Autoload'); $autoload = $composer->getPackage()->getAutoload(); $autoload['classmap'][] = $worker->getCacheDir(); $composer->getPackage()->setAutoload($autoload); }
/** * Rewrite a class * * @param string $parentFile The path to the parent class (rewritten class) * @param string $replacementFile The path to the replacement class (rewriter class) * * @return void */ public function rewriteClass($parentFile, $replacementFile) { // Adding a 'C' at the begin to avoid issue with '\' (namespace separator) $parentHash = 'C' . sha1_file($parentFile); // Adding a 'C' at the begin to avoid issue with '\' (namespace separator) $replacementHash = 'C' . sha1_file($replacementFile); $namespace = Getter::readFromFile($parentFile, Getter::TYPE_NAMESPACE); $className = Getter::readFromFile($parentFile, Getter::TYPE_SHORT_NAME); $parentFCQN = $namespace . '\\' . $parentHash; file_put_contents($this->cacheDir . DIRECTORY_SEPARATOR . $parentHash . '.php', $this->rebuildClass($parentFile, null, $parentHash)); file_put_contents($this->cacheDir . DIRECTORY_SEPARATOR . $replacementHash . '.php', $this->rebuildClass($replacementFile, null, $className, '\\' . $parentFCQN)); $this->rewritten[$replacementHash . '.php'] = $namespace . '\\' . $className; }