/** * Fetch factories from class constructor * * @param $file string * @param $reflectionClass mixed * @return array */ protected function _fetchDataBuilders($file, $reflectionClass) { $absentDataBuilders = []; if ($reflectionClass->hasMethod('__construct')) { $constructor = $reflectionClass->getMethod('__construct'); $parameters = $constructor->getParameters(); /** @var $parameter \ReflectionParameter */ foreach ($parameters as $parameter) { preg_match('/\\[\\s\\<\\w+?>\\s([\\w\\\\]+)/s', $parameter->__toString(), $matches); if (isset($matches[1]) && substr($matches[1], -11) == 'DataBuilder') { $factoryClassName = $matches[1]; if (class_exists($factoryClassName)) { continue; } $entityName = rtrim(substr($factoryClassName, 0, -11), '\\'); if (!class_exists($entityName) && !interface_exists($entityName . 'Interface')) { $this->_log->add(Log::CONFIGURATION_ERROR, $factoryClassName, 'Invalid DataBuilder for nonexistent class ' . $entityName . ' in file ' . $file); continue; } $absentDataBuilders[] = $factoryClassName; } } } return $absentDataBuilders; }
/** * Compile class definitions * * @param string $path * @param bool $validate * @return void */ public function compile($path, $validate = true) { $rdi = new \RecursiveDirectoryIterator(realpath($path)); $recursiveIterator = new \RecursiveIteratorIterator($rdi, 1); /** @var $item \SplFileInfo */ foreach ($recursiveIterator as $item) { if ($item->isFile() && pathinfo($item->getRealPath(), PATHINFO_EXTENSION) == 'php') { $fileScanner = new FileScanner($item->getRealPath()); $classNames = $fileScanner->getClassNames(); foreach ($classNames as $className) { $this->_current = $className; if (!class_exists($className)) { require_once $item->getRealPath(); } try { if ($validate) { $this->_validator->validate($className); } $signatureReader = new \Magento\Framework\Code\Reader\ClassReader(); $this->_definitions[$className] = $signatureReader->getConstructor($className); $this->_relations[$className] = $signatureReader->getParents($className); } catch (\Magento\Framework\Code\ValidationException $exception) { $this->_log->add(Log::COMPILATION_ERROR, $className, $exception->getMessage()); } catch (\ReflectionException $e) { $this->_log->add(Log::COMPILATION_ERROR, $className, $e->getMessage()); } $this->_processedClasses[$className] = 1; } } } }
/** * Filter found entities if needed * * @param array $output * @return array */ protected function _filterEntities(array $output) { $filteredEntities = array(); foreach ($output as $className) { $entityName = substr($className, -6) === '\\Proxy' ? substr($className, 0, -6) : $className; if (false === class_exists($className)) { if (class_exists($entityName) || interface_exists($entityName)) { array_push($filteredEntities, $className); } else { $this->_log->add(\Magento\Tools\Di\Compiler\Log\Log::CONFIGURATION_ERROR, $className, 'Invalid proxy class for ' . substr($className, 0, -5)); } } } return $filteredEntities; }
/** * Retrieves list of classes for given path * * @param string $path path to dir with files * * @return array */ public function getList($path) { $nameList = []; foreach ($this->classesScanner->getList($path) as $className) { try { if (!strpos($path, 'generation')) { // validate all classes except classes in var/generation dir $this->validator->validate($className); } $nameList[] = $className; } catch (\Magento\Framework\Code\ValidationException $exception) { $this->log->add(Log::COMPILATION_ERROR, $className, $exception->getMessage()); } catch (\ReflectionException $e) { $this->log->add(Log::COMPILATION_ERROR, $className, $e->getMessage()); } } $this->log->report(); return $nameList; }
/** * Filter found entities if needed * * @param array $output * @return array */ protected function _filterEntities(array $output) { $entitySuffix = '\\' . ucfirst(ProxyGenerator::ENTITY_TYPE); $filteredEntities = []; foreach ($output as $className) { $entityName = substr($className, -strlen($entitySuffix)) === $entitySuffix ? substr($className, 0, -strlen($entitySuffix)) : $className; $isClassExists = false; try { $isClassExists = class_exists($className); } catch (\Magento\Framework\Exception $e) { } if (false === $isClassExists) { if (class_exists($entityName) || interface_exists($entityName)) { array_push($filteredEntities, $className); } else { $this->_log->add(\Magento\Tools\Di\Compiler\Log\Log::CONFIGURATION_ERROR, $className, 'Invalid proxy class for ' . substr($className, 0, -5)); } } } return $filteredEntities; }
/** * Fetch factories from class constructor * * @param \ReflectionClass $reflectionClass * @param string $file * @return string[] */ protected function _fetchFactories($reflectionClass, $file) { $factorySuffix = '\\' . ucfirst(FactoryGenerator::ENTITY_TYPE); $absentFactories = $this->_findMissingClasses($file, $reflectionClass, '__construct', ucfirst(FactoryGenerator::ENTITY_TYPE)); foreach ($absentFactories as $key => $absentFactory) { if (substr($absentFactory, -strlen($factorySuffix)) == $factorySuffix) { $entityName = rtrim(substr($absentFactory, 0, -strlen($factorySuffix)), '\\'); $this->_log->add(Log::CONFIGURATION_ERROR, $absentFactory, 'Invalid Factory declaration for class ' . $entityName . ' in file ' . $file); unset($absentFactories[$key]); } } return $absentFactories; }
/** * Retrieves list of classes for given path * * @param string $path path to dir with files * * @return array */ public function getList($path) { foreach ($this->classesScanner->getList($path) as $className) { $this->current = $className; // for errorHandler function try { if ($path != $this->generationDir) { // validate all classes except classes in generation dir $this->validator->validate($className); } $this->relations[$className] = $this->classReader->getParents($className); } catch (\Magento\Framework\Code\ValidationException $exception) { $this->log->add(Log::COMPILATION_ERROR, $className, $exception->getMessage()); } catch (\ReflectionException $e) { $this->log->add(Log::COMPILATION_ERROR, $className, $e->getMessage()); } } return $this->relations; }
use Magento\Tools\Di\Definition\Serializer\Igbinary; use Magento\Tools\Di\Definition\Serializer\Standard; try { $opt = new Zend_Console_Getopt(['serializer=w' => 'serializer function that should be used (serialize|igbinary) default: serialize', 'verbose|v' => 'output report after tool run', 'extra-classes-file=s' => 'path to file with extra proxies and factories to generate', 'generation=s' => 'absolute path to generated classes, <magento_root>/var/generation by default', 'di=s' => 'absolute path to DI definitions directory, <magento_root>/var/di by default', 'exclude-pattern=s' => 'allows to exclude Paths from compilation (default is #[\\\\/]m1[\\\\/]#i)']); $opt->parse(); $generationDir = $opt->getOption('generation') ? $opt->getOption('generation') : $rootDir . '/var/generation'; $diDir = $opt->getOption('di') ? $opt->getOption('di') : $rootDir . '/var/di'; $testExcludePatterns = ["#^{$rootDir}/app/code/[\\w]+/[\\w]+/Test#", "#^{$rootDir}/lib/internal/[\\w]+/[\\w]+/([\\w]+/)?Test#", "#^{$rootDir}/setup/src/Magento/Setup/Test#", "#^{$rootDir}/dev/tools/Magento/Tools/[\\w]+/Test#"]; $fileExcludePatterns = $opt->getOption('exclude-pattern') ? [$opt->getOption('exclude-pattern')] : ['#[\\\\/]M1[\\\\/]#i']; $fileExcludePatterns = array_merge($fileExcludePatterns, $testExcludePatterns); $relationsFile = $diDir . '/relations.ser'; $pluginDefFile = $diDir . '/plugins.ser'; $compilationDirs = [$rootDir . '/app/code', $rootDir . '/lib/internal/Magento', $rootDir . '/dev/tools/Magento/Tools']; /** @var Writer\WriterInterface $logWriter Writer model for success messages */ $logWriter = $opt->getOption('v') ? new Writer\Console() : new Writer\Quiet(); $log = new Log($logWriter, new Writer\Console()); $serializer = $opt->getOption('serializer') == Igbinary::NAME ? new Igbinary() : new Standard(); AutoloaderRegistry::getAutoloader()->addPsr4('Magento\\', $generationDir . '/Magento/'); // 1 Code generation // 1.1 Code scan $filePatterns = ['php' => '/.*\\.php$/', 'di' => '/\\/etc\\/([a-zA-Z_]*\\/di|di)\\.xml$/']; $codeScanDir = realpath($rootDir . '/app'); $directoryScanner = new Scanner\DirectoryScanner(); $files = $directoryScanner->scan($codeScanDir, $filePatterns, $fileExcludePatterns); $files['additional'] = [$opt->getOption('extra-classes-file')]; $entities = []; $repositoryScanner = new Scanner\RepositoryScanner(); $repositories = $repositoryScanner->collectEntities($files['di']); $scanner = new Scanner\CompositeScanner(); $scanner->addChild(new Scanner\PhpScanner($log), 'php'); $scanner->addChild(new Scanner\XmlScanner($log), 'di');