Passed
Push — master ( dd2bb6...2f3656 )
by Aimeos
08:00
created

Html::addClientDecorators()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 53
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 18
nc 4
nop 3
dl 0
loc 53
rs 9.3554
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2015-2022
6
 * @package Client
7
 * @subpackage Html
8
 */
9
10
11
namespace Aimeos\Client;
12
13
14
/**
15
 * Common factory for HTML clients
16
 *
17
 * @package Client
18
 * @subpackage Html
19
 */
20
class Html
21
{
22
	private static $objects = [];
23
24
25
	/**
26
	 * Creates a new client object
27
	 *
28
	 * @param \Aimeos\MShop\ContextIface $context Shop context instance with necessary objects
29
	 * @param string $path Type of the client, e.g 'account/favorite' for \Aimeos\Client\Html\Account\Favorite\Standard
30
	 * @param string|null $name Client name (default: "Standard")
31
	 * @return \Aimeos\Client\Html\Iface HTML client implementing \Aimeos\Client\Html\Iface
32
	 * @throws \Aimeos\Client\Html\Exception If requested client implementation couldn't be found or initialisation fails
33
	 */
34
	public static function create( \Aimeos\MShop\ContextIface $context, string $path, string $name = null ) : \Aimeos\Client\Html\Iface
35
	{
36
		if( empty( $path ) ) {
37
			throw new \Aimeos\Client\Html\Exception( sprintf( 'Client path is empty' ) );
38
		}
39
40
		$parts = explode( '/', $path );
41
42
		foreach( $parts as $key => $part )
43
		{
44
			if( ctype_alnum( $part ) === false )
45
			{
46
				$msg = sprintf( 'Invalid characters in client name "%1$s"', $path );
47
				throw new \Aimeos\Client\Html\Exception( $msg, 400 );
48
			}
49
50
			$parts[$key] = ucfirst( $part );
51
		}
52
53
		if( empty( $name ) ) {
54
			$name = $context->config()->get( 'client/html/' . $path . '/name', 'Standard' );
55
		}
56
57
		$interface = '\\Aimeos\\Client\Html\\Iface';
58
		$classname = '\\Aimeos\\Client\\Html\\' . implode( '\\', $parts ) . '\\' . $name;
59
60
		if( ctype_alnum( $name ) === false )
61
		{
62
			$msg = $context->translate( 'client', 'Invalid characters in class name "%1$s"' );
63
			throw new \Aimeos\Client\Html\Exception( sprintf( $msg, $classname ) );
64
		}
65
66
		if( class_exists( $classname ) === false )
67
		{
68
			$msg = $context->translate( 'client', 'Class "%1$s" not available' );
69
			throw new \Aimeos\Client\Html\Exception( sprintf( $msg, $classname ) );
70
		}
71
72
		$client = self::createClient( $context, $classname, $interface );
73
		$client = self::addClientDecorators( $context, $client, $path );
74
75
		return $client->setObject( $client );
76
	}
77
78
79
	/**
80
	 * Injects a client object.
81
	 * The object is returned via create() if an instance of the class
82
	 * with the name name is requested.
83
	 *
84
	 * @param string $classname Full name of the class for which the object should be returned
85
	 * @param \Aimeos\Client\Html\Iface|null $client ExtJS client object
86
	 */
87
	public static function injectClient( string $classname, \Aimeos\Client\Html\Iface $client = null )
88
	{
89
		self::$objects[$classname] = $client;
90
	}
91
92
93
	/**
94
	 * Adds the decorators to the client object.
95
	 *
96
	 * @param \Aimeos\MShop\ContextIface $context Context instance with necessary objects
97
	 * @param \Aimeos\Client\Html\Iface $client Client object
98
	 * @param array $decorators List of decorator name that should be wrapped around the client
99
	 * @param string $classprefix Decorator class prefix, e.g. "\Aimeos\Client\Html\Catalog\Decorator\"
100
	 * @return \Aimeos\Client\Html\Iface Client object
101
	 */
102
	protected static function addDecorators( \Aimeos\MShop\ContextIface $context,
103
		\Aimeos\Client\Html\Iface $client, array $decorators, string $classprefix ) : \Aimeos\Client\Html\Iface
104
	{
105
		foreach( $decorators as $name )
106
		{
107
			if( ctype_alnum( $name ) === false )
108
			{
109
				$classname = is_string( $name ) ? $classprefix . $name : '<not a string>';
110
				throw new \Aimeos\Client\Html\Exception( sprintf( 'Invalid class name "%1$s"', $classname ) );
111
			}
112
113
			$classname = $classprefix . $name;
114
115
			if( class_exists( $classname ) === false ) {
116
				throw new \Aimeos\Client\Html\Exception( sprintf( 'Class "%1$s" not found', $classname ) );
117
			}
118
119
			$interface = '\\Aimeos\\Client\\Html\\Common\\Decorator\\Iface';
120
			$client = new $classname( $client, $context );
121
122
			if( !( $client instanceof $interface ) )
123
			{
124
				$msg = $context->translate( 'client', 'Class "%1$s" does not implement "%2$s"' );
125
				throw new \Aimeos\Client\Html\Exception( sprintf( $msg, $classname, $interface ) );
126
			}
127
		}
128
129
		return $client;
130
	}
131
132
133
	/**
134
	 * Adds the decorators to the client object.
135
	 *
136
	 * @param \Aimeos\MShop\ContextIface $context Context instance with necessary objects
137
	 * @param \Aimeos\Client\Html\Iface $client Client object
138
	 * @param string $path Path of the client in lower case, e.g. "catalog/detail"
139
	 * @return \Aimeos\Client\Html\Iface Client object
140
	 */
141
	protected static function addClientDecorators( \Aimeos\MShop\ContextIface $context,
142
		\Aimeos\Client\Html\Iface $client, string $path ) : \Aimeos\Client\Html\Iface
143
	{
144
		if( !is_string( $path ) || $path === '' ) {
0 ignored issues
show
introduced by
The condition is_string($path) is always true.
Loading history...
145
			throw new \Aimeos\Client\Html\Exception( sprintf( 'Invalid domain "%1$s"', $path ) );
146
		}
147
148
		$localClass = str_replace( '/', '\\', ucwords( $path, '/' ) );
149
		$config = $context->config();
150
151
		/** client/html/common/decorators/default
152
		 * Configures the list of decorators applied to all html clients
153
		 *
154
		 * Decorators extend the functionality of a class by adding new aspects
155
		 * (e.g. log what is currently done), executing the methods of the underlying
156
		 * class only in certain conditions (e.g. only for logged in users) or
157
		 * modify what is returned to the caller.
158
		 *
159
		 * This option allows you to configure a list of decorator names that should
160
		 * be wrapped around the original instance of all created clients:
161
		 *
162
		 *  client/html/common/decorators/default = array( 'decorator1', 'decorator2' )
163
		 *
164
		 * This would wrap the decorators named "decorator1" and "decorator2" around
165
		 * all client instances in that order. The decorator classes would be
166
		 * "\Aimeos\Client\Html\Common\Decorator\Decorator1" and
167
		 * "\Aimeos\Client\Html\Common\Decorator\Decorator2".
168
		 *
169
		 * @param array List of decorator names
170
		 * @since 2014.03
171
		 */
172
		$decorators = $config->get( 'client/html/common/decorators/default', [] );
173
		$excludes = $config->get( 'client/html/' . $path . '/decorators/excludes', [] );
174
175
		foreach( $decorators as $key => $name )
176
		{
177
			if( in_array( $name, $excludes ) ) {
178
				unset( $decorators[$key] );
179
			}
180
		}
181
182
		$classprefix = '\\Aimeos\\Client\\Html\\Common\\Decorator\\';
183
		$client = self::addDecorators( $context, $client, $decorators, $classprefix );
184
185
		$classprefix = '\\Aimeos\\Client\\Html\\Common\\Decorator\\';
186
		$decorators = $config->get( 'client/html/' . $path . '/decorators/global', [] );
187
		$client = self::addDecorators( $context, $client, $decorators, $classprefix );
188
189
		$classprefix = '\\Aimeos\\Client\\Html\\' . $localClass . '\\Decorator\\';
190
		$decorators = $config->get( 'client/html/' . $path . '/decorators/local', [] );
191
		$client = self::addDecorators( $context, $client, $decorators, $classprefix );
192
193
		return $client;
194
	}
195
196
197
	/**
198
	 * Creates a client object.
199
	 *
200
	 * @param \Aimeos\MShop\ContextIface $context Context instance with necessary objects
201
	 * @param string $classname Name of the client class
202
	 * @param string $interface Name of the client interface
203
	 * @return \Aimeos\Client\Html\Iface Client object
204
	 * @throws \Aimeos\Client\Html\Exception If client couldn't be found or doesn't implement the interface
205
	 */
206
	protected static function createClient( \Aimeos\MShop\ContextIface $context, string $classname, string $interface ) : \Aimeos\Client\Html\Iface
207
	{
208
		if( isset( self::$objects[$classname] ) ) {
209
			return self::$objects[$classname];
210
		}
211
212
		if( class_exists( $classname ) === false ) {
213
			throw new \Aimeos\Client\Html\Exception( sprintf( 'Class "%1$s" not available', $classname ) );
214
		}
215
216
		$client = new $classname( $context );
217
218
		if( !( $client instanceof $interface ) )
219
		{
220
			$msg = $context->translate( 'client', 'Class "%1$s" does not implement "%2$s"' );
221
			throw new \Aimeos\Client\Html\Exception( sprintf( $msg, $classname, $interface ) );
222
		}
223
224
		return $client;
225
	}
226
}
227