34 private $whiteListedBackendControllers = [];
41 private $aclResources;
48 $whitelistedClasses = [];
49 $path = sprintf(
'%s/_files/controller_acl_test_whitelist_*.txt',
__DIR__);
50 foreach (glob(
$path) as $listFile) {
51 $whitelistedClasses = array_merge(
53 file($listFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)
56 foreach ($whitelistedClasses as
$item) {
57 if (substr(
$item, 0, 1) ===
'#') {
60 $this->whiteListedBackendControllers[
$item] = 1;
70 $pathMask = sprintf(
'%s/../../../_files/changed_files*',
__DIR__, DIRECTORY_SEPARATOR);
73 $relativeFilePath = $line[0];
75 if ($this->isItTest($relativeFilePath)) {
79 $controllerPath = $this->getControllerPath($relativeFilePath);
80 if (!$controllerPath) {
84 $controllerClass = $this->getClassByFilePath($controllerPath);
86 if (isset($this->whiteListedBackendControllers[$controllerClass->getName()])) {
90 if ($controllerClass->isAbstract()) {
96 if (!$this->isClassExtendsBackendClass($controllerClass)) {
97 $inheritanceMessage =
"Backend controller $className have to inherit " . AbstractAction::class;
98 $errorMessages[] = $inheritanceMessage;
102 $isAclRedefinedInTheChildClass = $this->isConstantOverwritten($controllerClass)
103 || $this->isMethodOverwritten($controllerClass);
104 if (!$isAclRedefinedInTheChildClass) {
105 $errorMessages[] =
"Backend controller $className have to overwrite _isAllowed method or " 106 .
'ADMIN_RESOURCE constant';
109 $errorMessages = array_merge($errorMessages, $this->collectAclErrorsInTheXml($controllerClass));
111 sort($errorMessages);
112 $this->assertEmpty($errorMessages, implode(
"\n", $errorMessages));
121 private function collectAclErrorsInTheXml(\ReflectionClass
$class)
126 $codeLines = file(
$method->getFileName());
129 $codeOfTheMethod = implode(
' ', array_slice($codeLines,
$start, $length));
130 preg_match(
'~["\']Magento_.*?::.*?["\']~', $codeOfTheMethod, $matches);
131 $aclResources = $this->getAclResources();
133 $resourceUnquoted = str_replace([
'"',
"'"], [
'',
''],
$resource);
134 if (!isset($aclResources[$resourceUnquoted])) {
135 $errorMessages[] =
"ACL $resource exists in $className but doesn't exists in the acl.xml file";
138 return $errorMessages;
146 private function getAclResources()
148 if ($this->aclResources !==
null) {
149 return $this->aclResources;
151 $aclFiles =
Files::init()->getConfigFiles(
'acl.xml', []);
153 array_map(
function ($file) use (&$xmlResources) {
154 $config = simplexml_load_file($file[0]);
155 $nodes =
$config->xpath(
'.//resource/@id') ?: [];
156 foreach ($nodes as $node) {
157 $xmlResources[(string)$node] = $node;
160 $this->aclResources = $xmlResources;
161 return $this->aclResources;
170 private function isConstantOverwritten(\ReflectionClass
$class)
186 private function isMethodOverwritten(\ReflectionClass
$class)
193 }
catch (\ReflectionException $e) {
204 private function isClassExtendsBackendClass(\ReflectionClass
$class)
206 while ($parentClass =
$class->getParentClass()) {
207 if (AbstractAction::class === $parentClass->getName()) {
221 private function isItTest($relativeFilePath)
223 $isTest = (preg_match(
'~.*?(/dev/tests/|/Test/Unit/).*?\.php$~', $relativeFilePath) === 1);
233 private function getControllerPath($relativeFilePath)
235 if (preg_match(
'~(Magento\/[^\/]+\/Controller\/Adminhtml\/.*)\.php~', $relativeFilePath, $matches)) {
236 if (count($matches) === 2) {
237 $partPath = $matches[1];
250 private function getClassByFilePath($controllerPath)
252 $className = str_replace(
'/',
'\\', $controllerPath);
255 }
catch (\ReflectionException $e) {
static getPhpFiles($changedFilesList, $fileTypes=0)
defined('TESTS_BP')||define('TESTS_BP' __DIR__
$_option $_optionId $class
const DEFAULT_BACKEND_RESOURCE