1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
<?php
/**
* Test layout declaration and usage of block elements
*
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Test\Integrity\Layout;
use Magento\Framework\App\Utility\Files;
class BlocksTest extends \PHPUnit\Framework\TestCase
{
/**
* @var array
*/
protected static $_containerAliases = [];
/**
* @var array
*/
protected static $_blockAliases = [];
/**
* Collect declarations of containers per layout file that have aliases
*/
public static function setUpBeforeClass()
{
foreach (Files::init()->getLayoutFiles([], false) as $file) {
$xml = simplexml_load_file($file);
$elements = $xml->xpath('/layout//*[self::container or self::block]') ?: [];
/** @var $node \SimpleXMLElement */
foreach ($elements as $node) {
$alias = (string)$node['as'];
if (empty($alias)) {
$alias = (string)$node['name'];
}
if ($node->getName() == 'container') {
self::$_containerAliases[$alias]['files'][] = $file;
self::$_containerAliases[$alias]['names'][] = (string)$node['name'];
} else {
self::$_blockAliases[$alias]['files'][] = $file;
self::$_blockAliases[$alias]['names'][] = (string)$node['name'];
}
}
}
}
public function testBlocksNotContainers()
{
$invoker = new \Magento\Framework\App\Utility\AggregateInvoker($this);
$invoker(
/**
* Check that containers are not used as blocks in templates
*
* @param string $alias
* @param string $file
* @throws \Exception|PHPUnit\Framework\ExpectationFailedException
*/
function ($alias, $file) {
if (isset(self::$_containerAliases[$alias])) {
if (!isset(self::$_blockAliases[$alias])) {
$this->fail(
"Element with alias '{$alias}' is used as a block in file '{$file}' " .
"via getChildBlock() method," .
" while '{$alias}' alias is declared as a container in file(s): " .
join(
', ',
self::$_containerAliases[$alias]['files']
)
);
} else {
$this->markTestIncomplete(
"Element with alias '{$alias}' is used as a block in file '{$file}' " .
"via getChildBlock() method." .
" It's impossible to determine explicitly whether the element is a block or a container, " .
"as it is declared as a container in file(s): " .
join(
', ',
self::$_containerAliases[$alias]['files']
) . " and as a block in file(s): " . join(
', ',
self::$_blockAliases[$alias]['files']
)
);
}
}
},
$this->getChildBlockDataProvider()
);
}
/**
* @return array
*/
public function getChildBlockDataProvider()
{
$result = [];
$collectedFiles = Files::init()->getPhpFiles(
Files::INCLUDE_APP_CODE
| Files::INCLUDE_TEMPLATES
| Files::INCLUDE_NON_CLASSES
);
foreach ($collectedFiles as $file) {
$aliases = \Magento\Framework\App\Utility\Classes::getAllMatches(
file_get_contents($file),
'/\->getChildBlock\(\'([^\']+)\'\)/x'
);
foreach ($aliases as $alias) {
$result[$file] = [$alias, $file];
}
}
return $result;
}
}