Passed
Push — master ( 47e8e4...d5adc1 )
by Fabio
04:41
created

TBehaviorsModule::setAdditionalBehaviors()   A

Complexity

Conditions 6
Paths 8

Size

Total Lines 17
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 12
c 1
b 0
f 0
nc 8
nop 1
dl 0
loc 17
rs 9.2222
1
<?php
2
/**
3
 * TBehaviorsModule class
4
 *
5
 * @author Brad Anderson <[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\Exceptions\TConfigurationException;
14
use Prado\TApplication;
15
use Prado\TComponent;
16
use Prado\Xml\TXmlDocument;
17
use Prado\Xml\TXmlElement;
18
19
/**
20
 * TBehaviorsModule class.
21
 *
22
 * TBehaviorsModule loads and attaches {@link TBehaviors}.  This attaches
23
 * Behaviors to classes and to application components like the TApplication,
24
 * individual modules, and TPage of the TPageService.
25
 *
26
 * Contents enclosed within the module tag are treated as behaviors, e.g.,
27
 * <code>
28
 * <module class="Prado\Util\TBehaviorsModule" Parameter="AdditionalBehaviors">
29
 *   <behavior Name="pagethemeparameter" Class="Prado\Util\Behaviors\TParameterizeBehavior" AttachToClass="Prade\Web\UI\TPage" Priority="10" Parameter="ThemeName" Property="Theme"/>
30
 *   <behavior Name="sharedModuleBehavior" Class="FooModuleBehavior" AttachToClass="Prado\TModule" Attribute1="abc"/>
31
 *   <behavior name="TimeZoneBehavior" Class="Prado\Util\Behaviors\TTimeZoneParameterBehavior" AttachTo="Application" Priority="10" TimeZone="America/New York" TimeZoneParameter="prop:TimeZone" />
32
 *   <behavior name="MyModuleBehavior" Class="MyModuleBehavior" AttachTo="Module:page" Property1="Value1" Property2="Value2" ... />
33
 *   <behavior name="MyPageTitleBehavior" Class="Prado\Util\Behaviors\TParameterizeBehavior" AttachTo="Page" Priority="10" Parameter="PageTitle" Property="Title" Localize="true"/>
34
 * </module>
35
 * </code>
36
 *
37
 * When the Service is not TPageService, page behaviors are not installed and have no effect other than be ignored.
38
 *
39
 * When {@link setAdditionalBehaviors AdditionalBehaviors} is set, this module
40
 * loads the behaviors from that property. It can be an array of php behavior definition arrays.
41
 * or a string that is then passed through unserialize or json_decode; otherwise is treated as
42
 * an xml document of behavior like above.
43
 *
44
 * The format is in the PHP style module configuration:
45
 * </code>
46
 *		[['name' => 'behaviorname', 'class' => 'TMyBehaviorClass', 'attachto' => 'page', 'priority' => '10', 'behaviorProperty'=>"value1'], ...]
47
 * </code>
48
 *
49
 * This allows TBehaviorsModule to load behaviors, dynamically, from parameters with the TParameterizeBehavior.
50
 *
51
 * @author Brad Anderson <[email protected]>
52
 * @package Prado\Util
53
 * @since 4.2.0
54
 */
