Passed
Push — master ( e1e446...1b5c12 )
by Fabio
06:00
created

TBehaviorParameterLoader::attachModuleBehaviors()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 9
c 1
b 0
f 0
nc 4
nop 2
dl 0
loc 14
rs 9.9666
1
<?php
2
3
/**
4
 * TBehaviorParameterLoader class file.
5
 *
6
 * @author Brad Anderson <[email protected]>
7
 * @link https://github.com/pradosoft/prado
8
 * @license https://github.com/pradosoft/prado/blob/master/LICENSE
9
 */
10
11
namespace Prado\Util\Behaviors;
12
13
use Prado\Collections\TPriorityItemTrait;
14
use Prado\Exceptions\TConfigurationException;
15
use Prado\Prado;
16
use Prado\TComponent;
17
use Prado\TPropertyValue;
18
use Prado\Util\IBaseBehavior;
19
20
/**
21
 * TBehaviorParameterLoader class.
22
 *
23
 * TBehaviorParameterLoader implements attaching Behaviors from Parameters
24
 * before any work has been done.  Here is an example of how to attach a behavior
25
 * via parameter within an application.xml:
26
 * <code>
27
 * <application id="prado-app">
28
 *		<parameters>
29
 *		<parameter id="pagethemebehaviorloader" class="Prado\Util\Behaviors\TBehaviorParameterLoader" BehaviorName="testBehavior" BehaviorClass="Prado\Util\Behaviors\TParameterizeBehavior" Priority="10" AttachToClass="Prado\Web\UI\TPage" Parameter="ThemeName" Property="Theme" DefaultValue="ColoradoBlue2022" />
30
 *		<parameters>
31
 * 	  ...
32
 * </code>
33
 *
34
 * TBehaviorParameterLoader can be used in parameters to load behaviors through the
35
 * application configuration parameters, {@link TParameterModule}, as well in each
36
 * folder through the config.xml/php files.
37
 *
38
 * @author Brad Anderson <[email protected]>
39
 * @since 4.2.0
40
 */
