Completed
Branch master (099915)
by Fabio
08:02
created

TParameterModule::init()   A

Complexity

Conditions 6
Paths 5

Size

Total Lines 23
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 17
c 1
b 0
f 0
nc 5
nop 1
dl 0
loc 23
ccs 0
cts 23
cp 0
crap 42
rs 9.0777
1
<?php
2
/**
3
 * TParameterModule class
4
 *
5
 * @author Qiang Xue <[email protected]>
6
 * @link https://github.com/pradosoft/prado
7
 * @license https://github.com/pradosoft/prado/blob/master/LICENSE
8
 * @package Prado\Util
9
 */
10
11
namespace Prado\Util;
12
13
use Prado\Caching\TFileCacheDependency;
14
use Prado\Exceptions\TConfigurationException;
15
use Prado\Exceptions\TInvalidOperationException;
16
use Prado\Prado;
17
use Prado\TApplication;
18
use Prado\Xml\TXmlDocument;
19
use Prado\Xml\TXmlElement;
20
21
/**
22
 * TParameterModule class
23
 *
24
 * TParameterModule enables loading application parameters from external
25
 * storage other than the application configuration.
26
 * To load parameters from an XML file, configure the module by setting
27
 * its {@link setParameterFile ParameterFile} property.
28
 * Note, the property only accepts a file path in namespace format with
29
 * file extension being '.xml'. The file format is as follows,  which is
30
 * similar to the parameter portion in an application configuration,
31
 * <code>
32
 * <parameters>
33
 *   <parameter id="param1" value="paramValue1" />
34
 *   <parameter id="param2" Property1="Value1" Property2="Value2" ... />
35
 * </parameters>
36
 * </code>
37
 *
38
 * In addition, any content enclosed within the module tag is also treated
39
 * as parameters, e.g.,
40
 * <code>
41
 * <module class="Prado\Util\TParameterModule">
42
 *   <parameter id="param1" value="paramValue1" />
43
 *   <parameter id="param2" Property1="Value1" Property2="Value2" ... />
44
 * </module>
45
 * </code>
46
 *
47
 * If a parameter is defined both in the external file and within the module
48
 * tag, the former takes precedence.
49
 *
50
 * @author Qiang Xue <[email protected]>
51
 * @author Carl G. Mathisen <[email protected]>
52
 * @package Prado\Util
53
 * @since 3.0
54
 */
55
class TParameterModule extends \Prado\TModule
56
{
57
	const PARAM_FILE_EXT = '.xml';
58
	private $_initialized = false;
59
	private $_paramFile;
60
61
	/**
62
	 * Initializes the module by loading parameters.
63
	 * @param mixed $config content enclosed within the module tag
64
	 */
65
	public function init($config)
66
	{
67
		$this->loadParameters($config);
68
		if ($this->_paramFile !== null) {
69
			$configFile = null;
70
			if ($this->getApplication()->getConfigurationType() == TApplication::CONFIG_TYPE_XML && ($cache = $this->getApplication()->getCache()) !== null) {
71
				$cacheKey = 'TParameterModule:' . $this->_paramFile;
72
				if (($configFile = $cache->get($cacheKey)) === false) {
73
					$configFile = new TXmlDocument;
74
					$configFile->loadFromFile($this->_paramFile);
75
					$cache->set($cacheKey, $configFile, 0, new TFileCacheDependency($this->_paramFile));
76
				}
77
			} else {
78
				if ($this->getApplication()->getConfigurationType() == TApplication::CONFIG_TYPE_PHP) {
79
					$configFile = include $this->_paramFile;
80
				} else {
81
					$configFile = new TXmlDocument;
82
					$configFile->loadFromFile($this->_paramFile);
83
				}
84
			}
85
			$this->loadParameters($configFile);
86
		}
87
		$this->_initialized = true;
88
	}
89
90
	/**
91
	 * Loads parameters into application.
92
	 * @param mixed $config XML of PHP representation of the parameters
93
	 * @throws TConfigurationException if the parameter file format is invalid
94
	 */
95
	protected function loadParameters($config)
96
	{
97
		$parameters = [];
98
		if (is_array($config)) {
99
			foreach ($config as $id => $parameter) {
100
				if (is_array($parameter) && isset($parameter['class'])) {
101
					$properties = $parameter['properties'] ?? [];
102
					$parameters[$id] = [$parameter['class'], $properties];
103
				} else {
104
					$parameters[$id] = $parameter;
105
				}
106
			}
107
		} elseif ($config instanceof TXmlElement) {
108
			foreach ($config->getElementsByTagName('parameter') as $node) {
109
				$properties = $node->getAttributes();
110
				if (($id = $properties->remove('id')) === null) {
111
					throw new TConfigurationException('parametermodule_parameterid_required');
112
				}
113
				if (($type = $properties->remove('class')) === null) {
114
					if (($value = $properties->remove('value')) === null) {
115
						$parameters[$id] = $node;
116
					} else {
117
						$parameters[$id] = $value;
118
					}
119
				} else {
120
					$parameters[$id] = [$type, $properties->toArray()];
121
				}
122
			}
123
		}
124
125
		$appParams = $this->getApplication()->getParameters();
126
		foreach ($parameters as $id => $parameter) {
127
			if (is_array($parameter)) {
128
				$component = Prado::createComponent($parameter[0]);
129
				foreach ($parameter[1] as $name => $value) {
130
					$component->setSubProperty($name, $value);
131
				}
132
				$appParams->add($id, $component);
133
			} else {
134
				$appParams->add($id, $parameter);
135
			}
136
		}
137
	}
138
139
	/**
140
	 * @return string the parameter file path
141
	 */
142
	public function getParameterFile()
143
	{
144
		return $this->_paramFile;
145
	}
146
147
	/**
148
	 * @param string $value the parameter file path. It must be in namespace format
149
	 * and the file extension is '.xml'.
150
	 * @throws TInvalidOperationException if the module is initialized
151
	 * @throws TConfigurationException if the file is invalid
152
	 */
153
	public function setParameterFile($value)
154
	{
155
		if ($this->_initialized) {
156
			throw new TInvalidOperationException('parametermodule_parameterfile_unchangeable');
157
		} elseif (($this->_paramFile = Prado::getPathOfNamespace($value, $this->getApplication()->getConfigurationFileExt())) === null || !is_file($this->_paramFile)) {
158
			throw new TConfigurationException('parametermodule_parameterfile_invalid', $value);
159
		}
160
	}
161
}
162