55
class TBehaviorsModule extends \Prado\TModule
56
{
57
	/**
58
	 * @var Tbehavior[] behaviors attaching to the TPage
59
	 */
60
	private $_pageBehaviors = [];
61
	
62
	/**
63
	 * @var array[] additional behaviors in a configuration format: array[], serialized php object, json object, string of xml
64
	 */
65
	private $_additionalBehaviors;
66
	
67
	/**
68
	 * Initializes the module by loading behaviors.  If there are page behaviors, this
69
	 * attaches behaviors to TPage through TApplication::onBeginRequest and then
70
	 * TPageService::onPreRunPage.
71
	 * @param \Prado\Xml\TXmlElement $config configuration for this module, can be null
72
	 */
73
	public function init($config)
74
	{
75
		$this->loadBehaviors($config);
76
		$this->loadBehaviors(['behaviors' => $this->getAdditionalBehaviors()]);
77
		
78
		if (count($this->_pageBehaviors)) {
79
			$this->getApplication()->attachEventHandler('onBeginRequest', [$this, 'attachTPageServiceHandler']);
80
		}
81
		parent::init($config);
82
	}
83
	
84
	/**
85
	 * TApplication::onBeginRequest Handler that adds {@link attachTPageBehaviors} to
86
	 * TPageService::onPreRunPage. In turn, this attaches {@link attachTPageBehaviors}
87
	 * to TPageService to then adds the page behaviors.
88
	 * @param object $sender the object that raised the event
89
	 * @param mixed $param parameter of the event
90
	 */
91
	public function attachTPageServiceHandler($sender, $param)
0 ignored issues
show
Unused Code introduced by
The parameter $param is not used and could be removed. ( Ignorable by Annotation )

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

91
	public function attachTPageServiceHandler($sender, /** @scrutinizer ignore-unused */ $param)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $sender is not used and could be removed. ( Ignorable by Annotation )

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

91
	public function attachTPageServiceHandler(/** @scrutinizer ignore-unused */ $sender, $param)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
92
	{
93
		$service = $this->getService();
94
		if ($service->isa('Prado\\Web\\Services\\TPageService')) {
0 ignored issues
show
Bug introduced by
The method isa() does not exist on Prado\IService. Since it exists in all sub-types, consider adding an abstract or default implementation to Prado\IService. ( Ignorable by Annotation )

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

94
		if ($service->/** @scrutinizer ignore-call */ isa('Prado\\Web\\Services\\TPageService')) {
Loading history...
95
			$service->attachEventHandler('onPreRunPage', [$this, 'attachTPageBehaviors']);
0 ignored issues
show
Bug introduced by
The method attachEventHandler() does not exist on Prado\IService. Since it exists in all sub-types, consider adding an abstract or default implementation to Prado\IService. ( Ignorable by Annotation )

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

95
			$service->/** @scrutinizer ignore-call */ 
96
             attachEventHandler('onPreRunPage', [$this, 'attachTPageBehaviors']);
Loading history...
96
		}
97
	}
98
	
99
	/**
100
	 * This method attaches page behaviors to the TPage handling the TPageService::OnPreInitPage event.
101
	 * @param object $sender the object that raised the event
102
	 * @param TPage $page the page being initialized
0 ignored issues
show
Bug introduced by
The type Prado\Util\TPage was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
103
	 */
104
	public function attachTPageBehaviors($sender, $page)
105
	{
106
		foreach ($this->_pageBehaviors as $name => $properties) {
107
			$priority = $properties['priority'] ?? null;
108
			unset($properties['priority']);
109
			$page->attachBehavior($name, $properties, $priority);
110
		}
111
		$this->_pageBehaviors = [];
112
	}
113
114
	/**
115
	 * Loads behaviors and attach to the proper object. behaviors for pages are
116
	 * attached separately if and when the TPage is loaded on TPageSerivce::onPreRunPage
117
	 * @param mixed $config XML of PHP representation of the behaviors
118
	 * @throws prado\Exceptions\TConfigurationException if the parameter file format is invalid
119
	 */
120
	protected function loadBehaviors($config)
121
	{
122
		$isXml = false;
123
		if ($config instanceof TXmlElement) {
124
			$isXml = true;
125
			$config = $config->getElementsByTagName('behavior');
126
		} elseif (is_array($config)) {
127
			$config = $config['behaviors'];
128
		} elseif (!$config) {
129
			return;
130
		}
131
		foreach ($config as $properties) {
132
			if ($isXml) {
133
				$properties = array_change_key_case($properties->getAttributes()->toArray());
134
			} else {
135
				if (!is_array($properties)) {
136
					throw new TConfigurationException('behaviormodule_behavior_as_array_required');
137
				}
138
			}
139
			$name = $properties['name'];
140
			unset($properties['name']);
141
			if (!$name) {
142
				throw new TConfigurationException('behaviormodule_behaviorname_required');
143
			}
144
			
145
			$attachTo = $properties['attachto'] ?? null;
146
			$attachToClass = $properties['attachtoclass'] ?? null;
147
			unset($properties['attachto']);
148
			unset($properties['attachtoclass']);
149
			if ($attachTo === null && $attachToClass === null) {
150
				throw new TConfigurationException('behaviormodule_attachto_class_required');
151
			} elseif ($attachTo !== null && $attachToClass !== null) {
152
				throw new TConfigurationException('behaviormodule_attachto_and_class_only_one');
153
			}
154
			if ($attachToClass) {
155
				$priority = $properties['priority'] ?? null;
156
				unset($properties['priority']);
157
				TComponent::attachClassBehavior($name, $properties, $attachToClass, $priority);
0 ignored issues
show
Bug introduced by
$properties of type array 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

157
				TComponent::attachClassBehavior($name, /** @scrutinizer ignore-type */ $properties, $attachToClass, $priority);
Loading history...
158
			} else {
159
				if (strtolower($attachTo) == "page") {
160
					$this->_pageBehaviors[$name] = $properties;
161
					continue;
162
				} elseif (strncasecmp($attachTo, 'module:', 7) === 0) {
163
					$owner = $this->getApplication()->getModule(trim(substr($attachTo, 7)));
164
				} else {
165
					$owner = $this->getSubProperty($attachTo);
166
				}
167
				$priority = $properties['priority'] ?? null;
168
				unset($properties['priority']);
169
				if (!$owner) {
170
					throw new TConfigurationException('behaviormodule_behaviorowner_required', $attachTo);
171
				}
172
				$owner->attachBehavior($name, $properties, $priority);
173
			}
174
		}
175
	}
176
	
177
	/**
178
	 * @return array additional behaviors in a list.
179
	 */
180
	public function getAdditionalBehaviors()
181
	{
182
		return $this->_additionalBehaviors ?? [];
183
	}
184
	 
185
	/**
186
	 * this will take a string that is an array of behaviors that has been
187
	 * through serialize(), or json array of behaviors.  If one behavior is
188
	 * set as an array, then it is automatically placed into an array.
189
	 * @param array[]|string $behaviors additional behaviors
190
	 */
191
	public function setAdditionalBehaviors($behaviors)
192
	{
193
		if (is_string($behaviors)) {
194
			if (($b = @unserialize($behaviors)) !== false) {
195
				$behaviors = $b;
196
			} elseif (($b = json_decode($behaviors, true)) !== null) {
197
				$behaviors = $b;
198
			} else {
199
				$xmldoc = new TXmlDocument('1.0', 'utf-8');
200
				$xmldoc->loadFromString($behaviors);
201
				$behaviors = $xmldoc;
202
			}
203
		}
204
		if (is_array($behaviors) && isset($behaviors['class'])) {
205
			$behaviors = [$behaviors];
206
		}
207
		$this->_additionalBehaviors = $behaviors ?? [];
208
	}
209
}
210