41
class TBehaviorParameterLoader extends TComponent
42
{
43
	use TPriorityItemTrait;
44
45
	/** @var string name of the behavior attaching to the owner */
46
	private $_behaviorName;
47
48
	/** @var string class of the behavior attaching to the owner */
49
	private $_behaviorClass;
50
51
	/** @var string what object to attach the behavior */
52
	private $_attachto;
53
54
	/** @var string what class to attach the behavior */
55
	private $_attachtoclass;
56
57
	/** @var array<string, string> additional properties to feed the behavior */
58
	private $_properties = [];
59
60
	/** @var array<string, array<string, string>> the list of behaviors to attach to the page */
61
	private static $_pageBehaviors = [];
62
63
	/** @var array<string, array<object>> the list of behaviors to attach to the page */
64
	private static $_moduleBehaviors = [];
65
66
	/**
67
	 * Install the behavior via dynamic event dyInit, called after a parameter
68
	 * class is loaded in TParameterModule or TApplication configurations.
69
	 * @param null|mixed $config for Parameters this is null.
70
	 */
71
	public function dyInit($config)
72
	{
73
		if (!$this->_behaviorName) {
74
			throw new TConfigurationException('behaviorparameterloader_no_behavior_name');
75
		}
76
		if (!$this->_behaviorClass) {
77
			throw new TConfigurationException('behaviorparameterloader_no_behavior_class');
78
		}
79
80
		if ($this->_attachto === null && $this->_attachtoclass === null) {
81
			throw new TConfigurationException('behaviorparameterloader_attachto_class_required');
82
		} elseif ($this->_attachto !== null && $this->_attachtoclass !== null) {
83
			throw new TConfigurationException('behaviorparameterloader_attachto_and_class_only_one');
84
		}
85
		$this->_properties['class'] = $this->_behaviorClass;
86
		$this->_properties[IBaseBehavior::CONFIG_KEY] = $config;
87
		if ($this->_attachtoclass) {
88
			TComponent::attachClassBehavior($this->_behaviorName, $this->_properties, $this->_attachtoclass, $this->_priority);
0 ignored issues
show
Bug introduced by
$this->_properties of type array<string,string> is incompatible with the type object|string expected by parameter $behavior of Prado\TComponent::attachClassBehavior(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

88
			TComponent::attachClassBehavior($this->_behaviorName, /** @scrutinizer ignore-type */ $this->_properties, $this->_attachtoclass, $this->_priority);
Loading history...
Bug introduced by
It seems like $this->_priority can also be of type double; however, parameter $priority of Prado\TComponent::attachClassBehavior() does only seem to accept Prado\numeric|null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

88
			TComponent::attachClassBehavior($this->_behaviorName, $this->_properties, $this->_attachtoclass, /** @scrutinizer ignore-type */ $this->_priority);
Loading history...
89
		} else {
90
			if (strtolower($this->_attachto) == "page") {
91
				if (!count(self::$_pageBehaviors)) {
92
					Prado::getApplication()->attachEventHandler('onBeginRequest', [$this, 'attachTPageServiceHandler']);
93
				}
94
				self::$_pageBehaviors[$this->_behaviorName] = $this->_properties;
95
				return;
96
			} elseif (strncasecmp(strtolower($this->_attachto), 'module:', 7) === 0) {
97
				if (!count(self::$_moduleBehaviors)) {
98
					Prado::getApplication()->attachEventHandler('onInitComplete', [$this, 'attachModulesBehaviors'], -20);
0 ignored issues
show
Bug introduced by
-20 of type integer is incompatible with the type Prado\numeric|null expected by parameter $priority of Prado\TComponent::attachEventHandler(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

98
					Prado::getApplication()->attachEventHandler('onInitComplete', [$this, 'attachModulesBehaviors'], /** @scrutinizer ignore-type */ -20);
Loading history...
99
				}
100
				$moduleid = trim(substr($this->_attachto, 7));
101
				if (!$moduleid) {
102
					throw new TConfigurationException('behaviorparameterloader_moduleid_required', $moduleid);
103
				}
104
				self::$_moduleBehaviors[$moduleid] = self::$_moduleBehaviors[$moduleid] ?? [];
105
				self::$_moduleBehaviors[$moduleid][$this->_behaviorName] = $this->_properties;
106
				return;
107
			} elseif (strtolower($this->_attachto) == "application") {
108
				$owner = Prado::getApplication();
109
			} else {
110
				$owner = Prado::getApplication()->getSubProperty($this->_attachto);
111
			}
112
			$priority = $this->_properties['priority'] ?? null;
0 ignored issues
show
Unused Code introduced by
The assignment to $priority is dead and can be removed.
Loading history...
113
			unset($this->_properties['priority']);
114
			if (!$owner) {
115
				throw new TConfigurationException('behaviorparameterloader_behaviorowner_required', $this->_attachto);
116
			}
117
			$owner->attachBehavior($this->_behaviorName, $this->_properties, $this->_priority);
118
		}
119
	}
120
121
	/**
122
	 * TApplication::onBeginRequest Handler that adds {@link attachTPageBehaviors} to
123
	 * TPageService::onPreRunPage. In turn, this attaches {@link attachTPageBehaviors}
124
	 * to TPageService to then adds the page behaviors.
125
	 * @param object $sender the object that raised the event
126
	 * @param mixed $param parameter of the event
127
	 */
128
	public function attachTPageServiceHandler($sender, $param)
129
	{
130
		$service = Prado::getApplication()->getService();
131
		if ($service instanceof \Prado\Web\Services\TPageService) {
132
			$service->attachEventHandler('onPreRunPage', [$this, 'attachTPageBehaviors'], -20);
0 ignored issues
show
Bug introduced by
-20 of type integer is incompatible with the type Prado\numeric|null expected by parameter $priority of Prado\TComponent::attachEventHandler(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

132
			$service->attachEventHandler('onPreRunPage', [$this, 'attachTPageBehaviors'], /** @scrutinizer ignore-type */ -20);
Loading history...
133
		}
134
	}
135
136
	/**
137
	 * This method attaches page behaviors to the TPage handling the TPageService::OnPreInitPage event.
138
	 * @param object $sender the object that raised the event
139
	 * @param \Prado\Web\UI\TPage $page the page being initialized
140
	 */
141
	public function attachModuleBehaviors($sender, $page)
142
	{
143
		foreach (self::$_moduleBehaviors as $id => $behaviors) {
144
			$owner = Prado::getApplication()->getModule($id);
145
			if (!$owner) {
146
				throw new TConfigurationException('behaviorparameterloader_behaviormodule_not_found', $id);
147
			}
148
			foreach ($behaviors as $name => $properties) {
149
				$priority = $properties['priority'] ?? null;
150
				unset($properties['priority']);
151
				$owner->attachBehavior($name, $properties, $priority);
152
			}
153
		}
154
		self::$_moduleBehaviors = [];
155
	}
156
157
	/**
158
	 * This method attaches page behaviors to the TPage handling the TPageService::OnPreInitPage event.
159
	 * @param object $sender the object that raised the event
160
	 * @param \Prado\Web\UI\TPage $page the page being initialized
161
	 */
162
	public function attachTPageBehaviors($sender, $page)
163
	{
164
		foreach (self::$_pageBehaviors as $name => $properties) {
165
			$priority = $properties['priority'] ?? null;
166
			unset($properties['priority']);
167
			$page->attachBehavior($name, $properties, $priority);
0 ignored issues
show
Bug introduced by
It seems like $priority can also be of type string; however, parameter $priority of Prado\TComponent::attachBehavior() does only seem to accept Prado\numeric|null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

167
			$page->attachBehavior($name, $properties, /** @scrutinizer ignore-type */ $priority);
Loading history...
168
		}
169
		self::$_pageBehaviors = [];
170
	}
171
172
	/**
173
	 * This resets the module and page behavior cache data.
174
	 */
175
	public function reset()
176
	{
177
		if ($this->_attachtoclass) {
178
			TComponent::detachClassBehavior($this->_behaviorName, $this->_attachtoclass);
179
		}
180
		Prado::getApplication()->detachEventHandler('onInitComplete', [$this, 'attachModulesBehaviors']);
181
		Prado::getApplication()->detachEventHandler('onBeginRequest', [$this, 'attachTPageServiceHandler']);
182
		self::$_moduleBehaviors = [];
183
		self::$_pageBehaviors = [];
184
185
		$this->_behaviorName = null;
186
		$this->_behaviorClass = null;
187
		$this->_priority = null;
188
		$this->_attachto = null;
189
		$this->_attachtoclass = null;
190
		$this->_properties = [];
191
	}
192
193
	/**
194
	 * gets the name of the attaching behavior.
195
	 * @return string the name of the attaching behavior.
196
	 */
197
	public function getBehaviorName()
198
	{
199
		return $this->_behaviorName;
200
	}
201
202
	/**
203
	 * sets the name of the attaching behavior.
204
	 * @param string $name the name of the attaching behavior.
205
	 */
206
	public function setBehaviorName($name)
207
	{
208
		$this->_behaviorName = TPropertyValue::ensureString($name);
209
	}
210
211
	/**
212
	 * gets the class of the attaching behavior.
213
	 * @return string the class of the attaching behavior.
214
	 */
215
	public function getBehaviorClass()
216
	{
217
		return $this->_behaviorClass;
218
	}
219
220
	/**
221
	 * sets the class of the attaching behavior.
222
	 * @param string $className the class of the attaching behavior.
223
	 */
224
	public function setBehaviorClass($className)
225
	{
226
		$this->_behaviorClass = TPropertyValue::ensureString($className);
227
	}
228
229
	/**
230
	 * gets the AttachTo value.
231
	 * @return string the AttachTo value.
232
	 */
233
	public function getAttachTo()
234
	{
235
		return $this->_attachto;
236
	}
237
238
	/**
239
	 * Sets the AttachTo property.
240
	 * @param string $attachto the new AttachTo value.
241
	 */
242
	public function setAttachTo($attachto)
243
	{
244
		$this->_attachto = TPropertyValue::ensureString($attachto);
245
	}
246
247
	/**
248
	 * gets the AttachToClass value.
249
	 * @return string the AttachToClass value.
250
	 */
251
	public function getAttachToClass()
252
	{
253
		return $this->_attachtoclass;
254
	}
255
256
	/**
257
	 * Sets the AttachToClass property.
258
	 * @param string $attachto the new AttachToClass value.
259
	 */
260
	public function setAttachToClass($attachto)
261
	{
262
		$this->_attachtoclass = TPropertyValue::ensureString($attachto);
263
	}
264
265
	/**
266
	 * gets the Additional Properties of the behavior.
267
	 * @return array additional behaviors for the behavior class.
268
	 */
269
	public function getProperties()
270
	{
271
		return $this->_properties;
272
	}
273
274
	/**
275
	 * magic method for storing the properties for the behavior. If there is no
276
	 * set Property then it stores the property to set on the behavior.
277
	 * @param string $name name of the property being set.
278
	 * @param string $value value of the property being set.
279
	 */
280
	public function __set($name, $value)
281
	{
282
		if (method_exists($this, $setter = 'set' . $name)) {
283
			return $this->$setter($value);
284
		} else {
285
			$this->_properties[$name] = $value;
286
		}
287
	}
288
}
289