BlocksTest.php 4.1 KB

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