| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407 | 
							- <?php
 
- /**
 
-  * Rule for searching php file dependency
 
-  *
 
-  * Copyright © Magento, Inc. All rights reserved.
 
-  * See COPYING.txt for license details.
 
-  */
 
- namespace Magento\TestFramework\Dependency;
 
- use Magento\Framework\App\Utility\Files;
 
- class PhpRule implements RuleInterface
 
- {
 
-     /**
 
-      * List of filepaths for DI files
 
-      *
 
-      * @var array
 
-      */
 
-     private $diFiles;
 
-     /**
 
-      * Map from plugin classes to the subjects they modify
 
-      *
 
-      * @var array
 
-      */
 
-     private $pluginMap;
 
-     /**
 
-      * List of routers
 
-      *
 
-      * Format: array(
 
-      *  '{Router}' => '{Module_Name}'
 
-      * )
 
-      *
 
-      * @var array
 
-      */
 
-     protected $_mapRouters = [];
 
-     /**
 
-      * List of layout blocks
 
-      *
 
-      * Format: array(
 
-      *  '{Area}' => array(
 
-      *   '{Block_Name}' => array('{Module_Name}' => '{Module_Name}')
 
-      * ))
 
-      *
 
-      * @var array
 
-      */
 
-     protected $_mapLayoutBlocks = [];
 
-     /**
 
-      * Default modules list.
 
-      *
 
-      * @var array
 
-      */
 
-     protected $_defaultModules = [
 
-         'frontend' => 'Magento\Theme',
 
-         'adminhtml' => 'Magento\Adminhtml',
 
-     ];
 
-     /**
 
-      * Constructor
 
-      *
 
-      * @param array $mapRouters
 
-      * @param array $mapLayoutBlocks
 
-      * @param array $pluginMap
 
-      */
 
-     public function __construct(array $mapRouters, array $mapLayoutBlocks, array $pluginMap = [])
 
-     {
 
-         $this->_mapRouters = $mapRouters;
 
-         $this->_mapLayoutBlocks = $mapLayoutBlocks;
 
-         $this->_namespaces = implode('|', \Magento\Framework\App\Utility\Files::init()->getNamespaces());
 
-         $this->pluginMap = $pluginMap ?: null;
 
-     }
 
-     /**
 
-      * Gets alien dependencies information for current module by analyzing file's contents
 
-      *
 
-      * @param string $currentModule
 
-      * @param string $fileType
 
-      * @param string $file
 
-      * @param string $contents
 
-      * @return array
 
-      */
 
-     public function getDependencyInfo($currentModule, $fileType, $file, &$contents)
 
-     {
 
-         if (!in_array($fileType, ['php', 'template'])) {
 
-             return [];
 
-         }
 
-         $dependenciesInfo = [];
 
-         $dependenciesInfo = $this->considerCaseDependencies(
 
-             $dependenciesInfo,
 
-             $this->caseClassesAndIdentifiers($currentModule, $file, $contents)
 
-         );
 
-         $dependenciesInfo = $this->considerCaseDependencies(
 
-             $dependenciesInfo,
 
-             $this->_caseGetUrl($currentModule, $contents)
 
-         );
 
-         $dependenciesInfo = $this->considerCaseDependencies(
 
-             $dependenciesInfo,
 
-             $this->_caseLayoutBlock($currentModule, $fileType, $file, $contents)
 
-         );
 
-         return $dependenciesInfo;
 
-     }
 
-     /**
 
-      * Check references to classes and identifiers defined in other modules
 
-      *
 
-      * @param string $currentModule
 
-      * @param string $file
 
-      * @param string $contents
 
-      * @return array
 
-      */
 
-     private function caseClassesAndIdentifiers($currentModule, $file, &$contents)
 
-     {
 
-         $pattern = '~\b(?<class>(?<module>('
 
-             . implode(
 
-                 '[_\\\\]|',
 
-                 Files::init()->getNamespaces()
 
-             )
 
-             . '[_\\\\])[a-zA-Z0-9]+)'
 
-             . '(?<class_inside_module>[a-zA-Z0-9_\\\\]*))\b(?:::(?<module_scoped_key>[a-z0-9_]+)[\'"])?~';
 
-         if (!preg_match_all($pattern, $contents, $matches)) {
 
-             return [];
 
-         }
 
-         $dependenciesInfo = [];
 
-         $matches['module'] = array_unique($matches['module']);
 
-         foreach ($matches['module'] as $i => $referenceModule) {
 
-             $referenceModule = str_replace('_', '\\', $referenceModule);
 
-             if ($currentModule == $referenceModule) {
 
-                 continue;
 
-             }
 
-             $dependencyClass = trim($matches['class'][$i]);
 
-             if (empty($matches['class_inside_module'][$i]) && !empty($matches['module_scoped_key'][$i])) {
 
-                 $dependencyType = RuleInterface::TYPE_SOFT;
 
-             } else {
 
-                 $currentClass = $this->getClassFromFilepath($file, $currentModule);
 
-                 $dependencyType = $this->isPluginDependency($currentClass, $dependencyClass)
 
-                     ? RuleInterface::TYPE_SOFT
 
-                     : RuleInterface::TYPE_HARD;
 
-             }
 
-             $dependenciesInfo[] = [
 
-                 'module' => $referenceModule,
 
-                 'type' => $dependencyType,
 
-                 'source' => $dependencyClass,
 
-             ];
 
-         }
 
-         return $dependenciesInfo;
 
-     }
 
-     /**
 
-      * Get class name from filename based on class/file naming conventions
 
-      *
 
-      * @param string $filepath
 
-      * @param string $module
 
-      * @return string
 
-      */
 
-     private function getClassFromFilepath($filepath, $module)
 
-     {
 
-         $class = strstr($filepath, str_replace(['_', '\\', '/'], DIRECTORY_SEPARATOR, $module));
 
-         $class = str_replace(DIRECTORY_SEPARATOR, '\\', strstr($class, '.php', true));
 
-         return $class;
 
-     }
 
-     /**
 
-      * @return array
 
-      * @throws \Exception
 
-      */
 
-     private function loadDiFiles()
 
-     {
 
-         if (!$this->diFiles) {
 
-             $this->diFiles = Files::init()->getDiConfigs();
 
-         }
 
-         return $this->diFiles;
 
-     }
 
-     /**
 
-      * Generate an array of plugin info
 
-      *
 
-      * @return array
 
-      */
 
-     private function loadPluginMap()
 
-     {
 
-         if (!$this->pluginMap) {
 
-             foreach ($this->loadDiFiles() as $filepath) {
 
-                 $dom = new \DOMDocument();
 
-                 $dom->loadXML(file_get_contents($filepath));
 
-                 $typeNodes = $dom->getElementsByTagName('type');
 
-                 /** @var \DOMElement $type */
 
-                 foreach ($typeNodes as $type) {
 
-                     /** @var \DOMElement $plugin */
 
-                     foreach ($type->getElementsByTagName('plugin') as $plugin) {
 
-                         $subject = $type->getAttribute('name');
 
-                         $pluginType = $plugin->getAttribute('type');
 
-                         $this->pluginMap[$pluginType] = $subject;
 
-                     }
 
-                 }
 
-             }
 
-         }
 
-         return $this->pluginMap;
 
-     }
 
-     /**
 
-      * Determine whether a the dependency relation is because of a plugin
 
-      *
 
-      * True IFF the dependent is a plugin for some class in the same module as the dependency.
 
-      *
 
-      * @param string $dependent
 
-      * @param string $dependency
 
-      * @return bool
 
-      */
 
-     private function isPluginDependency($dependent, $dependency)
 
-     {
 
-         $pluginMap = $this->loadPluginMap();
 
-         $subject = isset($pluginMap[$dependent])
 
-             ? $pluginMap[$dependent]
 
-             : null;
 
-         if ($subject === $dependency) {
 
-             return true;
 
-         } elseif ($subject) {
 
-             $subjectModule = substr($subject, 0, strpos($subject, '\\', 9)); // (strlen('Magento\\') + 1) === 9
 
-             return strpos($dependency, $subjectModule) === 0;
 
-         } else {
 
-             return false;
 
-         }
 
-     }
 
-     /**
 
-      * Check get URL method
 
-      *
 
-      * Ex.: getUrl('{path}')
 
-      *
 
-      * @param $currentModule
 
-      * @param $contents
 
-      * @return array
 
-      */
 
-     protected function _caseGetUrl($currentModule, &$contents)
 
-     {
 
-         $pattern = '/[\->:]+(?<source>getUrl\([\'"](?<router>[\w\/*]+)[\'"])/';
 
-         $dependencies = [];
 
-         if (!preg_match_all($pattern, $contents, $matches, PREG_SET_ORDER)) {
 
-             return $dependencies;
 
-         }
 
-         foreach ($matches as $item) {
 
-             $router = str_replace('/', '\\', $item['router']);
 
-             if (isset($this->_mapRouters[$router])) {
 
-                 $modules = $this->_mapRouters[$router];
 
-                 if (!in_array($currentModule, $modules)) {
 
-                     foreach ($modules as $module) {
 
-                         $dependencies[] = [
 
-                             'module' => $module,
 
-                             'type' => RuleInterface::TYPE_HARD,
 
-                             'source' => $item['source'],
 
-                         ];
 
-                     }
 
-                 }
 
-             }
 
-         }
 
-         return $dependencies;
 
-     }
 
-     /**
 
-      * Check layout blocks
 
-      *
 
-      * @param $currentModule
 
-      * @param $fileType
 
-      * @param $file
 
-      * @param $contents
 
-      * @return array
 
-      */
 
-     protected function _caseLayoutBlock($currentModule, $fileType, $file, &$contents)
 
-     {
 
-         $pattern = '/[\->:]+(?<source>(?:getBlock|getBlockHtml)\([\'"](?<block>[\w\.\-]+)[\'"]\))/';
 
-         $area = $this->_getAreaByFile($file, $fileType);
 
-         $result = [];
 
-         if (!preg_match_all($pattern, $contents, $matches, PREG_SET_ORDER)) {
 
-             return $result;
 
-         }
 
-         foreach ($matches as $match) {
 
-             if (in_array($match['block'], ['root', 'content'])) {
 
-                 continue;
 
-             }
 
-             $check = $this->_checkDependencyLayoutBlock($currentModule, $area, $match['block']);
 
-             $module = isset($check['module']) ? $check['module'] : null;
 
-             if ($module) {
 
-                 $result[$module] = [
 
-                     'type' => RuleInterface::TYPE_HARD,
 
-                     'source' => $match['source'],
 
-                 ];
 
-             }
 
-         }
 
-         return $this->_getUniqueDependencies($result);
 
-     }
 
-     /**
 
-      * Get area from file path
 
-      *
 
-      * @param $file
 
-      * @param $fileType
 
-      * @return string|null
 
-      */
 
-     protected function _getAreaByFile($file, $fileType)
 
-     {
 
-         if ($fileType == 'php') {
 
-             return null;
 
-         }
 
-         $area = 'default';
 
-         if (preg_match('/\/(?<area>adminhtml|frontend)\//', $file, $matches)) {
 
-             $area = $matches['area'];
 
-         }
 
-         return $area;
 
-     }
 
-     /**
 
-      * Check layout block dependency
 
-      *
 
-      * Return: array(
 
-      *  'module'  // dependent module
 
-      *  'source'  // source text
 
-      * )
 
-      *
 
-      * @param $currentModule
 
-      * @param $area
 
-      * @param $block
 
-      * @return array
 
-      */
 
-     protected function _checkDependencyLayoutBlock($currentModule, $area, $block)
 
-     {
 
-         if (isset($this->_mapLayoutBlocks[$area][$block]) || $area === null) {
 
-             // CASE 1: No dependencies
 
-             $modules = [];
 
-             if ($area === null) {
 
-                 foreach ($this->_mapLayoutBlocks as $blocks) {
 
-                     if (array_key_exists($block, $blocks)) {
 
-                         $modules += $blocks[$block];
 
-                     }
 
-                 }
 
-             } else {
 
-                 $modules = $this->_mapLayoutBlocks[$area][$block];
 
-             }
 
-             if (isset($modules[$currentModule])) {
 
-                 return ['module' => null];
 
-             }
 
-             // CASE 2: Single dependency
 
-             if (1 == count($modules)) {
 
-                 return ['module' => current($modules)];
 
-             }
 
-             // CASE 3: Default module dependency
 
-             $defaultModule = $this->_getDefaultModuleName($area);
 
-             if (isset($modules[$defaultModule])) {
 
-                 return ['module' => $defaultModule];
 
-             }
 
-         }
 
-         // CASE 4: \Exception - Undefined block
 
-         return [];
 
-     }
 
-     /**
 
-      * Retrieve default module name (by area)
 
-      *
 
-      * @param string $area
 
-      * @return null
 
-      */
 
-     protected function _getDefaultModuleName($area = 'default')
 
-     {
 
-         if (isset($this->_defaultModules[$area])) {
 
-             return $this->_defaultModules[$area];
 
-         }
 
-         return null;
 
-     }
 
-     /**
 
-      * Retrieve unique dependencies
 
-      *
 
-      * @param array $dependencies
 
-      * @return array
 
-      */
 
-     protected function _getUniqueDependencies($dependencies = [])
 
-     {
 
-         $result = [];
 
-         foreach ($dependencies as $module => $value) {
 
-             $result[] = ['module' => $module, 'type' => $value['type'], 'source' => $value['source']];
 
-         }
 
-         return $result;
 
-     }
 
-     /**
 
-      * @param array $known
 
-      * @param array $new
 
-      * @return array
 
-      */
 
-     private function considerCaseDependencies($known, $new)
 
-     {
 
-         return array_merge($known, $new);
 
-     }
 
- }
 
 
  |