Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
ArgumentSequence.php
Go to the documentation of this file.
1 <?php
9 
11 
13 {
14  const REQUIRED = 'required';
15 
16  const OPTIONAL = 'optional';
17 
21  protected $_argumentsReader;
22 
26  protected $_cache;
27 
31  public function __construct(\Magento\Framework\Code\Reader\ArgumentsReader $argumentsReader = null)
32  {
33  $this->_argumentsReader = $argumentsReader ?: new \Magento\Framework\Code\Reader\ArgumentsReader();
34  }
35 
44  public function validate($className)
45  {
46  $class = new \ReflectionClass($className);
47  $classArguments = $this->_argumentsReader->getConstructorArguments($class);
48 
49  if ($this->_isContextOnly($classArguments)) {
50  return true;
51  }
52 
53  $parent = $class->getParentClass();
54  $parentArguments = [];
55  if ($parent) {
56  $parentClass = $parent->getName();
57  if (0 !== strpos($parentClass, '\\')) {
58  $parentClass = '\\' . $parentClass;
59  }
60 
61  if (isset($this->_cache[$parentClass])) {
62  $parentCall = $this->_argumentsReader->getParentCall($class, []);
63  if (empty($classArguments) || $parentCall) {
64  $parentArguments = $this->_cache[$parentClass];
65  }
66  }
67  }
68 
69  if (empty($classArguments)) {
70  $classArguments = $parentArguments;
71  }
72 
73  $requiredSequence = $this->_buildsSequence($classArguments, $parentArguments);
74  if (!empty($requiredSequence)) {
75  $this->_cache[$className] = $requiredSequence;
76  }
77 
78  if (false == $this->_checkArgumentSequence($classArguments, $requiredSequence)) {
79  $classPath = str_replace('\\', '/', $class->getFileName());
80  throw new \Magento\Framework\Exception\ValidatorException(
81  new \Magento\Framework\Phrase(
82  'Incorrect argument sequence in class %1 in %2%3Required: $%4%5Actual : $%6%7',
83  [
84  $className,
85  $classPath,
86  PHP_EOL,
87  implode(', $', array_keys($requiredSequence)),
88  PHP_EOL,
89  implode(', $', array_keys($classArguments)),
90  PHP_EOL
91  ]
92  )
93  );
94  }
95 
96  return true;
97  }
98 
106  protected function _checkArgumentSequence(array $actualSequence, array $requiredSequence)
107  {
108  $actualArgumentSequence = [];
109  $requiredArgumentSequence = [];
110 
111  foreach ($actualSequence as $name => $argument) {
112  if (false == $argument['isOptional']) {
113  $actualArgumentSequence[$name] = $argument;
114  } else {
115  break;
116  }
117  }
118 
119  foreach ($requiredSequence as $name => $argument) {
120  if (false == $argument['isOptional']) {
121  $requiredArgumentSequence[$name] = $argument;
122  } else {
123  break;
124  }
125  }
126  $actual = array_keys($actualArgumentSequence);
127  $required = array_keys($requiredArgumentSequence);
128  return $actual === $required;
129  }
130 
140  protected function _buildsSequence(array $classArguments, array $parentArguments = [])
141  {
142  $output = [];
143  if (empty($classArguments)) {
144  return $parentArguments;
145  }
146 
147  $classArgumentList = $this->_sortArguments($classArguments);
148  $parentArgumentList = $this->_sortArguments($parentArguments);
149 
150  $migrated = [];
151  foreach ($parentArgumentList[self::REQUIRED] as $name => $argument) {
152  if (!isset($classArgumentList[self::OPTIONAL][$name])) {
153  $output[$name] = isset(
154  $classArgumentList[self::REQUIRED][$name]
155  ) ? $classArgumentList[self::REQUIRED][$name] : $argument;
156  } else {
157  $migrated[$name] = $classArgumentList[self::OPTIONAL][$name];
158  }
159  }
160 
161  foreach ($classArgumentList[self::REQUIRED] as $name => $argument) {
162  if (!isset($output[$name])) {
163  $output[$name] = $argument;
164  }
165  }
166 
168  foreach ($migrated as $name => $argument) {
169  if (!isset($output[$name])) {
170  $output[$name] = $argument;
171  }
172  }
173 
174  foreach ($parentArgumentList[self::OPTIONAL] as $name => $argument) {
175  if (!isset($output[$name])) {
176  $output[$name] = isset(
177  $classArgumentList[self::OPTIONAL][$name]
178  ) ? $classArgumentList[self::OPTIONAL][$name] : $argument;
179  }
180  }
181 
182  foreach ($classArgumentList[self::OPTIONAL] as $name => $argument) {
183  if (!isset($output[$name])) {
184  $output[$name] = $argument;
185  }
186  }
187 
188  return $output;
189  }
190 
197  protected function _sortArguments($arguments)
198  {
199  $required = [];
200  $optional = [];
201 
202  foreach ($arguments as $name => $argument) {
203  if ($argument['isOptional']) {
204  $optional[$name] = $argument;
205  } else {
206  $required[$name] = $argument;
207  }
208  }
209 
210  return [self::REQUIRED => $required, self::OPTIONAL => $optional];
211  }
212 
219  protected function _isContextOnly(array $arguments)
220  {
221  if (count($arguments) !== 1) {
222  return false;
223  }
224  $argument = current($arguments);
225  return $argument['type'] && $this->_isContextType($argument['type']);
226  }
227 
234  protected function _isContextType($type)
235  {
236  return is_subclass_of($type, \Magento\Framework\ObjectManager\ContextInterface::class);
237  }
238 }
_checkArgumentSequence(array $actualSequence, array $requiredSequence)
is_subclass_of($obj, $className)
__construct(\Magento\Framework\Code\Reader\ArgumentsReader $argumentsReader=null)
_buildsSequence(array $classArguments, array $parentArguments=[])
$type
Definition: item.phtml:13
$_option $_optionId $class
Definition: date.phtml:13
$arguments
if($currentSelectedMethod==$_code) $className
Definition: form.phtml:31
$required
Definition: wrapper.phtml:8
if(!isset($_GET['name'])) $name
Definition: log.php:14