This one’s more interesting than it is useful (or its main use is as a debugging exercise), but while I was working on a UI Component tutorial I wanted to turn off the XSD validation for ui_component
files.
It turns out there’s a dedicated object that can control whether the XSD validations are applied ($this->validationState->isValidationRequired()
below.
#File: vendor/magento/framework/View/Element/UiComponent/Config/DomMerger.php
public function createDomDocument($xml)
{
$domDocument = new DOMDocument();
$domDocument->loadXML($xml);
if ($this->validationState->isValidationRequired() && $this->schema) {
$errors = $this->validateDomDocument($domDocument);
if (count($errors)) {
throw new MagentoFrameworkExceptionLocalizedException(
new MagentoFrameworkPhrase(implode("n", $errors))
);
}
}
return $domDocument;
}
Jumping up to the constructor we see that validationState
is
#File: vendor/magento/framework/View/Element/UiComponent/Config/DomMerger.php
//...
use MagentoFrameworkConfigValidationStateInterface;
//...
public function __construct(
ValidationStateInterface $validationState,
$schema,
$isMergeSimpleXMLElement = false,
array $contextXPath = [],
array $idAttributes = []
) {
$this->validationState = $validationState;
$this->schema = $schema;
$this->isMergeSimpleXMLElement = $isMergeSimpleXMLElement;
$this->contextXPath = $contextXPath;
$this->idAttributes = $idAttributes;
}
a MagentoFrameworkConfigValidationStateInterface
type/object/interface. Searching though the di.xml
files we see the MagentoFrameworkConfigValidationStateInterface
has
$ find vendor/magento/ -name di.xml | xargs grep ValidationStateInterface
vendor/magento//magento2-base/app/etc/di.xml: <preference for="MagentoFrameworkConfigValidationStateInterface" type="MagentoFrameworkAppArgumentsValidationState"></preference>
a concrete class of MagentoFrameworkAppArgumentsValidationState
. Peeking at this class’s source file
#File: vendor/magento/framework/App/Arguments/ValidationState.php
public function isValidationRequired()
{
return $this->_appMode == MagentoFrameworkAppState::MODE_DEVELOPER;
}
we see that the isValidationRequired
only checks to see if the mode is development. The interesting bit for me is this means production and default modes don’t apply the XSD validations.
As for skipping this in development mode, a little bit of pestle
let me configure a plugin for the MagentoFrameworkAppArgumentsValidationState
class.
$ pestle.phar generate_plugin_xml
Create in which module? (Pulsestorm_Helloworld)] Pulsestorm_SimpleUiComponent
Which class are you plugging into? (MagentoFrameworkLoggerMonolog)] MagentoFrameworkAppArgumentsValidationState
What's your plugin class name? (PulsestormSimpleUiComponentPluginMagentoFrameworkAppArgumentsValidationState)]
Added nodes to /Users/alanstorm/Sites/magento-2-1-1.dev/project-community-edition/app/code/;/SimpleUiComponent/etc/di.xml
Created file /Users/alanstorm/Sites/magento-2-1-1.dev/project-community-edition/app/code/Pulsestorm/SimpleUiComponent/Plugin/Magento/Framework/App/Arguments/ValidationState.php
and then drop a hard coded return false
into my plugin class.
<?php namespace PulsestormSimpleUiComponentPluginMagentoFrameworkAppArguments;
class ValidationState
{
public function afterIsValidationRequired($subject, $result)
{
return false;
}
}
Or – that’s what I thought anyways. Unfortunately, this ended up giving me the following error.
Fatal error: Maximum function nesting level of ‘300’ reached, aborting! in /Users/alanstorm/Sites/magento-2-1-1.dev/project-community-edition/vendor/colinmollenhour/cache-backend-file/File.php on line 404
The problem? Jumping into the call stack
118 2.8599 28646104 MagentoFrameworkAppArgumentsValidationStateInterceptor->isValidationRequired( ) .../Dom.php:387
119 2.8599 28646104 MagentoFrameworkInterceptionPluginListPluginList->getNext( ) .../Interceptor.php:22
120 2.8599 28646104 MagentoFrameworkInterceptionPluginListPluginList->_loadScopedData( ) .../PluginList.php:248
121 2.8599 28646216 MagentoFrameworkObjectManagerConfigReaderDomProxy->read( ) .../PluginList.php:280
122 2.8599 28646216 MagentoFrameworkConfigReaderFilesystem->read( ) .../Proxy.php:95
123 2.8633 28668096 MagentoFrameworkConfigReaderFilesystem->_readFiles( ) .../Filesystem.php:127
124 2.8633 28688712 MagentoFrameworkObjectManagerConfigReaderDom->_createConfigMerger( ) .../Filesystem.php:146
125 2.8633 28688872 MagentoFrameworkConfigDom->__construct( ) .../Dom.php:70
In order for plugins to work, Magento needs to instantiate a MagentoFrameworkConfigDom
object. This object has MagentoFrameworkConfigValidationStateInterface
as an injected dependency, and we end up in an endless loop (yay for xDebug saving us!).
So, in the end? I had to settle for a di.xml <preference></preference>
configuration. Not ideal, but when the (benign?) neglect of a system’s owner leads to situations like the above, developers are going to do the less-right thing that gets their jobs done.