Add XML config structure for automatized treatment

2.x
Julien Rosset 3 years ago
parent a01a6b49f5
commit ea3d2faf30

@ -3,9 +3,11 @@
namespace jrosset\EnvReader; namespace jrosset\EnvReader;
use Exception; use Exception;
use jrosset\ArrayClasses\InsensitiveCaseArrayClass; use jrosset\EnvReader\XmlStructure\IXmlStructure;
use SimpleXMLElement;
/**
* A XML file configuration class
*/
abstract class XmlConfig extends GenericConfig implements IExternalConfigFile { abstract class XmlConfig extends GenericConfig implements IExternalConfigFile {
use TMultiLevelProperties; use TMultiLevelProperties;
@ -13,11 +15,13 @@ abstract class XmlConfig extends GenericConfig implements IExternalConfigFile {
* @inheritDoc * @inheritDoc
*/ */
protected function readConfig (): void { protected function readConfig (): void {
//region Contrôle fichier existant
$configFile = $this->getConfigFilePath(); $configFile = $this->getConfigFilePath();
if (!file_exists($configFile)) { if (!file_exists($configFile)) {
throw new Exception('Unable to find configuration file "' . $configFile . '"'); throw new Exception('Unable to find configuration file "' . $configFile . '"');
} }
//endregion
//region Chargement fichier et traitement erreurs
if (($xml = simplexml_load_file($configFile)) === false) { if (($xml = simplexml_load_file($configFile)) === false) {
$errors = []; $errors = [];
foreach (libxml_get_errors() as $error) { foreach (libxml_get_errors() as $error) {
@ -41,15 +45,16 @@ abstract class XmlConfig extends GenericConfig implements IExternalConfigFile {
throw new Exception('Unable to read configuration file "' . $configFile . '": ' . PHP_EOL . implode(PHP_EOL, $errors)); throw new Exception('Unable to read configuration file "' . $configFile . '": ' . PHP_EOL . implode(PHP_EOL, $errors));
} }
$this->properties = $this->parseXml($xml); //endregion
//region Parsage XML
$this->properties = $this->getConfigStructure()->parseXml($xml);
//endregion
} }
/** /**
* Parse an XML node to properties * Obtient la structure de la configuration
*
* @param SimpleXMLElement $xmlNode The INI level
* @param InsensitiveCaseArrayClass $properties [OUT] The out properties list
* *
* @return void * @return IXmlStructure La structure de la configuration
*/ */
protected abstract function parseXml (SimpleXMLElement $xmlNode): InsensitiveCaseArrayClass; protected abstract function getConfigStructure (): IXmlStructure;
} }

@ -0,0 +1,75 @@
<?php
namespace jrosset\EnvReader\XmlStructure;
use jrosset\ArrayClasses\InsensitiveCaseArrayClass;
use SimpleXMLElement;
/**
* Structure about XML attributes
*/
class AttributeListXmlStructure implements IXmlStructure {
/**
* @var array Allowed attributes. Empty for all
*/
private array $allowed;
/**
* @var InsensitiveCaseArrayClass Mapping between attributes name and properties name
*/
private InsensitiveCaseArrayClass $mapping;
/**
* Initialize
*/
public function __construct () {
$this->allowed = [];
$this->mapping = new InsensitiveCaseArrayClass();
}
/**
* Add a new allowed attribute name
*
* @param string $attributeName The new allowed attribute name
* @param string|null $propertyName The corresponding property name. Null if identical to attribute name
*
* @return $this
*/
public function addAllowed (string $attributeName, ?string $propertyName = null): self {
$this->allowed[] = mb_strtolower($attributeName);
if ($propertyName !== null) {
$this->addMapping($attributeName, $propertyName);
}
return $this;
}
/**
* Add a new mapping
*
* @param string $attributeName The new attribute name
* @param string $propertyName The corresponding property name
*
* @return $this
*/
public function addMapping (string $attributeName, string $propertyName): self {
$this->mapping->set($attributeName, $propertyName);
return $this;
}
/**
* @inheritDoc
*/
public function parseXml (SimpleXMLElement $xmlNode): InsensitiveCaseArrayClass {
$properties = new InsensitiveCaseArrayClass();
if (($attributes = $xmlNode->attributes()) === null) {
return $properties;
}
$allowAll = count($this->allowed) === 0;
foreach ($attributes as $attributeName => $attributeValue) {
if (!$allowAll && !in_array(mb_strtolower($attributeName), $this->allowed)) {
continue;
}
$properties->set($this->mapping->get($attributeName, false) ?? $attributeName, (string)$attributeValue);
}
return $properties;
}
}

@ -0,0 +1,31 @@
<?php
namespace jrosset\EnvReader\XmlStructure;
use SimpleXMLElement;
/**
* Structure about a single attribute
*/
class AttributeSingleXmlStructure implements IXmlStructure {
/**
* @var string The attribute name
*/
private string $attributeName;
/**
* Initialize
*
* @param string $attributeName The attribute name
*/
public function __construct (string $attributeName) {
$this->attributeName = $attributeName;
}
/**
* @inheritDoc
*/
public function parseXml (SimpleXMLElement $xmlNode): string {
return (string)$xmlNode[$this->attributeName];
}
}

@ -0,0 +1,87 @@
<?php
namespace jrosset\EnvReader\XmlStructure;
use jrosset\ArrayClasses\ArrayClass;
use jrosset\ArrayClasses\InsensitiveCaseArrayClass;
use SimpleXMLElement;
/**
* Structure about children nodes
*/
class ChildrenXmlStructure implements IXmlStructure {
/**
* @var AttributeListXmlStructure|null The attribute structure. Null if none
*/
private ?AttributeListXmlStructure $attributesStructure;
/**
* @var ArrayClass The children nodes
*/
private ArrayClass $childrenNodes;
/**
* @var InsensitiveCaseArrayClass Mapping between child node name and properties name
*/
private ArrayClass $mapping;
/**
* Initialize
*/
public function __construct () {
$this->attributesStructure = null;
$this->childrenNodes = new ArrayClass();
$this->mapping = new ArrayClass();
}
/**
* Set the attribute structure
*
* @param AttributeListXmlStructure|null $attributesStructure The new attribute structure. Null if none
*
* @return $this
*/
public function setAttributesStructure (?AttributeListXmlStructure $attributesStructure = null): self {
$this->attributesStructure = $attributesStructure;
return $this;
}
/**
* Add a child node
*
* @param string $childNodeName The child node's name
* @param IXmlStructure $childNodeStructure The child node's structure
* @param string|null $propertyName The corresponding property name. Null if identical to child node's name
*
* @return $this
*/
public function addChildNode (string $childNodeName, IXmlStructure $childNodeStructure, ?string $propertyName = null): self {
$this->childrenNodes->set($childNodeName, $childNodeStructure);
if ($propertyName !== null) {
$this->mapping->set($childNodeName, $propertyName);
}
return $this;
}
/**
* @inheritDoc
*/
public function parseXml (SimpleXMLElement $xmlNode): InsensitiveCaseArrayClass {
if ($this->attributesStructure === null) {
$properties = new InsensitiveCaseArrayClass();
}
else {
$properties = $this->attributesStructure->parseXml($xmlNode);
}
/** @var IXmlStructure $childNodeStructure */
foreach ($this->childrenNodes as $childNodeName => $childNodeStructure) {
if (!isset($xmlNode->$childNodeName)) {
continue;
}
$properties->set(
$this->mapping->get($childNodeName, false) ?? $childNodeName,
$childNodeStructure->parseXml($xmlNode->$childNodeName)
);
}
return $properties;
}
}

@ -0,0 +1,19 @@
<?php
namespace jrosset\EnvReader\XmlStructure;
use SimpleXMLElement;
/**
* The interface of XML structure
*/
interface IXmlStructure {
/**
* Parse a XML node
*
* @param SimpleXMLElement $xmlNode The XML node
*
* @return mixed The extracted value
*/
public function parseXml (SimpleXMLElement $xmlNode);
}

@ -0,0 +1,47 @@
<?php
namespace jrosset\EnvReader\XmlStructure;
use jrosset\ArrayClasses\InsensitiveCaseArrayClass;
use SimpleXMLElement;
/**
* Structure about children list
*/
class ListXmlStructure implements IXmlStructure {
/**
* @var string The child node's name
*/
private string $childNodeName;
/**
* @var IXmlStructure The child node's structure
*/
private IXmlStructure $childNodeStructure;
/**
* Initialize
*
* @param string $childNodeName The child node's name
* @param IXmlStructure $childNodeStructure The child node's structure
*/
public function __construct (string $childNodeName, IXmlStructure $childNodeStructure) {
$this->childNodeName = $childNodeName;
$this->childNodeStructure = $childNodeStructure;
}
/**
* @inheritDoc
*/
public function parseXml (SimpleXMLElement $xmlNode): InsensitiveCaseArrayClass {
$properties = new InsensitiveCaseArrayClass();
if (!isset($xmlNode->{$this->childNodeName})) {
return $properties;
}
foreach ($xmlNode->{$this->childNodeName} as $childNode) {
$childProperties = $this->childNodeStructure->parseXml($childNode);
$properties->push($childProperties);
}
return $properties;
}
}

@ -0,0 +1,17 @@
<?php
namespace jrosset\EnvReader\XmlStructure;
use SimpleXMLElement;
/**
* Structure about XML node's text
*/
class TextXmlStructure implements IXmlStructure {
/**
* @inheritDoc
*/
public function parseXml (SimpleXMLElement $xmlNode): string {
return (string)$xmlNode;
}
}
Loading…
Cancel
Save