123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370 |
- <?php
- /**
- * A helper for handling Magento-specific class names in various use cases
- *
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
- namespace Magento\Framework\App\Utility;
- use Magento\Framework\Component\ComponentRegistrar;
- /**
- * Utility for class names processing
- */
- class Classes
- {
- /**
- * virtual class declarations collected from the whole system
- *
- * @var array
- */
- protected static $_virtualClasses = [];
- /**
- * Find all unique matches in specified content using specified PCRE
- *
- * @param string $contents
- * @param string $regex
- * @param array &$result
- * @return array
- */
- public static function getAllMatches($contents, $regex, &$result = [])
- {
- preg_match_all($regex, $contents, $matches);
- array_shift($matches);
- foreach ($matches as $row) {
- $result = array_merge($result, $row);
- }
- $result = array_filter(
- array_unique($result),
- function ($value) {
- return !empty($value);
- }
- );
- return $result;
- }
- /**
- * Get XML node text values using specified xPath
- *
- * The node must contain specified attribute
- *
- * @param \SimpleXMLElement $xml
- * @param string $xPath
- * @return array
- */
- public static function getXmlNodeValues(\SimpleXMLElement $xml, $xPath)
- {
- $result = [];
- $nodes = $xml->xpath($xPath) ?: [];
- foreach ($nodes as $node) {
- $result[] = (string)$node;
- }
- return $result;
- }
- /**
- * Get XML node names using specified xPath
- *
- * @param \SimpleXMLElement $xml
- * @param string $xpath
- * @return array
- */
- public static function getXmlNodeNames(\SimpleXMLElement $xml, $xpath)
- {
- $result = [];
- $nodes = $xml->xpath($xpath) ?: [];
- foreach ($nodes as $node) {
- $result[] = $node->getName();
- }
- return $result;
- }
- /**
- * Get XML node attribute values using specified xPath
- *
- * @param \SimpleXMLElement $xml
- * @param string $xPath
- * @param string $attributeName
- * @return array
- */
- public static function getXmlAttributeValues(\SimpleXMLElement $xml, $xPath, $attributeName)
- {
- $result = [];
- $nodes = $xml->xpath($xPath) ?: [];
- foreach ($nodes as $node) {
- $node = (array)$node;
- if (isset($node['@attributes'][$attributeName])) {
- $result[] = $node['@attributes'][$attributeName];
- }
- }
- return $result;
- }
- /**
- * Extract class name from a conventional callback specification "Class::method"
- *
- * @param string $callbackName
- * @return string
- */
- public static function getCallbackClass($callbackName)
- {
- $class = explode('::', $callbackName);
- return $class[0];
- }
- /**
- * Find classes in a configuration XML-file (assumes any files under Namespace/Module/etc/*.xml)
- *
- * @param \SimpleXMLElement $xml
- * @return array
- */
- public static function collectClassesInConfig(\SimpleXMLElement $xml)
- {
- // @todo this method must be refactored after implementation of MAGETWO-7689 (valid configuration)
- $classes = self::getXmlNodeValues(
- $xml,
- '
- /config//resource_adapter | /config/*[not(name()="sections")]//class[not(ancestor::observers)]
- | //model[not(parent::connection)] | //backend_model | //source_model | //price_model
- | //model_token | //writer_model | //clone_model | //frontend_model | //working_model
- | //admin_renderer | //renderer | /config/*/di/preferences/*'
- );
- $classes = array_merge($classes, self::getXmlAttributeValues($xml, '//@backend_model', 'backend_model'));
- $classes = array_merge(
- $classes,
- self::getXmlNodeNames(
- $xml,
- '/logging/*/expected_models/* | /logging/*/actions/*/expected_models/* | /config/*/di/preferences/*'
- )
- );
- $classes = array_map([\Magento\Framework\App\Utility\Classes::class, 'getCallbackClass'], $classes);
- $classes = array_map('trim', $classes);
- $classes = array_unique($classes);
- $classes = array_filter(
- $classes,
- function ($value) {
- return !empty($value);
- }
- );
- return $classes;
- }
- /**
- * Find classes in a layout configuration XML-file
- *
- * @param \SimpleXMLElement $xml
- * @return array
- */
- public static function collectLayoutClasses(\SimpleXMLElement $xml)
- {
- $classes = self::getXmlAttributeValues($xml, '/layout//block[@class]', 'class');
- $classes = array_merge(
- $classes,
- self::getXmlNodeValues(
- $xml,
- '/layout//action/attributeType | /layout//action[@method="addTab"]/content
- | /layout//action[@method="addMergeSettingsBlockType"
- or @method="addInformationRenderer"
- or @method="addDatabaseBlock"]/*[2]
- | /layout//action[@method="setMassactionBlockName"]/name
- | /layout//action[@method="setEntityModelClass"]/code'
- )
- );
- return array_unique($classes);
- }
- /**
- * Scan application source code and find classes
- *
- * Sub-type pattern allows to distinguish "type" of a class within a module (for example, Block, Model)
- * Returns array(<class> => <module>)
- *
- * @param string $subTypePattern
- * @return array
- */
- public static function collectModuleClasses($subTypePattern = '[A-Za-z]+')
- {
- $componentRegistrar = new ComponentRegistrar();
- $result = [];
- foreach ($componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $moduleName => $modulePath) {
- $pattern = '/^' . preg_quote($modulePath, '/') . '\/(' . $subTypePattern . '\/.+)\.php$/';
- foreach (Files::init()->getFiles([$modulePath], '*.php') as $file) {
- if (preg_match($pattern, $file)) {
- $partialFileName = substr($file, strlen($modulePath) + 1);
- $partialFileName = substr($partialFileName, 0, strlen($partialFileName) - strlen('.php'));
- $partialClassName = str_replace('/', '\\', $partialFileName);
- $className = str_replace('_', '\\', $moduleName) . '\\' . $partialClassName;
- $result[$className] = $moduleName;
- }
- }
- }
- return $result;
- }
- /**
- * Fetch virtual class declarations from DI configs
- *
- * @return array
- */
- public static function getVirtualClasses()
- {
- if (!empty(self::$_virtualClasses)) {
- return self::$_virtualClasses;
- }
- $configFiles = Files::init()->getDiConfigs();
- foreach ($configFiles as $fileName) {
- $configDom = new \DOMDocument();
- $configDom->load($fileName);
- $xPath = new \DOMXPath($configDom);
- $vTypes = $xPath->query('/config/virtualType');
- /** @var \DOMNode $virtualType */
- foreach ($vTypes as $virtualType) {
- $name = $virtualType->attributes->getNamedItem('name')->textContent;
- if (!$virtualType->attributes->getNamedItem('type')) {
- continue;
- }
- $type = $virtualType->attributes->getNamedItem('type')->textContent;
- self::$_virtualClasses[$name] = $type;
- }
- }
- return self::$_virtualClasses;
- }
- /**
- * Check if instance is virtual type
- *
- * @param string $className
- * @return bool
- */
- public static function isVirtual($className)
- {
- //init virtual classes if necessary
- self::getVirtualClasses();
- return array_key_exists($className, self::$_virtualClasses);
- }
- /**
- * Get real type name for virtual type
- *
- * @param string $className
- * @return string
- */
- public static function resolveVirtualType($className)
- {
- if (false == self::isVirtual($className)) {
- return $className;
- }
- $resolvedName = self::$_virtualClasses[$className];
- return self::resolveVirtualType($resolvedName);
- }
- /**
- * Check class is auto-generated
- *
- * @param string $className
- * @return bool
- */
- public static function isAutogenerated($className)
- {
- if (preg_match(
- '/.*\\\\[a-zA-Z0-9]{1,}(Factory|SearchResults|DataBuilder|Extension|ExtensionInterface)$/',
- $className
- )
- || preg_match('/Magento\\\\[\w]+\\\\(Test\\\\(Page|Fixture))\\\\/', $className)
- || preg_match('/.*\\\\[a-zA-Z0-9]{1,}\\\\Proxy$/', $className)
- ) {
- return true;
- }
- return false;
- }
- /**
- * Scan contents as PHP-code and find class name occurrences
- *
- * @param string $contents
- * @param array &$classes
- * @return array
- */
- public static function collectPhpCodeClasses($contents, &$classes = [])
- {
- self::getAllMatches(
- $contents,
- '/
- # ::getModel ::getSingleton ::getResourceModel ::getResourceSingleton
- \:\:get(?:Resource)?(?:Model | Singleton)\(\s*[\'"]([^\'"]+)[\'"]\s*[\),]
- # addBlock createBlock getBlockSingleton
- | (?:addBlock | createBlock | getBlockSingleton)\(\s*[\'"]([^\'"]+)[\'"]\s*[\),]
- # various methods, first argument
- | \->(?:initReport | setEntityModelClass
- | setAttributeModel | setBackendModel | setFrontendModel | setSourceModel | setModel
- )\(\s*[\'"]([^\'"]+)[\'"]\s*[\),]
- # various methods, second argument
- | \->add(?:ProductConfigurationHelper | OptionsRenderCfg)\(.+,\s*[\'"]([^\'"]+)[\'"]\s*[\),]
- # models in install or setup
- | [\'"](?:resource_model | attribute_model | entity_model | entity_attribute_collection
- | source | backend | frontend | input_renderer | frontend_input_renderer
- )[\'"]\s*=>\s*[\'"]([^\'"]+)[\'"]
- # misc
- | function\s_getCollectionClass\(\)\s+{\s+return\s+[\'"]([a-z\d_\/]+)[\'"]
- | (?:_parentResourceModelName | _checkoutType | _apiType)\s*=\s*\'([a-z\d_\/]+)\'
- | \'renderer\'\s*=>\s*\'([a-z\d_\/]+)\'
- | protected\s+\$_(?:form|info|backendForm|iframe)BlockType\s*=\s*[\'"]([^\'"]+)[\'"]
- /Uix',
- $classes
- );
- // check ->_init | parent::_init
- $skipForInit = implode(
- '|',
- [
- 'id',
- '[\w\d_]+_id',
- 'pk',
- 'code',
- 'status',
- 'serial_number',
- 'entity_pk_value',
- 'currency_code',
- 'unique_key'
- ]
- );
- self::getAllMatches(
- $contents,
- '/
- (?:parent\:\: | \->)_init\(\s*[\'"]([^\'"]+)[\'"]\s*\)
- | (?:parent\:\: | \->)_init\(\s*[\'"]([^\'"]+)[\'"]\s*,\s*[\'"]((?!(' .
- $skipForInit .
- '))[^\'"]+)[\'"]\s*\)
- /Uix',
- $classes
- );
- return $classes;
- }
- /**
- * Retrieve module name by class
- *
- * @param string $class
- * @return string
- */
- public static function getClassModuleName($class)
- {
- $parts = explode('\\', trim($class, '\\'));
- return $parts[0] . '_' . $parts[1];
- }
- }
|