Passed
Push — master ( 287441...495603 )
by Aimeos
04:43
created

lib/mwlib/src/MW/View/Standard.php (1 issue)

Labels
Severity
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Metaways Infosystems GmbH, 2012
6
 * @copyright Aimeos (aimeos.org), 2015-2018
7
 * @package MW
8
 * @subpackage View
9
 */
10
11
12
namespace Aimeos\MW\View;
13
14
15
/**
16
 * Default view implementation.
17
 *
18
 * @method mixed config(string $name = null, string|array $default = null) Returns the config value for the given key
19
 * @method \Aimeos\MW\View\Helper\Iface csrf() Returns the CSRF helper object
20
 * @method string date(string $date) Returns the formatted date
21
 * @method \Aimeos\MW\View\Helper\Iface encoder() Returns the encoder helper object
22
 * @method string formparam(string|array $names) Returns the name for the HTML form parameter
23
 * @method \Aimeos\MW\Mail\Message\Iface mail() Returns the e-mail message object
24
 * @method string number(integer|float|decimal $number, integer $decimals = 2) Returns the formatted number
25
 * @method string|array param(string|null $name, string|array $default) Returns the parameter value
26
 * @method string partial(string $filepath, array $params = [] ) Renders the partial template
27
 * @method \Aimeos\MW\View\Helper\Iface request() Returns the request helper object
28
 * @method string translate(string $domain, string $singular, string $plural = '', integer $number = 1) Returns the translated string or the original one if no translation is available
29
 * @method string url(string|null $target, string|null $controller = null, string|null $action = null, array $params = [], array $trailing = [], array $config = []) Returns the URL assembled from the given arguments
30
 *
31
 * @package MW
32
 * @subpackage View
33
 */
