123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434 |
- <?php
- /**
- * Validation configuration files handler
- *
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
- namespace Magento\Framework\Validator;
- use Magento\Framework\Validator\Constraint\Option;
- use Magento\Framework\Validator\Constraint\Option\Callback;
- use Magento\Framework\Validator\Constraint\OptionInterface;
- class Config extends \Magento\Framework\Config\AbstractXml
- {
- /**#@+
- * Constraints types
- */
- const CONSTRAINT_TYPE_ENTITY = 'entity';
- const CONSTRAINT_TYPE_PROPERTY = 'property';
- /**#@-*/
- /**#@-*/
- protected $_defaultBuilderClass = \Magento\Framework\Validator\Builder::class;
- /**
- * @var \Magento\Framework\Validator\UniversalFactory
- */
- protected $_builderFactory;
- /**
- * @param array $configFiles
- * @param \Magento\Framework\Config\DomFactory $domFactory
- * @param \Magento\Framework\Validator\UniversalFactory $builderFactory
- */
- public function __construct(
- $configFiles,
- \Magento\Framework\Config\DomFactory $domFactory,
- \Magento\Framework\Validator\UniversalFactory $builderFactory
- ) {
- $this->_builderFactory = $builderFactory;
- parent::__construct($configFiles, $domFactory);
- }
- /**
- * Create validator builder instance based on entity and group.
- *
- * @param string $entityName
- * @param string $groupName
- * @param array|null $builderConfig
- * @throws \InvalidArgumentException
- * @return \Magento\Framework\Validator\Builder
- */
- public function createValidatorBuilder($entityName, $groupName, array $builderConfig = null)
- {
- if (!isset($this->_data[$entityName])) {
- throw new \InvalidArgumentException(sprintf('Unknown validation entity "%s"', $entityName));
- }
- if (!isset($this->_data[$entityName][$groupName])) {
- throw new \InvalidArgumentException(
- sprintf('Unknown validation group "%s" in entity "%s"', $groupName, $entityName)
- );
- }
- $builderClass = isset(
- $this->_data[$entityName][$groupName]['builder']
- ) ? $this->_data[$entityName][$groupName]['builder'] : $this->_defaultBuilderClass;
- if (!class_exists($builderClass)) {
- throw new \InvalidArgumentException(sprintf('Builder class "%s" was not found', $builderClass));
- }
- $builder = $this->_builderFactory->create(
- $builderClass,
- ['constraints' => $this->_data[$entityName][$groupName]['constraints']]
- );
- if (!$builder instanceof \Magento\Framework\Validator\Builder) {
- throw new \InvalidArgumentException(
- sprintf('Builder "%s" must extend \Magento\Framework\Validator\Builder', $builderClass)
- );
- }
- if ($builderConfig) {
- $builder->addConfigurations($builderConfig);
- }
- return $builder;
- }
- /**
- * Create validator based on entity and group.
- *
- * @param string $entityName
- * @param string $groupName
- * @param array|null $builderConfig
- * @return \Magento\Framework\Validator
- */
- public function createValidator($entityName, $groupName, array $builderConfig = null)
- {
- return $this->createValidatorBuilder($entityName, $groupName, $builderConfig)->createValidator();
- }
- /**
- * Extract configuration data from the DOM structure
- *
- * @param \DOMDocument $dom
- * @return array
- */
- protected function _extractData(\DOMDocument $dom)
- {
- $result = [];
- /** @var \DOMElement $entity */
- foreach ($dom->getElementsByTagName('entity') as $entity) {
- $result[$entity->getAttribute('name')] = $this->_extractEntityGroupsConstraintsData($entity);
- }
- return $result;
- }
- /**
- * Extract constraints associated with entity group using rules
- *
- * @param \DOMElement $entity
- * @return array
- */
- protected function _extractEntityGroupsConstraintsData(\DOMElement $entity)
- {
- $result = [];
- $rulesConstraints = $this->_extractRulesConstraintsData($entity);
- /** @var \DOMElement $group */
- foreach ($entity->getElementsByTagName('group') as $group) {
- $groupConstraints = [];
- /** @var \DOMElement $use */
- foreach ($group->getElementsByTagName('use') as $use) {
- $ruleName = $use->getAttribute('rule');
- if (isset($rulesConstraints[$ruleName])) {
- $groupConstraints = array_merge($groupConstraints, $rulesConstraints[$ruleName]);
- }
- }
- $result[$group->getAttribute('name')] = ['constraints' => $groupConstraints];
- if ($group->hasAttribute('builder')) {
- $result[$group->getAttribute('name')]['builder'] = $group->getAttribute('builder');
- }
- }
- unset($groupConstraints);
- unset($rulesConstraints);
- return $result;
- }
- /**
- * Extract constraints associated with rules
- *
- * @param \DOMElement $entity
- * @return array
- */
- protected function _extractRulesConstraintsData(\DOMElement $entity)
- {
- $rules = [];
- /** @var \DOMElement $rule */
- foreach ($entity->getElementsByTagName('rule') as $rule) {
- $ruleName = $rule->getAttribute('name');
- /** @var \DOMElement $propertyConstraints */
- foreach ($rule->getElementsByTagName('property_constraints') as $propertyConstraints) {
- /** @var \DOMElement $property */
- foreach ($propertyConstraints->getElementsByTagName('property') as $property) {
- /** @var \DOMElement $constraint */
- foreach ($property->getElementsByTagName('constraint') as $constraint) {
- $rules[$ruleName][] = [
- 'alias' => $constraint->getAttribute('alias'),
- 'class' => $constraint->getAttribute('class'),
- 'options' => $this->_extractConstraintOptions($constraint),
- 'property' => $property->getAttribute('name'),
- 'type' => self::CONSTRAINT_TYPE_PROPERTY,
- ];
- }
- }
- }
- /** @var \DOMElement $entityConstraints */
- foreach ($rule->getElementsByTagName('entity_constraints') as $entityConstraints) {
- /** @var \DOMElement $constraint */
- foreach ($entityConstraints->getElementsByTagName('constraint') as $constraint) {
- $rules[$ruleName][] = [
- 'alias' => $constraint->getAttribute('alias'),
- 'class' => $constraint->getAttribute('class'),
- 'options' => $this->_extractConstraintOptions($constraint),
- 'type' => self::CONSTRAINT_TYPE_ENTITY,
- ];
- }
- }
- }
- return $rules;
- }
- /**
- * Extract constraint options.
- *
- * @param \DOMElement $constraint
- * @return array|null
- */
- protected function _extractConstraintOptions(\DOMElement $constraint)
- {
- if (!$constraint->hasChildNodes()) {
- return null;
- }
- $options = [];
- $children = $this->_collectChildren($constraint);
- /**
- * Read constructor arguments
- *
- * <constraint class="Constraint">
- * <argument>
- * <option name="minValue">123</option>
- * <option name="maxValue">234</option>
- * </argument>
- * <argument>0</argument>
- * <argument>
- * <callback class="Class" method="method" />
- * </argument>
- * </constraint>
- */
- $arguments = $this->_readArguments($children);
- if ($arguments) {
- $options['arguments'] = $arguments;
- }
- /**
- * Read constraint configurator callback
- *
- * <constraint class="Constraint">
- * <callback class="Magento\Foo\Helper\Data" method="configureValidator"/>
- * </constraint>
- */
- $callback = $this->_readCallback($children);
- if ($callback) {
- $options['callback'] = $callback;
- }
- /**
- * Read constraint method configuration
- */
- $methods = $this->_readMethods($children);
- if ($methods) {
- $options['methods'] = $methods;
- }
- return $options;
- }
- /**
- * Get element children.
- *
- * @param \DOMElement $element
- * @return array
- */
- protected function _collectChildren($element)
- {
- $children = [];
- /** @var $node \DOMElement */
- foreach ($element->childNodes as $node) {
- if (!$node instanceof \DOMElement) {
- continue;
- }
- $nodeName = strtolower($node->nodeName);
- if (!array_key_exists($nodeName, $children)) {
- $children[$nodeName] = [];
- }
- $children[$nodeName][] = $node;
- }
- return $children;
- }
- /**
- * Get arguments.
- *
- * @param array $children
- * @return OptionInterface[]|null
- */
- protected function _readArguments($children)
- {
- if (array_key_exists('argument', $children)) {
- $arguments = [];
- /** @var $node \DOMElement */
- foreach ($children['argument'] as $node) {
- $nodeChildren = $this->_collectChildren($node);
- $callback = $this->_readCallback($nodeChildren);
- $options = $this->_readOptions($nodeChildren);
- if ($callback) {
- $arguments[] = $callback[0];
- } elseif ($options) {
- $arguments[] = $options;
- } else {
- $argument = $node->textContent;
- $arguments[] = new Option(trim($argument));
- }
- }
- return $arguments;
- }
- return null;
- }
- /**
- * Get callback rules.
- *
- * @param array $children
- * @return Callback[]|null
- */
- protected function _readCallback($children)
- {
- if (array_key_exists('callback', $children)) {
- $callbacks = [];
- /** @var $callbackData \DOMElement */
- foreach ($children['callback'] as $callbackData) {
- $callbacks[] = new Callback(
- [trim($callbackData->getAttribute('class')), trim($callbackData->getAttribute('method'))],
- null,
- true
- );
- }
- return $callbacks;
- }
- return null;
- }
- /**
- * Get options array.
- *
- * @param array $children
- * @return Option|null
- */
- protected function _readOptions($children)
- {
- if (array_key_exists('option', $children)) {
- $data = [];
- /** @var $option \DOMElement */
- foreach ($children['option'] as $option) {
- $value = trim($option->textContent);
- if ($option->hasAttribute('name')) {
- $data[$option->getAttribute('name')] = $value;
- } else {
- $data[] = $value;
- }
- }
- return new Option($data);
- }
- return null;
- }
- /**
- * Get methods configuration.
- *
- * Example of method configuration:
- * <constraint class="Constraint">
- * <method name="setMaxValue">
- * <argument>
- * <option name="minValue">123</option>
- * <option name="maxValue">234</option>
- * </argument>
- * <argument>0</argument>
- * <argument>
- * <callback class="Class" method="method" />
- * </argument>
- * </method>
- * </constraint>
- *
- * @param array $children
- * @return array|null
- */
- protected function _readMethods($children)
- {
- if (array_key_exists('method', $children)) {
- $methods = [];
- /** @var $method \DOMElement */
- foreach ($children['method'] as $method) {
- $children = $this->_collectChildren($method);
- $methodName = $method->getAttribute('name');
- $methodOptions = ['method' => $methodName];
- $arguments = $this->_readArguments($children);
- if ($arguments) {
- $methodOptions['arguments'] = $arguments;
- }
- $methods[$methodName] = $methodOptions;
- }
- return $methods;
- }
- return null;
- }
- /**
- * Get absolute path to validation.xsd
- *
- * @return string
- */
- public function getSchemaFile()
- {
- return __DIR__ . '/etc/validation.xsd';
- }
- /**
- * Get initial XML of a valid document.
- *
- * @return string
- */
- protected function _getInitialXml()
- {
- return '<?xml version="1.0" encoding="UTF-8"?>' .
- '<validation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"></validation>';
- }
- /**
- * Define id attributes for entities
- *
- * @return array
- */
- protected function _getIdAttributes()
- {
- return [
- '/validation/entity' => 'name',
- '/validation/entity/rules/rule' => 'name',
- '/validation/entity/rules/rule/entity_constraints/constraint' => 'class',
- '/validation/entity/rules/rule/property_constraints/property/constraint' => 'class',
- '/validation/entity/rules/rule/property_constraints/property' => 'name',
- '/validation/entity/groups/group' => 'name',
- '/validation/entity/groups/group/uses/use' => 'rule'
- ];
- }
- }
|