mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-27 12:38:44 +02:00
N°6934 - Symfony 6.4 - upgrade Symfony bundles to 6.4 (#580)
* Update Symfony lib to version ~6.4.0 * Update code missing return type * Add an iTop general configuration entry to store application secret (Symfony mandatory parameter) * Use dependency injection in ExceptionListener & UserProvider classes
This commit is contained in:
@@ -24,6 +24,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Exception\LogicException;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
@@ -40,10 +41,7 @@ class XmlFileLoader extends FileLoader
|
||||
|
||||
protected $autoRegisterAliasesForSinglyImplementedInterfaces = false;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load($resource, string $type = null)
|
||||
public function load(mixed $resource, string $type = null): mixed
|
||||
{
|
||||
$path = $this->locator->locate($resource);
|
||||
|
||||
@@ -95,10 +93,7 @@ class XmlFileLoader extends FileLoader
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports($resource, string $type = null)
|
||||
public function supports(mixed $resource, string $type = null): bool
|
||||
{
|
||||
if (!\is_string($resource)) {
|
||||
return false;
|
||||
@@ -111,14 +106,14 @@ class XmlFileLoader extends FileLoader
|
||||
return 'xml' === $type;
|
||||
}
|
||||
|
||||
private function parseParameters(\DOMDocument $xml, string $file, \DOMNode $root = null)
|
||||
private function parseParameters(\DOMDocument $xml, string $file, \DOMNode $root = null): void
|
||||
{
|
||||
if ($parameters = $this->getChildren($root ?? $xml->documentElement, 'parameters')) {
|
||||
$this->container->getParameterBag()->add($this->getArgumentsAsPhp($parameters[0], 'parameter', $file));
|
||||
}
|
||||
}
|
||||
|
||||
private function parseImports(\DOMDocument $xml, string $file, \DOMNode $root = null)
|
||||
private function parseImports(\DOMDocument $xml, string $file, \DOMNode $root = null): void
|
||||
{
|
||||
$xpath = new \DOMXPath($xml);
|
||||
$xpath->registerNamespace('container', self::NS);
|
||||
@@ -134,7 +129,7 @@ class XmlFileLoader extends FileLoader
|
||||
}
|
||||
}
|
||||
|
||||
private function parseDefinitions(\DOMDocument $xml, string $file, Definition $defaults, \DOMNode $root = null)
|
||||
private function parseDefinitions(\DOMDocument $xml, string $file, Definition $defaults, \DOMNode $root = null): void
|
||||
{
|
||||
$xpath = new \DOMXPath($xml);
|
||||
$xpath->registerNamespace('container', self::NS);
|
||||
@@ -184,7 +179,7 @@ class XmlFileLoader extends FileLoader
|
||||
}
|
||||
$excludes = [$service->getAttribute('exclude')];
|
||||
}
|
||||
$this->registerClasses($definition, (string) $service->getAttribute('namespace'), (string) $service->getAttribute('resource'), $excludes);
|
||||
$this->registerClasses($definition, (string) $service->getAttribute('namespace'), (string) $service->getAttribute('resource'), $excludes, $file);
|
||||
} else {
|
||||
$this->setDefinition((string) $service->getAttribute('id'), $definition);
|
||||
}
|
||||
@@ -227,11 +222,11 @@ class XmlFileLoader extends FileLoader
|
||||
$version = $deprecated[0]->getAttribute('version') ?: '';
|
||||
|
||||
if (!$deprecated[0]->hasAttribute('package')) {
|
||||
trigger_deprecation('symfony/dependency-injection', '5.1', 'Not setting the attribute "package" of the node "deprecated" in "%s" is deprecated.', $file);
|
||||
throw new InvalidArgumentException(sprintf('Missing attribute "package" at node "deprecated" in "%s".', $file));
|
||||
}
|
||||
|
||||
if (!$deprecated[0]->hasAttribute('version')) {
|
||||
trigger_deprecation('symfony/dependency-injection', '5.1', 'Not setting the attribute "version" of the node "deprecated" in "%s" is deprecated.', $file);
|
||||
throw new InvalidArgumentException(sprintf('Missing attribute "version" at node "deprecated" in "%s".', $file));
|
||||
}
|
||||
|
||||
$alias->setDeprecated($package, $version, $message);
|
||||
@@ -258,7 +253,7 @@ class XmlFileLoader extends FileLoader
|
||||
foreach (['class', 'public', 'shared', 'synthetic', 'abstract'] as $key) {
|
||||
if ($value = $service->getAttribute($key)) {
|
||||
$method = 'set'.$key;
|
||||
$definition->$method($value = XmlUtils::phpize($value));
|
||||
$definition->$method(XmlUtils::phpize($value));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,12 +281,12 @@ class XmlFileLoader extends FileLoader
|
||||
$package = $deprecated[0]->getAttribute('package') ?: '';
|
||||
$version = $deprecated[0]->getAttribute('version') ?: '';
|
||||
|
||||
if ('' === $package) {
|
||||
trigger_deprecation('symfony/dependency-injection', '5.1', 'Not setting the attribute "package" of the node "deprecated" in "%s" is deprecated.', $file);
|
||||
if (!$deprecated[0]->hasAttribute('package')) {
|
||||
throw new InvalidArgumentException(sprintf('Missing attribute "package" at node "deprecated" in "%s".', $file));
|
||||
}
|
||||
|
||||
if ('' === $version) {
|
||||
trigger_deprecation('symfony/dependency-injection', '5.1', 'Not setting the attribute "version" of the node "deprecated" in "%s" is deprecated.', $file);
|
||||
if (!$deprecated[0]->hasAttribute('version')) {
|
||||
throw new InvalidArgumentException(sprintf('Missing attribute "version" at node "deprecated" in "%s".', $file));
|
||||
}
|
||||
|
||||
$definition->setDeprecated($package, $version, $message);
|
||||
@@ -304,6 +299,11 @@ class XmlFileLoader extends FileLoader
|
||||
$factory = $factories[0];
|
||||
if ($function = $factory->getAttribute('function')) {
|
||||
$definition->setFactory($function);
|
||||
} elseif ($expression = $factory->getAttribute('expression')) {
|
||||
if (!class_exists(Expression::class)) {
|
||||
throw new \LogicException('The "expression" attribute cannot be used on factories without the ExpressionLanguage component. Try running "composer require symfony/expression-language".');
|
||||
}
|
||||
$definition->setFactory('@='.$expression);
|
||||
} else {
|
||||
if ($childService = $factory->getAttribute('service')) {
|
||||
$class = new Reference($childService, ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE);
|
||||
@@ -315,6 +315,14 @@ class XmlFileLoader extends FileLoader
|
||||
}
|
||||
}
|
||||
|
||||
if ($constructor = $service->getAttribute('constructor')) {
|
||||
if (null !== $definition->getFactory()) {
|
||||
throw new LogicException(sprintf('The "%s" service cannot declare a factory as well as a constructor.', $service->getAttribute('id')));
|
||||
}
|
||||
|
||||
$definition->setFactory([null, $constructor]);
|
||||
}
|
||||
|
||||
if ($configurators = $this->getChildren($service, 'configurator')) {
|
||||
$configurator = $configurators[0];
|
||||
if ($function = $configurator->getAttribute('function')) {
|
||||
@@ -337,10 +345,14 @@ class XmlFileLoader extends FileLoader
|
||||
$tags = $this->getChildren($service, 'tag');
|
||||
|
||||
foreach ($tags as $tag) {
|
||||
$parameters = [];
|
||||
$tagName = $tag->nodeValue;
|
||||
$tagNameComesFromAttribute = $tag->childElementCount || '' === $tag->nodeValue;
|
||||
if ('' === $tagName = $tagNameComesFromAttribute ? $tag->getAttribute('name') : $tag->nodeValue) {
|
||||
throw new InvalidArgumentException(sprintf('The tag name for service "%s" in "%s" must be a non-empty string.', (string) $service->getAttribute('id'), $file));
|
||||
}
|
||||
|
||||
$parameters = $this->getTagAttributes($tag, sprintf('The attribute name of tag "%s" for service "%s" in %s must be a non-empty string.', $tagName, (string) $service->getAttribute('id'), $file));
|
||||
foreach ($tag->attributes as $name => $node) {
|
||||
if ('name' === $name && '' === $tagName) {
|
||||
if ($tagNameComesFromAttribute && 'name' === $name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -351,10 +363,6 @@ class XmlFileLoader extends FileLoader
|
||||
$parameters[$name] = XmlUtils::phpize($node->nodeValue);
|
||||
}
|
||||
|
||||
if ('' === $tagName && '' === $tagName = $tag->getAttribute('name')) {
|
||||
throw new InvalidArgumentException(sprintf('The tag name for service "%s" in "%s" must be a non-empty string.', $service->getAttribute('id'), $file));
|
||||
}
|
||||
|
||||
$definition->addTag($tagName, $parameters);
|
||||
}
|
||||
|
||||
@@ -391,6 +399,52 @@ class XmlFileLoader extends FileLoader
|
||||
$definition->setDecoratedService($decorates, $renameId, $priority, $invalidBehavior);
|
||||
}
|
||||
|
||||
if ($callable = $this->getChildren($service, 'from-callable')) {
|
||||
if ($definition instanceof ChildDefinition) {
|
||||
throw new InvalidArgumentException(sprintf('Attribute "parent" is unsupported when using "<from-callable>" on service "%s".', (string) $service->getAttribute('id')));
|
||||
}
|
||||
|
||||
foreach ([
|
||||
'Attribute "synthetic"' => 'isSynthetic',
|
||||
'Attribute "file"' => 'getFile',
|
||||
'Tag "<factory>"' => 'getFactory',
|
||||
'Tag "<argument>"' => 'getArguments',
|
||||
'Tag "<property>"' => 'getProperties',
|
||||
'Tag "<configurator>"' => 'getConfigurator',
|
||||
'Tag "<call>"' => 'getMethodCalls',
|
||||
] as $key => $method) {
|
||||
if ($definition->$method()) {
|
||||
throw new InvalidArgumentException($key.sprintf(' is unsupported when using "<from-callable>" on service "%s".', (string) $service->getAttribute('id')));
|
||||
}
|
||||
}
|
||||
|
||||
$definition->setFactory(['Closure', 'fromCallable']);
|
||||
|
||||
if ('Closure' !== ($definition->getClass() ?? 'Closure')) {
|
||||
$definition->setLazy(true);
|
||||
} else {
|
||||
$definition->setClass('Closure');
|
||||
}
|
||||
|
||||
$callable = $callable[0];
|
||||
if ($function = $callable->getAttribute('function')) {
|
||||
$definition->setArguments([$function]);
|
||||
} elseif ($expression = $callable->getAttribute('expression')) {
|
||||
if (!class_exists(Expression::class)) {
|
||||
throw new \LogicException('The "expression" attribute cannot be used without the ExpressionLanguage component. Try running "composer require symfony/expression-language".');
|
||||
}
|
||||
$definition->setArguments(['@='.$expression]);
|
||||
} else {
|
||||
if ($childService = $callable->getAttribute('service')) {
|
||||
$class = new Reference($childService, ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE);
|
||||
} else {
|
||||
$class = $callable->hasAttribute('class') ? $callable->getAttribute('class') : null;
|
||||
}
|
||||
|
||||
$definition->setArguments([[$class, $callable->getAttribute('method') ?: '__invoke']]);
|
||||
}
|
||||
}
|
||||
|
||||
return $definition;
|
||||
}
|
||||
|
||||
@@ -402,7 +456,7 @@ class XmlFileLoader extends FileLoader
|
||||
private function parseFileToDOM(string $file): \DOMDocument
|
||||
{
|
||||
try {
|
||||
$dom = XmlUtils::loadFile($file, [$this, 'validateSchema']);
|
||||
$dom = XmlUtils::loadFile($file, $this->validateSchema(...));
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
throw new InvalidArgumentException(sprintf('Unable to parse file "%s": ', $file).$e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
@@ -415,7 +469,7 @@ class XmlFileLoader extends FileLoader
|
||||
/**
|
||||
* Processes anonymous services.
|
||||
*/
|
||||
private function processAnonymousServices(\DOMDocument $xml, string $file, \DOMNode $root = null)
|
||||
private function processAnonymousServices(\DOMDocument $xml, string $file, \DOMNode $root = null): void
|
||||
{
|
||||
$definitions = [];
|
||||
$count = 0;
|
||||
@@ -480,6 +534,7 @@ class XmlFileLoader extends FileLoader
|
||||
$key = $arg->getAttribute('key');
|
||||
}
|
||||
|
||||
$trim = $arg->hasAttribute('trim') && XmlUtils::phpize($arg->getAttribute('trim'));
|
||||
$onInvalid = $arg->getAttribute('on-invalid');
|
||||
$invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
|
||||
if ('ignore' == $onInvalid) {
|
||||
@@ -490,7 +545,7 @@ class XmlFileLoader extends FileLoader
|
||||
$invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE;
|
||||
}
|
||||
|
||||
switch ($arg->getAttribute('type')) {
|
||||
switch ($type = $arg->getAttribute('type')) {
|
||||
case 'service':
|
||||
if ('' === $arg->getAttribute('id')) {
|
||||
throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="service" has no or empty "id" attribute in "%s".', $name, $file));
|
||||
@@ -510,38 +565,49 @@ class XmlFileLoader extends FileLoader
|
||||
break;
|
||||
case 'iterator':
|
||||
$arg = $this->getArgumentsAsPhp($arg, $name, $file);
|
||||
try {
|
||||
$arguments[$key] = new IteratorArgument($arg);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="iterator" only accepts collections of type="service" references in "%s".', $name, $file));
|
||||
}
|
||||
$arguments[$key] = new IteratorArgument($arg);
|
||||
break;
|
||||
case 'closure':
|
||||
case 'service_closure':
|
||||
if ('' === $arg->getAttribute('id')) {
|
||||
throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="service_closure" has no or empty "id" attribute in "%s".', $name, $file));
|
||||
if ('' !== $arg->getAttribute('id')) {
|
||||
$arg = new Reference($arg->getAttribute('id'), $invalidBehavior);
|
||||
} else {
|
||||
$arg = $this->getArgumentsAsPhp($arg, $name, $file);
|
||||
}
|
||||
|
||||
$arguments[$key] = new ServiceClosureArgument(new Reference($arg->getAttribute('id'), $invalidBehavior));
|
||||
$arguments[$key] = match ($type) {
|
||||
'service_closure' => new ServiceClosureArgument($arg),
|
||||
'closure' => (new Definition('Closure'))
|
||||
->setFactory(['Closure', 'fromCallable'])
|
||||
->addArgument($arg),
|
||||
};
|
||||
break;
|
||||
case 'service_locator':
|
||||
$arg = $this->getArgumentsAsPhp($arg, $name, $file);
|
||||
try {
|
||||
$arguments[$key] = new ServiceLocatorArgument($arg);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="service_locator" only accepts maps of type="service" references in "%s".', $name, $file));
|
||||
|
||||
if (isset($arg[0])) {
|
||||
trigger_deprecation('symfony/dependency-injection', '6.3', 'Skipping "key" argument or using integers as values in a "service_locator" tag is deprecated. The keys will default to the IDs of the original services in 7.0.');
|
||||
}
|
||||
|
||||
$arguments[$key] = new ServiceLocatorArgument($arg);
|
||||
break;
|
||||
case 'tagged':
|
||||
case 'tagged_iterator':
|
||||
case 'tagged_locator':
|
||||
$type = $arg->getAttribute('type');
|
||||
$forLocator = 'tagged_locator' === $type;
|
||||
|
||||
if (!$arg->getAttribute('tag')) {
|
||||
throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="%s" has no or empty "tag" attribute in "%s".', $name, $type, $file));
|
||||
}
|
||||
|
||||
$arguments[$key] = new TaggedIteratorArgument($arg->getAttribute('tag'), $arg->getAttribute('index-by') ?: null, $arg->getAttribute('default-index-method') ?: null, $forLocator, $arg->getAttribute('default-priority-method') ?: null);
|
||||
$excludes = array_column($this->getChildren($arg, 'exclude'), 'nodeValue');
|
||||
if ($arg->hasAttribute('exclude')) {
|
||||
if (\count($excludes) > 0) {
|
||||
throw new InvalidArgumentException('You cannot use both the attribute "exclude" and <exclude> tags at the same time.');
|
||||
}
|
||||
$excludes = [$arg->getAttribute('exclude')];
|
||||
}
|
||||
|
||||
$arguments[$key] = new TaggedIteratorArgument($arg->getAttribute('tag'), $arg->getAttribute('index-by') ?: null, $arg->getAttribute('default-index-method') ?: null, $forLocator, $arg->getAttribute('default-priority-method') ?: null, $excludes, !$arg->hasAttribute('exclude-self') || XmlUtils::phpize($arg->getAttribute('exclude-self')));
|
||||
|
||||
if ($forLocator) {
|
||||
$arguments[$key] = new ServiceLocatorArgument($arguments[$key]);
|
||||
@@ -557,13 +623,13 @@ class XmlFileLoader extends FileLoader
|
||||
$arguments[$key] = new AbstractArgument($arg->nodeValue);
|
||||
break;
|
||||
case 'string':
|
||||
$arguments[$key] = $arg->nodeValue;
|
||||
$arguments[$key] = $trim ? trim($arg->nodeValue) : $arg->nodeValue;
|
||||
break;
|
||||
case 'constant':
|
||||
$arguments[$key] = \constant(trim($arg->nodeValue));
|
||||
break;
|
||||
default:
|
||||
$arguments[$key] = XmlUtils::phpize($arg->nodeValue);
|
||||
$arguments[$key] = XmlUtils::phpize($trim ? trim($arg->nodeValue) : $arg->nodeValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -587,14 +653,36 @@ class XmlFileLoader extends FileLoader
|
||||
return $children;
|
||||
}
|
||||
|
||||
private function getTagAttributes(\DOMNode $node, string $missingName): array
|
||||
{
|
||||
$parameters = [];
|
||||
$children = $this->getChildren($node, 'attribute');
|
||||
|
||||
foreach ($children as $childNode) {
|
||||
if ('' === $name = $childNode->getAttribute('name')) {
|
||||
throw new InvalidArgumentException($missingName);
|
||||
}
|
||||
|
||||
if ($this->getChildren($childNode, 'attribute')) {
|
||||
$parameters[$name] = $this->getTagAttributes($childNode, $missingName);
|
||||
} else {
|
||||
if (str_contains($name, '-') && !str_contains($name, '_') && !\array_key_exists($normalizedName = str_replace('-', '_', $name), $parameters)) {
|
||||
$parameters[$normalizedName] = XmlUtils::phpize($childNode->nodeValue);
|
||||
}
|
||||
// keep not normalized key
|
||||
$parameters[$name] = XmlUtils::phpize($childNode->nodeValue);
|
||||
}
|
||||
}
|
||||
|
||||
return $parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a documents XML schema.
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @throws RuntimeException When extension references a non-existent XSD file
|
||||
*/
|
||||
public function validateSchema(\DOMDocument $dom)
|
||||
public function validateSchema(\DOMDocument $dom): bool
|
||||
{
|
||||
$schemaLocations = ['http://symfony.com/schema/dic/services' => str_replace('\\', '/', __DIR__.'/schema/dic/services/services-1.0.xsd')];
|
||||
|
||||
@@ -671,11 +759,6 @@ EOF
|
||||
|
||||
private function shouldEnableEntityLoader(): bool
|
||||
{
|
||||
// Version prior to 8.0 can be enabled without deprecation
|
||||
if (\PHP_VERSION_ID < 80000) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static $dom, $schema;
|
||||
if (null === $dom) {
|
||||
$dom = new \DOMDocument();
|
||||
@@ -699,7 +782,7 @@ EOF
|
||||
return !@$dom->schemaValidateSource($schema);
|
||||
}
|
||||
|
||||
private function validateAlias(\DOMElement $alias, string $file)
|
||||
private function validateAlias(\DOMElement $alias, string $file): void
|
||||
{
|
||||
foreach ($alias->attributes as $name => $node) {
|
||||
if (!\in_array($name, ['alias', 'id', 'public'])) {
|
||||
@@ -711,7 +794,7 @@ EOF
|
||||
if (!$child instanceof \DOMElement || self::NS !== $child->namespaceURI) {
|
||||
continue;
|
||||
}
|
||||
if (!\in_array($child->localName, ['deprecated'], true)) {
|
||||
if ('deprecated' !== $child->localName) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid child element "%s" defined for alias "%s" in "%s".', $child->localName, $alias->getAttribute('id'), $file));
|
||||
}
|
||||
}
|
||||
@@ -722,7 +805,7 @@ EOF
|
||||
*
|
||||
* @throws InvalidArgumentException When no extension is found corresponding to a tag
|
||||
*/
|
||||
private function validateExtensions(\DOMDocument $dom, string $file)
|
||||
private function validateExtensions(\DOMDocument $dom, string $file): void
|
||||
{
|
||||
foreach ($dom->documentElement->childNodes as $node) {
|
||||
if (!$node instanceof \DOMElement || 'http://symfony.com/schema/dic/services' === $node->namespaceURI) {
|
||||
@@ -731,7 +814,7 @@ EOF
|
||||
|
||||
// can it be handled by an extension?
|
||||
if (!$this->container->hasExtension($node->namespaceURI)) {
|
||||
$extensionNamespaces = array_filter(array_map(function (ExtensionInterface $ext) { return $ext->getNamespace(); }, $this->container->getExtensions()));
|
||||
$extensionNamespaces = array_filter(array_map(fn (ExtensionInterface $ext) => $ext->getNamespace(), $this->container->getExtensions()));
|
||||
throw new InvalidArgumentException(sprintf('There is no extension able to load the configuration for "%s" (in "%s"). Looked for namespace "%s", found "%s".', $node->tagName, $file, $node->namespaceURI, $extensionNamespaces ? implode('", "', $extensionNamespaces) : 'none'));
|
||||
}
|
||||
}
|
||||
@@ -740,7 +823,7 @@ EOF
|
||||
/**
|
||||
* Loads from an extension.
|
||||
*/
|
||||
private function loadFromExtensions(\DOMDocument $xml)
|
||||
private function loadFromExtensions(\DOMDocument $xml): void
|
||||
{
|
||||
foreach ($xml->documentElement->childNodes as $node) {
|
||||
if (!$node instanceof \DOMElement || self::NS === $node->namespaceURI) {
|
||||
@@ -772,10 +855,8 @@ EOF
|
||||
* * The nested-tags are converted to keys (<foo><foo>bar</foo></foo>)
|
||||
*
|
||||
* @param \DOMElement $element A \DOMElement instance
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function convertDomElementToArray(\DOMElement $element)
|
||||
public static function convertDomElementToArray(\DOMElement $element): mixed
|
||||
{
|
||||
return XmlUtils::convertDomElementToArray($element);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user