34
class Standard implements \Aimeos\MW\View\Iface
35
{
36
	private $helper = [];
37
	private $values = [];
38
	private $engines;
39
	private $paths;
40
41
42
	/**
43
	 * Initializes the view object
44
	 *
45
	 * @param array $paths Associative list of base paths as keys and list of relative paths as value
46
	 * @param array $engines Associative list of file extensions as keys and \Aimeos\MW\View\Engine\Iface as value
47
	 */
48
	public function __construct( array $paths = [], array $engines = [] )
49
	{
50
		$this->engines = $engines;
51
		$this->paths = $paths;
52
	}
53
54
55
	/**
56
	 * Calls the view helper with the given name and arguments and returns it's output.
57
	 *
58
	 * @param string $name Name of the view helper
59
	 * @param array $args Arguments passed to the view helper
60
	 * @return mixed Output depending on the view helper
61
	 */
62
	public function __call( $name, array $args )
63
	{
64
		if( !isset( $this->helper[$name] ) )
65
		{
66
			if( ctype_alnum( $name ) === false )
67
			{
68
				$classname = is_string( $name ) ? '\\Aimeos\\MW\\View\\Helper\\' . $name : '<not a string>';
69
				throw new \Aimeos\MW\View\Exception( sprintf( 'Invalid characters in class name "%1$s"', $classname ) );
70
			}
71
72
			$iface = '\\Aimeos\\MW\\View\\Helper\\Iface';
73
			$classname = '\\Aimeos\\MW\\View\\Helper\\' . ucfirst( $name ) . '\\Standard';
74
75
			if( class_exists( $classname ) === false ) {
76
				throw new \Aimeos\MW\View\Exception( sprintf( 'Class "%1$s" not available', $classname ) );
77
			}
78
79
			$helper = new $classname( $this );
80
81
			if( !( $helper instanceof $iface ) ) {
82
				throw new \Aimeos\MW\View\Exception( sprintf( 'Class "%1$s" does not implement interface "%2$s"', $classname, $iface ) );
83
			}
84
85
			$this->helper[$name] = $helper;
86
		}
87
88
		return call_user_func_array( array( $this->helper[$name], 'transform' ), $args );
89
	}
90
91
92
	/**
93
	 * Clones internal objects of the view.
94
	 */
95
	public function __clone()
96
	{
97
		foreach( $this->helper as $name => $helper )
98
		{
99
			$helper = clone $helper;
100
101
			// reset view so view helpers will use the current one (for translation, etc.)
102
			$helper->setView( $this );
103
104
			$this->helper[$name] = $helper;
105
		}
106
	}
107
108
109
	/**
110
	 * Returns the value associated to the given key.
111
	 *
112
	 * @param string $key Name of the value that should be returned
113
	 * @return mixed Value associated to the given key
114
	 * @throws \Aimeos\MW\View\Exception If the requested key isn't available
115
	 */
116
	public function __get( $key )
117
	{
118
		if( !isset( $this->values[$key] ) ) {
119
			throw new \Aimeos\MW\View\Exception( sprintf( 'No value for key "%1$s" found', $key ) );
120
		}
121
122
		return $this->values[$key];
123
	}
124
125
126
	/**
127
	 * Tests if a key with the given name exists.
128
	 *
129
	 * @param string $key Name of the value that should be tested
130
	 * @return boolean True if the key exists, false if not
131
	 */
132
	public function __isset( $key )
133
	{
134
		return isset( $this->values[$key] );
135
	}
136
137
138
	/**
139
	 * Removes a key from the stored values.
140
	 *
141
	 * @param string $key Name of the value that should be removed
142
	 */
143
	public function __unset( $key )
144
	{
145
		unset( $this->values[$key] );
146
	}
147
148
149
	/**
150
	 * Sets a new value for the given key.
151
	 *
152
	 * @param string $key Name of the value that should be set
153
	 * @param mixed $value Value associated to the given key
154
	 */
155
	public function __set( $key, $value )
156
	{
157
		$this->values[$key] = $value;
158
	}
159
160
161
	/**
162
	 * Adds a view helper instance to the view.
163
	 *
164
	 * @param string $name Name of the view helper as called in the template
165
	 * @param \Aimeos\MW\View\Helper\Iface $helper View helper instance
166
	 * @return \Aimeos\MW\View\Iface View object for method chaining
167
	 */
168
	public function addHelper( $name, \Aimeos\MW\View\Helper\Iface $helper )
169
	{
170
		$this->helper[$name] = $helper;
171
		return $this;
172
	}
173
174
175
	/**
176
	 * Assigns a whole set of values at once to the view.
177
	 * This method overwrites already existing key/value pairs set by the magic method.
178
	 *
179
	 * @param array $values Associative list of key/value pairs
180
	 */
181
	public function assign( array $values )
182
	{
183
		$this->values = $values;
184
	}
185
186
187
	/**
188
	 * Returns the value associated to the given key or the default value if the key is not available.
189
	 *
190
	 * @param string $key Name of the value that should be returned
191
	 * @param mixed $default Default value returned if ths key is not available
192
	 * @return mixed Value associated to the given key or the default value
193
	 */
194
	public function get( $key, $default = null )
195
	{
196
		$values = $this->values;
197
198
		foreach( explode( '/', ltrim( $key, '/' ) ) as $part )
199
		{
200
			if( is_array( $values ) && isset( $values[$part] ) ) {
201
				$values = $values[$part];
202
			} else {
203
				return $default;
204
			}
205
		}
206
207
		return $values;
208
	}
209
210
211
	/**
212
	 * Renders the output based on the given template file name and the key/value pairs.
213
	 *
214
	 * @param string|array $filename File name of list of file names for the view templates
215
	 * @return string Output generated by the template
216
	 * @throws \Aimeos\MW\View\Exception If the template isn't found
217
	 */
218
	public function render( $filename )
219
	{
220
		foreach( $this->engines as $fileext => $engine )
221
		{
222
			if( ( $filepath = $this->resolve( $filename, $fileext ) ) !== false ) {
223
				return str_replace( ["\t", '    '], '', $engine->render( $this, $filepath, $this->values ) );
224
			}
225
		}
226
227
		if( ( $filepath = $this->resolve( $filename, '.php' ) ) === false ) {
228
			throw new \Aimeos\MW\View\Exception( sprintf( 'Template "%1$s" not available', $filename ) );
0 ignored issues
show
It seems like $filename can also be of type array; however, parameter $args of sprintf() does only seem to accept string, 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

228
			throw new \Aimeos\MW\View\Exception( sprintf( 'Template "%1$s" not available', /** @scrutinizer ignore-type */ $filename ) );
Loading history...
229
		}
230
231
		try
232
		{
233
			ob_start();
234
235
			$this->includeFile( $filepath );
236
237
			return str_replace( ["\t", '    '], '', ob_get_clean() );
238
		}
239
		catch( \Exception $e )
240
		{
241
			ob_end_clean();
242
			throw $e;
243
		}
244
	}
245
246
247
	/**
248
	 * Includes the template file and processes the PHP instructions.
249
	 * The filename is passed as first argument but without variable name to prevent messing the variable scope.
250
	 */
251
	protected function includeFile()
252
	{
253
		include func_get_arg( 0 );
254
	}
255
256
257
	/**
258
	 * Returns the absolute file name for the given relative one
259
	 *
260
	 * @param string|array $files File name of list of file names for the view templates
261
	 * @return string|false Absolute path to the template file of false if not found
262
	 */
263
	protected function resolve( $files, $fileext )
264
	{
265
		foreach( (array) $files as $file )
266
		{
267
			if( is_file( $file . $fileext ) ) {
268
				return $file . $fileext;
269
			}
270
271
			$ds = DIRECTORY_SEPARATOR;
272
273
			foreach( array_reverse( $this->paths ) as $path => $relPaths )
274
			{
275
				foreach( $relPaths as $relPath )
276
				{
277
					$absPath = $path . $ds . $relPath . $ds . $file . $fileext;
278
279
					if( $ds !== '/' ) {
280
						$absPath = str_replace( '/', $ds, $absPath );
281
					}
282
283
					if( is_file( $absPath ) ) {
284
						return $absPath;
285
					}
286
				}
287
			}
288
		}
289
290
		return false;
291
	}
292
}
293