Validator.php 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Theme\Model\Design\Config;
  7. use \Magento\Framework\Exception\LocalizedException;
  8. use \Magento\Theme\Api\Data\DesignConfigInterface;
  9. use \Magento\Theme\Api\Data\DesignConfigDataInterface;
  10. use \Magento\Framework\Mail\TemplateInterfaceFactory as TemplateFactory;
  11. use \Magento\Framework\Filter\Template;
  12. use \Magento\Framework\Filter\Template\Tokenizer\Parameter as ParameterTokenizer;
  13. /**
  14. * Design configuration validator
  15. */
  16. class Validator
  17. {
  18. /**
  19. * @var string[]
  20. */
  21. private $fields = [];
  22. /**
  23. * @var TemplateFactory
  24. */
  25. private $templateFactory;
  26. /**
  27. * Initialize dependencies.
  28. *
  29. * @param TemplateFactory $templateFactory
  30. * @param string[] $fields
  31. */
  32. public function __construct(TemplateFactory $templateFactory, $fields = [])
  33. {
  34. $this->templateFactory = $templateFactory;
  35. $this->fields = $fields;
  36. }
  37. /**
  38. * Validate if design configuration has recursive references
  39. *
  40. * @param DesignConfigInterface $designConfig
  41. *
  42. * @throws LocalizedException
  43. * @return void
  44. */
  45. public function validate(DesignConfigInterface $designConfig)
  46. {
  47. /** @var DesignConfigDataInterface[] $designConfigData */
  48. $designConfigData = $designConfig->getExtensionAttributes()->getDesignConfigData();
  49. $elements = [];
  50. foreach ($designConfigData as $designElement) {
  51. if (!in_array($designElement->getFieldConfig()['field'], $this->fields)) {
  52. continue;
  53. }
  54. /* Save mapping between field names and config paths */
  55. $elements[$designElement->getFieldConfig()['field']] = [
  56. 'config_path' => $designElement->getPath(),
  57. 'value' => $designElement->getValue()
  58. ];
  59. }
  60. foreach ($elements as $name => $data) {
  61. $templateId = $data['value'];
  62. $text = $this->getTemplateText($templateId, $designConfig);
  63. // Check if template body has a reference to the same config path
  64. if (preg_match_all(Template::CONSTRUCTION_TEMPLATE_PATTERN, $text, $constructions, PREG_SET_ORDER)) {
  65. foreach ($constructions as $construction) {
  66. $configPath = isset($construction[2]) ? $construction[2] : '';
  67. $params = $this->getParameters($configPath);
  68. if (isset($params['config_path']) && $params['config_path'] == $data['config_path']) {
  69. throw new LocalizedException(
  70. __(
  71. 'The "%templateName" template contains an incorrect configuration, with a reference '
  72. . 'to itself. Remove or change the reference, then try again.',
  73. ["templateName" => $name]
  74. )
  75. );
  76. }
  77. }
  78. }
  79. }
  80. }
  81. /**
  82. * Returns store identifier if is store scope
  83. *
  84. * @param DesignConfigInterface $designConfig
  85. * @return string|bool
  86. */
  87. private function getScopeId(DesignConfigInterface $designConfig)
  88. {
  89. if ($designConfig->getScope() == 'stores') {
  90. return $designConfig->getScopeId();
  91. }
  92. return false;
  93. }
  94. /**
  95. * Load template text in configured scope
  96. *
  97. * @param integer|string $templateId
  98. * @param DesignConfigInterface $designConfig
  99. * @return string
  100. */
  101. private function getTemplateText($templateId, DesignConfigInterface $designConfig)
  102. {
  103. // Load template object by configured template id
  104. $template = $this->templateFactory->create();
  105. $template->emulateDesign($this->getScopeId($designConfig));
  106. if (is_numeric($templateId)) {
  107. $template->load($templateId);
  108. } else {
  109. $template->setForcedArea($templateId);
  110. $template->loadDefault($templateId);
  111. }
  112. $text = $template->getTemplateText();
  113. $template->revertDesign();
  114. return $text;
  115. }
  116. /**
  117. * Return associative array of parameters.
  118. *
  119. * @param string $value raw parameters
  120. * @return array
  121. */
  122. private function getParameters($value)
  123. {
  124. $tokenizer = new ParameterTokenizer();
  125. $tokenizer->setString($value);
  126. $params = $tokenizer->tokenize();
  127. return $params;
  128. }
  129. }