Commit a826eb70 by lmf

增加遗留文件

parent 915033c4
Options None
<FilesMatch "\.(xml|phtml)$">
Deny from all
</FilesMatch>
<IfModule mod_rewrite.c>
RewriteEngine Off
</IfModule>
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
require_once 'processorFactory.php';
$processorFactory = new \Magento\Framework\Error\ProcessorFactory();
$processor = $processorFactory->createProcessor();
$response = $processor->process404();
$response->sendResponse();
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
require_once 'processorFactory.php';
$processorFactory = new \Magento\Framework\Error\ProcessorFactory();
$processor = $processorFactory->createProcessor();
$response = $processor->process503();
$response->sendResponse();
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
?>
<h1>404 error: Page not found.</h1>
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
?>
<h1>Service Temporarily Unavailable</h1>
<p>
The server is temporarily unable to service your request due to maintenance downtime or capacity problems.
Please try again later.
</p>
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
body{background:#fff;color:#333;font-family:Arial,Helvetica,sans-serif;font-size:14px;line-height:1.4;margin:0;padding:0;text-align:left}main{display:block}img{border:0}a{color:#1979c3;text-decoration:underline}a:hover{text-decoration:none}h1{font-size:30px;font-weight:700;margin:0 0 20px}h2{font-size:20px;font-weight:700;margin:0 0 10px}input[type=text],textarea{box-sizing:border-box;background:#fff;border:1px solid #c2c2c2;border-radius:1px;width:100%;font-size:14px;font-family:Arial,Helvetica,sans-serif;line-height:1.42857143;background-clip:padding-box;vertical-align:baseline}input[type=text]{height:32px;padding:0 9px}textarea{height:auto;padding:10px;resize:vertical}input[type=text]:focus,textarea:focus{box-shadow:0 0 3px 1px #68a8e0}button{background:#1979c3;border:none;border-radius:3px;color:#fff;cursor:pointer;display:inline-block;font-size:14px;font-weight:700;line-height:16px;padding:7px 15px;text-align:center}button:hover{background:#006bb4}p{margin:0 0 10px}ol,ul{list-style:none}.page-main{padding:20px 30px}.trace{background:#f1f1f1;min-height:250px;overflow:auto;width:100%}.message{border:1px solid;background-position:10px 11px;background-repeat:no-repeat;margin:20px 0;padding:10px 20px 10px 35px}.error{border-color:#b30000;background-color:#fae5e5;background-image:url(../images/i_msg-error.gif);color:#b30000}.success{border-color:#006400;background-color:#e5efe5;background-image:url(../images/i_msg-success.gif);color:#006400}.info{border-color:#6f4400;background-color:#fdf0d5;background-image:url(../images/i_msg-note.gif);color:#6f4400}.fieldset{border:0;margin:0 0 20px;padding:0}.fieldset .legend{box-sizing:border-box;float:left;font-size:20px;line-height:1.2;margin:0 0 25px;padding:0}.fieldset .legend+br{display:block;clear:both;height:0;overflow:hidden;visibility:hidden}.fieldset:last-child{margin-bottom:0}.fieldset:after{content:attr(data-hasrequired);color:#e02b27;display:block;font-size:12px;letter-spacing:normal;margin:10px 0 0;word-spacing:normal}.field{margin:0 0 20px}.label{font-weight:700}.label:after{content:"*";font-size:12px;color:#e02b27;margin:0 0 0 5px}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
?>
<h1>Service Temporarily Unavailable</h1>
<p>The application can't retrieve cached config data. Please try again later.</p>
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
?>
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title><?= $this->pageTitle ?></title>
<base href="<?= $this->getViewFileUrl() ?>" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="robots" content="*"/>
<link rel="stylesheet" href="css/styles.css" type="text/css" />
<link rel="icon" href="images/favicon.ico" type="image/x-icon" />
<link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon" />
</head>
<body>
<main class="page-main">
<?php require_once $contentTemplate; ?>
</main>
</body>
</html>
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
// @codingStandardsIgnoreFile
?>
<h1>There has been an error processing your request</h1>
<?php if ($this->showSentMsg): ?>
<div class="message success message-success">
<div>Your message was submitted and will be responded as soon as possible. Thank you for reporting.</div>
</div>
<?php endif; ?>
<?php if ($this->showSendForm): ?>
<div class="message info message-info">
<div>
We are currently experiencing some technical issues. We apologize for the inconvenience and will contact you shortly to resolve the issue. To help us serve you please fill in the form below.
</div>
</div>
<?php if ($this->showErrorMsg): ?>
<div class="message error message-error">
<div>
Please fill all required fields with valid information
</div>
</div>
<?php endif; ?>
<form action="<?= "{$this->getBaseUrl(true)}errors/report.php?id={$this->reportId}" ?>" method="post" id="form-validate" class="form">
<fieldset class="fieldset" data-hasrequired="* Required Fields">
<legend class="legend"><span>Personal Information</span></legend><br />
<div class="field firstname required">
<label for="firstname" class="label">First Name</label>
<div class="control">
<input type="text" name="firstname" id="firstname" value="<?= $this->postData['firstName'] ?>" title="First Name" class="required-entry input-text" />
</div>
</div>
<div class="field lastname required">
<label for="lastname" class="label">Last Name</label>
<div class="control">
<input type="text" name="lastname" id="lastname" value="<?= $this->postData['lastName'] ?>" title="Last Name" class="required-entry input-text" />
</div>
</div>
<div class="field email required">
<label for="email_address" class="label">Email Address</label>
<div class="control">
<input type="text" name="email" id="email_address" value="<?= $this->postData['email'] ?>" title="Email Address" class="validate-email required-entry input-text" />
</div>
</div>
<div class="field telephone">
<label for="telephone" class="label">Telephone</label>
<div class="control">
<input type="tel" name="telephone" id="telephone" value="<?= $this->postData['telephone'] ?>" title="Telephone" class="input-text" />
</div>
</div>
<div class="field comment">
<label for="comment" class="label">Comment</label>
<div class="control">
<textarea name="comment" cols="5" rows="3" class="textarea"><?= $this->postData['comment'] ?></textarea>
</div>
</div>
</fieldset>
<div class="actions-toolbar">
<button name="submit" class="action primary" type="submit"><span>Submit</span></button>
</div>
</form>
<?php elseif ('' == $this->reportAction): ?>
<p><em>Exception printing is disabled by default for security reasons.</em></p>
<?php endif; ?>
<?php if ($this->reportAction == 'print'): ?>
<div class="trace-container">
<div class="trace">
<pre><?= htmlspecialchars($this->reportData[0]) ?></pre>
</div>
</div>
<?php endif; ?>
<?php if ($this->reportId): ?>
<p>Error log record number: <?= $this->reportId ?></p>
<?php endif; ?>
<?xml version="1.0"?>
<!--
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<config>
<skin>default</skin>
</config>
<?xml version="1.0"?>
<!--
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<config>
<skin>default</skin>
<report>
<!--
"action" can be set to "print" to show exception on screen and "email"
to send exception on specified email
-->
<action>print</action>
<!--
in "subject" you can set subject of email
-->
<subject>Store Debug Information</subject>
<!--
"email_address" admin email address
-->
<email_address></email_address>
<!--
"trash" is handle about trace info
value "leave" is for store on disk
value "delete" is for cleaning
-->
<trash>leave</trash>
<!--
The number of subdirectories that will be created to save the report.
Valid Values: Integers from 0 to 32
Example:
If we have the report name as hash sha256('') = 44ffb1087a44e61b018b3cdee72284d017f22e52755c24e5c85cbac1647ae7a7
dir_nesting_level=0 -> <magento_root>/var/report/44ffb1087a44e61b018b3cdee72284d017f22e52755c24e5c85cbac1647ae7a7
dir_nesting_level=1 -> <magento_root>/var/report/44/44ffb1087a44e61b018b3cdee72284d017f22e52755c24e5c85cbac1647ae7a7
dir_nesting_level=2 -> <magento_root>/var/report/44/ff/44ffb1087a44e61b018b3cdee72284d017f22e52755c24e5c85cbac1647ae7a7
...
dir_nesting_level=32 -> <magento_root>/var/report/44/ff/b1/08/7a/44/e6/1b/01/8b/3c/de/e7/22/84/d0/17/f2/2e/52/75/5c/24/e5/c8/5c/ba/c1/64/7a/e7/a7/44ffb1087a44e61b018b3cdee72284d017f22e52755c24e5c85cbac1647ae7a7
If you use an environment variable MAGE_ERROR_REPORT_DIR_NESTING_LEVEL, this property will be ignored.
Environment variable has a higher priority.
-->
<dir_nesting_level>0</dir_nesting_level>
</report>
</config>
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
require_once 'processorFactory.php';
$processorFactory = new \Magento\Framework\Error\ProcessorFactory();
$processor = $processorFactory->createProcessor();
$response = $processor->processNoCache();
$response->sendResponse();
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Framework\Error;
require_once realpath(__DIR__) . '/../../app/bootstrap.php';
require_once 'processor.php';
/**
* Error processor factory
*/
class ProcessorFactory
{
/**
* Create Processor
*
* @return Processor
*/
public function createProcessor()
{
$objectManagerFactory = \Magento\Framework\App\Bootstrap::createObjectManagerFactory(BP, $_SERVER);
$objectManager = $objectManagerFactory->create($_SERVER);
$response = $objectManager->create(\Magento\Framework\App\Response\Http::class);
return new Processor($response);
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
require_once 'processorFactory.php';
$processorFactory = new \Magento\Framework\Error\ProcessorFactory();
$processor = $processorFactory->createProcessor();
if (isset($reportData) && is_array($reportData)) {
$reportUrl = $processor->saveReport($reportData);
if (headers_sent()) {
echo '<script type="text/javascript">';
echo "window.location.href = '{$reportUrl}';";
echo '</script>';
exit;
}
}
$response = $processor->processReport();
$response->sendResponse();
<?php
/**
*
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Setup\Module\Di\Code;
use Magento\Framework\Code\Generator as FrameworkGenerator;
use Magento\Framework\Code\Generator\DefinedClasses;
use Magento\Framework\ObjectManagerInterface;
/**
* Class Generator
* @package Magento\Setup\Module\Di\Code
*/
class Generator extends FrameworkGenerator
{
/**
* List of class methods
*
* @var array
*/
private $classMethods = [];
/**
* @param ObjectManagerInterface $objectManagerInterface
* @param FrameworkGenerator\Io $ioObject
* @param array $generatedEntities
* @param DefinedClasses $definedClasses
*/
public function __construct(
ObjectManagerInterface $objectManagerInterface,
\Magento\Framework\Code\Generator\Io $ioObject = null,
array $generatedEntities = [],
DefinedClasses $definedClasses = null
) {
parent::__construct($ioObject, $generatedEntities, $definedClasses);
$this->setObjectManager($objectManagerInterface);
}
/**
* Create entity generator
*
* @param string $generatorClass
* @param string $entityName
* @param string $className
* @return \Magento\Framework\Code\Generator\EntityAbstract
*/
protected function createGeneratorInstance($generatorClass, $entityName, $className)
{
$generatorClass = parent::createGeneratorInstance($generatorClass, $entityName, $className);
$generatorClass->setInterceptedMethods($this->classMethods);
return $generatorClass;
}
/**
* Generates list of classes
*
* @param array $classesToGenerate
* @throws \Magento\Framework\Exception\LocalizedException
* @return void
*/
public function generateList($classesToGenerate)
{
foreach ($classesToGenerate as $class => $methods) {
$this->setClassMethods($methods);
$this->generateClass($class . '\\Interceptor');
$this->clearClassMethods();
}
}
/**
* Sets class methods
*
* @param array $methods
* @return void
*/
private function setClassMethods($methods)
{
$this->classMethods = $methods;
}
/**
* Clear class methods
* @return void
*/
private function clearClassMethods()
{
$this->classMethods = [];
}
}
<?php
/**
*
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Setup\Module\Di\Code\Generator;
use Magento\Framework\App\Area;
use Magento\Framework\App\Cache\Manager;
use Magento\Framework\App\Interception\Cache\CompiledConfig;
use Magento\Framework\Interception\Config\Config as InterceptionConfig;
use Magento\Setup\Module\Di\Code\Reader\Type;
use Magento\Framework\ObjectManager\InterceptableValidator;
class InterceptionConfigurationBuilder
{
/**
* Area code list: global, frontend, etc.
*
* @var array
*/
private $areaCodesList = [];
/**
* @var InterceptionConfig
*/
private $interceptionConfig;
/**
* @var PluginList
*/
private $pluginList;
/**
* @var Type
*/
private $typeReader;
/**
* @var Manager
*/
private $cacheManager;
/**
* @var InterceptableValidator
*/
private $interceptableValidator;
/**
* @param InterceptionConfig $interceptionConfig
* @param PluginList $pluginList
* @param Type $typeReader
* @param Manager $cacheManager
* @param InterceptableValidator $interceptableValidator
*/
public function __construct(
InterceptionConfig $interceptionConfig,
PluginList $pluginList,
Type $typeReader,
Manager $cacheManager,
InterceptableValidator $interceptableValidator
) {
$this->interceptionConfig = $interceptionConfig;
$this->pluginList = $pluginList;
$this->typeReader = $typeReader;
$this->cacheManager = $cacheManager;
$this->interceptableValidator = $interceptableValidator;
}
/**
* Adds area code
*
* @param string $areaCode
* @return void
*/
public function addAreaCode($areaCode)
{
if (empty($this->areaCodesList[$areaCode])) {
$this->areaCodesList[] = $areaCode;
}
}
/**
* Builds interception configuration for all defined classes
*
* @param array $definedClasses
* @return array
*/
public function getInterceptionConfiguration($definedClasses)
{
$interceptedInstances = $this->getInterceptedClasses($definedClasses);
$inheritedConfig = $this->getPluginsList($interceptedInstances);
$mergedAreaPlugins = $this->mergeAreaPlugins($inheritedConfig);
$interceptedMethods = $this->getInterceptedMethods($mergedAreaPlugins);
return $interceptedMethods;
}
/**
* Get intercepted instances from defined class list
*
* @param array $definedClasses
* @return array
*/
private function getInterceptedClasses($definedClasses)
{
$intercepted = [];
foreach ($definedClasses as $definedClass) {
if ($this->interceptionConfig->hasPlugins($definedClass) && $this->typeReader->isConcrete($definedClass)
&& $this->interceptableValidator->validate($definedClass)
) {
$intercepted[] = $definedClass;
}
}
return $intercepted;
}
/**
* Returns plugin list:
* ['concrete class name' => ['plugin name' => [instance => 'instance name', 'order' => 'Order Number']]]
*
* @param array $interceptedInstances
* @return array
*/
private function getPluginsList($interceptedInstances)
{
$this->cacheManager->setEnabled([CompiledConfig::TYPE_IDENTIFIER], true);
$this->pluginList->setInterceptedClasses($interceptedInstances);
$inheritedConfig = [];
foreach ($this->areaCodesList as $areaKey) {
$scopePriority = [Area::AREA_GLOBAL];
$pluginListCloned = clone $this->pluginList;
if ($areaKey != Area::AREA_GLOBAL) {
$scopePriority[] = $areaKey;
$pluginListCloned->setScopePriorityScheme($scopePriority);
}
$key = implode('', $scopePriority);
$inheritedConfig[$key] = $this->filterNullInheritance($pluginListCloned->getPluginsConfig());
}
return $inheritedConfig;
}
/**
* Filters plugin inheritance list for instances without plugins, and abstract/interface
*
* @param array $pluginInheritance
* @return array
*/
private function filterNullInheritance($pluginInheritance)
{
$filteredData = [];
foreach ($pluginInheritance as $instance => $plugins) {
if ($plugins === null || !$this->typeReader->isConcrete($instance)) {
continue;
}
$pluginInstances = [];
foreach ($plugins as $plugin) {
if (in_array($plugin['instance'], $pluginInstances)) {
continue;
}
$pluginInstances[] = $plugin['instance'];
}
$filteredData[$instance] = $pluginInstances;
}
return $filteredData;
}
/**
* Merge plugins in areas
*
* @param array $inheritedConfig
* @return array
*/
private function mergeAreaPlugins($inheritedConfig)
{
$mergedConfig = [];
foreach ($inheritedConfig as $configuration) {
$mergedConfig = array_merge_recursive($mergedConfig, $configuration);
}
foreach ($mergedConfig as &$plugins) {
$plugins = array_unique($plugins);
}
return $mergedConfig;
}
/**
* Returns interception configuration with plugin methods
*
* @param array $interceptionConfiguration
* @return array
*/
private function getInterceptedMethods($interceptionConfiguration)
{
$pluginDefinitionList = new \Magento\Framework\Interception\Definition\Runtime();
foreach ($interceptionConfiguration as &$plugins) {
$pluginsMethods = [];
foreach ($plugins as $plugin) {
$pluginsMethods = array_unique(
array_merge($pluginsMethods, array_keys($pluginDefinitionList->getMethodList($plugin)))
);
}
$plugins = $pluginsMethods;
}
return $interceptionConfiguration;
}
}
<?php
/**
*
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Setup\Module\Di\Code\Generator;
use Magento\Framework\Interception\Code\Generator\Interceptor as FrameworkInterceptor;
class Interceptor extends FrameworkInterceptor
{
/**
* Intercepted methods list
*
* @var array
*/
private $interceptedMethods = [];
/**
* Whether method is intercepted
*
* @param \ReflectionMethod $method
*
* @return bool
*/
protected function isInterceptedMethod(\ReflectionMethod $method)
{
return parent::isInterceptedMethod($method) && in_array($method->getName(), $this->interceptedMethods);
}
/**
* Sets list of intercepted methods
*
* @param array $interceptedMethods
*
* @return void
*/
public function setInterceptedMethods($interceptedMethods)
{
$this->interceptedMethods = $interceptedMethods;
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Setup\Module\Di\Code\Generator;
use Magento\Framework\Interception;
/**
* Provides plugin list configuration
*/
class PluginList extends Interception\PluginList\PluginList
{
/**
* @var array
*/
private $interceptedClasses;
/**
* Returns plugins config
*
* @return array
*/
public function getPluginsConfig()
{
$this->_loadScopedData();
return $this->_inherited;
}
/**
* Sets scope priority scheme
*
* @param array $areaCodes
* @return void
*/
public function setScopePriorityScheme($areaCodes)
{
$this->_scopePriorityScheme = $areaCodes;
}
/**
* Whether scope code is current scope code
*
* @param string $scopeCode
*
* @return bool
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
protected function isCurrentScope($scopeCode)
{
return false;
}
/**
* @param array $interceptedClasses
* @return void
*/
public function setInterceptedClasses($interceptedClasses)
{
$this->interceptedClasses = $interceptedClasses;
}
/**
* Returns class definitions
*
* @return array
*/
protected function getClassDefinitions()
{
return $this->interceptedClasses;
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Setup\Module\Di\Code;
use Magento\Framework\ObjectManagerInterface;
class GeneratorFactory
{
/**
* @var ObjectManagerInterface
*/
private $objectManager;
/**
* @param ObjectManagerInterface $objectManager
*/
public function __construct(ObjectManagerInterface $objectManager)
{
$this->objectManager = $objectManager;
}
/**
* Creates operation
*
* @param array $arguments
* @return Generator
*/
public function create($arguments = [])
{
return $this->objectManager->create(\Magento\Setup\Module\Di\Code\Generator::class, $arguments);
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Setup\Module\Di\Code\Reader;
use Magento\Setup\Module\Di\Compiler\ConstructorArgument;
class ClassReaderDecorator implements \Magento\Framework\Code\Reader\ClassReaderInterface
{
/**
* @var \Magento\Framework\Code\Reader\ClassReader
*/
private $classReader;
/**
* @param \Magento\Framework\Code\Reader\ClassReader $classReader
*/
public function __construct(\Magento\Framework\Code\Reader\ClassReader $classReader)
{
$this->classReader = $classReader;
}
/**
* Read class constructor signature
*
* @param string $className
* @return ConstructorArgument[]|null
* @throws \ReflectionException
*/
public function getConstructor($className)
{
$unmappedArguments = $this->classReader->getConstructor($className);
if ($unmappedArguments === null) {
return $unmappedArguments;
}
$arguments = [];
foreach ($unmappedArguments as $argument) {
$arguments[] = new ConstructorArgument($argument);
}
return $arguments;
}
/**
* Retrieve parent relation information for type in a following format
* array(
* 'Parent_Class_Name',
* 'Interface_1',
* 'Interface_2',
* ...
* )
*
* @param string $className
* @return string[]
*/
public function getParents($className)
{
return $this->classReader->getParents($className);
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\Setup\Module\Di\Code\Reader;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\Exception\FileSystemException;
/**
* Class ClassesScanner
*/
class ClassesScanner implements ClassesScannerInterface
{
/**
* @var array
*/
protected $excludePatterns = [];
/**
* @var array
*/
private $fileResults = [];
/**
* @var string
*/
private $generationDirectory;
/**
* @param array $excludePatterns
* @param DirectoryList|null $directoryList
* @throws FileSystemException
*/
public function __construct(array $excludePatterns = [], DirectoryList $directoryList = null)
{
$this->excludePatterns = $excludePatterns;
if ($directoryList === null) {
$directoryList = ObjectManager::getInstance()->get(DirectoryList::class);
}
$this->generationDirectory = $directoryList->getPath(DirectoryList::GENERATION);
}
/**
* Adds exclude patterns
*
* @param array $excludePatterns
* @return void
*/
public function addExcludePatterns(array $excludePatterns)
{
$this->excludePatterns = array_merge($this->excludePatterns, $excludePatterns);
}
/**
* Retrieves list of classes for given path
*
* @param string $path
* @return array
* @throws FileSystemException
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function getList($path)
{
// phpcs:ignore
$realPath = realpath($path);
$isGeneration = strpos($realPath, $this->generationDirectory) === 0;
// Generation folders should not have their results cached since they may actually change during compile
if (!$isGeneration && isset($this->fileResults[$realPath])) {
return $this->fileResults[$realPath];
}
if (!(bool)$realPath) {
throw new FileSystemException(
new \Magento\Framework\Phrase('The "%1" path is invalid. Verify the path and try again.', [$path])
);
}
$recursiveIterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($realPath, \FilesystemIterator::FOLLOW_SYMLINKS),
\RecursiveIteratorIterator::SELF_FIRST
);
$classes = $this->extract($recursiveIterator);
if (!$isGeneration) {
$this->fileResults[$realPath] = $classes;
}
return $classes;
}
/**
* Extracts all the classes from the recursive iterator
*
* @param \RecursiveIteratorIterator $recursiveIterator
* @return array
*/
private function extract(\RecursiveIteratorIterator $recursiveIterator)
{
$classes = [];
foreach ($recursiveIterator as $fileItem) {
/** @var $fileItem \SplFileInfo */
if ($fileItem->isDir() || $fileItem->getExtension() !== 'php' || $fileItem->getBasename()[0] == '.') {
continue;
}
$fileItemPath = $fileItem->getRealPath();
foreach ($this->excludePatterns as $excludePatterns) {
if ($this->isExclude($fileItemPath, $excludePatterns)) {
continue 2;
}
}
$fileScanner = new FileClassScanner($fileItemPath);
$className = $fileScanner->getClassName();
if (!empty($className)) {
$this->includeClass($className, $fileItemPath);
$classes[] = $className;
}
}
return $classes;
}
/**
* Include class from file path.
*
* @param string $className
* @param string $fileItemPath
* @return bool Whether the class is included or not
*/
private function includeClass(string $className, string $fileItemPath): bool
{
if (!class_exists($className)) {
// phpcs:ignore
require_once $fileItemPath;
return true;
}
return false;
}
/**
* Find out if file should be excluded
*
* @param string $fileItemPath
* @param string $patterns
* @return bool
*/
private function isExclude($fileItemPath, $patterns)
{
if (!is_array($patterns)) {
$patterns = (array)$patterns;
}
foreach ($patterns as $pattern) {
if (preg_match($pattern, str_replace('\\', '/', $fileItemPath))) {
return true;
}
}
return false;
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Setup\Module\Di\Code\Reader;
/**
* Interface ClassesScannerInterface
*
* @package Magento\Setup\Module\Di\Code\Reader
*/
interface ClassesScannerInterface
{
/**
* Retrieves list of classes for given path
*
* @param string $path path to dir with files
*
* @return array
*/
public function getList($path);
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Setup\Module\Di\Code\Reader\Decorator;
use Magento\Setup\Module\Di\Code\Reader\ClassesScanner;
use Magento\Setup\Module\Di\Code\Reader\ClassReaderDecorator;
use Magento\Framework\Exception\FileSystemException;
/**
* Class Area
*
* @package Magento\Setup\Module\Di\Code\Reader\Decorator
*/
class Area implements \Magento\Setup\Module\Di\Code\Reader\ClassesScannerInterface
{
/**
* @var ClassReaderDecorator
*/
private $classReaderDecorator;
/**
* @var ClassesScanner
*/
private $classesScanner;
/**
* @param ClassesScanner $classesScanner
* @param ClassReaderDecorator $classReaderDecorator
*/
public function __construct(
ClassesScanner $classesScanner,
ClassReaderDecorator $classReaderDecorator
) {
$this->classReaderDecorator = $classReaderDecorator;
$this->classesScanner = $classesScanner;
}
/**
* Retrieves list of classes for given path
*
* @param string $path path to dir with files
*
* @return array
* @throws FileSystemException
*/
public function getList($path)
{
$classes = [];
foreach ($this->classesScanner->getList($path) as $className) {
$classes[$className] = $this->classReaderDecorator->getConstructor($className);
}
return $classes;
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Setup\Module\Di\Code\Reader\Decorator;
use Magento\Setup\Module\Di\Compiler\Log\Log;
/**
* Class Directory
*
* @package Magento\Setup\Module\Di\Code\Reader\Decorator
*/
class Directory implements \Magento\Setup\Module\Di\Code\Reader\ClassesScannerInterface
{
/**
* @var string
*/
private $current;
/**
* @var \Magento\Setup\Module\Di\Compiler\Log\Log
*/
private $log;
/**
* @var array
*/
private $relations = [];
/**
* @var \Magento\Framework\Code\Validator
*/
private $validator;
/**
* @var \Magento\Framework\Code\Reader\ClassReader
*/
private $classReader;
/**
* @var \Magento\Setup\Module\Di\Code\Reader\ClassesScanner
*/
private $classesScanner;
/**
* @var string
*/
private $generationDir;
/**
* @param \Magento\Setup\Module\Di\Compiler\Log\Log $log Logging object
* @param \Magento\Framework\Code\Reader\ClassReader $classReader
* @param \Magento\Setup\Module\Di\Code\Reader\ClassesScanner $classesScanner
* @param \Magento\Framework\Code\Validator $validator
* @param string $generationDir directory where generated files is
*/
public function __construct(
\Magento\Setup\Module\Di\Compiler\Log\Log $log,
\Magento\Framework\Code\Reader\ClassReader $classReader,
\Magento\Setup\Module\Di\Code\Reader\ClassesScanner $classesScanner,
\Magento\Framework\Code\Validator $validator,
$generationDir
) {
$this->log = $log;
$this->classReader = $classReader;
$this->classesScanner = $classesScanner;
$this->validator = $validator;
$this->generationDir = $generationDir;
set_error_handler([$this, 'errorHandler'], E_STRICT);
}
/**
* ErrorHandler for logging
*
* @param int $errorNumber
* @param string $msg
*
* @return void
*/
public function errorHandler($errorNumber, $msg)
{
$this->log->add(Log::COMPILATION_ERROR, $this->current, '#' . $errorNumber . ' ' . $msg);
}
/**
* 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\Exception\ValidatorException $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;
}
/**
* @return array
*/
public function getRelations()
{
return $this->relations;
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Setup\Module\Di\Code\Reader\Decorator;
use Magento\Setup\Module\Di\Compiler\Log\Log;
use Magento\Framework\App\Filesystem\DirectoryList;
/**
* Class Interceptions
*
* @package Magento\Setup\Module\Di\Code\Reader\Decorator
*/
class Interceptions implements \Magento\Setup\Module\Di\Code\Reader\ClassesScannerInterface
{
/**
* @var \Magento\Setup\Module\Di\Code\Reader\ClassReaderDecorator
*/
private $classReader;
/**
* @var \Magento\Setup\Module\Di\Code\Reader\ClassesScanner
*/
private $classesScanner;
/**
* @var \Magento\Setup\Module\Di\Compiler\Log\Log
*/
private $log;
/**
* @var \Magento\Framework\Code\Validator
*/
private $validator;
/**
* @param \Magento\Setup\Module\Di\Code\Reader\ClassesScanner $classesScanner
* @param \Magento\Framework\Code\Reader\ClassReader $classReader
* @param \Magento\Framework\Code\Validator $validator
* @param \Magento\Framework\Code\Validator\ConstructorIntegrity $constructorIntegrityValidator
* @param Log $log
*/
public function __construct(
\Magento\Setup\Module\Di\Code\Reader\ClassesScanner $classesScanner,
\Magento\Framework\Code\Reader\ClassReader $classReader,
\Magento\Framework\Code\Validator $validator,
\Magento\Framework\Code\Validator\ConstructorIntegrity $constructorIntegrityValidator,
Log $log
) {
$this->classReader = $classReader;
$this->classesScanner = $classesScanner;
$this->validator = $validator;
$this->log = $log;
$this->validator->add($constructorIntegrityValidator);
}
/**
* 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 {
// validate all classes except classes in generated/code dir
$generatedCodeDir = DirectoryList::getDefaultConfig()[DirectoryList::GENERATED_CODE];
if (strpos($path, $generatedCodeDir[DirectoryList::PATH]) === false) {
$this->validator->validate($className);
}
$nameList[] = $className;
} catch (\Magento\Framework\Exception\ValidatorException $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;
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\Setup\Module\Di\Code\Reader;
/**
* Class FileClassScanner
*/
class FileClassScanner
{
private const NAMESPACE_TOKENS = [
T_WHITESPACE => true,
T_STRING => true,
T_NS_SEPARATOR => true
];
private const ALLOWED_OPEN_BRACES_TOKENS = [
T_CURLY_OPEN => true,
T_DOLLAR_OPEN_CURLY_BRACES => true,
T_STRING_VARNAME => true
];
/**
* The filename of the file to introspect
*
* @var string
*/
private $filename;
/**
* The class name found in the file.
*
* @var bool
*/
private $className = false;
/**
* @var array
*/
private $tokens;
/**
* Constructor for the file class scanner. Requires the filename
*
* @param string $filename
*/
public function __construct($filename)
{
// phpcs:ignore
$filename = realpath($filename);
// phpcs:ignore
if (!file_exists($filename) || !\is_file($filename)) {
throw new InvalidFileException(
sprintf(
'The file "%s" does not exist or is not a file',
$filename
)
);
}
$this->filename = $filename;
}
/**
* Retrieves the contents of a file. Mostly here for Mock injection
*
* @return string
*/
public function getFileContents()
{
// phpcs:ignore
return file_get_contents($this->filename);
}
/**
* Retrieves the first class found in a class file.
*
* @return string
*/
public function getClassName(): string
{
if ($this->className === false) {
$this->className = $this->extract();
}
return $this->className;
}
/**
* Extracts the fully qualified class name from a file.
*
* It only searches for the first match and stops looking as soon as it enters the class definition itself.
*
* Warnings are suppressed for this method due to a micro-optimization that only really shows up when this logic
* is called several millions of times, which can happen quite easily with even moderately sized codebases.
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
* @return string
*/
private function extract(): string
{
$namespaceParts = [];
$class = '';
$triggerClass = false;
$triggerNamespace = false;
$braceLevel = 0;
$bracedNamespace = false;
// phpcs:ignore
$this->tokens = token_get_all($this->getFileContents());
foreach ($this->tokens as $index => $token) {
$tokenIsArray = is_array($token);
// Is either a literal brace or an interpolated brace with a variable
if ($token === '{' || ($tokenIsArray && isset(self::ALLOWED_OPEN_BRACES_TOKENS[$token[0]]))) {
$braceLevel++;
} elseif ($token === '}') {
$braceLevel--;
}
// The namespace keyword was found in the last loop
if ($triggerNamespace) {
// A string ; or a discovered namespace that looks like "namespace name { }"
if (!$tokenIsArray || ($namespaceParts && $token[0] === T_WHITESPACE)) {
$triggerNamespace = false;
$namespaceParts[] = '\\';
continue;
}
$namespaceParts[] = $token[1];
// `class` token is not used with a valid class name
} elseif ($triggerClass && !$tokenIsArray) {
$triggerClass = false;
// The class keyword was found in the last loop
} elseif ($triggerClass && $token[0] === T_STRING) {
$triggerClass = false;
$class = $token[1];
}
switch ($token[0]) {
case T_NAMESPACE:
// Current loop contains the namespace keyword. Between this and the semicolon is the namespace
$triggerNamespace = true;
$namespaceParts = [];
$bracedNamespace = $this->isBracedNamespace($index);
break;
case T_CLASS:
// Current loop contains the class keyword. Next loop will have the class name itself.
if ($braceLevel == 0 || ($bracedNamespace && $braceLevel == 1)) {
$triggerClass = true;
}
break;
}
// We have a class name, let's concatenate and return it!
if ($class !== '') {
$fqClassName = trim(join('', $namespaceParts)) . trim($class);
return $fqClassName;
}
}
return $class;
}
/**
* Looks forward from the current index to determine if the namespace is nested in {} or terminated with ;
*
* @param integer $index
* @return bool
*/
private function isBracedNamespace($index)
{
$len = count($this->tokens);
while ($index++ < $len) {
if (!is_array($this->tokens[$index])) {
if ($this->tokens[$index] === ';') {
return false;
} elseif ($this->tokens[$index] === '{') {
return true;
}
continue;
}
if (!isset(self::NAMESPACE_TOKENS[$this->tokens[$index][0]])) {
throw new InvalidFileException('Namespace not defined properly');
}
}
throw new InvalidFileException('Could not find namespace termination');
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Setup\Module\Di\Code\Reader;
class InvalidFileException extends \InvalidArgumentException
{
}
<?php
/**
*
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Setup\Module\Di\Code\Reader;
class Type
{
/**
* Whether instance is concrete implementation
*
* @param string $type
* @return bool
*/
public function isConcrete($type)
{
try {
$instance = new \ReflectionClass($type);
} catch (\ReflectionException $e) {
return false;
}
return !$instance->isAbstract() && !$instance->isInterface();
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Setup\Module\Di\Code\Scanner;
class ArrayScanner implements ScannerInterface
{
/**
* Scan files
*
* @param array $files
* @return array
*/
public function collectEntities(array $files)
{
$output = [];
foreach ($files as $file) {
if (file_exists($file)) {
$data = include $file;
$output = array_merge($output, $data);
}
}
return $output;
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Setup\Module\Di\Code\Scanner;
class CompositeScanner implements ScannerInterface
{
/**
* @var ScannerInterface[]
*/
protected $_children = [];
/**
* Add child scanner
*
* @param ScannerInterface $scanner
* @param string $type
* @return void
*/
public function addChild(ScannerInterface $scanner, $type)
{
$this->_children[$type] = $scanner;
}
/**
* Scan files
*
* @param array $files
* @return array
*/
public function collectEntities(array $files)
{
$output = [];
foreach ($this->_children as $type => $scanner) {
if (!isset($files[$type]) || !is_array($files[$type])) {
continue;
}
$output[$type] = array_unique($scanner->collectEntities($files[$type]));
}
return $output;
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Setup\Module\Di\Code\Scanner;
use Magento\Framework\App\Area;
class ConfigurationScanner
{
/**
* @var \Magento\Framework\App\Config\FileResolver
*/
private $fileResolver;
/**
* @var \Magento\Framework\App\AreaList
*/
private $areaList;
/**
* ConfigurationScanner constructor.
*
* @param \Magento\Framework\App\Config\FileResolver $fileResolver
* @param \Magento\Framework\App\AreaList $areaList
*/
public function __construct(
\Magento\Framework\App\Config\FileResolver $fileResolver,
\Magento\Framework\App\AreaList $areaList
) {
$this->fileResolver = $fileResolver;
$this->areaList = $areaList;
}
/**
* Scan configuration files
*
* @param string $fileName
*
* @return array of paths to the configuration files
*/
public function scan($fileName)
{
$files = [];
$areaCodes = array_merge(
['primary', Area::AREA_GLOBAL],
$this->areaList->getCodes()
);
foreach ($areaCodes as $area) {
$files = array_merge_recursive(
$files,
$this->fileResolver->get($fileName, $area)->toArray()
);
}
return array_keys($files);
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Setup\Module\Di\Code\Scanner;
class DirectoryScanner
{
/**
* Scan directory
*
* @param string $dir
* @param array $patterns
* @param string[] $excludePatterns
* @return array
*/
public function scan($dir, array $patterns = [], array $excludePatterns = [])
{
$recursiveIterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($dir, \FilesystemIterator::FOLLOW_SYMLINKS)
);
$output = [];
foreach ($recursiveIterator as $file) {
/** @var $file \SplFileInfo */
if ($file->isDir()) {
continue;
}
$filePath = str_replace('\\', '/', $file->getRealPath());
if (!empty($excludePatterns)) {
foreach ($excludePatterns as $excludePattern) {
if (preg_match($excludePattern, $filePath)) {
continue 2;
}
}
}
foreach ($patterns as $type => $pattern) {
if (preg_match($pattern, $filePath)) {
$output[$type][] = $filePath;
break;
}
}
}
return $output;
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Setup\Module\Di\Code\Scanner;
use Magento\Framework\ObjectManager\InterceptableValidator;
class InheritanceInterceptorScanner implements ScannerInterface
{
/**
* @var InterceptableValidator
*/
private $interceptableValidator;
/**
* @param InterceptableValidator $interceptableValidator
*/
public function __construct(InterceptableValidator $interceptableValidator)
{
$this->interceptableValidator = $interceptableValidator;
}
/**
* Get intercepted class names
*
* @param array $classes
* @param array $interceptedEntities
* @return array
*/
public function collectEntities(array $classes, array $interceptedEntities = [])
{
$output = [];
foreach ($classes as $class) {
foreach ($interceptedEntities as $interceptorClass) {
$interceptedEntity = substr($interceptorClass, 0, -12);
if (is_subclass_of($class, $interceptedEntity) && $this->interceptableValidator->validate($class)) {
$reflectionClass = new \ReflectionClass($class);
if (!$reflectionClass->isAbstract() && !$reflectionClass->isFinal()) {
$output[] = $class . '\\Interceptor';
}
}
}
}
$output = array_merge($this->filterOutAbstractClasses($interceptedEntities), $output);
$output = array_unique($output);
return $output;
}
/**
* Filter out Interceptors defined for abstract classes
*
* @param string[] $interceptedEntities
* @return string[]
*/
private function filterOutAbstractClasses($interceptedEntities)
{
$interceptedEntitiesFiltered = [];
foreach ($interceptedEntities as $interceptorClass) {
$interceptedEntity = substr($interceptorClass, 0, -12);
$reflectionInterceptedEntity = new \ReflectionClass($interceptedEntity);
if (!$reflectionInterceptedEntity->isAbstract() && !$reflectionInterceptedEntity->isFinal()) {
$interceptedEntitiesFiltered[] = $interceptorClass;
}
}
return $interceptedEntitiesFiltered;
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Setup\Module\Di\Code\Scanner;
class InterceptedInstancesScanner implements ScannerInterface
{
/**
* Get array of class names
*
* @param array $files
* @return array
*/
public function collectEntities(array $files)
{
$interceptedInstances = [];
foreach ($files as $fileName) {
$dom = new \DOMDocument();
$dom->loadXML(file_get_contents($fileName));
$xpath = new \DOMXPath($dom);
/** @var $node \DOMNode */
foreach ($xpath->query('//type/plugin|//virtualType/plugin') as $node) {
$parentTypeNode = $node->parentNode->attributes->getNamedItem('name');
if ($parentTypeNode === null) {
continue;
}
if (!isset($interceptedInstances[$parentTypeNode->nodeValue])) {
$interceptedInstances[$parentTypeNode->nodeValue] = [];
}
$pluginTypeNode = $node->attributes->getNamedItem('type');
if ($pluginTypeNode !== null) {
$interceptedInstances[$parentTypeNode->nodeValue][] = $pluginTypeNode->nodeValue;
}
}
}
return $interceptedInstances;
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Setup\Module\Di\Code\Scanner;
class PluginScanner implements ScannerInterface
{
/**
* Get array of class names
*
* @param array $files
* @return array
*/
public function collectEntities(array $files)
{
$pluginClassNames = [];
foreach ($files as $fileName) {
$dom = new \DOMDocument();
$dom->loadXML(file_get_contents($fileName));
$xpath = new \DOMXPath($dom);
/** @var $node \DOMNode */
foreach ($xpath->query('//type/plugin|//virtualType/plugin') as $node) {
$pluginTypeNode = $node->attributes->getNamedItem('type');
if ($pluginTypeNode !== null) {
$pluginClassNames[] = $pluginTypeNode->nodeValue;
}
}
}
return $pluginClassNames;
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Setup\Module\Di\Code\Scanner;
use Magento\Framework\Autoload\AutoloaderRegistry;
/**
* Class RepositoryScanner
*/
class RepositoryScanner implements ScannerInterface
{
/**
* @var bool
*/
private $useAutoload = true;
/**
* Get array of class names
*
* @param array $files
* @return array
*/
public function collectEntities(array $files)
{
$repositoryClassNames = [];
foreach ($files as $fileName) {
$dom = new \DOMDocument();
$dom->loadXML(file_get_contents($fileName));
$xpath = new \DOMXPath($dom);
/** @var $node \DOMNode */
foreach ($xpath->query('//preference') as $node) {
$forType = $node->attributes->getNamedItem('for');
$replacementType = $node->attributes->getNamedItem('type');
if ($forType !== null
&& $replacementType !== null
&& (substr($forType->nodeValue, -19) == 'RepositoryInterface')
) {
if (!class_exists($replacementType->nodeValue, false)
&& !AutoloaderRegistry::getAutoloader()->loadClass($replacementType->nodeValue)) {
$persistor = str_replace('\\Repository', 'InterfacePersistor', $replacementType->nodeValue);
$factory = str_replace('\\Repository', 'InterfaceFactory', $replacementType->nodeValue);
$searchResultFactory
= str_replace('\\Repository', 'SearchResultInterfaceFactory', $replacementType->nodeValue);
$repositoryClassNames[$persistor] = $persistor;
$repositoryClassNames[$factory] = $factory;
$repositoryClassNames[$searchResultFactory] = $searchResultFactory;
$repositoryClassNames[$replacementType->nodeValue] = $replacementType->nodeValue;
}
}
}
}
return $repositoryClassNames;
}
/**
* Sets autoload flag
*
* @param boolean $useAutoload
* @return void
*/
public function setUseAutoload($useAutoload)
{
$this->useAutoload = $useAutoload;
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Setup\Module\Di\Code\Scanner;
/**
* Interface \Magento\Setup\Module\Di\Code\Scanner\ScannerInterface
*
*/
interface ScannerInterface
{
/**
* Get array of class names
*
* @param array $files
* @return array
*/
public function collectEntities(array $files);
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Setup\Module\Di\Code\Scanner;
/**
* Class ServiceDataAttributesScanner
*/
class ServiceDataAttributesScanner implements ScannerInterface
{
/**
* Scan provided extension_attributes.xml and find extenstion classes.
*
* @param array $files
* @return array
*/
public function collectEntities(array $files)
{
$extensionClasses = [];
foreach ($files as $fileName) {
$dom = new \DOMDocument();
$dom->loadXML(file_get_contents($fileName));
$xpath = new \DOMXPath($dom);
/** @var $node \DOMNode */
foreach ($xpath->query('//extension_attributes') as $node) {
$forType = $node->attributes->getNamedItem('for')->nodeValue;
$extensionClasses[] = str_replace('Interface', 'ExtensionInterface', $forType);
$extensionClasses[] = str_replace('Interface', 'Extension', $forType);
}
}
return $extensionClasses;
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Setup\Module\Di\Code\Scanner;
class XmlInterceptorScanner implements ScannerInterface
{
/**
* Get array of interceptor class names
*
* @param array $files
* @return array
*/
public function collectEntities(array $files)
{
$output = [];
foreach ($files as $file) {
$output = array_merge($output, $this->_collectEntitiesFromString(file_get_contents($file)));
}
$output = array_unique($output);
$output = $this->_filterEntities($output);
return $output;
}
/**
* Collect entities from XML string
*
*
* @param string $content
* @return array
*/
protected function _collectEntitiesFromString($content)
{
$output = [];
$dom = new \DOMDocument();
$dom->loadXML($content);
$xpath = new \DOMXPath($dom);
/** @var $entityNode \DOMNode */
foreach ($xpath->query('//type[plugin]|//virtualType[plugin]') as $entityNode) {
$attributes = $entityNode->attributes;
$type = $attributes->getNamedItem('type');
if ($type !== null) {
$output[] = $type->nodeValue;
} else {
$output[] = $attributes->getNamedItem('name')->nodeValue;
}
}
return $output;
}
/**
* Filter found entities if needed
*
* @param array $output
* @return array
*/
protected function _filterEntities(array $output)
{
$filteredEntities = [];
foreach ($output as $entityName) {
// @todo the controller handling logic below must be removed when controllers become PSR-0 compliant
$controllerSuffix = 'Controller';
$pathParts = explode('_', $entityName);
if (strrpos(
$entityName,
$controllerSuffix
) === strlen(
$entityName
) - strlen(
$controllerSuffix
) && isset(
$pathParts[2]
) && !in_array(
$pathParts[2],
['Block', 'Helper', 'Model']
)
) {
$this->_handleControllerClassName($entityName);
}
if (class_exists($entityName) || interface_exists($entityName)) {
$filteredEntities[] = $entityName . '\\Interceptor';
}
}
return $filteredEntities;
}
/**
* Include file with controller declaration if needed
*
* @param string $className
* @return void
*/
protected function _handleControllerClassName($className)
{
if (!class_exists($className)) {
$className = preg_replace('/[^a-zA-Z0-9_]/', '', $className);
$className = preg_replace('/^([0-9A-Za-z]*)_([0-9A-Za-z]*)/', '\\1_\\2_controllers', $className);
$filePath = stream_resolve_include_path(str_replace('_', '/', $className) . '.php');
if (file_exists($filePath)) {
require_once $filePath;
}
}
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Setup\Module\Di\Code\Scanner;
use Magento\Framework\ObjectManager\Code\Generator\Proxy as ProxyGenerator;
class XmlScanner implements ScannerInterface
{
/**
* @var \Magento\Setup\Module\Di\Compiler\Log\Log $log
*/
protected $_log;
/**
* @param \Magento\Setup\Module\Di\Compiler\Log\Log $log
*/
public function __construct(\Magento\Setup\Module\Di\Compiler\Log\Log $log)
{
$this->_log = $log;
}
/**
* Get array of class names
*
* @param array $files
* @return array
*/
public function collectEntities(array $files)
{
$virtualTypes = [];
$output = [];
$factoriesOutput = [];
foreach ($files as $file) {
$dom = new \DOMDocument();
$dom->load($file);
$xpath = new \DOMXPath($dom);
$xpath->registerNamespace("php", "http://php.net/xpath");
$xpath->registerPhpFunctions('preg_match');
$virtualTypeQuery = "//virtualType/@name";
foreach ($xpath->query($virtualTypeQuery) as $virtualNode) {
$virtualTypes[] = $virtualNode->nodeValue;
}
$regex = '/^(.*)\\\(.*)Proxy$/';
$query = "/config/preference[ php:functionString('preg_match', '{$regex}', @type) > 0]/@type | " .
"//argument[@xsi:type='object' and php:functionString('preg_match', '{$regex}', text()) > 0] |" .
"//item[@xsi:type='object' and php:functionString('preg_match', '{$regex}', text()) > 0] |" .
"/config/virtualType[ php:functionString('preg_match', '{$regex}', @type) > 0]/@type";
/** @var \DOMNode $node */
foreach ($xpath->query($query) as $node) {
$output[] = $node->nodeValue;
}
$factoriesOutput = array_merge($factoriesOutput, $this->scanFactories($xpath));
}
$output = array_unique($output);
$factoriesOutput = array_unique($factoriesOutput);
$factoriesOutput = array_diff($factoriesOutput, $virtualTypes);
return array_merge($this->_filterEntities($output), $factoriesOutput);
}
/**
* Scan factories from all di.xml and retrieve non virtual one
*
* @param \DOMXPath $domXpath
* @return array
*/
private function scanFactories(\DOMXPath $domXpath)
{
$output = [];
$regex = '/^(.*)Factory$/';
$query = "//argument[@xsi:type='object' and php:functionString('preg_match', '{$regex}', text()) > 0] |" .
"//item[@xsi:type='object' and php:functionString('preg_match', '{$regex}', text()) > 0]";
foreach ($domXpath->query($query) as $node) {
$output[] = $node->nodeValue;
}
return $output;
}
/**
* 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 (\RuntimeException $e) {
}
if (false === $isClassExists) {
if (class_exists($entityName) || interface_exists($entityName)) {
$filteredEntities[] = $className;
} else {
$this->_log->add(
\Magento\Setup\Module\Di\Compiler\Log\Log::CONFIGURATION_ERROR,
$className,
'Invalid proxy class for ' . substr($className, 0, -5)
);
}
}
}
return $filteredEntities;
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Setup\Module\Di\Compiler\Log;
class Log
{
const GENERATION_ERROR = 1;
const GENERATION_SUCCESS = 2;
const COMPILATION_ERROR = 3;
const CONFIGURATION_ERROR = 4;
/**
* Success log writer
*
* @var Writer\Console
*/
protected $_successWriter;
/**
* Error log writer
*
* @var Writer\Console
*/
protected $_errorWriter;
/**
* List of success log entries
*
* @var array
*/
protected $_successEntries = [];
/**
* List of error entries
*
* @var array
*/
protected $_errorEntries = [];
/**
* @param Writer\Console $successWriter
* @param Writer\Console $errorWriter
*/
public function __construct(Writer\Console $successWriter, Writer\Console $errorWriter)
{
$this->_successWriter = $successWriter;
$this->_errorWriter = $errorWriter;
$this->_successEntries[self::GENERATION_SUCCESS] = [];
$this->_errorEntries = [
self::CONFIGURATION_ERROR => [],
self::GENERATION_ERROR => [],
self::COMPILATION_ERROR => [],
];
}
/**
* Add log message
*
* @param string $type
* @param string $key
* @param string $message
* @return void
*/
public function add($type, $key, $message = '')
{
if (array_key_exists($type, $this->_successEntries)) {
$this->_successEntries[$type][$key][] = $message;
} else {
$this->_errorEntries[$type][$key][] = $message;
}
}
/**
* Write entries
*
* @return void
* @throws \Magento\Framework\Validator\Exception
*/
public function report()
{
$this->_successWriter->write($this->_successEntries);
$this->_errorWriter->write($this->_errorEntries);
//do not take into account empty items since they are initialized in constructor.
$errors = array_filter($this->_errorEntries);
if (count($errors) > 0) {
throw new \Magento\Framework\Validator\Exception(__('Error during compilation'));
}
}
/**
* Check whether error exists
*
* @return bool
*/
public function hasError()
{
foreach ($this->_errorEntries as $data) {
if (count($data)) {
return true;
}
}
return false;
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Setup\Module\Di\Compiler\Log\Writer;
use Magento\Setup\Module\Di\Compiler\Log\Log;
use Symfony\Component\Console\Output\OutputInterface;
class Console
{
/**
* Report messages by type
*
* @var array
*/
protected $_messages = [
Log::GENERATION_SUCCESS => 'Generated classes:',
Log::GENERATION_ERROR => 'Errors during class generation:',
Log::COMPILATION_ERROR => 'Errors during compilation:',
Log::CONFIGURATION_ERROR => 'Errors during configuration scanning:',
];
/**
* Console
*
* @var OutputInterface
*/
protected $console;
/**
* @param OutputInterface $output
*/
public function __construct(OutputInterface $output)
{
$this->console = $output;
}
/**
* Output log data
*
* @param array $data
* @return void
*/
public function write(array $data)
{
$errorsCount = 0;
foreach ($data as $type => $classes) {
if (!count($classes)) {
continue;
}
$this->console->writeln($this->getStartTag($type) . $this->_messages[$type] . $this->getEndTag($type));
foreach ($classes as $className => $messages) {
if (count($messages)) {
$this->console->writeln($this->getStartTag($type) . "\t" . $className . $this->getEndTag($type));
foreach ($messages as $message) {
if ($message) {
$this->console->writeln(
$this->getStartTag($type) . "\t\t" . $message . $this->getEndTag($type)
);
if ($type != Log::GENERATION_SUCCESS) {
$errorsCount++;
}
}
}
}
}
}
if ($errorsCount) {
$this->console->writeln('<error>' . 'Total Errors Count: ' . $errorsCount . '</error>');
}
}
/**
* Retrieve starting output tag
*
* @param string $type
* @return string
*/
private function getStartTag($type)
{
if ($type === Log::GENERATION_SUCCESS) {
return '<info>';
} else {
return '<error>';
}
}
/**
* Retrieve ending output tag
*
* @param string $type
* @return string
*/
private function getEndTag($type)
{
if ($type === Log::GENERATION_SUCCESS) {
return '</info>';
} else {
return '</error>';
}
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\Setup\Test\Unit\Module\Di\Code\Generator;
use Magento\Framework\App\Cache\Manager;
use Magento\Framework\App\Interception\Cache\CompiledConfig;
use Magento\Framework\Interception\Config\Config;
use Magento\Framework\ObjectManager\InterceptableValidator;
use Magento\Setup\Module\Di\Code\Generator\InterceptionConfigurationBuilder;
use Magento\Setup\Module\Di\Code\Generator\PluginList;
use Magento\Setup\Module\Di\Code\Reader\Type;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
class InterceptionConfigurationBuilderTest extends TestCase
{
/**
* @var InterceptionConfigurationBuilder
*/
protected $model;
/**
* @var MockObject
*/
protected $interceptionConfig;
/**
* @var MockObject
*/
protected $pluginList;
/**
* @var MockObject
*/
protected $typeReader;
/**
* @var MockObject
*/
private $cacheManager;
/**
* @var InterceptableValidator|MockObject
*/
private $interceptableValidator;
protected function setUp(): void
{
$this->interceptionConfig =
$this->createPartialMock(Config::class, ['hasPlugins']);
$this->pluginList = $this->createPartialMock(
PluginList::class,
['setInterceptedClasses', 'setScopePriorityScheme', 'getPluginsConfig']
);
$this->cacheManager = $this->createMock(Manager::class);
$this->interceptableValidator =
$this->createMock(InterceptableValidator::class);
$this->typeReader = $this->createPartialMock(Type::class, ['isConcrete']);
$this->model = new InterceptionConfigurationBuilder(
$this->interceptionConfig,
$this->pluginList,
$this->typeReader,
$this->cacheManager,
$this->interceptableValidator
);
}
/**
* @dataProvider getInterceptionConfigurationDataProvider
*/
public function testGetInterceptionConfiguration($plugins)
{
$definedClasses = ['Class1'];
$this->interceptionConfig->expects($this->once())
->method('hasPlugins')
->with('Class1')
->willReturn(true);
$this->typeReader->expects($this->any())
->method('isConcrete')
->willReturnMap([
['Class1', true],
['instance', true],
]);
$this->interceptableValidator->expects($this->any())
->method('validate')
->with('Class1')
->willReturn(true);
$this->cacheManager->expects($this->once())
->method('setEnabled')
->with([CompiledConfig::TYPE_IDENTIFIER], true);
$this->pluginList->expects($this->once())
->method('setInterceptedClasses')
->with($definedClasses);
$this->pluginList->expects($this->once())
->method('setScopePriorityScheme')
->with(['global', 'areaCode']);
$this->pluginList->expects($this->once())
->method('getPluginsConfig')
->willReturn(['instance' => $plugins]);
$this->model->addAreaCode('areaCode');
$this->model->getInterceptionConfiguration($definedClasses);
}
/**
* @return array
*/
public function getInterceptionConfigurationDataProvider()
{
return [
[null],
[['plugin' => ['instance' => 'someinstance']]],
[['plugin' => ['instance' => 'someinstance'], 'plugin2' => ['instance' => 'someinstance']]]
];
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\Setup\Test\Unit\Module\Di\Code\Reader;
use Magento\Framework\Code\Reader\ClassReader;
use Magento\Setup\Module\Di\Code\Reader\ClassReaderDecorator;
use Magento\Setup\Module\Di\Compiler\ConstructorArgument;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
class ClassReaderDecoratorTest extends TestCase
{
/**
* @var ClassReaderDecorator
*/
private $model;
/**
* @var ClassReader|MockObject
*/
private $classReaderMock;
protected function setUp(): void
{
$this->classReaderMock = $this->getMockBuilder(ClassReader::class)
->disableOriginalConstructor()
->setMethods([])
->getMock();
$this->model = new ClassReaderDecorator($this->classReaderMock);
}
/**
* @param $expectation
* @param $className
* @param $willReturn
* @dataProvider getConstructorDataProvider
*/
public function testGetConstructor($expectation, $className, $willReturn)
{
$this->classReaderMock->expects($this->once())
->method('getConstructor')
->with($className)
->willReturn($willReturn);
$this->assertEquals(
$expectation,
$this->model->getConstructor($className)
);
}
/**
* @return array
*/
public function getConstructorDataProvider()
{
return [
[null, 'null', null],
[
[new ConstructorArgument(['name', 'type', 'isRequired', 'defaultValue'])],
'array',
[['name', 'type', 'isRequired', 'defaultValue']]
]
];
}
public function testGetParents()
{
$stringArray = ['Parent_Class_Name1', 'Interface_1'];
$this->classReaderMock->expects($this->once())
->method('getParents')
->with('Child_Class_Name')
->willReturn($stringArray);
$this->assertEquals($stringArray, $this->model->getParents('Child_Class_Name'));
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\Setup\Test\Unit\Module\Di\Code\Reader;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Setup\Module\Di\Code\Reader\ClassesScanner;
use PHPUnit\Framework\TestCase;
class ClassesScannerTest extends TestCase
{
/**
* @var ClassesScanner
*/
private $model;
/**
* the /var/generation directory realpath
*
* @var string
*/
private $generation;
protected function setUp(): void
{
$this->generation = realpath(__DIR__ . '/../../_files/var/generation');
$mock = $this->getMockBuilder(DirectoryList::class)
->disableOriginalConstructor()
->setMethods(
['getPath']
)->getMock();
$mock->method('getPath')->willReturn($this->generation);
$this->model = new ClassesScanner([], $mock);
}
public function testGetList()
{
$pathToScan = str_replace('\\', '/', realpath(__DIR__ . '/../../') . '/_files/app/code/Magento/SomeModule');
$actual = $this->model->getList($pathToScan);
$this->assertIsArray($actual);
$this->assertCount(6, $actual);
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\Setup\Test\Unit\Module\Di\Code\Reader;
use Magento\Setup\Module\Di\Code\Reader\FileClassScanner;
use Magento\Setup\Module\Di\Code\Reader\InvalidFileException;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
class FileClassScannerTest extends TestCase
{
public function testInvalidFileThrowsException()
{
$this->expectException(InvalidFileException::class);
new FileClassScanner('');
}
public function testEmptyArrayForFileWithoutNamespaceOrClass()
{
$scanner = $this->getScannerMockObject();
$scanner->expects(self::once())
->method('getFileContents')
->willReturn(
<<<PHP
<?php
echo 'hello world';
if (class_exists('some_class')) {
\$object = new some_class();
}
PHP
);
/** @var $scanner FileClassScanner */
$result = $scanner->getClassName();
self::assertEmpty($result);
}
public function testGetClassName()
{
$scanner = $this->getScannerMockObject();
$scanner->expects(self::once())
->method('getFileContents')
->willReturn(
<<<PHP
<?php
class ThisIsATest {
}
PHP
);
/** @var $scanner FileClassScanner */
$result = $scanner->getClassName();
self::assertEquals('ThisIsATest', $result);
}
public function testGetClassNameAndSingleNamespace()
{
$scanner = $this->getScannerMockObject();
$scanner->expects(self::once())
->method('getFileContents')
->willReturn(
<<<PHP
<?php
namespace NS;
class ThisIsMyTest {
}
PHP
);
/** @var $scanner FileClassScanner */
$result = $scanner->getClassName();
self::assertEquals('NS\ThisIsMyTest', $result);
}
public function testGetClassNameAndMultiNamespace()
{
$scanner = $this->getScannerMockObject();
$scanner->expects(self::once())
->method('getFileContents')
->willReturn(
<<<PHP
<?php
namespace This\Is\My\Ns;
class ThisIsMyTest {
public function __construct()
{
\This\Is\Another\Ns::class;
}
public function test()
{
}
}
PHP
);
/** @var $scanner FileClassScanner */
$result = $scanner->getClassName();
self::assertEquals('This\Is\My\Ns\ThisIsMyTest', $result);
}
public function testGetMultiClassNameAndMultiNamespace()
{
$scanner = $this->getScannerMockObject();
$scanner->expects(self::once())
->method('getFileContents')
->willReturn(
<<<PHP
<?php
namespace This\Is\My\Ns;
class ThisIsMyTest {
public function __construct()
{
\$this->get(\This\Is\Another\Ns::class)->method();
self:: class;
}
public function test()
{
}
}
class ThisIsForBreaking {
}
PHP
);
/** @var $scanner FileClassScanner */
$result = $scanner->getClassName();
// only a single class should be in the file
self::assertEquals('This\Is\My\Ns\ThisIsMyTest', $result);
}
public function testBracketedNamespacesAndClasses()
{
$scanner = $this->getScannerMockObject();
$scanner->expects(self::once())
->method('getFileContents')
->willReturn(
<<<PHP
<?php
namespace This\Is\My\Ns {
class ThisIsMyTest
{
public function __construct()
{
\This\Is\Another\Ns::class;
self:: class;
}
}
class ThisIsForBreaking
{
}
}
namespace This\Is\Not\My\Ns {
class ThisIsNotMyTest
{
}
}
PHP
);
/** @var $scanner FileClassScanner */
$result = $scanner->getClassName();
// only a single class should in the file
self::assertEquals('This\Is\My\Ns\ThisIsMyTest', $result);
}
public function testMultipleClassKeywordsInMiddleOfFileWithStringVariableParsing()
{
$scanner = $this->getScannerMockObject();
$scanner->expects(self::once())
->method('getFileContents')
->willReturn(
<<<'PHP'
<?php
namespace This\Is\My\Ns;
use stdClass;
class ThisIsMyTest
{
protected function firstMethod()
{
$test = 1;
$testString = "foo {$test}";
$className = stdClass::class;
$testString2 = "bar {$test}";
}
protected function secondMethod()
{
$this->doMethod(stdClass::class)->runAction();
}
}
PHP
);
/* @var $scanner FileClassScanner */
$result = $scanner->getClassName();
self::assertEquals('This\Is\My\Ns\ThisIsMyTest', $result);
}
public function testInvalidPHPCodeThrowsExceptionWhenCannotDetermineBraceOrSemiColon()
{
$this->expectException(InvalidFileException::class);
$scanner = $this->getScannerMockObject();
$scanner->expects(self::once())
->method('getFileContents')
->willReturn(
<<<PHP
<?php
namespace This\Is\My\Ns
class ThisIsMyTest
{
}
PHP
);
/** @var $scanner FileClassScanner */
$scanner->getClassName();
}
/**
* Checks a case when file with class also contains `class_alias` function for backward compatibility.
*/
public function testFileContainsClassAliasFunction(): void
{
$scanner = $this->getScannerMockObject();
$scanner->expects(self::once())
->method('getFileContents')
->willReturn(
<<<'PHP'
<?php
namespace This\Is\My\Ns;
use stdClass;
class ThisIsMyTest
{
public function doMethod()
{
$className = stdClass::class;
return $className;
}
public function secondMethod()
{
$this->doMethod();
}
}
class_alias(\This\Is\My\Ns\ThisIsMyTest::class, stdClass::class);
PHP
);
/* @var $scanner FileClassScanner */
$result = $scanner->getClassName();
self::assertEquals('This\Is\My\Ns\ThisIsMyTest', $result);
}
/**
* Checks a case when file with class also contains `class_exists` function.
*/
public function testFileContainsClassExistsFunction(): void
{
$scanner = $this->getScannerMockObject();
$scanner->expects(self::once())
->method('getFileContents')
->willReturn(
<<<PHP
<?php
namespace This\Is\My\Ns;
if (false) {
class ThisIsMyTest {}
}
class_exists(\This\Is\My\Ns\ThisIsMySecondTest::class);
trigger_error('This class is does not supported');
PHP
);
/* @var $scanner FileClassScanner */
$result = $scanner->getClassName();
self::assertEmpty($result);
}
/**
* Creates file class scanner mock object.
*
* @return MockObject
*/
private function getScannerMockObject(): MockObject
{
$scanner = $this->getMockBuilder(FileClassScanner::class)
->disableOriginalConstructor()
->setMethods(['getFileContents'])
->getMock();
return $scanner;
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\Setup\Test\Unit\Module\Di\Code\Reader;
use Magento\Setup\Module\Di\Code\Reader\FileScanner;
use PHPUnit\Framework\TestCase;
class FileScannerTest extends TestCase
{
/**
* @var FileScanner
*/
private $object;
protected function setUp(): void
{
$this->object = new FileScanner(
__DIR__ . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'classes.php'
);
}
public function testGetClassesReturnsAllClassesAndInterfacesDeclaredInFile()
{
$classes = [
'My\NamespaceA\InterfaceA',
'My\NamespaceA\ClassA',
'My\NamespaceB\InterfaceB',
'My\NamespaceB\ClassB',
];
$this->assertCount(4, $this->object->getClasses());
foreach ($this->object->getClasses() as $key => $class) {
$this->assertEquals($classes[$key], $class->getName());
}
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\Setup\Test\Unit\Module\Di\Code\Reader\InstancesNamesList;
use Magento\Setup\Module\Di\Code\Reader\ClassesScanner;
use Magento\Setup\Module\Di\Code\Reader\ClassReaderDecorator;
use Magento\Setup\Module\Di\Code\Reader\Decorator\Area;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
class AreaTest extends TestCase
{
/**
* @var ClassesScanner|MockObject
*/
private $classesScannerMock;
/**
* @var ClassReaderDecorator|MockObject
*/
private $classReaderDecoratorMock;
/**
* @var Area
*/
private $model;
protected function setUp(): void
{
$this->classesScannerMock = $this->getMockBuilder(ClassesScanner::class)
->disableOriginalConstructor()
->setMethods(['getList'])
->getMock();
$this->classReaderDecoratorMock = $this->getMockBuilder(
ClassReaderDecorator::class
)
->disableOriginalConstructor()
->setMethods(['getConstructor'])
->getMock();
$this->model = new Area(
$this->classesScannerMock,
$this->classReaderDecoratorMock
);
}
public function testGetList()
{
$path = '/tmp/test';
$classes = ['NameSpace1\ClassName1', 'NameSpace1\ClassName2'];
$this->classesScannerMock->expects($this->once())
->method('getList')
->with($path)
->willReturn($classes);
$constructors = [
['NameSpace1\ClassName1', ['arg1' => 'NameSpace1\class5', 'arg2' => 'NameSpace1\ClassName4']],
['NameSpace1\ClassName2', ['arg1' => 'NameSpace1\class5']]
];
$this->classReaderDecoratorMock->expects($this->exactly(count($classes)))
->method('getConstructor')
->willReturnMap($constructors);
$result = $this->model->getList($path);
$expected = [
$classes[0] => $constructors[0][1],
$classes[1] => $constructors[1][1]
];
$this->assertEquals($result, $expected);
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\Setup\Test\Unit\Module\Di\Code\Reader\InstancesNamesList;
use Magento\Framework\Code\Reader\ClassReader;
use Magento\Framework\Code\Validator;
use Magento\Framework\Exception\ValidatorException;
use Magento\Framework\Phrase;
use Magento\Setup\Module\Di\Code\Reader\ClassesScanner;
use Magento\Setup\Module\Di\Code\Reader\Decorator\Directory;
use Magento\Setup\Module\Di\Compiler\Log\Log;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
/**
* Test for Directory Decorator
*/
class DirectoryTest extends TestCase
{
/**
* @var ClassesScanner|MockObject
*/
private $classesScanner;
/**
* @var ClassReader|MockObject
*/
private $classReaderMock;
/**
* @var Directory
*/
private $model;
/**
* @var Validator|MockObject
*/
private $validatorMock;
/**
* @var Log|MockObject
*/
private $logMock;
/**
* @inheritdoc
*/
protected function setUp(): void
{
$this->logMock = $this->getMockBuilder(Log::class)
->disableOriginalConstructor()
->setMethods(['add'])
->getMock();
$this->classesScanner = $this->getMockBuilder(ClassesScanner::class)
->disableOriginalConstructor()
->setMethods(['getList'])
->getMock();
$this->classReaderMock = $this->getMockBuilder(ClassReader::class)
->disableOriginalConstructor()
->setMethods(['getParents'])
->getMock();
$this->validatorMock = $this->getMockBuilder(Validator::class)
->disableOriginalConstructor()
->setMethods(['validate'])
->getMock();
$this->model = new Directory(
$this->logMock,
$this->classReaderMock,
$this->classesScanner,
$this->validatorMock,
'/generated/code'
);
}
public function testGetList()
{
$path = '/tmp/test';
$classes = ['NameSpace1\ClassName1', 'NameSpace1\ClassName2'];
$this->classesScanner->expects($this->once())
->method('getList')
->with($path)
->willReturn($classes);
$parents = [
['NameSpace1\ClassName1', ['Parent_Class_Name', 'Interface_1', 'Interface_2']],
['NameSpace1\ClassName2', ['Parent_Class_Name', 'Interface_1', 'Interface_2']]
];
$this->classReaderMock->expects(
$this->exactly(
count($classes)
)
)
->method('getParents')
->willReturnMap(
$parents
);
$this->logMock->expects($this->never())
->method('add');
$this->validatorMock->expects($this->exactly(count($classes)))
->method('validate');
$this->model->getList($path);
$result = $this->model->getRelations();
$expected = [
$classes[0] => $parents[0][1],
$classes[1] => $parents[1][1]
];
$this->assertEquals($result, $expected);
}
public function testGetListNoValidation()
{
$path = '/generated/code';
$classes = ['NameSpace1\ClassName1', 'NameSpace1\ClassName2'];
$this->classesScanner->expects($this->once())
->method('getList')
->with($path)
->willReturn($classes);
$parents = [
['NameSpace1\ClassName1', ['Parent_Class_Name', 'Interface_1', 'Interface_2']],
['NameSpace1\ClassName2', ['Parent_Class_Name', 'Interface_1', 'Interface_2']]
];
$this->classReaderMock->expects($this->exactly(count($classes)))
->method('getParents')
->willReturnMap(
$parents
);
$this->logMock->expects($this->never())
->method('add');
$this->validatorMock->expects($this->never())
->method('validate');
$this->model->getList($path);
$result = $this->model->getRelations();
$expected = [
$classes[0] => $parents[0][1],
$classes[1] => $parents[1][1]
];
$this->assertEquals($result, $expected);
}
/**
* @dataProvider getListExceptionDataProvider
*
* @param $exception
*/
public function testGetListException(\Exception $exception)
{
$path = '/tmp/test';
$classes = ['NameSpace1\ClassName1'];
$this->classesScanner->expects($this->once())
->method('getList')
->with($path)
->willReturn($classes);
$this->logMock->expects($this->once())
->method('add')
->with(Log::COMPILATION_ERROR, $classes[0], $exception->getMessage());
$this->validatorMock->expects($this->exactly(count($classes)))
->method('validate')
->willThrowException(
$exception
);
$this->model->getList($path);
$result = $this->model->getRelations();
$this->assertEquals($result, []);
}
/**
* DataProvider for test testGetListException
*
* @return array
*/
public function getListExceptionDataProvider()
{
return [
[new ValidatorException(new Phrase('Not Valid!'))],
[new \ReflectionException('Not Valid!')]
];
}
/**
* @inheritdoc
*/
protected function tearDown(): void
{
restore_error_handler();
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\Setup\Test\Unit\Module\Di\Code\Reader\InstancesNamesList;
use Magento\Framework\Code\Reader\ClassReader;
use Magento\Framework\Code\Validator;
use Magento\Framework\Code\Validator\ConstructorIntegrity;
use Magento\Framework\Exception\ValidatorException;
use Magento\Framework\Phrase;
use Magento\Setup\Module\Di\Code\Reader\ClassesScanner;
use Magento\Setup\Module\Di\Code\Reader\Decorator\Directory;
use Magento\Setup\Module\Di\Code\Reader\Decorator\Interceptions;
use Magento\Setup\Module\Di\Compiler\Log\Log;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
class InterceptionsTest extends TestCase
{
/**
* @var ClassesScanner|MockObject
*/
private $classesScanner;
/**
* @var ClassReader|MockObject
*/
private $classReaderMock;
/**
* @var Directory
*/
private $model;
/**
* @var Validator|MockObject
*/
private $validatorMock;
/**
* @var Log|MockObject
*/
private $logMock;
/**
* @inheritdoc
*/
protected function setUp(): void
{
$this->logMock = $this->getMockBuilder(Log::class)
->disableOriginalConstructor()
->setMethods(['add', 'report'])
->getMock();
$this->classesScanner = $this->getMockBuilder(ClassesScanner::class)
->disableOriginalConstructor()
->setMethods(['getList'])
->getMock();
$this->classReaderMock = $this->getMockBuilder(ClassReader::class)
->disableOriginalConstructor()
->setMethods(['getParents'])
->getMock();
$this->validatorMock = $this->getMockBuilder(Validator::class)
->disableOriginalConstructor()
->setMethods(['validate', 'add'])
->getMock();
$this->model = new Interceptions(
$this->classesScanner,
$this->classReaderMock,
$this->validatorMock,
new ConstructorIntegrity(),
$this->logMock
);
}
public function testGetList()
{
$path = '/tmp/test';
$classes = ['NameSpace1\ClassName1', 'NameSpace1\ClassName2'];
$this->classesScanner->expects($this->once())
->method('getList')
->with($path)
->willReturn($classes);
$this->logMock->expects($this->never())
->method('add');
$this->logMock->expects($this->once())->method('report');
$this->validatorMock->expects($this->exactly(count($classes)))
->method('validate');
$result = $this->model->getList($path);
$this->assertEquals($result, $classes);
}
public function testGetListNoValidation()
{
$path = '/generated/code';
$classes = ['NameSpace1\ClassName1', 'NameSpace1\ClassName2'];
$this->classesScanner->expects($this->once())
->method('getList')
->with($path)
->willReturn($classes);
$this->logMock->expects($this->never())
->method('add');
$this->validatorMock->expects($this->never())
->method('validate');
$this->logMock->expects($this->once())->method('report');
$result = $this->model->getList($path);
$this->assertEquals($result, $classes);
}
/**
* @dataProvider getListExceptionDataProvider
*
* @param $exception
*/
public function testGetListException(\Exception $exception)
{
$path = '/tmp/test';
$classes = ['NameSpace1\ClassName1'];
$this->classesScanner->expects($this->once())
->method('getList')
->with($path)
->willReturn($classes);
$this->logMock->expects($this->once())
->method('add')
->with(Log::COMPILATION_ERROR, $classes[0], $exception->getMessage());
$this->validatorMock->expects($this->exactly(count($classes)))
->method('validate')
->willThrowException(
$exception
);
$this->logMock->expects($this->once())->method('report');
$result = $this->model->getList($path);
$this->assertEquals($result, []);
}
/**
* DataProvider for test testGetListException
*
* @return array
*/
public function getListExceptionDataProvider()
{
return [
[new ValidatorException(new Phrase('Not Valid!'))],
[new \ReflectionException('Not Valid!')]
];
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
// @codingStandardsIgnoreStart
namespace My\NamespaceA;
interface InterfaceA
{
}
class ClassA
{
}
namespace My\NamespaceB;
interface InterfaceB
{
}
class ClassB
{
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\Setup\Test\Unit\Module\Di\Code\Scanner;
use Magento\Setup\Module\Di\Code\Scanner\ArrayScanner;
use PHPUnit\Framework\TestCase;
class ArrayScannerTest extends TestCase
{
/**
* @var ArrayScanner
*/
protected $_model;
/**
* @var string
*/
protected $_testDir;
protected function setUp(): void
{
$this->_model = new ArrayScanner();
$this->_testDir = str_replace('\\', '/', realpath(__DIR__ . '/../../') . '/_files');
}
public function testCollectEntities()
{
$actual = $this->_model->collectEntities([$this->_testDir . '/additional.php']);
$expected = ['Some_Model_Proxy', 'Some_Model_EntityFactory'];
$this->assertEquals($expected, $actual);
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\Setup\Test\Unit\Module\Di\Code\Scanner;
use Magento\Setup\Module\Di\Code\Scanner\CompositeScanner;
use Magento\Setup\Module\Di\Code\Scanner\ScannerInterface;
use PHPUnit\Framework\TestCase;
class CompositeScannerTest extends TestCase
{
/**
* @var CompositeScanner
*/
protected $_model;
protected function setUp(): void
{
$this->_model = new CompositeScanner();
}
public function testScan()
{
$phpFiles = ['one/file/php', 'two/file/php'];
$configFiles = ['one/file/config', 'two/file/config'];
$files = ['php' => $phpFiles, 'config' => $configFiles];
$scannerPhp = $this->getMockForAbstractClass(ScannerInterface::class);
$scannerXml = $this->getMockForAbstractClass(ScannerInterface::class);
$scannerPhpExpected = ['Model_OneProxy', 'Model_TwoFactory'];
$scannerXmlExpected = ['Model_OneProxy', 'Model_ThreeFactory'];
$scannerPhp->expects(
$this->once()
)->method(
'collectEntities'
)->with(
$phpFiles
)->willReturn(
$scannerPhpExpected
);
$scannerXml->expects(
$this->once()
)->method(
'collectEntities'
)->with(
$configFiles
)->willReturn(
$scannerXmlExpected
);
$this->_model->addChild($scannerPhp, 'php');
$this->_model->addChild($scannerXml, 'config');
$actual = $this->_model->collectEntities($files);
$expected = [$scannerPhpExpected, $scannerXmlExpected];
$this->assertEquals($expected, array_values($actual));
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\Setup\Test\Unit\Module\Di\Code\Scanner;
use Magento\Framework\App\AreaList;
use Magento\Framework\App\Config\FileResolver;
use Magento\Framework\Config\FileIterator;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
use Magento\Setup\Module\Di\Code\Scanner\ConfigurationScanner;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
class ConfigurationScannerTest extends TestCase
{
/**
* @var FileResolver|MockObject
*/
private $fileResolverMock;
/**
* @var AreaList|MockObject
*/
private $areaListMock;
/**
* @var ConfigurationScanner
*/
private $model;
protected function setUp(): void
{
$this->fileResolverMock = $this->getMockBuilder(FileResolver::class)
->disableOriginalConstructor()
->getMock();
$this->areaListMock = $this->getMockBuilder(AreaList::class)
->disableOriginalConstructor()
->getMock();
$objectManagerHelper = new ObjectManager($this);
$this->model = $objectManagerHelper->getObject(
ConfigurationScanner::class,
[
'fileResolver' => $this->fileResolverMock,
'areaList' => $this->areaListMock,
]
);
}
public function testScan()
{
$codes = ['code1', 'code2'];
$iteratorMock = $this->getMockBuilder(FileIterator::class)
->disableOriginalConstructor()
->getMock();
$this->areaListMock->expects($this->once())
->method('getCodes')
->willReturn($codes);
$counts = count($codes) + 2;
$this->fileResolverMock->expects($this->exactly($counts))
->method('get')
->willReturn($iteratorMock);
$files = ['file1' => 'onefile', 'file2' => 'anotherfile'];
$iteratorMock->expects($this->exactly($counts))
->method('toArray')
->willReturn($files);
$this->assertEquals(array_keys($files), $this->model->scan('di.xml'));
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\Setup\Test\Unit\Module\Di\Code\Scanner;
use Magento\Setup\Module\Di\Code\Scanner\DirectoryScanner;
use PHPUnit\Framework\TestCase;
class DirectoryScannerTest extends TestCase
{
/**
* @var DirectoryScanner
*/
protected $_model;
/**
* @var string
*/
protected $_testDir;
protected function setUp(): void
{
$this->_model = new DirectoryScanner();
$this->_testDir = str_replace('\\', '/', realpath(__DIR__ . '/../../') . '/_files');
}
public function testScan()
{
$filePatterns = [
'php' => '/.*\.php$/',
'etc' => '/\/app\/etc\/.*\.xml$/',
'config' => '/\/etc\/(config([a-z0-9\.]*)?|adminhtml\/system)\.xml$/',
'view' => '/\/view\/[a-z0-9A-Z\/\.]*\.xml$/',
'design' => '/\/app\/design\/[a-z0-9A-Z\/\.]*\.xml$/',
];
$actual = $this->_model->scan($this->_testDir, $filePatterns);
$expected = [
'php' => [
$this->_testDir . '/additional.php',
$this->_testDir . '/app/bootstrap.php',
$this->_testDir . '/app/code/Magento/SomeModule/Helper/Test.php',
$this->_testDir . '/app/code/Magento/SomeModule/Model/Test.php',
],
'config' => [
$this->_testDir . '/app/code/Magento/SomeModule/etc/adminhtml/system.xml',
$this->_testDir . '/app/code/Magento/SomeModule/etc/config.xml',
],
'view' => [$this->_testDir . '/app/code/Magento/SomeModule/view/frontend/default.xml'],
'design' => [$this->_testDir . '/app/design/adminhtml/Magento/backend/layout.xml'],
'etc' => [$this->_testDir . '/app/etc/additional.xml', $this->_testDir . '/app/etc/config.xml'],
];
$this->assertEquals(sort($expected['php']), sort($actual['php']), 'Incorrect php files list');
$this->assertEquals(sort($expected['config']), sort($actual['config']), 'Incorrect config files list');
$this->assertEquals(sort($expected['view']), sort($actual['view']), 'Incorrect view files list');
$this->assertEquals(sort($expected['design']), sort($actual['design']), 'Incorrect design files list');
$this->assertEquals(sort($expected['etc']), sort($actual['etc']), 'Incorrect etc files list');
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\Setup\Test\Unit\Module\Di\Code\Scanner;
use Magento\Framework\Reflection\TypeProcessor;
require_once __DIR__ . '/../../_files/app/code/Magento/SomeModule/Helper/Test.php';
require_once __DIR__ . '/../../_files/app/code/Magento/SomeModule/ElementFactory.php';
require_once __DIR__ . '/../../_files/app/code/Magento/SomeModule/Model/DoubleColon.php';
require_once __DIR__ . '/../../_files/app/code/Magento/SomeModule/Api/Data/SomeInterface.php';
require_once __DIR__ . '/../../_files/app/code/Magento/SomeModule/Model/StubWithAnonymousClass.php';
use Magento\Setup\Module\Di\Code\Scanner\PhpScanner;
use Magento\Setup\Module\Di\Compiler\Log\Log;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
class PhpScannerTest extends TestCase
{
/**
* @var PhpScanner
*/
private $scanner;
/**
* @var string
*/
private $testDir;
/**
* @var Log|MockObject
*/
private $log;
protected function setUp(): void
{
$this->log = $this->createMock(Log::class);
$this->scanner = new PhpScanner($this->log, new TypeProcessor());
$this->testDir = str_replace('\\', '/', realpath(__DIR__ . '/../../') . '/_files');
}
public function testCollectEntities()
{
$testFiles = [
$this->testDir . '/app/code/Magento/SomeModule/Helper/Test.php',
$this->testDir . '/app/code/Magento/SomeModule/Model/DoubleColon.php',
$this->testDir . '/app/code/Magento/SomeModule/Api/Data/SomeInterface.php',
$this->testDir . '/app/code/Magento/SomeModule/Model/StubWithAnonymousClass.php',
];
$this->log->expects(self::at(0))
->method('add')
->with(
4,
'Magento\SomeModule\Module\Factory',
'Invalid Factory for nonexistent class Magento\SomeModule\Module in file ' . $testFiles[0]
);
$this->log->expects(self::at(1))
->method('add')
->with(
4,
'Magento\SomeModule\Element\Factory',
'Invalid Factory declaration for class Magento\SomeModule\Element in file ' . $testFiles[0]
);
$result = $this->scanner->collectEntities($testFiles);
self::assertEquals(
['\\' . \Magento\Eav\Api\Data\AttributeExtensionInterface::class],
$result
);
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\Setup\Test\Unit\Module\Di\Code\Scanner;
use Magento\Setup\Module\Di\Code\Scanner\PluginScanner;
use PHPUnit\Framework\TestCase;
class PluginScannerTest extends TestCase
{
/**
* @var PluginScanner
*/
private $model;
/**
* @var string[]
*/
private $testFiles;
/**
* @inheritDoc
*/
protected function setUp(): void
{
$this->model = new PluginScanner();
$testDir = str_replace('\\', '/', realpath(__DIR__ . '/../../') . '/_files');
$this->testFiles = [
$testDir . '/app/code/Magento/SomeModule/etc/di.xml',
$testDir . '/app/etc/di/config.xml',
];
}
protected function tearDown(): void
{
unset($this->model);
}
public function testCollectEntities()
{
$actual = $this->model->collectEntities($this->testFiles);
$expected = [\Magento\Framework\App\Cache\TagPlugin::class, \Magento\Store\Model\Action\Plugin::class];
$this->assertEquals($expected, $actual);
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\Setup\Test\Unit\Module\Di\Code\Scanner;
use Magento\Setup\Module\Di\Code\Scanner\ServiceDataAttributesScanner;
use PHPUnit\Framework\TestCase;
class ServiceDataAttributesScannerTest extends TestCase
{
/**
* @var ServiceDataAttributesScanner
*/
protected $model;
/**
* @var string
*/
protected $testFile;
protected function setUp(): void
{
$this->model = new ServiceDataAttributesScanner();
$this->testFile = str_replace('\\', '/', realpath(__DIR__ . '/../../') . '/_files/extension_attributes.xml');
}
public function testCollectEntities()
{
$files = [$this->testFile];
$expectedResult = [
\Magento\Sales\Api\Data\OrderExtensionInterface::class,
\Magento\Sales\Api\Data\OrderExtension::class,
\Magento\Sales\Api\Data\OrderItemExtensionInterface::class,
\Magento\Sales\Api\Data\OrderItemExtension::class,
];
$this->assertSame($expectedResult, $this->model->collectEntities($files));
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\Setup\Test\Unit\Module\Di\Code\Scanner;
use Magento\Setup\Module\Di\Code\Scanner\XmlInterceptorScanner;
use PHPUnit\Framework\TestCase;
class XmlInterceptorScannerTest extends TestCase
{
/**
* @var XmlInterceptorScanner
*/
protected $_model;
/**
* @var string
*/
protected $_testDir;
/**
* @var array
*/
protected $_testFiles = [];
protected function setUp(): void
{
$this->_model = new XmlInterceptorScanner();
$this->_testDir = str_replace('\\', '/', realpath(__DIR__ . '/../../') . '/_files');
$this->_testFiles = [
$this->_testDir . '/app/code/Magento/SomeModule/etc/di.xml',
$this->_testDir . '/app/etc/di/config.xml',
];
}
public function testCollectEntities()
{
$actual = $this->_model->collectEntities($this->_testFiles);
$expected = [
\Magento\Framework\App\Cache\Interceptor::class,
\Magento\Framework\App\Action\Context\Interceptor::class,
];
$this->assertEquals($expected, $actual);
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\Setup\Test\Unit\Module\Di\Code\Scanner;
use Magento\Setup\Module\Di\Code\Scanner\XmlScanner;
use Magento\Setup\Module\Di\Compiler\Log\Log;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
class XmlScannerTest extends TestCase
{
/**
* @var XmlScanner
*/
protected $_model;
/**
* @var MockObject
*/
protected $_logMock;
/**
* @var array
*/
protected $_testFiles = [];
protected function setUp(): void
{
$this->_model = new XmlScanner(
$this->_logMock = $this->createMock(Log::class)
);
$testDir = __DIR__ . '/../../' . '/_files';
$this->_testFiles = [
$testDir . '/app/code/Magento/SomeModule/etc/adminhtml/system.xml',
$testDir . '/app/code/Magento/SomeModule/etc/di.xml',
$testDir . '/app/code/Magento/SomeModule/view/frontend/default.xml',
];
}
public function testCollectEntities()
{
$className = 'Magento\Store\Model\Config\Invalidator\Proxy';
$this->_logMock->expects(
$this->at(0)
)->method(
'add'
)->with(
4,
$className,
'Invalid proxy class for ' . substr($className, 0, -5)
);
$this->_logMock->expects(
$this->at(1)
)->method(
'add'
)->with(
4,
'\Magento\SomeModule\Model\Element\Proxy',
'Invalid proxy class for ' . substr('\Magento\SomeModule\Model\Element\Proxy', 0, -5)
);
$this->_logMock->expects(
$this->at(2)
)->method(
'add'
)->with(
4,
'\Magento\SomeModule\Model\Nested\Element\Proxy',
'Invalid proxy class for ' . substr('\Magento\SomeModule\Model\Nested\Element\Proxy', 0, -5)
);
$actual = $this->_model->collectEntities($this->_testFiles);
$expected = [];
$this->assertEquals($expected, $actual);
}
}
<?php
/**
*
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\SomeModule\Api\Data;
use Magento\Framework\Api\CustomAttributesDataInterface;
interface SomeInterface extends CustomAttributesDataInterface
{
/**
* @return \Magento\Eav\Api\Data\AttributeExtensionInterface|null
*/
public function getExtensionAttributes();
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\SomeModule;
class Element
{
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\SomeModule;
use Magento\Framework\ObjectManagerInterface;
require_once __DIR__ . '/Element.php';
class ElementFactory
{
/**
* @var ObjectManagerInterface
*/
protected $_objectManager;
/**
* @param ObjectManagerInterface $objectManager
*/
public function __construct(ObjectManagerInterface $objectManager)
{
$this->_objectManager = $objectManager;
}
/**
* @param string $className
* @param array $data
* @return mixed
*/
public function create($className, array $data = [])
{
$instance = $this->_objectManager->create($className, $data);
return $instance;
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\SomeModule\Helper;
use Magento\SomeModule\ElementFactory;
/**
* @SuppressWarnings(PHPMD.ConstructorWithNameAsEnclosingClass)
*/
class Test
{
/**
* @var \Magento\SomeModule\ElementFactory\Proxy
*/
protected $_factory;
/**
* @var \Magento\SomeModule\Element\Factory
*/
protected $_elementFactory;
/**
* @var ElementFactory
*/
protected $_newElementFactory;
/**
* Test constructor.
* @param \Magento\SomeModule\Module\Factory $factory
* @param \Magento\SomeModule\Element\Factory $elementFactory
* @param ElementFactory $rightElementFactory
*/
public function __construct(
\Magento\SomeModule\Module\Factory $factory,
\Magento\SomeModule\Element\Factory $elementFactory,
ElementFactory $rightElementFactory
) {
$this->_factory = $factory;
$this->_elementFactory = $elementFactory;
$this->_newElementFactory = $rightElementFactory;
}
/**
* @param ElementFactory $factory
* @param array $data
*/
public function testHelper(ElementFactory $factory, array $data = [])
{
$factory->create(ElementFactory::class, ['data' => $data]);
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\SomeModule\Model;
class DoubleColon
{
public function __construct()
{
DoubleColon::class;
}
public function method()
{
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\SomeModule\Model;
use Magento\SomeModule\DummyFactory;
class StubWithAnonymousClass
{
/**
* @var DummyFactory
*/
private $factory;
public function __construct(DummyFactory $factory)
{
$this->factory = $factory;
}
public function getSerializable(): \JsonSerializable
{
return new class() implements \JsonSerializable {
/**
* @inheritDoc
*/
public function jsonSerialize()
{
return [1, 2, 3];
}
};
}
}
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\SomeModule\Model;
/**
* @SuppressWarnings(PHPMD.ConstructorWithNameAsEnclosingClass)
*/
class Test
{
public function __construct()
{
new \Magento\SomeModule\Model\Element\Proxy();
}
/**
* @param \Magento\SomeModule\ModelFactory $factory
* @param array $data
*/
public function testModel(\Magento\SomeModule\ModelFactory $factory, array $data = [])
{
$factory->create(\Magento\SomeModule\Model\BlockFactory::class, ['data' => $data]);
}
}
<?xml version="1.0"?>
<!--
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
<system>
<section id="advanced" translate="label" type="text" sortOrder="910" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Advanced</label>
<tab>advanced</tab>
<resource>Magento_Config::advanced</resource>
<group id="modules_disable_output" translate="label" type="text" sortOrder="2" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Disable Modules Output</label>
<frontend_model>Magento\Config\Block\System\Config\Form\Fieldset\Modules\DisableOutput\Proxy</frontend_model>
</group>
</section>
</system>
</config>
<?xml version='1.0' encoding="utf-8" ?>
<!--
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\Store\Model\Config\InvalidatorInterface" type="Magento\Store\Model\Config\Invalidator\Proxy" />
<preference for="Magento\Framework\App\CacheInterface" type="Magento\Framework\App\Cache\Proxy" />
<virtualType name="custom_cache_instance" type="Magento\Framework\App\Cache">
<plugin name="tag" type="Magento\Framework\App\Cache\TagPlugin" />
</virtualType>
<type name="Magento\SomeModule\Model\Test">
<arguments>
<argument name="proxy" xsi:type="object">\Magento\SomeModule\Model\Element\Proxy</argument>
<argument name="array" xsi:type="array">
<item name="proxy" xsi:type="object">\Magento\SomeModule\Model\Nested\Element\Proxy</item>
</argument>
</arguments>
</type>
</config>
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
/**
* This file exists for the sake of \Magento\Setup\Test\Unit\Module\Di\Code\Reader\ClassesScannerTest, in order
* to verify that PHP files are correctly scanned and things that are not PHP files (like this file and its parent
* directory) are not scanned.
*/
/**
* True Function
*
* @return bool
*/
public function someTrueFunction()
{
return true;
}
<?xml version='1.0' encoding="utf-8" ?>
<!--
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_layout.xsd">
<referenceBlock name="root">
<block class="Magento\Backend\Block\Menu\Proxy" name="menu" as="menu" template="Magento_Backend::menu.phtml" />
</referenceBlock>
</layout>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment