Completed
Pull Request — master (#578)
by Fabio
19:18 queued 07:13
created

TFont::mergeWith()   C

Complexity

Conditions 17
Paths 129

Size

Total Lines 19
Code Lines 17

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 19
rs 6.377
cc 17
eloc 17
nc 129
nop 1

How to fix   Complexity   

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
 * File Name: pradolite.php
4
 * Last Update: 2016/03/09 11:34:32
5
 * Generated By: buildscripts/phpbuilder/build.php
6
 *
7
 * This file is used in lieu of prado.php to boost PRADO application performance.
8
 * It is generated by expanding prado.php with included files.
9
 * Comments and trace statements are stripped off.
10
 *
11
 * Do not modify this file manually.
12
 */
13
14
if(!defined('PRADO_DIR'))
15
	define('PRADO_DIR',dirname(__FILE__));
16
if(!defined('PRADO_CHMOD'))
17
	define('PRADO_CHMOD',0777);
18
class PradoBase
19
{
20
	const CLASS_FILE_EXT='.php';
21
	private static $_aliases=array('System'=>PRADO_DIR);
22
	private static $_usings=array();
23
	private static $_application=null;
24
	private static $_logger=null;
25
	protected static $classExists = array();
26
	public static function getVersion()
27
	{
28
		return '3.3.0';
29
	}
30
	public static function initErrorHandlers()
31
	{
32
		set_error_handler(array('PradoBase','phpErrorHandler'));
33
		register_shutdown_function(array('PradoBase','phpFatalErrorHandler'));
34
		set_exception_handler(array('PradoBase','exceptionHandler'));
35
	}
36
	public static function autoload($className)
37
	{
38
		include_once($className.self::CLASS_FILE_EXT);
39
		if(!class_exists($className,false) && !interface_exists($className,false))
40
			self::fatalError("Class file for '$className' cannot be found.");
41
	}
42
	public static function poweredByPrado($logoType=0)
43
	{
44
		$logoName=$logoType==1?'powered2':'powered';
45
		if(self::$_application!==null)
46
		{
47
			$am=self::$_application->getAssetManager();
48
			$url=$am->publishFilePath(self::getPathOfNamespace('System.'.$logoName,'.gif'));
49
		}
50
		else
51
			$url='http://pradosoft.github.io/docs/'.$logoName.'.gif';
52
		return '<a title="Powered by PRADO" href="https://github.com/pradosoft/prado" target="_blank"><img src="'.$url.'" style="border-width:0px;" alt="Powered by PRADO" /></a>';
53
	}
54
	public static function phpErrorHandler($errno,$errstr,$errfile,$errline)
55
	{
56
		if(error_reporting() & $errno)
57
			throw new TPhpErrorException($errno,$errstr,$errfile,$errline);
58
	}
59
	public static function phpFatalErrorHandler()
60
	{
61
		$error = error_get_last();
62
		if($error && 
0 ignored issues
show
Bug Best Practice introduced by
The expression $error of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
63
			TPhpErrorException::isFatalError($error) &&
64
			error_reporting() & $error['type'])
65
		{
66
			self::exceptionHandler(new TPhpErrorException($error['type'],$error['message'],$error['file'],$error['line']));
67
		}
68
	}
69
	public static function exceptionHandler($exception)
70
	{
71
		if(self::$_application!==null && ($errorHandler=self::$_application->getErrorHandler())!==null)
72
		{
73
			$errorHandler->handleError(null,$exception);
74
		}
75
		else
76
		{
77
			echo $exception;
78
		}
79
		exit(1);
0 ignored issues
show
Coding Style Compatibility introduced by
The method exceptionHandler() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
80
	}
81
	public static function setApplication($application)
82
	{
83
		if(self::$_application!==null && !defined('PRADO_TEST_RUN'))
84
			throw new TInvalidOperationException('prado_application_singleton_required');
85
		self::$_application=$application;
86
	}
87
	public static function getApplication()
88
	{
89
		return self::$_application;
90
	}
91
	public static function getFrameworkPath()
92
	{
93
		return PRADO_DIR;
94
	}
95
	public static function createComponent($type)
96
	{
97
		if(!isset(self::$classExists[$type]))
98
			self::$classExists[$type] = class_exists($type, false);
99
		if( !isset(self::$_usings[$type]) && !self::$classExists[$type]) {
100
			self::using($type);
101
			self::$classExists[$type] = class_exists($type, false);
102
		}
103
		if( ($pos = strrpos($type, '.')) !== false)
104
			$type = substr($type,$pos+1);
105
		if(($n=func_num_args())>1)
106
		{
107
			$args = func_get_args();
108
			switch($n) {
109
				case 2:
110
					return new $type($args[1]);
111
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
112
				case 3:
113
					return new $type($args[1], $args[2]);
114
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
115
				case 4:
116
					return new $type($args[1], $args[2], $args[3]);
117
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
118
				case 5:
119
					return new $type($args[1], $args[2], $args[3], $args[4]);
120
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
121
				default:
122
					$s='$args[1]';
123
					for($i=2;$i<$n;++$i)
124
						$s.=",\$args[$i]";
125
					eval("\$component=new $type($s);");
0 ignored issues
show
Coding Style introduced by
It is generally not recommended to use eval unless absolutely required.

On one hand, eval might be exploited by malicious users if they somehow manage to inject dynamic content. On the other hand, with the emergence of faster PHP runtimes like the HHVM, eval prevents some optimization that they perform.

Loading history...
126
					return $component;
0 ignored issues
show
Bug introduced by
The variable $component does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
127
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
128
			}
129
		}
130
		else
131
			return new $type;
132
	}
133
	public static function using($namespace,$checkClassExistence=true)
134
	{
135
		if(isset(self::$_usings[$namespace]) || class_exists($namespace,false))
136
			return;
137
		if(($pos=strrpos($namespace,'.'))===false)  		{
138
			try
139
			{
140
				include_once($namespace.self::CLASS_FILE_EXT);
141
			}
142
			catch(Exception $e)
143
			{
144
				if($checkClassExistence && !class_exists($namespace,false))
145
					throw new TInvalidOperationException('prado_component_unknown',$namespace,$e->getMessage());
146
				else
147
					throw $e;
148
			}
149
		}
150
		else if(($path=self::getPathOfNamespace($namespace,self::CLASS_FILE_EXT))!==null)
151
		{
152
			$className=substr($namespace,$pos+1);
153
			if($className==='*')  			{
154
				self::$_usings[$namespace]=$path;
155
				set_include_path(get_include_path().PATH_SEPARATOR.$path);
156
			}
157
			else  			{
158
				self::$_usings[$namespace]=$path;
159
				if(!$checkClassExistence || !class_exists($className,false))
160
				{
161
					try
162
					{
163
						include_once($path);
164
					}
165
					catch(Exception $e)
166
					{
167
						if($checkClassExistence && !class_exists($className,false))
168
							throw new TInvalidOperationException('prado_component_unknown',$className,$e->getMessage());
169
						else
170
							throw $e;
171
					}
172
				}
173
			}
174
		}
175
		else
176
			throw new TInvalidDataValueException('prado_using_invalid',$namespace);
177
	}
178
	public static function getPathOfNamespace($namespace, $ext='')
179
	{
180
		if(self::CLASS_FILE_EXT === $ext || empty($ext))
181
		{
182
			if(isset(self::$_usings[$namespace]))
183
				return self::$_usings[$namespace];
184
			if(isset(self::$_aliases[$namespace]))
185
				return self::$_aliases[$namespace];
186
		}
187
		$segs = explode('.',$namespace);
188
		$alias = array_shift($segs);
189
		if(null !== ($file = array_pop($segs)) && null !== ($root = self::getPathOfAlias($alias)))
190
			return rtrim($root.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR ,$segs),'/\\').(($file === '*') ? '' : DIRECTORY_SEPARATOR.$file.$ext);
191
		return null;
192
	}
193
	public static function getPathOfAlias($alias)
194
	{
195
		return isset(self::$_aliases[$alias])?self::$_aliases[$alias]:null;
196
	}
197
	protected static function getPathAliases()
198
	{
199
		return self::$_aliases;
200
	}
201
	public static function setPathOfAlias($alias,$path)
202
	{
203
		if(isset(self::$_aliases[$alias]) && !defined('PRADO_TEST_RUN'))
204
			throw new TInvalidOperationException('prado_alias_redefined',$alias);
205
		else if(($rp=realpath($path))!==false && is_dir($rp))
206
		{
207
			if(strpos($alias,'.')===false)
208
				self::$_aliases[$alias]=$rp;
209
			else
210
				throw new TInvalidDataValueException('prado_aliasname_invalid',$alias);
211
		}
212
		else
213
			throw new TInvalidDataValueException('prado_alias_invalid',$alias,$path);
214
	}
215
	public static function fatalError($msg)
216
	{
217
		echo '<h1>Fatal Error</h1>';
218
		echo '<p>'.$msg.'</p>';
219
		if(!function_exists('debug_backtrace'))
220
			return;
221
		echo '<h2>Debug Backtrace</h2>';
222
		echo '<pre>';
223
		$index=-1;
224
		foreach(debug_backtrace() as $t)
225
		{
226
			$index++;
227
			if($index==0)  				continue;
228
			echo '#'.$index.' ';
229
			if(isset($t['file']))
230
				echo basename($t['file']) . ':' . $t['line'];
231
			else
232
				 echo '<PHP inner-code>';
233
			echo ' -- ';
234
			if(isset($t['class']))
235
				echo $t['class'] . $t['type'];
236
			echo $t['function'] . '(';
237
			if(isset($t['args']) && sizeof($t['args']) > 0)
238
			{
239
				$count=0;
240
				foreach($t['args'] as $item)
241
				{
242
					if(is_string($item))
243
					{
244
						$str=htmlentities(str_replace("\r\n", "", $item), ENT_QUOTES);
245
						if (strlen($item) > 70)
246
							echo "'". substr($str, 0, 70) . "...'";
247
						else
248
							echo "'" . $str . "'";
249
					}
250
					else if (is_int($item) || is_float($item))
251
						echo $item;
252
					else if (is_object($item))
253
						echo get_class($item);
254
					else if (is_array($item))
255
						echo 'array(' . count($item) . ')';
256
					else if (is_bool($item))
257
						echo $item ? 'true' : 'false';
258
					else if ($item === null)
259
						echo 'NULL';
260
					else if (is_resource($item))
261
						echo get_resource_type($item);
262
					$count++;
263
					if (count($t['args']) > $count)
264
						echo ', ';
265
				}
266
			}
267
			echo ")\n";
268
		}
269
		echo '</pre>';
270
		exit(1);
0 ignored issues
show
Coding Style Compatibility introduced by
The method fatalError() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
271
	}
272
	public static function getUserLanguages()
0 ignored issues
show
Coding Style introduced by
getUserLanguages uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
273
	{
274
		static $languages=null;
275
		if($languages===null)
276
		{
277
			if(!isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
278
				$languages[0]='en';
279
			else
280
			{
281
				$languages=array();
282
				foreach(explode(',',$_SERVER['HTTP_ACCEPT_LANGUAGE']) as $language)
283
				{
284
					$array=explode(';q=',trim($language));
285
					$languages[trim($array[0])]=isset($array[1])?(float)$array[1]:1.0;
286
				}
287
				arsort($languages);
288
				$languages=array_keys($languages);
289
				if(empty($languages))
290
					$languages[0]='en';
291
			}
292
		}
293
		return $languages;
294
	}
295
	public static function getPreferredLanguage()
296
	{
297
		static $language=null;
298
		if($language===null)
299
		{
300
			$langs=Prado::getUserLanguages();
301
			$lang=explode('-',$langs[0]);
302
			if(empty($lang[0]) || !ctype_alpha($lang[0]))
303
				$language='en';
304
			else
305
				$language=$lang[0];
306
		}
307
		return $language;
308
	}
309
	public static function trace($msg,$category='Uncategorized',$ctl=null)
310
	{
311
		if(self::$_application && self::$_application->getMode()===TApplicationMode::Performance)
312
			return;
313
		if(!self::$_application || self::$_application->getMode()===TApplicationMode::Debug)
314
		{
315
			$trace=debug_backtrace();
316
			if(isset($trace[0]['file']) && isset($trace[0]['line']))
317
				$msg.=" (line {$trace[0]['line']}, {$trace[0]['file']})";
318
			$level=TLogger::DEBUG;
319
		}
320
		else
321
			$level=TLogger::INFO;
322
		self::log($msg,$level,$category,$ctl);
323
	}
324
	public static function log($msg,$level=TLogger::INFO,$category='Uncategorized',$ctl=null)
325
	{
326
		if(self::$_logger===null)
327
			self::$_logger=new TLogger;
328
		self::$_logger->log($msg,$level,$category,$ctl);
329
	}
330
	public static function getLogger()
331
	{
332
		if(self::$_logger===null)
333
			self::$_logger=new TLogger;
334
		return self::$_logger;
335
	}
336
	public static function varDump($var,$depth=10,$highlight=false)
337
	{
338
		Prado::using('System.Util.TVarDumper');
339
		return TVarDumper::dump($var,$depth,$highlight);
340
	}
341
	public static function localize($text, $parameters=array(), $catalogue=null, $charset=null)
342
	{
343
		Prado::using('System.I18N.Translation');
344
		$app = Prado::getApplication()->getGlobalization(false);
345
		$params = array();
346
		foreach($parameters as $key => $value)
347
			$params['{'.$key.'}'] = $value;
348
				if($app===null || ($config = $app->getTranslationConfiguration())===null)
349
			return strtr($text, $params);
350
		if ($catalogue===null)
351
			$catalogue=isset($config['catalogue'])?$config['catalogue']:'messages';
352
		Translation::init($catalogue);
353
				$appCharset = $app===null ? '' : $app->getCharset();
354
				$defaultCharset = ($app===null) ? 'UTF-8' : $app->getDefaultCharset();
355
				if(empty($charset)) $charset = $appCharset;
356
		if(empty($charset)) $charset = $defaultCharset;
357
		return Translation::formatter($catalogue)->format($text,$params,$catalogue,$charset);
358
	}
359
}
360
PradoBase::using('System.TComponent');
361
PradoBase::using('System.Exceptions.TException');
362
PradoBase::using('System.Util.TLogger');
363
if(!class_exists('Prado',false))
364
{
365
	class Prado extends PradoBase
366
	{
367
	}
368
}
369
spl_autoload_register(array('Prado','autoload'));
370
Prado::initErrorHandlers();
371
interface IModule
372
{
373
	public function init($config);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
374
	public function getID();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
375
	public function setID($id);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
376
}
377
interface IService
378
{
379
	public function init($config);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
380
	public function getID();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
381
	public function setID($id);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
382
	public function getEnabled();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
383
	public function setEnabled($value);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
384
	public function run();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
385
}
386
interface ITextWriter
387
{
388
	public function write($str);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
389
	public function flush();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
390
}
391
interface IUser
392
{
393
	public function getName();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
394
	public function setName($value);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
395
	public function getIsGuest();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
396
	public function setIsGuest($value);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
397
	public function getRoles();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
398
	public function setRoles($value);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
399
	public function isInRole($role);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
400
	public function saveToString();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
401
	public function loadFromString($string);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
402
}
403
interface IStatePersister
404
{
405
	public function load();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
406
	public function save($state);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
407
}
408
interface ICache
409
{
410
	public function get($id);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
411
	public function set($id,$value,$expire=0,$dependency=null);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
412
	public function add($id,$value,$expire=0,$dependency=null);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
413
	public function delete($id);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
414
	public function flush();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
415
}
416
interface ICacheDependency
417
{
418
	public function getHasChanged();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
419
}
420
interface IRenderable
421
{
422
	public function render($writer);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
423
}
424
interface IBindable
425
{
426
	public function dataBind();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
427
}
428
interface IStyleable
429
{
430
	public function getHasStyle();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
431
	public function getStyle();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
432
	public function clearStyle();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
433
}
434
interface IActiveControl
435
{
436
	public function getActiveControl();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
437
}
438
interface ICallbackEventHandler
439
{
440
	public function raiseCallbackEvent($eventArgument);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
441
}
442
interface IDataRenderer
443
{
444
	public function getData();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
445
	public function setData($value);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
446
}
447
class TApplicationComponent extends TComponent
448
{
449
	public function getApplication()
450
	{
451
		return Prado::getApplication();
452
	}
453
	public function getService()
454
	{
455
		return Prado::getApplication()->getService();
456
	}
457
	public function getRequest()
458
	{
459
		return Prado::getApplication()->getRequest();
460
	}
461
	public function getResponse()
462
	{
463
		return Prado::getApplication()->getResponse();
464
	}
465
	public function getSession()
466
	{
467
		return Prado::getApplication()->getSession();
468
	}
469
	public function getUser()
470
	{
471
		return Prado::getApplication()->getUser();
472
	}
473
	public function publishAsset($assetPath,$className=null)
474
	{
475
		if($className===null)
476
			$className=get_class($this);
477
		$class=new ReflectionClass($className);
478
		$fullPath=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$assetPath;
479
		return $this->publishFilePath($fullPath);
480
	}
481
	public function publishFilePath($fullPath, $checkTimestamp=false)
482
	{
483
		return Prado::getApplication()->getAssetManager()->publishFilePath($fullPath, $checkTimestamp);
484
	}
485
}
486
abstract class TModule extends TApplicationComponent implements IModule
487
{
488
	private $_id;
489
	public function init($config)
490
	{
491
	}
492
	public function getID()
493
	{
494
		return $this->_id;
495
	}
496
	public function setID($value)
497
	{
498
		$this->_id=$value;
499
	}
500
}
501
abstract class TService extends TApplicationComponent implements IService
502
{
503
	private $_id;
504
	private $_enabled=true;
505
	public function init($config)
506
	{
507
	}
508
	public function getID()
509
	{
510
		return $this->_id;
511
	}
512
	public function setID($value)
513
	{
514
		$this->_id=$value;
515
	}
516
	public function getEnabled()
517
	{
518
		return $this->_enabled;
519
	}
520
	public function setEnabled($value)
521
	{
522
		$this->_enabled=TPropertyValue::ensureBoolean($value);
523
	}
524
	public function run()
525
	{
526
	}
527
}
528
class TErrorHandler extends TModule
529
{
530
	const ERROR_FILE_NAME='error';
531
	const EXCEPTION_FILE_NAME='exception';
532
	const SOURCE_LINES=12;
533
	private $_templatePath=null;
534
	public function init($config)
535
	{
536
		$this->getApplication()->setErrorHandler($this);
537
	}
538
	public function getErrorTemplatePath()
539
	{
540
		if($this->_templatePath===null)
541
			$this->_templatePath=Prado::getFrameworkPath().'/Exceptions/templates';
542
		return $this->_templatePath;
543
	}
544
	public function setErrorTemplatePath($value)
545
	{
546
		if(($templatePath=Prado::getPathOfNamespace($value))!==null && is_dir($templatePath))
547
			$this->_templatePath=$templatePath;
548
		else
549
			throw new TConfigurationException('errorhandler_errortemplatepath_invalid',$value);
550
	}
551
	public function handleError($sender,$param)
552
	{
553
		static $handling=false;
554
								restore_error_handler();
555
		restore_exception_handler();
556
				if($handling)
557
			$this->handleRecursiveError($param);
558
		else
559
		{
560
			$handling=true;
561
			if(($response=$this->getResponse())!==null)
562
				$response->clear();
563
			if(!headers_sent())
564
				header('Content-Type: text/html; charset=UTF-8');
565
			if($param instanceof THttpException)
566
				$this->handleExternalError($param->getStatusCode(),$param);
567
			else if($this->getApplication()->getMode()===TApplicationMode::Debug)
568
				$this->displayException($param);
569
			else
570
				$this->handleExternalError(500,$param);
571
		}
572
	}
573
	protected static function hideSecurityRelated($value, $exception=null)
0 ignored issues
show
Coding Style introduced by
hideSecurityRelated uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
574
	{
575
		$aRpl = array();
576
		if($exception !== null && $exception instanceof Exception)
577
		{
578
			$aTrace = $exception->getTrace();
579
			foreach($aTrace as $item)
580
			{
581
				if(isset($item['file']))
582
					$aRpl[dirname($item['file']) . DIRECTORY_SEPARATOR] = '<hidden>' . DIRECTORY_SEPARATOR;
583
			}
584
		}
585
		$aRpl[$_SERVER['DOCUMENT_ROOT']] = '${DocumentRoot}';
586
		$aRpl[str_replace('/', DIRECTORY_SEPARATOR, $_SERVER['DOCUMENT_ROOT'])] = '${DocumentRoot}';
587
		$aRpl[PRADO_DIR . DIRECTORY_SEPARATOR] = '${PradoFramework}' . DIRECTORY_SEPARATOR;
588
		if(isset($aRpl[DIRECTORY_SEPARATOR])) unset($aRpl[DIRECTORY_SEPARATOR]);
589
		$aRpl = array_reverse($aRpl, true);
590
		return str_replace(array_keys($aRpl), $aRpl, $value);
591
	}
592
	protected function handleExternalError($statusCode,$exception)
0 ignored issues
show
Coding Style introduced by
handleExternalError uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
593
	{
594
		if(!($exception instanceof THttpException))
595
			error_log($exception->__toString());
596
		$content=$this->getErrorTemplate($statusCode,$exception);
597
		$serverAdmin=isset($_SERVER['SERVER_ADMIN'])?$_SERVER['SERVER_ADMIN']:'';
598
		$isDebug = $this->getApplication()->getMode()===TApplicationMode::Debug;
599
		$errorMessage = $exception->getMessage();
600
		if($isDebug)
601
			$version=$_SERVER['SERVER_SOFTWARE'].' <a href="https://github.com/pradosoft/prado">PRADO</a>/'.Prado::getVersion();
602
		else
603
		{
604
			$version='';
605
			$errorMessage = self::hideSecurityRelated($errorMessage, $exception);
606
		}
607
		$tokens=array(
608
			'%%StatusCode%%' => "$statusCode",
609
			'%%ErrorMessage%%' => htmlspecialchars($errorMessage),
610
			'%%ServerAdmin%%' => $serverAdmin,
611
			'%%Version%%' => $version,
612
			'%%Time%%' => @strftime('%Y-%m-%d %H:%M',time())
613
		);
614
		$this->getApplication()->getResponse()->setStatusCode($statusCode, $isDebug ? $exception->getMessage() : null);
615
		echo strtr($content,$tokens);
616
	}
617
	protected function handleRecursiveError($exception)
618
	{
619
		if($this->getApplication()->getMode()===TApplicationMode::Debug)
620
		{
621
			echo "<html><head><title>Recursive Error</title></head>\n";
622
			echo "<body><h1>Recursive Error</h1>\n";
623
			echo "<pre>".$exception->__toString()."</pre>\n";
624
			echo "</body></html>";
625
		}
626
		else
627
		{
628
			error_log("Error happened while processing an existing error:\n".$exception->__toString());
629
			header('HTTP/1.0 500 Internal Error');
630
		}
631
	}
632
	protected function displayException($exception)
0 ignored issues
show
Coding Style introduced by
displayException uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
633
	{
634
		if(php_sapi_name()==='cli')
635
		{
636
			echo $exception->getMessage()."\n";
637
			echo $exception->getTraceAsString();
638
			return;
639
		}
640
		if($exception instanceof TTemplateException)
641
		{
642
			$fileName=$exception->getTemplateFile();
643
			$lines=empty($fileName)?explode("\n",$exception->getTemplateSource()):@file($fileName);
644
			$source=$this->getSourceCode($lines,$exception->getLineNumber());
645
			if($fileName==='')
646
				$fileName='---embedded template---';
647
			$errorLine=$exception->getLineNumber();
648
		}
649
		else
650
		{
651
			if(($trace=$this->getExactTrace($exception))!==null)
652
			{
653
				$fileName=$trace['file'];
654
				$errorLine=$trace['line'];
655
			}
656
			else
657
			{
658
				$fileName=$exception->getFile();
659
				$errorLine=$exception->getLine();
660
			}
661
			$source=$this->getSourceCode(@file($fileName),$errorLine);
662
		}
663
		if($this->getApplication()->getMode()===TApplicationMode::Debug)
664
			$version=$_SERVER['SERVER_SOFTWARE'].' <a href="https://github.com/pradosoft/prado">PRADO</a>/'.Prado::getVersion();
665
		else
666
			$version='';
667
		$tokens=array(
668
			'%%ErrorType%%' => get_class($exception),
669
			'%%ErrorMessage%%' => $this->addLink(htmlspecialchars($exception->getMessage())),
670
			'%%SourceFile%%' => htmlspecialchars($fileName).' ('.$errorLine.')',
671
			'%%SourceCode%%' => $source,
672
			'%%StackTrace%%' => htmlspecialchars($exception->getTraceAsString()),
673
			'%%Version%%' => $version,
674
			'%%Time%%' => @strftime('%Y-%m-%d %H:%M',time())
675
		);
676
		$content=$this->getExceptionTemplate($exception);
677
		echo strtr($content,$tokens);
678
	}
679
	protected function getExceptionTemplate($exception)
680
	{
681
		$lang=Prado::getPreferredLanguage();
682
		$exceptionFile=Prado::getFrameworkPath().'/Exceptions/templates/'.self::EXCEPTION_FILE_NAME.'-'.$lang.'.html';
683
		if(!is_file($exceptionFile))
684
			$exceptionFile=Prado::getFrameworkPath().'/Exceptions/templates/'.self::EXCEPTION_FILE_NAME.'.html';
685
		if(($content=@file_get_contents($exceptionFile))===false)
686
			die("Unable to open exception template file '$exceptionFile'.");
0 ignored issues
show
Coding Style Compatibility introduced by
The method getExceptionTemplate() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
687
		return $content;
688
	}
689
	protected function getErrorTemplate($statusCode,$exception)
690
	{
691
		$base=$this->getErrorTemplatePath().DIRECTORY_SEPARATOR.self::ERROR_FILE_NAME;
692
		$lang=Prado::getPreferredLanguage();
693
		if(is_file("$base$statusCode-$lang.html"))
694
			$errorFile="$base$statusCode-$lang.html";
695
		else if(is_file("$base$statusCode.html"))
696
			$errorFile="$base$statusCode.html";
697
		else if(is_file("$base-$lang.html"))
698
			$errorFile="$base-$lang.html";
699
		else
700
			$errorFile="$base.html";
701
		if(($content=@file_get_contents($errorFile))===false)
702
			die("Unable to open error template file '$errorFile'.");
0 ignored issues
show
Coding Style Compatibility introduced by
The method getErrorTemplate() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
703
		return $content;
704
	}
705
	private function getExactTrace($exception)
706
	{
707
		$trace=$exception->getTrace();
708
		$result=null;
709
						if($exception instanceof TPhpErrorException)
710
		{
711
			if(isset($trace[0]['file']))
712
				$result=$trace[0];
713
			elseif(isset($trace[1]))
714
				$result=$trace[1];
715
		}
716
		else if($exception instanceof TInvalidOperationException)
717
		{
718
						if(($result=$this->getPropertyAccessTrace($trace,'__get'))===null)
719
				$result=$this->getPropertyAccessTrace($trace,'__set');
720
		}
721
		if($result!==null && strpos($result['file'],': eval()\'d code')!==false)
722
			return null;
723
		return $result;
724
	}
725
	private function getPropertyAccessTrace($trace,$pattern)
726
	{
727
		$result=null;
728
		foreach($trace as $t)
729
		{
730
			if(isset($t['function']) && $t['function']===$pattern)
731
				$result=$t;
732
			else
733
				break;
734
		}
735
		return $result;
736
	}
737
	private function getSourceCode($lines,$errorLine)
738
	{
739
		$beginLine=$errorLine-self::SOURCE_LINES>=0?$errorLine-self::SOURCE_LINES:0;
740
		$endLine=$errorLine+self::SOURCE_LINES<=count($lines)?$errorLine+self::SOURCE_LINES:count($lines);
741
		$source='';
742
		for($i=$beginLine;$i<$endLine;++$i)
743
		{
744
			if($i===$errorLine-1)
745
			{
746
				$line=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",'    ',$lines[$i])));
747
				$source.="<div class=\"error\">".$line."</div>";
748
			}
749
			else
750
				$source.=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",'    ',$lines[$i])));
751
		}
752
		return $source;
753
	}
754
	private function addLink($message)
755
	{
756
		$baseUrl='http://pradosoft.github.io/docs/manual/class-';
757
		return preg_replace('/\b(T[A-Z]\w+)\b/',"<a href=\"$baseUrl\${1}\" target=\"_blank\">\${1}</a>",$message);
758
	}
759
}
760
class TList extends TComponent implements IteratorAggregate,ArrayAccess,Countable
0 ignored issues
show
Coding Style introduced by
Expected 1 space before "ArrayAccess"; 0 found
Loading history...
Coding Style introduced by
Expected 1 space before "Countable"; 0 found
Loading history...
761
{
762
	private $_d=array();
763
	private $_c=0;
764
	private $_r=false;
765
	public function __construct($data=null,$readOnly=false)
766
	{
767
		if($data!==null)
768
			$this->copyFrom($data);
769
		$this->setReadOnly($readOnly);
770
	}
771
	public function getReadOnly()
772
	{
773
		return $this->_r;
774
	}
775
	protected function setReadOnly($value)
776
	{
777
		$this->_r=TPropertyValue::ensureBoolean($value);
778
	}
779
	public function getIterator()
780
	{
781
		return new ArrayIterator( $this->_d );
782
	}
783
	public function count()
784
	{
785
		return $this->getCount();
786
	}
787
	public function getCount()
788
	{
789
		return $this->_c;
790
	}
791
	public function itemAt($index)
792
	{
793
		if($index>=0 && $index<$this->_c)
794
			return $this->_d[$index];
795
		else
796
			throw new TInvalidDataValueException('list_index_invalid',$index);
797
	}
798
	public function add($item)
799
	{
800
		$this->insertAt($this->_c,$item);
801
		return $this->_c-1;
802
	}
803
	public function insertAt($index,$item)
804
	{
805
		if(!$this->_r)
806
		{
807
			if($index===$this->_c)
808
				$this->_d[$this->_c++]=$item;
809
			else if($index>=0 && $index<$this->_c)
810
			{
811
				array_splice($this->_d,$index,0,array($item));
812
				$this->_c++;
813
			}
814
			else
815
				throw new TInvalidDataValueException('list_index_invalid',$index);
816
		}
817
		else
818
			throw new TInvalidOperationException('list_readonly',get_class($this));
819
	}
820
	public function remove($item)
821
	{
822
		if(!$this->_r)
823
		{
824
			if(($index=$this->indexOf($item))>=0)
825
			{
826
				$this->removeAt($index);
827
				return $index;
828
			}
829
			else
830
				throw new TInvalidDataValueException('list_item_inexistent');
831
		}
832
		else
833
			throw new TInvalidOperationException('list_readonly',get_class($this));
834
	}
835
	public function removeAt($index)
836
	{
837
		if(!$this->_r)
838
		{
839
			if($index>=0 && $index<$this->_c)
840
			{
841
				$this->_c--;
842
				if($index===$this->_c)
843
					return array_pop($this->_d);
844
				else
845
				{
846
					$item=$this->_d[$index];
847
					array_splice($this->_d,$index,1);
848
					return $item;
849
				}
850
			}
851
			else
852
				throw new TInvalidDataValueException('list_index_invalid',$index);
853
		}
854
		else
855
			throw new TInvalidOperationException('list_readonly',get_class($this));
856
	}
857
	public function clear()
858
	{
859
		for($i=$this->_c-1;$i>=0;--$i)
860
			$this->removeAt($i);
861
	}
862
	public function contains($item)
863
	{
864
		return $this->indexOf($item)>=0;
865
	}
866
	public function indexOf($item)
867
	{
868
		if(($index=array_search($item,$this->_d,true))===false)
869
			return -1;
870
		else
871
			return $index;
872
	}
873
	public function insertBefore($baseitem, $item)
874
	{
875
		if(!$this->_r)
876
		{
877
			if(($index = $this->indexOf($baseitem)) == -1)
878
				throw new TInvalidDataValueException('list_item_inexistent');
879
			$this->insertAt($index, $item);
880
			return $index;
881
		}
882
		else
883
			throw new TInvalidOperationException('list_readonly',get_class($this));
884
	}
885
	public function insertAfter($baseitem, $item)
886
	{
887
		if(!$this->_r)
888
		{
889
			if(($index = $this->indexOf($baseitem)) == -1)
890
				throw new TInvalidDataValueException('list_item_inexistent');
891
			$this->insertAt($index + 1, $item);
892
			return $index + 1;
893
		}
894
		else
895
			throw new TInvalidOperationException('list_readonly',get_class($this));
896
	}
897
	public function toArray()
898
	{
899
		return $this->_d;
900
	}
901
	public function copyFrom($data)
902
	{
903
		if(is_array($data) || ($data instanceof Traversable))
904
		{
905
			if($this->_c>0)
906
				$this->clear();
907
			foreach($data as $item)
908
				$this->add($item);
909
		}
910
		else if($data!==null)
911
			throw new TInvalidDataTypeException('list_data_not_iterable');
912
	}
913
	public function mergeWith($data)
914
	{
915
		if(is_array($data) || ($data instanceof Traversable))
916
		{
917
			foreach($data as $item)
918
				$this->add($item);
919
		}
920
		else if($data!==null)
921
			throw new TInvalidDataTypeException('list_data_not_iterable');
922
	}
923
	public function offsetExists($offset)
924
	{
925
		return ($offset>=0 && $offset<$this->_c);
926
	}
927
	public function offsetGet($offset)
928
	{
929
		return $this->itemAt($offset);
930
	}
931
	public function offsetSet($offset,$item)
932
	{
933
		if($offset===null || $offset===$this->_c)
934
			$this->insertAt($this->_c,$item);
935
		else
936
		{
937
			$this->removeAt($offset);
938
			$this->insertAt($offset,$item);
939
		}
940
	}
941
	public function offsetUnset($offset)
942
	{
943
		$this->removeAt($offset);
944
	}
945
}
946
class TListIterator extends ArrayIterator
947
{
948
}
949
abstract class TCache extends TModule implements ICache, ArrayAccess
950
{
951
	private $_prefix=null;
952
	private $_primary=true;
953
	public function init($config)
954
	{
955
		if($this->_prefix===null)
956
			$this->_prefix=$this->getApplication()->getUniqueID();
957
		if($this->_primary)
958
		{
959
			if($this->getApplication()->getCache()===null)
960
				$this->getApplication()->setCache($this);
961
			else
962
				throw new TConfigurationException('cache_primary_duplicated',get_class($this));
963
		}
964
	}
965
	public function getPrimaryCache()
966
	{
967
		return $this->_primary;
968
	}
969
	public function setPrimaryCache($value)
970
	{
971
		$this->_primary=TPropertyValue::ensureBoolean($value);
972
	}
973
	public function getKeyPrefix()
974
	{
975
		return $this->_prefix;
976
	}
977
	public function setKeyPrefix($value)
978
	{
979
		$this->_prefix=$value;
980
	}
981
	protected function generateUniqueKey($key)
982
	{
983
		return md5($this->_prefix.$key);
984
	}
985
	public function get($id)
986
	{
987
		if(($data=$this->getValue($this->generateUniqueKey($id)))!==false)
988
		{
989
			if(!is_array($data))
990
				return false;
991
			if(!($data[1] instanceof ICacheDependency) || !$data[1]->getHasChanged())
992
				return $data[0];
993
		}
994
		return false;
995
	}
996
	public function set($id,$value,$expire=0,$dependency=null)
997
	{
998
		if(empty($value) && $expire === 0)
999
			$this->delete($id);
1000
		else
1001
		{
1002
			$data=array($value,$dependency);
1003
			return $this->setValue($this->generateUniqueKey($id),$data,$expire);
1004
		}
1005
	}
1006
	public function add($id,$value,$expire=0,$dependency=null)
1007
	{
1008
		if(empty($value) && $expire === 0)
1009
			return false;
1010
		$data=array($value,$dependency);
1011
		return $this->addValue($this->generateUniqueKey($id),$data,$expire);
1012
	}
1013
	public function delete($id)
1014
	{
1015
		return $this->deleteValue($this->generateUniqueKey($id));
1016
	}
1017
	public function flush()
1018
	{
1019
		throw new TNotSupportedException('cache_flush_unsupported');
1020
	}
1021
	abstract protected function getValue($key);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
1022
	abstract protected function setValue($key,$value,$expire);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
1023
	abstract protected function addValue($key,$value,$expire);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
1024
	abstract protected function deleteValue($key);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
1025
	public function offsetExists($id)
1026
	{
1027
		return $this->get($id) !== false;
1028
	}
1029
	public function offsetGet($id)
1030
	{
1031
		return $this->get($id);
1032
	}
1033
	public function offsetSet($id, $value)
1034
	{
1035
		$this->set($id, $value);
1036
	}
1037
	public function offsetUnset($id)
1038
	{
1039
		$this->delete($id);
1040
	}
1041
}
1042
abstract class TCacheDependency extends TComponent implements ICacheDependency
1043
{
1044
}
1045
class TFileCacheDependency extends TCacheDependency
1046
{
1047
	private $_fileName;
1048
	private $_timestamp;
1049
	public function __construct($fileName)
1050
	{
1051
		$this->setFileName($fileName);
1052
	}
1053
	public function getFileName()
1054
	{
1055
		return $this->_fileName;
1056
	}
1057
	public function setFileName($value)
1058
	{
1059
		$this->_fileName=$value;
1060
		$this->_timestamp=@filemtime($value);
1061
	}
1062
	public function getTimestamp()
1063
	{
1064
		return $this->_timestamp;
1065
	}
1066
	public function getHasChanged()
1067
	{
1068
		return @filemtime($this->_fileName)!==$this->_timestamp;
1069
	}
1070
}
1071
class TDirectoryCacheDependency extends TCacheDependency
1072
{
1073
	private $_recursiveCheck=true;
1074
	private $_recursiveLevel=-1;
1075
	private $_timestamps;
1076
	private $_directory;
1077
	public function __construct($directory)
1078
	{
1079
		$this->setDirectory($directory);
1080
	}
1081
	public function getDirectory()
1082
	{
1083
		return $this->_directory;
1084
	}
1085
	public function setDirectory($directory)
1086
	{
1087
		if(($path=realpath($directory))===false || !is_dir($path))
1088
			throw new TInvalidDataValueException('directorycachedependency_directory_invalid',$directory);
1089
		$this->_directory=$path;
1090
		$this->_timestamps=$this->generateTimestamps($path);
1091
	}
1092
	public function getRecursiveCheck()
1093
	{
1094
		return $this->_recursiveCheck;
1095
	}
1096
	public function setRecursiveCheck($value)
1097
	{
1098
		$this->_recursiveCheck=TPropertyValue::ensureBoolean($value);
1099
	}
1100
	public function getRecursiveLevel()
1101
	{
1102
		return $this->_recursiveLevel;
1103
	}
1104
	public function setRecursiveLevel($value)
1105
	{
1106
		$this->_recursiveLevel=TPropertyValue::ensureInteger($value);
1107
	}
1108
	public function getHasChanged()
1109
	{
1110
		return $this->generateTimestamps($this->_directory)!=$this->_timestamps;
1111
	}
1112
	protected function validateFile($fileName)
1113
	{
1114
		return true;
1115
	}
1116
	protected function validateDirectory($directory)
1117
	{
1118
		return true;
1119
	}
1120
	protected function generateTimestamps($directory,$level=0)
1121
	{
1122
		if(($dir=opendir($directory))===false)
1123
			throw new TIOException('directorycachedependency_directory_invalid',$directory);
1124
		$timestamps=array();
1125
		while(($file=readdir($dir))!==false)
1126
		{
1127
			$path=$directory.DIRECTORY_SEPARATOR.$file;
1128
			if($file==='.' || $file==='..')
1129
				continue;
1130
			else if(is_dir($path))
1131
			{
1132
				if(($this->_recursiveLevel<0 || $level<$this->_recursiveLevel) && $this->validateDirectory($path))
1133
					$timestamps=array_merge($this->generateTimestamps($path,$level+1));
1134
			}
1135
			else if($this->validateFile($path))
1136
				$timestamps[$path]=filemtime($path);
1137
		}
1138
		closedir($dir);
1139
		return $timestamps;
1140
	}
1141
}
1142
class TGlobalStateCacheDependency extends TCacheDependency
1143
{
1144
	private $_stateName;
1145
	private $_stateValue;
1146
	public function __construct($name)
1147
	{
1148
		$this->setStateName($name);
1149
	}
1150
	public function getStateName()
1151
	{
1152
		return $this->_stateName;
1153
	}
1154
	public function setStateName($value)
1155
	{
1156
		$this->_stateName=$value;
1157
		$this->_stateValue=Prado::getApplication()->getGlobalState($value);
1158
	}
1159
	public function getHasChanged()
1160
	{
1161
		return $this->_stateValue!==Prado::getApplication()->getGlobalState($this->_stateName);
1162
	}
1163
}
1164
class TChainedCacheDependency extends TCacheDependency
1165
{
1166
	private $_dependencies=null;
1167
	public function getDependencies()
1168
	{
1169
		if($this->_dependencies===null)
1170
			$this->_dependencies=new TCacheDependencyList;
1171
		return $this->_dependencies;
1172
	}
1173
	public function getHasChanged()
1174
	{
1175
		if($this->_dependencies!==null)
1176
		{
1177
			foreach($this->_dependencies as $dependency)
1178
				if($dependency->getHasChanged())
1179
					return true;
1180
		}
1181
		return false;
1182
	}
1183
}
1184
class TApplicationStateCacheDependency extends TCacheDependency
1185
{
1186
	public function getHasChanged()
1187
	{
1188
		return Prado::getApplication()->getMode()!==TApplicationMode::Performance;
1189
	}
1190
}
1191
class TCacheDependencyList extends TList
1192
{
1193
	public function insertAt($index,$item)
1194
	{
1195
		if($item instanceof ICacheDependency)
1196
			parent::insertAt($index,$item);
1197
		else
1198
			throw new TInvalidDataTypeException('cachedependencylist_cachedependency_required');
1199
	}
1200
}
1201
class TTextWriter extends TComponent implements ITextWriter
1202
{
1203
	private $_str='';
1204
	public function flush()
1205
	{
1206
		$str=$this->_str;
1207
		$this->_str='';
1208
		return $str;
1209
	}
1210
	public function write($str)
1211
	{
1212
		$this->_str.=$str;
1213
	}
1214
	public function writeLine($str='')
1215
	{
1216
		$this->write($str."\n");
1217
	}
1218
}
1219
class TPriorityList extends TList
1220
{
1221
	private $_d=array();
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1222
	private $_o=false;
1223
	private $_fd=null;
1224
	private $_c=0;
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1225
	private $_dp=10;
1226
	private $_p=8;
1227
	public function __construct($data=null,$readOnly=false,$defaultPriority=10,$precision=8)
1228
	{
1229
		parent::__construct();
1230
		if($data!==null)
1231
			$this->copyFrom($data);
1232
		$this->setReadOnly($readOnly);
1233
		$this->setPrecision($precision);
1234
		$this->setDefaultPriority($defaultPriority);
1235
	}
1236
	public function count()
1237
	{
1238
		return $this->getCount();
1239
	}
1240
	public function getCount()
1241
	{
1242
		return $this->_c;
1243
	}
1244
	public function getPriorityCount($priority=null)
1245
	{
1246
		if($priority===null)
1247
			$priority=$this->getDefaultPriority();
1248
		$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1249
		if(!isset($this->_d[$priority]) || !is_array($this->_d[$priority]))
1250
			return false;
1251
		return count($this->_d[$priority]);
1252
	}
1253
	public function getDefaultPriority()
1254
	{
1255
		return $this->_dp;
1256
	}
1257
	protected function setDefaultPriority($value)
1258
	{
1259
		$this->_dp=(string)round(TPropertyValue::ensureFloat($value),$this->_p);
0 ignored issues
show
Documentation Bug introduced by
It seems like (string) round(\TPropert...oat($value), $this->_p) of type string is incompatible with the declared type object<numeric> of property $_dp.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1260
	}
1261
	public function getPrecision()
1262
	{
1263
		return $this->_p;
1264
	}
1265
	protected function setPrecision($value)
1266
	{
1267
		$this->_p=TPropertyValue::ensureInteger($value);
1268
	}
1269
	public function getIterator()
1270
	{
1271
		return new ArrayIterator($this->flattenPriorities());
1272
	}
1273
	public function getPriorities()
1274
	{
1275
		$this->sortPriorities();
1276
		return array_keys($this->_d);
1277
	}
1278
	protected function sortPriorities() {
1279
		if(!$this->_o) {
1280
			ksort($this->_d,SORT_NUMERIC);
1281
			$this->_o=true;
1282
		}
1283
	}
1284
	protected function flattenPriorities() {
1285
		if(is_array($this->_fd))
1286
			return $this->_fd;
1287
		$this->sortPriorities();
1288
		$this->_fd=array();
1289
		foreach($this->_d as $priority => $itemsatpriority)
1290
			$this->_fd=array_merge($this->_fd,$itemsatpriority);
1291
		return $this->_fd;
1292
	}
1293
	public function itemAt($index)
1294
	{
1295
		if($index>=0&&$index<$this->getCount()) {
1296
			$arr=$this->flattenPriorities();
1297
			return $arr[$index];
1298
		} else
1299
			throw new TInvalidDataValueException('list_index_invalid',$index);
1300
	}
1301
	public function itemsAtPriority($priority=null)
1302
	{
1303
		if($priority===null)
1304
			$priority=$this->getDefaultPriority();
1305
		$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1306
		return isset($this->_d[$priority])?$this->_d[$priority]:null;
1307
	}
1308
	public function itemAtIndexInPriority($index,$priority=null)
1309
	{
1310
		if($priority===null)
1311
			$priority=$this->getDefaultPriority();
1312
		$priority=(string)round(TPropertyValue::ensureFloat($priority), $this->_p);
1313
		return !isset($this->_d[$priority])?false:(
1314
				isset($this->_d[$priority][$index])?$this->_d[$priority][$index]:false
1315
			);
1316
	}
1317
	public function add($item,$priority=null)
1318
	{
1319
		if($this->getReadOnly())
1320
			throw new TInvalidOperationException('list_readonly',get_class($this));
1321
		return $this->insertAtIndexInPriority($item,false,$priority,true);
1322
	}
1323
	public function insertAt($index,$item)
1324
	{
1325
		if($this->getReadOnly())
1326
			throw new TInvalidOperationException('list_readonly',get_class($this));
1327
		if(($priority=$this->priorityAt($index,true))!==false)
1328
			$this->insertAtIndexInPriority($item,$priority[1],$priority[0]);
1329
		else
1330
			throw new TInvalidDataValueException('list_index_invalid',$index);
1331
	}
1332
	public function insertAtIndexInPriority($item,$index=false,$priority=null,$preserveCache=false)
1333
	{
1334
		if($this->getReadOnly())
1335
			throw new TInvalidOperationException('list_readonly',get_class($this));
1336
		if($priority===null)
1337
			$priority=$this->getDefaultPriority();
1338
		$priority=(string)round(TPropertyValue::ensureFloat($priority), $this->_p);
1339
		if($preserveCache) {
1340
			$this->sortPriorities();
1341
			$cc=0;
1342
			foreach($this->_d as $prioritykey=>$items)
1343
				if($prioritykey>=$priority)
1344
					break;
1345
				else
1346
					$cc+=count($items);
1347
			if($index===false&&isset($this->_d[$priority])) {
1348
				$c=count($this->_d[$priority]);
1349
				$c+=$cc;
1350
				$this->_d[$priority][]=$item;
1351
			} else if(isset($this->_d[$priority])) {
1352
				$c=$index+$cc;
1353
				array_splice($this->_d[$priority],$index,0,array($item));
1354
			} else {
1355
				$c = $cc;
1356
				$this->_o = false;
1357
				$this->_d[$priority]=array($item);
1358
			}
1359
			if($this->_fd&&is_array($this->_fd)) 				array_splice($this->_fd,$c,0,array($item));
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->_fd of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1360
		} else {
1361
			$c=null;
1362
			if($index===false&&isset($this->_d[$priority])) {
1363
				$cc=count($this->_d[$priority]);
1364
				$this->_d[$priority][]=$item;
1365
			} else if(isset($this->_d[$priority])) {
1366
				$cc=$index;
1367
				array_splice($this->_d[$priority],$index,0,array($item));
1368
			} else {
1369
				$cc=0;
1370
				$this->_o=false;
1371
				$this->_d[$priority]=array($item);
1372
			}
1373
			if($this->_fd&&is_array($this->_fd)&&count($this->_d)==1)
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->_fd of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1374
				array_splice($this->_fd,$cc,0,array($item));
1375
			else
1376
				$this->_fd=null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $_fd.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1377
		}
1378
		$this->_c++;
1379
		return $c;
1380
	}
1381
	public function remove($item,$priority=false)
1382
	{
1383
		if($this->getReadOnly())
1384
			throw new TInvalidOperationException('list_readonly',get_class($this));
1385
		if(($p=$this->priorityOf($item,true))!==false)
1386
		{
1387
			if($priority!==false) {
1388
				if($priority===null)
1389
					$priority=$this->getDefaultPriority();
1390
				$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1391
				if($p[0]!=$priority)
1392
					throw new TInvalidDataValueException('list_item_inexistent');
1393
			}
1394
			$this->removeAtIndexInPriority($p[1],$p[0]);
1395
			return $p[2];
1396
		}
1397
		else
1398
			throw new TInvalidDataValueException('list_item_inexistent');
1399
	}
1400
	public function removeAt($index)
1401
	{
1402
		if($this->getReadOnly())
1403
			throw new TInvalidOperationException('list_readonly',get_class($this));
1404
		if(($priority=$this->priorityAt($index, true))!==false)
1405
			return $this->removeAtIndexInPriority($priority[1],$priority[0]);
1406
		throw new TInvalidDataValueException('list_index_invalid',$index);
1407
	}
1408
	public function removeAtIndexInPriority($index, $priority=null)
1409
	{
1410
		if($this->getReadOnly())
1411
			throw new TInvalidOperationException('list_readonly',get_class($this));
1412
		if($priority===null)
1413
			$priority=$this->getDefaultPriority();
1414
		$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1415
		if(!isset($this->_d[$priority])||$index<0||$index>=count($this->_d[$priority]))
1416
			throw new TInvalidDataValueException('list_item_inexistent');
1417
				$value=array_splice($this->_d[$priority],$index,1);
1418
		$value=$value[0];
1419
		if(!count($this->_d[$priority]))
1420
			unset($this->_d[$priority]);
1421
		$this->_c--;
1422
		$this->_fd=null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $_fd.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1423
		return $value;
1424
	}
1425
	public function clear()
1426
	{
1427
		if($this->getReadOnly())
1428
			throw new TInvalidOperationException('list_readonly',get_class($this));
1429
		$d=array_reverse($this->_d,true);
0 ignored issues
show
Unused Code introduced by
$d is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1430
		foreach($this->_d as $priority=>$items) {
1431
			for($index=count($items)-1;$index>=0;$index--)
1432
				$this->removeAtIndexInPriority($index,$priority);
1433
			unset($this->_d[$priority]);
1434
		}
1435
	}
1436
	public function contains($item)
1437
	{
1438
		return $this->indexOf($item)>=0;
1439
	}
1440
	public function indexOf($item)
1441
	{
1442
		if(($index=array_search($item,$this->flattenPriorities(),true))===false)
1443
			return -1;
1444
		else
1445
			return $index;
1446
	}
1447
	public function priorityOf($item,$withindex = false)
1448
	{
1449
		$this->sortPriorities();
1450
		$absindex = 0;
1451
		foreach($this->_d as $priority=>$items) {
1452
			if(($index=array_search($item,$items,true))!==false) {
1453
				$absindex+=$index;
1454
				return $withindex?array($priority,$index,$absindex,
1455
						'priority'=>$priority,'index'=>$index,'absindex'=>$absindex):$priority;
1456
			} else
1457
				$absindex+=count($items);
1458
		}
1459
		return false;
1460
	}
1461
	public function priorityAt($index,$withindex = false)
1462
	{
1463
		if($index<0||$index>=$this->getCount())
1464
			throw new TInvalidDataValueException('list_index_invalid',$index);
1465
		$absindex=$index;
1466
		$this->sortPriorities();
1467
		foreach($this->_d as $priority=>$items) {
1468
			if($index>=($c=count($items)))
1469
				$index-=$c;
1470
			else
1471
				return $withindex?array($priority,$index,$absindex,
1472
						'priority'=>$priority,'index'=>$index,'absindex'=>$absindex):$priority;
1473
		}
1474
		return false;
1475
	}
1476
	public function insertBefore($indexitem, $item)
1477
	{
1478
		if($this->getReadOnly())
1479
			throw new TInvalidOperationException('list_readonly',get_class($this));
1480
		if(($priority=$this->priorityOf($indexitem,true))===false)
1481
			throw new TInvalidDataValueException('list_item_inexistent');
1482
		$this->insertAtIndexInPriority($item,$priority[1],$priority[0]);
1483
		return $priority[2];
1484
	}
1485
	public function insertAfter($indexitem, $item)
1486
	{
1487
		if($this->getReadOnly())
1488
			throw new TInvalidOperationException('list_readonly',get_class($this));
1489
		if(($priority=$this->priorityOf($indexitem,true))===false)
1490
			throw new TInvalidDataValueException('list_item_inexistent');
1491
		$this->insertAtIndexInPriority($item,$priority[1]+1,$priority[0]);
1492
		return $priority[2]+1;
1493
	}
1494
	public function toArray()
1495
	{
1496
		return $this->flattenPriorities();
1497
	}
1498
	public function toPriorityArray()
1499
	{
1500
		$this->sortPriorities();
1501
		return $this->_d;
1502
	}
1503
	public function toArrayBelowPriority($priority,$inclusive=false)
1504
	{
1505
		$this->sortPriorities();
1506
		$items=array();
1507
		foreach($this->_d as $itemspriority=>$itemsatpriority)
1508
		{
1509
			if((!$inclusive&&$itemspriority>=$priority)||$itemspriority>$priority)
1510
				break;
1511
			$items=array_merge($items,$itemsatpriority);
1512
		}
1513
		return $items;
1514
	}
1515
	public function toArrayAbovePriority($priority,$inclusive=true)
1516
	{
1517
		$this->sortPriorities();
1518
		$items=array();
1519
		foreach($this->_d as $itemspriority=>$itemsatpriority)
1520
		{
1521
			if((!$inclusive&&$itemspriority<=$priority)||$itemspriority<$priority)
1522
				continue;
1523
			$items=array_merge($items,$itemsatpriority);
1524
		}
1525
		return $items;
1526
	}
1527
	public function copyFrom($data)
1528
	{
1529
		if($data instanceof TPriorityList)
1530
		{
1531
			if($this->getCount()>0)
1532
				$this->clear();
1533
			foreach($data->getPriorities() as $priority)
1534
			{
1535
				foreach($data->itemsAtPriority($priority) as $index=>$item)
1536
					$this->insertAtIndexInPriority($item,$index,$priority);
1537
			}
1538
		} else if(is_array($data)||$data instanceof Traversable) {
1539
			if($this->getCount()>0)
1540
				$this->clear();
1541
			foreach($data as $key=>$item)
1542
				$this->add($item);
1543
		} else if($data!==null)
1544
			throw new TInvalidDataTypeException('map_data_not_iterable');
1545
	}
1546
	public function mergeWith($data)
1547
	{
1548
		if($data instanceof TPriorityList)
1549
		{
1550
			foreach($data->getPriorities() as $priority)
1551
			{
1552
				foreach($data->itemsAtPriority($priority) as $index=>$item)
1553
					$this->insertAtIndexInPriority($item,false,$priority);
1554
			}
1555
		}
1556
		else if(is_array($data)||$data instanceof Traversable)
1557
		{
1558
			foreach($data as $priority=>$item)
1559
				$this->add($item);
1560
		}
1561
		else if($data!==null)
1562
			throw new TInvalidDataTypeException('map_data_not_iterable');
1563
	}
1564
	public function offsetExists($offset)
1565
	{
1566
		return ($offset>=0&&$offset<$this->getCount());
1567
	}
1568
	public function offsetGet($offset)
1569
	{
1570
		return $this->itemAt($offset);
1571
	}
1572
	public function offsetSet($offset,$item)
1573
	{
1574
		if($offset===null)
1575
			return $this->add($item);
1576
		if($offset===$this->getCount()) {
1577
			$priority=$this->priorityAt($offset-1,true);
1578
			$priority[1]++;
1579
		} else {
1580
			$priority=$this->priorityAt($offset,true);
1581
			$this->removeAtIndexInPriority($priority[1],$priority[0]);
1582
		}
1583
		$this->insertAtIndexInPriority($item,$priority[1],$priority[0]);
1584
	}
1585
	public function offsetUnset($offset)
1586
	{
1587
		$this->removeAt($offset);
1588
	}
1589
}
1590
class TMap extends TComponent implements IteratorAggregate,ArrayAccess,Countable
0 ignored issues
show
Coding Style introduced by
Expected 1 space before "ArrayAccess"; 0 found
Loading history...
Coding Style introduced by
Expected 1 space before "Countable"; 0 found
Loading history...
1591
{
1592
	private $_d=array();
1593
	private $_r=false;
1594
	protected function _getZappableSleepProps(&$exprops)
1595
	{
1596
		parent::_getZappableSleepProps($exprops);
1597
		if ($this->_d===array())
1598
			$exprops[] = "\0TMap\0_d";
1599
		if ($this->_r===false)
1600
			$exprops[] = "\0TMap\0_r";
1601
	}
1602
	public function __construct($data=null,$readOnly=false)
1603
	{
1604
		if($data!==null)
1605
			$this->copyFrom($data);
1606
		$this->setReadOnly($readOnly);
1607
	}
1608
	public function getReadOnly()
1609
	{
1610
		return $this->_r;
1611
	}
1612
	protected function setReadOnly($value)
1613
	{
1614
		$this->_r=TPropertyValue::ensureBoolean($value);
1615
	}
1616
	public function getIterator()
1617
	{
1618
		return new ArrayIterator( $this->_d );
1619
	}
1620
	public function count()
1621
	{
1622
		return $this->getCount();
1623
	}
1624
	public function getCount()
1625
	{
1626
		return count($this->_d);
1627
	}
1628
	public function getKeys()
1629
	{
1630
		return array_keys($this->_d);
1631
	}
1632
	public function itemAt($key)
1633
	{
1634
		return isset($this->_d[$key]) ? $this->_d[$key] : null;
1635
	}
1636
	public function add($key,$value)
1637
	{
1638
		if(!$this->_r)
1639
			$this->_d[$key]=$value;
1640
		else
1641
			throw new TInvalidOperationException('map_readonly',get_class($this));
1642
	}
1643
	public function remove($key)
1644
	{
1645
		if(!$this->_r)
1646
		{
1647
			if(isset($this->_d[$key]) || array_key_exists($key,$this->_d))
1648
			{
1649
				$value=$this->_d[$key];
1650
				unset($this->_d[$key]);
1651
				return $value;
1652
			}
1653
			else
1654
				return null;
1655
		}
1656
		else
1657
			throw new TInvalidOperationException('map_readonly',get_class($this));
1658
	}
1659
	public function clear()
1660
	{
1661
		foreach(array_keys($this->_d) as $key)
1662
			$this->remove($key);
1663
	}
1664
	public function contains($key)
1665
	{
1666
		return isset($this->_d[$key]) || array_key_exists($key,$this->_d);
1667
	}
1668
	public function toArray()
1669
	{
1670
		return $this->_d;
1671
	}
1672
	public function copyFrom($data)
1673
	{
1674
		if(is_array($data) || $data instanceof Traversable)
1675
		{
1676
			if($this->getCount()>0)
1677
				$this->clear();
1678
			foreach($data as $key=>$value)
1679
				$this->add($key,$value);
1680
		}
1681
		else if($data!==null)
1682
			throw new TInvalidDataTypeException('map_data_not_iterable');
1683
	}
1684
	public function mergeWith($data)
1685
	{
1686
		if(is_array($data) || $data instanceof Traversable)
1687
		{
1688
			foreach($data as $key=>$value)
1689
				$this->add($key,$value);
1690
		}
1691
		else if($data!==null)
1692
			throw new TInvalidDataTypeException('map_data_not_iterable');
1693
	}
1694
	public function offsetExists($offset)
1695
	{
1696
		return $this->contains($offset);
1697
	}
1698
	public function offsetGet($offset)
1699
	{
1700
		return $this->itemAt($offset);
1701
	}
1702
	public function offsetSet($offset,$item)
1703
	{
1704
		$this->add($offset,$item);
1705
	}
1706
	public function offsetUnset($offset)
1707
	{
1708
		$this->remove($offset);
1709
	}
1710
}
1711
class TMapIterator extends ArrayIterator
1712
{
1713
}
1714
class TPriorityMap extends TMap
1715
{
1716
	private $_d=array();
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1717
	private $_r=false;
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
1718
	private $_o=false;
1719
	private $_fd=null;
1720
	private $_c=0;
1721
	private $_dp=10;
1722
	private $_p=8;
1723
	public function __construct($data=null,$readOnly=false,$defaultPriority=10,$precision=8)
1724
	{
1725
		if($data!==null)
1726
			$this->copyFrom($data);
1727
		$this->setReadOnly($readOnly);
1728
		$this->setPrecision($precision);
1729
		$this->setDefaultPriority($defaultPriority);
1730
	}
1731
	public function getReadOnly()
1732
	{
1733
		return $this->_r;
1734
	}
1735
	protected function setReadOnly($value)
1736
	{
1737
		$this->_r=TPropertyValue::ensureBoolean($value);
1738
	}
1739
	public function getDefaultPriority()
1740
	{
1741
		return $this->_dp;
1742
	}
1743
	protected function setDefaultPriority($value)
1744
	{
1745
		$this->_dp = (string)round(TPropertyValue::ensureFloat($value), $this->_p);
0 ignored issues
show
Documentation Bug introduced by
It seems like (string) round(\TPropert...oat($value), $this->_p) of type string is incompatible with the declared type object<numeric> of property $_dp.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1746
	}
1747
	public function getPrecision()
1748
	{
1749
		return $this->_p;
1750
	}
1751
	protected function setPrecision($value)
1752
	{
1753
		$this->_p=TPropertyValue::ensureInteger($value);
1754
	}
1755
	public function getIterator()
1756
	{
1757
		return new ArrayIterator($this->flattenPriorities());
1758
	}
1759
	protected function sortPriorities() {
1760
		if(!$this->_o) {
1761
			ksort($this->_d, SORT_NUMERIC);
1762
			$this->_o=true;
1763
		}
1764
	}
1765
	protected function flattenPriorities() {
1766
		if(is_array($this->_fd))
1767
			return $this->_fd;
1768
		$this->sortPriorities();
1769
		$this->_fd = array();
1770
		foreach($this->_d as $priority => $itemsatpriority)
1771
			$this->_fd = array_merge($this->_fd, $itemsatpriority);
1772
		return $this->_fd;
1773
	}
1774
	public function count()
1775
	{
1776
		return $this->getCount();
1777
	}
1778
	public function getCount()
1779
	{
1780
		return $this->_c;
1781
	}
1782
	public function getPriorityCount($priority=null)
1783
	{
1784
		if($priority===null)
1785
			$priority=$this->getDefaultPriority();
1786
		$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1787
		if(!isset($this->_d[$priority])||!is_array($this->_d[$priority]))
1788
			return false;
1789
		return count($this->_d[$priority]);
1790
	}
1791
	public function getPriorities()
1792
	{
1793
		$this->sortPriorities();
1794
		return array_keys($this->_d);
1795
	}
1796
	public function getKeys()
1797
	{
1798
		return array_keys($this->flattenPriorities());
1799
	}
1800
	public function itemAt($key,$priority=false)
1801
	{
1802
		if($priority===false){
1803
			$map=$this->flattenPriorities();
1804
			return isset($map[$key])?$map[$key]:null;
1805
		} else {
1806
			if($priority===null)
1807
				$priority=$this->getDefaultPriority();
1808
			$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1809
			return (isset($this->_d[$priority])&&isset($this->_d[$priority][$key]))?$this->_d[$priority][$key]:null;
1810
		}
1811
	}
1812
	public function setPriorityAt($key,$priority=null)
1813
	{
1814
		if($priority===null)
1815
			$priority=$this->getDefaultPriority();
1816
		$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1817
		$oldpriority=$this->priorityAt($key);
1818
		if($oldpriority!==false&&$oldpriority!=$priority) {
1819
			$value=$this->remove($key,$oldpriority);
1820
			$this->add($key,$value,$priority);
1821
		}
1822
		return $oldpriority;
1823
	}
1824
	public function itemsAtPriority($priority=null)
1825
	{
1826
		if($priority===null)
1827
			$priority=$this->getDefaultPriority();
1828
		$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1829
		return isset($this->_d[$priority])?$this->_d[$priority]:null;
1830
	}
1831
	public function priorityOf($item)
1832
	{
1833
		$this->sortPriorities();
1834
		foreach($this->_d as $priority=>$items)
1835
			if(($index=array_search($item,$items,true))!==false)
1836
				return $priority;
1837
		return false;
1838
	}
1839
	public function priorityAt($key)
1840
	{
1841
		$this->sortPriorities();
1842
		foreach($this->_d as $priority=>$items)
1843
			if(array_key_exists($key,$items))
1844
				return $priority;
1845
		return false;
1846
	}
1847
	public function add($key,$value,$priority=null)
1848
	{
1849
		if($priority===null)
1850
			$priority=$this->getDefaultPriority();
1851
		$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1852
		if(!$this->_r)
1853
		{
1854
			foreach($this->_d as $innerpriority=>$items)
1855
				if(array_key_exists($key,$items))
1856
				{
1857
					unset($this->_d[$innerpriority][$key]);
1858
					$this->_c--;
1859
					if(count($this->_d[$innerpriority])===0)
1860
						unset($this->_d[$innerpriority]);
1861
				}
1862
			if(!isset($this->_d[$priority])) {
1863
				$this->_d[$priority]=array($key=>$value);
1864
				$this->_o=false;
1865
			}
1866
			else
1867
				$this->_d[$priority][$key]=$value;
1868
			$this->_c++;
1869
			$this->_fd=null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $_fd.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1870
		}
1871
		else
1872
			throw new TInvalidOperationException('map_readonly',get_class($this));
1873
		return $priority;
1874
	}
1875
	public function remove($key,$priority=false)
1876
	{
1877
		if(!$this->_r)
1878
		{
1879
			if($priority===null)
1880
				$priority=$this->getDefaultPriority();
1881
			if($priority===false)
1882
			{
1883
				$this->sortPriorities();
1884
				foreach($this->_d as $priority=>$items)
1885
					if(array_key_exists($key,$items))
1886
					{
1887
						$value=$this->_d[$priority][$key];
1888
						unset($this->_d[$priority][$key]);
1889
						$this->_c--;
1890
						if(count($this->_d[$priority])===0)
1891
						{
1892
							unset($this->_d[$priority]);
1893
							$this->_o=false;
1894
						}
1895
						$this->_fd=null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $_fd.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1896
						return $value;
1897
					}
1898
				return null;
1899
			}
1900
			else
1901
			{
1902
				$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1903
				if(isset($this->_d[$priority])&&(isset($this->_d[$priority][$key])||array_key_exists($key,$this->_d[$priority])))
1904
				{
1905
					$value=$this->_d[$priority][$key];
1906
					unset($this->_d[$priority][$key]);
1907
					$this->_c--;
1908
					if(count($this->_d[$priority])===0) {
1909
						unset($this->_d[$priority]);
1910
						$this->_o=false;
1911
					}
1912
					$this->_fd=null;
1913
					return $value;
1914
				}
1915
				else
1916
					return null;
1917
			}
1918
		}
1919
		else
1920
			throw new TInvalidOperationException('map_readonly',get_class($this));
1921
	}
1922
	public function clear()
1923
	{
1924
		foreach($this->_d as $priority=>$items)
1925
			foreach(array_keys($items) as $key)
1926
				$this->remove($key);
1927
	}
1928
	public function contains($key)
1929
	{
1930
		$map=$this->flattenPriorities();
1931
		return isset($map[$key])||array_key_exists($key,$map);
1932
	}
1933
	public function toArray()
1934
	{
1935
		return $this->flattenPriorities();
1936
	}
1937
	public function toArrayBelowPriority($priority,$inclusive=false)
1938
	{
1939
		$this->sortPriorities();
1940
		$items=array();
1941
		foreach($this->_d as $itemspriority=>$itemsatpriority)
1942
		{
1943
			if((!$inclusive&&$itemspriority>=$priority)||$itemspriority>$priority)
1944
				break;
1945
			$items=array_merge($items,$itemsatpriority);
1946
		}
1947
		return $items;
1948
	}
1949
	public function toArrayAbovePriority($priority,$inclusive=true)
1950
	{
1951
		$this->sortPriorities();
1952
		$items=array();
1953
		foreach($this->_d as $itemspriority=>$itemsatpriority)
1954
		{
1955
			if((!$inclusive&&$itemspriority<=$priority)||$itemspriority<$priority)
1956
				continue;
1957
			$items=array_merge($items,$itemsatpriority);
1958
		}
1959
		return $items;
1960
	}
1961
	public function copyFrom($data)
1962
	{
1963
		if($data instanceof TPriorityMap)
1964
		{
1965
			if($this->getCount()>0)
1966
				$this->clear();
1967
			foreach($data->getPriorities() as $priority) {
1968
				foreach($data->itemsAtPriority($priority) as $key => $value) {
1969
					$this->add($key,$value,$priority);
1970
				}
1971
			}
1972
		}
1973
		else if(is_array($data)||$data instanceof Traversable)
1974
		{
1975
			if($this->getCount()>0)
1976
				$this->clear();
1977
			foreach($data as $key=>$value)
1978
				$this->add($key,$value);
1979
		}
1980
		else if($data!==null)
1981
			throw new TInvalidDataTypeException('map_data_not_iterable');
1982
	}
1983
	public function mergeWith($data)
1984
	{
1985
		if($data instanceof TPriorityMap)
1986
		{
1987
			foreach($data->getPriorities() as $priority)
1988
			{
1989
				foreach($data->itemsAtPriority($priority) as $key => $value)
1990
					$this->add($key,$value,$priority);
1991
			}
1992
		}
1993
		else if(is_array($data)||$data instanceof Traversable)
1994
		{
1995
			foreach($data as $key=>$value)
1996
				$this->add($key,$value);
1997
		}
1998
		else if($data!==null)
1999
			throw new TInvalidDataTypeException('map_data_not_iterable');
2000
	}
2001
	public function offsetExists($offset)
2002
	{
2003
		return $this->contains($offset);
2004
	}
2005
	public function offsetGet($offset)
2006
	{
2007
		return $this->itemAt($offset);
2008
	}
2009
	public function offsetSet($offset,$item)
2010
	{
2011
		$this->add($offset,$item);
2012
	}
2013
	public function offsetUnset($offset)
2014
	{
2015
		$this->remove($offset);
2016
	}
2017
}
2018
class TStack extends TComponent implements IteratorAggregate,Countable
0 ignored issues
show
Coding Style introduced by
Expected 1 space before "Countable"; 0 found
Loading history...
2019
{
2020
	private $_d=array();
2021
	private $_c=0;
2022
	public function __construct($data=null)
2023
	{
2024
		if($data!==null)
2025
			$this->copyFrom($data);
2026
	}
2027
	public function toArray()
2028
	{
2029
		return $this->_d;
2030
	}
2031
	public function copyFrom($data)
2032
	{
2033
		if(is_array($data) || ($data instanceof Traversable))
2034
		{
2035
			$this->clear();
2036
			foreach($data as $item)
2037
			{
2038
				$this->_d[]=$item;
2039
				++$this->_c;
2040
			}
2041
		}
2042
		else if($data!==null)
2043
			throw new TInvalidDataTypeException('stack_data_not_iterable');
2044
	}
2045
	public function clear()
2046
	{
2047
		$this->_c=0;
2048
		$this->_d=array();
2049
	}
2050
	public function contains($item)
2051
	{
2052
		return array_search($item,$this->_d,true)!==false;
2053
	}
2054
	public function peek()
2055
	{
2056
		if($this->_c===0)
2057
			throw new TInvalidOperationException('stack_empty');
2058
		else
2059
			return $this->_d[$this->_c-1];
2060
	}
2061
	public function pop()
2062
	{
2063
		if($this->_c===0)
2064
			throw new TInvalidOperationException('stack_empty');
2065
		else
2066
		{
2067
			--$this->_c;
2068
			return array_pop($this->_d);
2069
		}
2070
	}
2071
	public function push($item)
2072
	{
2073
		++$this->_c;
2074
		$this->_d[] = $item;
2075
	}
2076
	public function getIterator()
2077
	{
2078
		return new ArrayIterator( $this->_d );
2079
	}
2080
	public function getCount()
2081
	{
2082
		return $this->_c;
2083
	}
2084
	public function count()
2085
	{
2086
		return $this->getCount();
2087
	}
2088
}
2089
class TStackIterator implements Iterator
2090
{
2091
	private $_d;
2092
	private $_i;
2093
	private $_c;
2094
	public function __construct(&$data)
2095
	{
2096
		$this->_d=&$data;
2097
		$this->_i=0;
2098
		$this->_c=count($this->_d);
2099
	}
2100
	public function rewind()
2101
	{
2102
		$this->_i=0;
2103
	}
2104
	public function key()
2105
	{
2106
		return $this->_i;
2107
	}
2108
	public function current()
2109
	{
2110
		return $this->_d[$this->_i];
2111
	}
2112
	public function next()
2113
	{
2114
		$this->_i++;
2115
	}
2116
	public function valid()
2117
	{
2118
		return $this->_i<$this->_c;
2119
	}
2120
}
2121
class TXmlElement extends TComponent
2122
{
2123
	private $_parent=null;
2124
	private $_tagName='unknown';
2125
	private $_value='';
2126
	private $_elements=null;
2127
	private $_attributes=null;
2128
	public function __construct($tagName)
2129
	{
2130
		$this->setTagName($tagName);
2131
	}
2132
	public function getParent()
2133
	{
2134
		return $this->_parent;
2135
	}
2136
	public function setParent($parent)
2137
	{
2138
		$this->_parent=$parent;
2139
	}
2140
	public function getTagName()
2141
	{
2142
		return $this->_tagName;
2143
	}
2144
	public function setTagName($tagName)
2145
	{
2146
		$this->_tagName=$tagName;
2147
	}
2148
	public function getValue()
2149
	{
2150
		return $this->_value;
2151
	}
2152
	public function setValue($value)
2153
	{
2154
		$this->_value=TPropertyValue::ensureString($value);
2155
	}
2156
	public function getHasElement()
2157
	{
2158
		return $this->_elements!==null && $this->_elements->getCount()>0;
2159
	}
2160
	public function getHasAttribute()
2161
	{
2162
		return $this->_attributes!==null && $this->_attributes->getCount()>0;
2163
	}
2164
	public function getAttribute($name)
2165
	{
2166
		if($this->_attributes!==null)
2167
			return $this->_attributes->itemAt($name);
2168
		else
2169
			return null;
2170
	}
2171
	public function setAttribute($name,$value)
2172
	{
2173
		$this->getAttributes()->add($name,TPropertyValue::ensureString($value));
2174
	}
2175
	public function getElements()
2176
	{
2177
		if(!$this->_elements)
2178
			$this->_elements=new TXmlElementList($this);
2179
		return $this->_elements;
2180
	}
2181
	public function getAttributes()
2182
	{
2183
		if(!$this->_attributes)
2184
			$this->_attributes=new TMap;
2185
		return $this->_attributes;
2186
	}
2187
	public function getElementByTagName($tagName)
2188
	{
2189
		if($this->_elements)
2190
		{
2191
			foreach($this->_elements as $element)
2192
				if($element->_tagName===$tagName)
2193
					return $element;
2194
		}
2195
		return null;
2196
	}
2197
	public function getElementsByTagName($tagName)
2198
	{
2199
		$list=new TList;
2200
		if($this->_elements)
2201
		{
2202
			foreach($this->_elements as $element)
2203
				if($element->_tagName===$tagName)
2204
					$list->add($element);
2205
		}
2206
		return $list;
2207
	}
2208
	public function toString($indent=0)
2209
	{
2210
		$attr='';
2211
		if($this->_attributes!==null)
2212
		{
2213
			foreach($this->_attributes as $name=>$value)
2214
			{
2215
				$value=$this->xmlEncode($value);
2216
				$attr.=" $name=\"$value\"";
2217
			}
2218
		}
2219
		$prefix=str_repeat(' ',$indent*4);
2220
		if($this->getHasElement())
2221
		{
2222
			$str=$prefix."<{$this->_tagName}$attr>\n";
2223
			foreach($this->getElements() as $element)
2224
				$str.=$element->toString($indent+1)."\n";
2225
			$str.=$prefix."</{$this->_tagName}>";
2226
			return $str;
2227
		}
2228
		else if(($value=$this->getValue())!=='')
2229
		{
2230
			$value=$this->xmlEncode($value);
2231
			return $prefix."<{$this->_tagName}$attr>$value</{$this->_tagName}>";
2232
		}
2233
		else
2234
			return $prefix."<{$this->_tagName}$attr />";
2235
	}
2236
	public function __toString()
2237
	{
2238
		return $this->toString();
2239
	}
2240
	private function xmlEncode($str)
2241
	{
2242
		return strtr($str,array(
2243
			'>'=>'&gt;',
2244
			'<'=>'&lt;',
2245
			'&'=>'&amp;',
2246
			'"'=>'&quot;',
2247
			"\r"=>'&#xD;',
2248
			"\t"=>'&#x9;',
2249
			"\n"=>'&#xA;'));
2250
	}
2251
}
2252
class TXmlDocument extends TXmlElement
2253
{
2254
	private $_version;
2255
	private $_encoding;
2256
	public function __construct($version='1.0',$encoding='')
2257
	{
2258
		parent::__construct('');
2259
		$this->setVersion($version);
2260
		$this->setEncoding($encoding);
2261
	}
2262
	public function getVersion()
2263
	{
2264
		return $this->_version;
2265
	}
2266
	public function setVersion($version)
2267
	{
2268
		$this->_version=$version;
2269
	}
2270
	public function getEncoding()
2271
	{
2272
		return $this->_encoding;
2273
	}
2274
	public function setEncoding($encoding)
2275
	{
2276
		$this->_encoding=$encoding;
2277
	}
2278
	public function loadFromFile($file)
2279
	{
2280
		if(($str=@file_get_contents($file))!==false)
2281
			return $this->loadFromString($str);
2282
		else
2283
			throw new TIOException('xmldocument_file_read_failed',$file);
2284
	}
2285
	public function loadFromString($string)
2286
	{
2287
				$doc=new DOMDocument();
2288
		if($doc->loadXML($string)===false)
2289
			return false;
2290
		$this->setEncoding($doc->encoding);
2291
		$this->setVersion($doc->xmlVersion);
2292
		$element=$doc->documentElement;
2293
		$this->setTagName($element->tagName);
2294
		$this->setValue($element->nodeValue);
2295
		$elements=$this->getElements();
2296
		$attributes=$this->getAttributes();
2297
		$elements->clear();
2298
		$attributes->clear();
2299
		static $bSimpleXml;
2300
		if($bSimpleXml === null)
2301
			$bSimpleXml = (boolean)function_exists('simplexml_load_string');
2302
		if($bSimpleXml)
2303
		{
2304
			$simpleDoc = simplexml_load_string($string);
2305
			$docNamespaces = $simpleDoc->getDocNamespaces(false);
2306
			$simpleDoc = null;
0 ignored issues
show
Unused Code introduced by
$simpleDoc is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2307
			foreach($docNamespaces as $prefix => $uri)
2308
			{
2309
 				if($prefix === '')
2310
   					$attributes->add('xmlns', $uri);
2311
   				else
2312
   					$attributes->add('xmlns:'.$prefix, $uri);
2313
			}
2314
		}
2315
		foreach($element->attributes as $name=>$attr)
2316
			$attributes->add(($attr->prefix === '' ? '' : $attr->prefix . ':') .$name,$attr->value);
2317
		foreach($element->childNodes as $child)
2318
		{
2319
			if($child instanceof DOMElement)
2320
				$elements->add($this->buildElement($child));
2321
		}
2322
		return true;
2323
	}
2324
	public function saveToFile($file)
2325
	{
2326
		if(($fw=fopen($file,'w'))!==false)
2327
		{
2328
			fwrite($fw,$this->saveToString());
2329
			fclose($fw);
2330
		}
2331
		else
2332
			throw new TIOException('xmldocument_file_write_failed',$file);
2333
	}
2334
	public function saveToString()
2335
	{
2336
		$version=empty($this->_version)?' version="1.0"':' version="'.$this->_version.'"';
2337
		$encoding=empty($this->_encoding)?'':' encoding="'.$this->_encoding.'"';
2338
		return "<?xml{$version}{$encoding}?>\n".$this->toString(0);
2339
	}
2340
	public function __toString()
2341
	{
2342
		return $this->saveToString();
2343
	}
2344
	protected function buildElement($node)
2345
	{
2346
		$element=new TXmlElement($node->tagName);
2347
		$element->setValue($node->nodeValue);
2348
		foreach($node->attributes as $name=>$attr)
2349
			$element->getAttributes()->add(($attr->prefix === '' ? '' : $attr->prefix . ':') . $name,$attr->value);
2350
		foreach($node->childNodes as $child)
2351
		{
2352
			if($child instanceof DOMElement)
2353
				$element->getElements()->add($this->buildElement($child));
2354
		}
2355
		return $element;
2356
	}
2357
}
2358
class TXmlElementList extends TList
2359
{
2360
	private $_o;
2361
	public function __construct(TXmlElement $owner)
2362
	{
2363
		$this->_o=$owner;
2364
	}
2365
	protected function getOwner()
2366
	{
2367
		return $this->_o;
2368
	}
2369
	public function insertAt($index,$item)
2370
	{
2371
		if($item instanceof TXmlElement)
2372
		{
2373
			parent::insertAt($index,$item);
2374
			if($item->getParent()!==null)
2375
				$item->getParent()->getElements()->remove($item);
2376
			$item->setParent($this->_o);
2377
		}
2378
		else
2379
			throw new TInvalidDataTypeException('xmlelementlist_xmlelement_required');
2380
	}
2381
	public function removeAt($index)
2382
	{
2383
		$item=parent::removeAt($index);
2384
		if($item instanceof TXmlElement)
2385
			$item->setParent(null);
2386
		return $item;
2387
	}
2388
}
2389
class TAuthorizationRule extends TComponent
2390
{
2391
	private $_action;
2392
	private $_users;
2393
	private $_roles;
2394
	private $_verb;
2395
	private $_ipRules;
2396
	private $_everyone;
2397
	private $_guest;
2398
	private $_authenticated;
2399
	public function __construct($action,$users,$roles,$verb='',$ipRules='')
2400
	{
2401
		$action=strtolower(trim($action));
2402
		if($action==='allow' || $action==='deny')
2403
			$this->_action=$action;
2404
		else
2405
			throw new TInvalidDataValueException('authorizationrule_action_invalid',$action);
2406
		$this->_users=array();
2407
		$this->_roles=array();
2408
		$this->_ipRules=array();
2409
		$this->_everyone=false;
2410
		$this->_guest=false;
2411
		$this->_authenticated=false;
2412
		if(trim($users)==='')
2413
			$users='*';
2414
		foreach(explode(',',$users) as $user)
2415
		{
2416
			if(($user=trim(strtolower($user)))!=='')
2417
			{
2418
				if($user==='*')
2419
				{
2420
					$this->_everyone=true;
2421
					break;
2422
				}
2423
				else if($user==='?')
2424
					$this->_guest=true;
2425
				else if($user==='@')
2426
					$this->_authenticated=true;
2427
				else
2428
					$this->_users[]=$user;
2429
			}
2430
		}
2431
		if(trim($roles)==='')
2432
			$roles='*';
2433
		foreach(explode(',',$roles) as $role)
2434
		{
2435
			if(($role=trim(strtolower($role)))!=='')
2436
				$this->_roles[]=$role;
2437
		}
2438
		if(($verb=trim(strtolower($verb)))==='')
2439
			$verb='*';
2440
		if($verb==='*' || $verb==='get' || $verb==='post')
2441
			$this->_verb=$verb;
2442
		else
2443
			throw new TInvalidDataValueException('authorizationrule_verb_invalid',$verb);
2444
		if(trim($ipRules)==='')
2445
			$ipRules='*';
2446
		foreach(explode(',',$ipRules) as $ipRule)
2447
		{
2448
			if(($ipRule=trim($ipRule))!=='')
2449
				$this->_ipRules[]=$ipRule;
2450
		}
2451
	}
2452
	public function getAction()
2453
	{
2454
		return $this->_action;
2455
	}
2456
	public function getUsers()
2457
	{
2458
		return $this->_users;
2459
	}
2460
	public function getRoles()
2461
	{
2462
		return $this->_roles;
2463
	}
2464
	public function getVerb()
2465
	{
2466
		return $this->_verb;
2467
	}
2468
	public function getIPRules()
2469
	{
2470
		return $this->_ipRules;
2471
	}
2472
	public function getGuestApplied()
2473
	{
2474
		return $this->_guest || $this->_everyone;
2475
	}
2476
	public function getEveryoneApplied()
2477
	{
2478
		return $this->_everyone;
2479
	}
2480
	public function getAuthenticatedApplied()
2481
	{
2482
		return $this->_authenticated || $this->_everyone;
2483
	}
2484
	public function isUserAllowed(IUser $user,$verb,$ip)
2485
	{
2486
		if($this->isVerbMatched($verb) && $this->isIpMatched($ip) && $this->isUserMatched($user) && $this->isRoleMatched($user))
2487
			return ($this->_action==='allow')?1:-1;
2488
		else
2489
			return 0;
2490
	}
2491
	private function isIpMatched($ip)
2492
	{
2493
		if(empty($this->_ipRules))
2494
			return 1;
2495
		foreach($this->_ipRules as $rule)
2496
		{
2497
			if($rule==='*' || $rule===$ip || (($pos=strpos($rule,'*'))!==false && strncmp($ip,$rule,$pos)===0))
2498
				return 1;
2499
		}
2500
		return 0;
2501
	}
2502
	private function isUserMatched($user)
2503
	{
2504
		return ($this->_everyone || ($this->_guest && $user->getIsGuest()) || ($this->_authenticated && !$user->getIsGuest()) || in_array(strtolower($user->getName()),$this->_users));
2505
	}
2506
	private function isRoleMatched($user)
2507
	{
2508
		foreach($this->_roles as $role)
2509
		{
2510
			if($role==='*' || $user->isInRole($role))
2511
				return true;
2512
		}
2513
		return false;
2514
	}
2515
	private function isVerbMatched($verb)
2516
	{
2517
		return ($this->_verb==='*' || strcasecmp($verb,$this->_verb)===0);
2518
	}
2519
}
2520
class TAuthorizationRuleCollection extends TList
2521
{
2522
	public function isUserAllowed($user,$verb,$ip)
2523
	{
2524
		if($user instanceof IUser)
2525
		{
2526
			$verb=strtolower(trim($verb));
2527
			foreach($this as $rule)
2528
			{
2529
				if(($decision=$rule->isUserAllowed($user,$verb,$ip))!==0)
2530
					return ($decision>0);
2531
			}
2532
			return true;
2533
		}
2534
		else
2535
			return false;
2536
	}
2537
	public function insertAt($index,$item)
2538
	{
2539
		if($item instanceof TAuthorizationRule)
2540
			parent::insertAt($index,$item);
2541
		else
2542
			throw new TInvalidDataTypeException('authorizationrulecollection_authorizationrule_required');
2543
	}
2544
}
2545
class TSecurityManager extends TModule
2546
{
2547
	const STATE_VALIDATION_KEY = 'prado:securitymanager:validationkey';
2548
	const STATE_ENCRYPTION_KEY = 'prado:securitymanager:encryptionkey';
2549
	private $_validationKey = null;
2550
	private $_encryptionKey = null;
2551
	private $_hashAlgorithm = 'sha1';
2552
	private $_cryptAlgorithm = 'rijndael-256';
2553
	private $_mbstring;
2554
	public function init($config)
2555
	{
2556
		$this->_mbstring=extension_loaded('mbstring');
2557
		$this->getApplication()->setSecurityManager($this);
2558
	}
2559
	protected function generateRandomKey()
2560
	{
2561
		return sprintf('%08x%08x%08x%08x',mt_rand(),mt_rand(),mt_rand(),mt_rand());
2562
	}
2563
	public function getValidationKey()
2564
	{
2565
		if(null === $this->_validationKey) {
2566
			if(null === ($this->_validationKey = $this->getApplication()->getGlobalState(self::STATE_VALIDATION_KEY))) {
2567
				$this->_validationKey = $this->generateRandomKey();
2568
				$this->getApplication()->setGlobalState(self::STATE_VALIDATION_KEY, $this->_validationKey, null, true);
2569
			}
2570
		}
2571
		return $this->_validationKey;
2572
	}
2573
	public function setValidationKey($value)
2574
	{
2575
		if('' === $value)
2576
			throw new TInvalidDataValueException('securitymanager_validationkey_invalid');
2577
		$this->_validationKey = $value;
2578
	}
2579
	public function getEncryptionKey()
2580
	{
2581
		if(null === $this->_encryptionKey) {
2582
			if(null === ($this->_encryptionKey = $this->getApplication()->getGlobalState(self::STATE_ENCRYPTION_KEY))) {
2583
				$this->_encryptionKey = $this->generateRandomKey();
2584
				$this->getApplication()->setGlobalState(self::STATE_ENCRYPTION_KEY, $this->_encryptionKey, null, true);
2585
			}
2586
		}
2587
		return $this->_encryptionKey;
2588
	}
2589
	public function setEncryptionKey($value)
2590
	{
2591
		if('' === $value)
2592
			throw new TInvalidDataValueException('securitymanager_encryptionkey_invalid');
2593
		$this->_encryptionKey = $value;
2594
	}
2595
	public function getValidation()
2596
	{
2597
		return $this->_hashAlgorithm;
2598
	}
2599
	public function getHashAlgorithm()
2600
	{
2601
		return $this->_hashAlgorithm;
2602
	}
2603
	public function setValidation($value)
2604
	{
2605
		$this->_hashAlgorithm = TPropertyValue::ensureEnum($value, 'TSecurityManagerValidationMode');
2606
	}
2607
	public function setHashAlgorithm($value)
2608
	{
2609
		$this->_hashAlgorithm = TPropertyValue::ensureString($value);
2610
	}
2611
	public function getEncryption()
2612
	{
2613
		if(is_string($this->_cryptAlgorithm))
2614
			return $this->_cryptAlgorithm;
2615
				return "3DES";
2616
	}
2617
	public function setEncryption($value)
2618
	{
2619
		$this->_cryptAlgorithm = $value;
2620
	}
2621
	public function getCryptAlgorithm()
2622
	{
2623
		return $this->_cryptAlgorithm;
2624
	}
2625
	public function setCryptAlgorithm($value)
2626
	{
2627
		$this->_cryptAlgorithm = $value;
2628
	}
2629
	public function encrypt($data)
2630
	{
2631
		$module=$this->openCryptModule();
2632
		$key = $this->substr(md5($this->getEncryptionKey()), 0, mcrypt_enc_get_key_size($module));
2633
		srand();
2634
		$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($module), MCRYPT_RAND);
2635
		mcrypt_generic_init($module, $key, $iv);
2636
		$encrypted = $iv.mcrypt_generic($module, $data);
2637
		mcrypt_generic_deinit($module);
2638
		mcrypt_module_close($module);
2639
		return $encrypted;
2640
	}
2641
	public function decrypt($data)
2642
	{
2643
		$module=$this->openCryptModule();
2644
		$key = $this->substr(md5($this->getEncryptionKey()), 0, mcrypt_enc_get_key_size($module));
2645
		$ivSize = mcrypt_enc_get_iv_size($module);
2646
		$iv = $this->substr($data, 0, $ivSize);
2647
		mcrypt_generic_init($module, $key, $iv);
2648
		$decrypted = mdecrypt_generic($module, $this->substr($data, $ivSize, $this->strlen($data)));
2649
		mcrypt_generic_deinit($module);
2650
		mcrypt_module_close($module);
2651
		return $decrypted;
2652
	}
2653
	protected function openCryptModule()
2654
	{
2655
		if(extension_loaded('mcrypt'))
2656
		{
2657
			if(is_array($this->_cryptAlgorithm))
2658
				$module=@call_user_func_array('mcrypt_module_open',$this->_cryptAlgorithm);
2659
			else
2660
				$module=@mcrypt_module_open($this->_cryptAlgorithm,'', MCRYPT_MODE_CBC,'');
2661
			if($module===false)
2662
				throw new TNotSupportedException('securitymanager_mcryptextension_initfailed');
2663
			return $module;
2664
		}
2665
		else
2666
			throw new TNotSupportedException('securitymanager_mcryptextension_required');
2667
	}
2668
	public function hashData($data)
2669
	{
2670
		$hmac = $this->computeHMAC($data);
2671
		return $hmac.$data;
2672
	}
2673
	public function validateData($data)
2674
	{
2675
		$len=$this->strlen($this->computeHMAC('test'));
2676
		if($this->strlen($data) < $len)
2677
			return false;
2678
		$hmac = $this->substr($data, 0, $len);
2679
		$data2=$this->substr($data, $len, $this->strlen($data));
2680
		return $hmac === $this->computeHMAC($data2) ? $data2 : false;
2681
	}
2682
	protected function computeHMAC($data)
2683
	{
2684
		$key = $this->getValidationKey();
2685
		if(function_exists('hash_hmac'))
2686
			return hash_hmac($this->_hashAlgorithm, $data, $key);
2687
		if(!strcasecmp($this->_hashAlgorithm,'sha1'))
2688
		{
2689
			$pack = 'H40';
2690
			$func = 'sha1';
2691
		} else {
2692
			$pack = 'H32';
2693
			$func = 'md5';
2694
		}
2695
		$key = str_pad($func($key), 64, chr(0));
2696
		return $func((str_repeat(chr(0x5C), 64) ^ substr($key, 0, 64)) . pack($pack, $func((str_repeat(chr(0x36), 64) ^ substr($key, 0, 64)) . $data)));
2697
	}
2698
	private function strlen($string)
2699
	{
2700
		return $this->_mbstring ? mb_strlen($string,'8bit') : strlen($string);
2701
	}
2702
	private function substr($string,$start,$length)
2703
	{
2704
		return $this->_mbstring ? mb_substr($string,$start,$length,'8bit') : substr($string,$start,$length);
2705
	}
2706
}
2707
class TSecurityManagerValidationMode extends TEnumerable
2708
{
2709
	const MD5 = 'MD5';
2710
	const SHA1 = 'SHA1';
2711
}
2712
class THttpUtility
2713
{
2714
	private static $_encodeTable=array('<'=>'&lt;','>'=>'&gt;','"'=>'&quot;');
2715
	private static $_decodeTable=array('&lt;'=>'<','&gt;'=>'>','&quot;'=>'"');
2716
	private static $_stripTable=array('&lt;'=>'','&gt;'=>'','&quot;'=>'');
2717
	public static function htmlEncode($s)
2718
	{
2719
		return strtr($s,self::$_encodeTable);
2720
	}
2721
	public static function htmlDecode($s)
2722
	{
2723
		return strtr($s,self::$_decodeTable);
2724
	}
2725
	public static function htmlStrip($s)
2726
	{
2727
		return strtr($s,self::$_stripTable);
2728
	}
2729
}
2730
class TJavaScript
2731
{
2732
	public static function renderScriptFiles($files)
2733
	{
2734
		$str='';
2735
		foreach($files as $file)
2736
			$str.= self::renderScriptFile($file);
2737
		return $str;
2738
	}
2739
	public static function renderScriptFile($file)
2740
	{
2741
		return '<script type="text/javascript" src="'.THttpUtility::htmlEncode($file)."\"></script>\n";
2742
	}
2743
	public static function renderScriptBlocks($scripts)
2744
	{
2745
		if(count($scripts))
2746
			return "<script type=\"text/javascript\">\n/*<![CDATA[*/\n".implode("\n",$scripts)."\n/*]]>*/\n</script>\n";
2747
		else
2748
			return '';
2749
	}
2750
	public static function renderScriptBlocksCallback($scripts)
2751
	{
2752
		if(count($scripts))
2753
			return implode("\n",$scripts)."\n";
2754
		else
2755
			return '';
2756
	}
2757
	public static function renderScriptBlock($script)
2758
	{
2759
		return "<script type=\"text/javascript\">\n/*<![CDATA[*/\n{$script}\n/*]]>*/\n</script>\n";
2760
	}
2761
	public static function quoteString($js)
2762
	{
2763
		return self::jsonEncode($js,JSON_HEX_QUOT | JSON_HEX_APOS | JSON_HEX_TAG);
2764
	}
2765
	public static function quoteJsLiteral($js)
2766
	{
2767
		if($js instanceof TJavaScriptLiteral)
2768
			return $js;
2769
		else
2770
			return new TJavaScriptLiteral($js);
2771
	}
2772
	public static function quoteFunction($js)
2773
	{
2774
		return self::quoteJsLiteral($js);
2775
	}
2776
	public static function isJsLiteral($js)
2777
	{
2778
		return ($js instanceof TJavaScriptLiteral);
2779
	}
2780
	public static function isFunction($js)
2781
	{
2782
		return self::isJsLiteral($js);
2783
	}
2784
	public static function encode($value,$toMap=true,$encodeEmptyStrings=false)
2785
	{
2786
		if(is_string($value))
2787
			return self::quoteString($value);
2788
		else if(is_bool($value))
2789
			return $value?'true':'false';
2790
		else if(is_array($value))
2791
		{
2792
			$results='';
2793
			if(($n=count($value))>0 && array_keys($value)!==range(0,$n-1))
2794
			{
2795
				foreach($value as $k=>$v)
2796
				{
2797
					if($v!=='' || $encodeEmptyStrings)
2798
					{
2799
						if($results!=='')
2800
							$results.=',';
2801
						$results.="'$k':".self::encode($v,$toMap,$encodeEmptyStrings);
2802
					}
2803
				}
2804
				return '{'.$results.'}';
2805
			}
2806
			else
2807
			{
2808
				foreach($value as $v)
2809
				{
2810
					if($v!=='' || $encodeEmptyStrings)
2811
					{
2812
						if($results!=='')
2813
							$results.=',';
2814
						$results.=self::encode($v,$toMap, $encodeEmptyStrings);
2815
					}
2816
				}
2817
				return '['.$results.']';
2818
			}
2819
		}
2820
		else if(is_integer($value))
2821
			return "$value";
2822
		else if(is_float($value))
2823
		{
2824
			switch($value)
2825
			{
2826
				case -INF:
2827
					return 'Number.NEGATIVE_INFINITY';
2828
					break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
2829
				case INF:
2830
					return 'Number.POSITIVE_INFINITY';
2831
					break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
2832
				default:
2833
					$locale=localeConv();
2834
					if($locale['decimal_point']=='.')
2835
						return "$value";
2836
					else
2837
						return str_replace($locale['decimal_point'], '.', "$value");
2838
					break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
2839
			}
2840
		}
2841
		else if(is_object($value))
2842
			if ($value instanceof TJavaScriptLiteral)
2843
				return $value->toJavaScriptLiteral();
2844
			else
2845
				return self::encode(get_object_vars($value),$toMap);
2846
		else if($value===null)
2847
			return 'null';
2848
		else
2849
			return '';
2850
	}
2851
	public static function jsonEncode($value, $options = 0)
2852
	{
2853
		if (($g=Prado::getApplication()->getGlobalization(false))!==null &&
2854
			strtoupper($enc=$g->getCharset())!='UTF-8') {
2855
			self::convertToUtf8($value, $enc);
2856
		}
2857
		$s = @json_encode($value,$options);
2858
		self::checkJsonError();
2859
		return $s;
2860
	}
2861
	private static function convertToUtf8(&$value, $sourceEncoding) {
2862
		if(is_string($value))
2863
			$value=iconv($sourceEncoding, 'UTF-8', $value);
2864
		else if (is_array($value))
2865
		{
2866
			foreach($value as &$element)
2867
				self::convertToUtf8($element, $sourceEncoding);
2868
		}
2869
	}
2870
	public static function jsonDecode($value, $assoc = false, $depth = 512)
2871
	{
2872
		$s= @json_decode($value, $assoc, $depth);
2873
		self::checkJsonError();
2874
		return $s;
2875
	}
2876
	private static function checkJsonError()
2877
	{
2878
		switch ($err = json_last_error())
2879
		{
2880
			case JSON_ERROR_NONE:
2881
				return;
2882
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
2883
			case JSON_ERROR_DEPTH:
2884
				$msg = 'Maximum stack depth exceeded';
2885
				break;
2886
			case JSON_ERROR_STATE_MISMATCH:
2887
				$msg = 'Underflow or the modes mismatch';
2888
				break;
2889
			case JSON_ERROR_CTRL_CHAR:
2890
				$msg = 'Unexpected control character found';
2891
				break;
2892
			case JSON_ERROR_SYNTAX:
2893
				$msg = 'Syntax error, malformed JSON';
2894
				break;
2895
			case JSON_ERROR_UTF8:
2896
				$msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
2897
				break;
2898
			default:
2899
				$msg = 'Unknown error';
2900
				break;
2901
		}
2902
		throw new Exception("JSON error ($err): $msg");
2903
	}
2904
	public static function JSMin($code)
2905
	{
2906
		Prado::using('System.Web.Javascripts.JSMin');
2907
		return JSMin::minify($code);
2908
	}
2909
}
2910
class TUrlManager extends TModule
2911
{
2912
	public function constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems)
2913
	{
2914
		$url=$serviceID.'='.urlencode($serviceParam);
2915
		$amp=$encodeAmpersand?'&amp;':'&';
2916
		$request=$this->getRequest();
2917
		if(is_array($getItems) || $getItems instanceof Traversable)
2918
		{
2919
			if($encodeGetItems)
2920
			{
2921
				foreach($getItems as $name=>$value)
2922
				{
2923
					if(is_array($value))
2924
					{
2925
						$name=urlencode($name.'[]');
2926
						foreach($value as $v)
2927
							$url.=$amp.$name.'='.urlencode($v);
2928
					}
2929
					else
2930
						$url.=$amp.urlencode($name).'='.urlencode($value);
2931
				}
2932
			}
2933
			else
2934
			{
2935
				foreach($getItems as $name=>$value)
2936
				{
2937
					if(is_array($value))
2938
					{
2939
						foreach($value as $v)
2940
							$url.=$amp.$name.'[]='.$v;
2941
					}
2942
					else
2943
						$url.=$amp.$name.'='.$value;
2944
				}
2945
			}
2946
		}
2947
		switch($request->getUrlFormat())
2948
		{
2949
			case THttpRequestUrlFormat::Path:
2950
				return $request->getApplicationUrl().'/'.strtr($url,array($amp=>'/','?'=>'/','='=>$request->getUrlParamSeparator()));
2951
			case THttpRequestUrlFormat::HiddenPath:
2952
				return rtrim(dirname($request->getApplicationUrl()), '/').'/'.strtr($url,array($amp=>'/','?'=>'/','='=>$request->getUrlParamSeparator()));
2953
			default:
2954
				return $request->getApplicationUrl().'?'.$url;
2955
		}
2956
	}
2957
	public function parseUrl()
2958
	{
2959
		$request=$this->getRequest();
2960
		$pathInfo=trim($request->getPathInfo(),'/');
2961
		if(($request->getUrlFormat()===THttpRequestUrlFormat::Path ||
2962
			$request->getUrlFormat()===THttpRequestUrlFormat::HiddenPath) &&
2963
			$pathInfo!=='')
2964
		{
2965
			$separator=$request->getUrlParamSeparator();
2966
			$paths=explode('/',$pathInfo);
2967
			$getVariables=array();
2968
			foreach($paths as $path)
2969
			{
2970
				if(($path=trim($path))!=='')
2971
				{
2972
					if(($pos=strpos($path,$separator))!==false)
2973
					{
2974
						$name=substr($path,0,$pos);
2975
						$value=substr($path,$pos+1);
2976
						if(($pos=strpos($name,'[]'))!==false)
2977
							$getVariables[substr($name,0,$pos)][]=$value;
2978
						else
2979
							$getVariables[$name]=$value;
2980
					}
2981
					else
2982
						$getVariables[$path]='';
2983
				}
2984
			}
2985
			return $getVariables;
2986
		}
2987
		else
2988
			return array();
2989
	}
2990
}
2991
class THttpRequest extends TApplicationComponent implements IteratorAggregate,ArrayAccess,Countable,IModule
0 ignored issues
show
Coding Style introduced by
Expected 1 space before "ArrayAccess"; 0 found
Loading history...
Coding Style introduced by
Expected 1 space before "Countable"; 0 found
Loading history...
Coding Style introduced by
Expected 1 space before "IModule"; 0 found
Loading history...
2992
{
2993
	const CGIFIX__PATH_INFO		= 1;
2994
	const CGIFIX__SCRIPT_NAME	= 2;
2995
	private $_urlManager=null;
2996
	private $_urlManagerID='';
2997
	private $_separator=',';
2998
	private $_serviceID=null;
2999
	private $_serviceParam=null;
3000
	private $_cookies=null;
3001
	private $_requestUri;
3002
	private $_pathInfo;
3003
	private $_cookieOnly=null;
3004
	private $_urlFormat=THttpRequestUrlFormat::Get;
3005
	private $_services;
0 ignored issues
show
Unused Code introduced by
The property $_services is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
3006
	private $_requestResolved=false;
3007
	private $_enableCookieValidation=false;
3008
	private $_cgiFix=0;
3009
	private $_enableCache=false;
3010
	private $_url=null;
3011
	private $_id;
3012
	private $_items=array();
3013
	public function getID()
3014
	{
3015
		return $this->_id;
3016
	}
3017
	public function setID($value)
3018
	{
3019
		$this->_id=$value;
3020
	}
3021
	public function init($config)
0 ignored issues
show
Coding Style introduced by
init uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
init uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
init uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
init uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
init uses the super-global variable $_COOKIE which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
3022
	{
3023
				if(php_sapi_name()==='cli')
3024
		{
3025
			$_SERVER['REMOTE_ADDR']='127.0.0.1';
3026
			$_SERVER['REQUEST_METHOD']='GET';
3027
			$_SERVER['SERVER_NAME']='localhost';
3028
			$_SERVER['SERVER_PORT']=80;
3029
			$_SERVER['HTTP_USER_AGENT']='';
3030
		}
3031
														if(isset($_SERVER['REQUEST_URI']))
3032
			$this->_requestUri=$_SERVER['REQUEST_URI'];
3033
		else  			$this->_requestUri=$_SERVER['SCRIPT_NAME'].(empty($_SERVER['QUERY_STRING'])?'':'?'.$_SERVER['QUERY_STRING']);
3034
		if($this->_cgiFix&self::CGIFIX__PATH_INFO && isset($_SERVER['ORIG_PATH_INFO']))
3035
			$this->_pathInfo=substr($_SERVER['ORIG_PATH_INFO'], strlen($_SERVER['SCRIPT_NAME']));
3036
		elseif(isset($_SERVER['PATH_INFO']))
3037
			$this->_pathInfo=$_SERVER['PATH_INFO'];
3038
		else if(strpos($_SERVER['PHP_SELF'],$_SERVER['SCRIPT_NAME'])===0 && $_SERVER['PHP_SELF']!==$_SERVER['SCRIPT_NAME'])
3039
			$this->_pathInfo=substr($_SERVER['PHP_SELF'],strlen($_SERVER['SCRIPT_NAME']));
3040
		else
3041
			$this->_pathInfo='';
3042
		if(get_magic_quotes_gpc())
3043
		{
3044
			if(isset($_GET))
3045
				$_GET=$this->stripSlashes($_GET);
3046
			if(isset($_POST))
3047
				$_POST=$this->stripSlashes($_POST);
3048
			if(isset($_REQUEST))
3049
				$_REQUEST=$this->stripSlashes($_REQUEST);
3050
			if(isset($_COOKIE))
3051
				$_COOKIE=$this->stripSlashes($_COOKIE);
3052
		}
3053
		$this->getApplication()->setRequest($this);
3054
	}
3055
	public function stripSlashes(&$data)
3056
	{
3057
		return is_array($data)?array_map(array($this,'stripSlashes'),$data):stripslashes($data);
3058
	}
3059
	public function getUrl()
0 ignored issues
show
Coding Style introduced by
getUrl uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
3060
	{
3061
		if($this->_url===null)
3062
		{
3063
			$secure=$this->getIsSecureConnection();
3064
			$url=$secure?'https://':'http://';
3065
			if(empty($_SERVER['HTTP_HOST']))
3066
			{
3067
				$url.=$_SERVER['SERVER_NAME'];
3068
				$port=$_SERVER['SERVER_PORT'];
3069
				if(($port!=80 && !$secure) || ($port!=443 && $secure))
3070
					$url.=':'.$port;
3071
			}
3072
			else
3073
				$url.=$_SERVER['HTTP_HOST'];
3074
			$url.=$this->getRequestUri();
3075
			$this->_url=new TUri($url);
3076
		}
3077
		return $this->_url;
3078
	}
3079
	public function setEnableCache($value)
3080
	{
3081
		$this->_enableCache = TPropertyValue::ensureBoolean($value);
3082
	}
3083
	public function getEnableCache()
3084
	{
3085
		return $this->_enableCache;
3086
	}
3087
	protected function getCacheKey()
3088
	{
3089
		return $this->getID();
3090
	}
3091
	protected function cacheUrlManager($manager)
3092
	{
3093
		if($this->getEnableCache())
3094
		{
3095
			$cache = $this->getApplication()->getCache();
3096
			if($cache !== null)
3097
			{
3098
				$dependencies = null;
3099
				if($this->getApplication()->getMode() !== TApplicationMode::Performance)
3100
					if ($manager instanceof TUrlMapping && $fn = $manager->getConfigFile())
3101
					{
3102
						$fn = Prado::getPathOfNamespace($fn,$this->getApplication()->getConfigurationFileExt());
3103
						$dependencies = new TFileCacheDependency($fn);
3104
					}
3105
				return $cache->set($this->getCacheKey(), $manager, 0, $dependencies);
3106
			}
3107
		}
3108
		return false;
3109
	}
3110
	protected function loadCachedUrlManager()
3111
	{
3112
		if($this->getEnableCache())
3113
		{
3114
			$cache = $this->getApplication()->getCache();
3115
			if($cache !== null)
3116
			{
3117
				$manager = $cache->get($this->getCacheKey());
3118
				if($manager instanceof TUrlManager)
3119
					return $manager;
3120
			}
3121
		}
3122
		return null;
3123
	}
3124
	public function getUrlManager()
3125
	{
3126
		return $this->_urlManagerID;
3127
	}
3128
	public function setUrlManager($value)
3129
	{
3130
		$this->_urlManagerID=$value;
3131
	}
3132
	public function getUrlManagerModule()
3133
	{
3134
		if($this->_urlManager===null)
3135
		{
3136
			if(($this->_urlManager = $this->loadCachedUrlManager())===null)
3137
			{
3138
				if(empty($this->_urlManagerID))
3139
				{
3140
					$this->_urlManager=new TUrlManager;
3141
					$this->_urlManager->init(null);
3142
				}
3143
				else
3144
				{
3145
					$this->_urlManager=$this->getApplication()->getModule($this->_urlManagerID);
3146
					if($this->_urlManager===null)
3147
						throw new TConfigurationException('httprequest_urlmanager_inexist',$this->_urlManagerID);
3148
					if(!($this->_urlManager instanceof TUrlManager))
3149
						throw new TConfigurationException('httprequest_urlmanager_invalid',$this->_urlManagerID);
3150
				}
3151
				$this->cacheUrlManager($this->_urlManager);
3152
			}
3153
		}
3154
		return $this->_urlManager;
3155
	}
3156
	public function getUrlFormat()
3157
	{
3158
		return $this->_urlFormat;
3159
	}
3160
	public function setUrlFormat($value)
3161
	{
3162
		$this->_urlFormat=TPropertyValue::ensureEnum($value,'THttpRequestUrlFormat');
3163
	}
3164
	public function getUrlParamSeparator()
3165
	{
3166
		return $this->_separator;
3167
	}
3168
	public function setUrlParamSeparator($value)
3169
	{
3170
		if(strlen($value)===1)
3171
			$this->_separator=$value;
3172
		else
3173
			throw new TInvalidDataValueException('httprequest_separator_invalid');
3174
	}
3175
	public function getRequestType()
0 ignored issues
show
Coding Style introduced by
getRequestType uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
3176
	{
3177
		return isset($_SERVER['REQUEST_METHOD'])?$_SERVER['REQUEST_METHOD']:null;
3178
	}
3179
	public function getContentType($mimetypeOnly = true)
0 ignored issues
show
Coding Style introduced by
getContentType uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
3180
	{
3181
		if(!isset($_SERVER['CONTENT_TYPE']))
3182
			return null;
3183
		if($mimetypeOnly === true && ($_pos = strpos(';', $_SERVER['CONTENT_TYPE'])) !== false)
3184
			return substr($_SERVER['CONTENT_TYPE'], 0, $_pos);
3185
		return $_SERVER['CONTENT_TYPE'];
3186
	}
3187
	public function getIsSecureConnection()
0 ignored issues
show
Coding Style introduced by
getIsSecureConnection uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
3188
	{
3189
			return isset($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'],'off');
3190
	}
3191
	public function getPathInfo()
3192
	{
3193
		return $this->_pathInfo;
3194
	}
3195
	public function getQueryString()
0 ignored issues
show
Coding Style introduced by
getQueryString uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
3196
	{
3197
		return isset($_SERVER['QUERY_STRING'])?$_SERVER['QUERY_STRING']:null;
3198
	}
3199
	public function getHttpProtocolVersion()
0 ignored issues
show
Coding Style introduced by
getHttpProtocolVersion uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
3200
	{
3201
		return isset($_SERVER['SERVER_PROTOCOL'])?$_SERVER['SERVER_PROTOCOL']:null;
3202
	}
3203
	public function getHeaders($case=null)
0 ignored issues
show
Coding Style introduced by
getHeaders uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
3204
	{
3205
		static $result;
3206
		if($result === null && function_exists('apache_request_headers')) {
3207
			$result = apache_request_headers();
3208
		}
3209
		elseif($result === null) {
3210
			$result = array();
3211
			foreach($_SERVER as $key=>$value) {
3212
				if(strncasecmp($key, 'HTTP_', 5) !== 0) continue;
3213
					$key = str_replace(' ','-', ucwords(strtolower(str_replace('_',' ', substr($key, 5)))));
3214
					$result[$key] = $value;
3215
			}
3216
		}
3217
		if($case !== null)
3218
			return array_change_key_case($result, $case);
3219
		return $result;
3220
	}
3221
	public function getRequestUri()
3222
	{
3223
		return $this->_requestUri;
3224
	}
3225
	public function getBaseUrl($forceSecureConnection=null)
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $forceSecureConnection exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
3226
	{
3227
		$url=$this->getUrl();
3228
		$scheme=($forceSecureConnection)?"https": (($forceSecureConnection === null)?$url->getScheme():'http');
3229
		$host=$url->getHost();
3230
		if (($port=$url->getPort())) $host.=':'.$port;
3231
		return $scheme.'://'.$host;
3232
	}
3233
	public function getApplicationUrl()
0 ignored issues
show
Coding Style introduced by
getApplicationUrl uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
3234
	{
3235
		if($this->_cgiFix&self::CGIFIX__SCRIPT_NAME && isset($_SERVER['ORIG_SCRIPT_NAME']))
3236
			return $_SERVER['ORIG_SCRIPT_NAME'];
3237
		return isset($_SERVER['SCRIPT_NAME'])?$_SERVER['SCRIPT_NAME']:null;
3238
	}
3239
	public function getAbsoluteApplicationUrl($forceSecureConnection=null)
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $forceSecureConnection exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
3240
	{
3241
		return $this->getBaseUrl($forceSecureConnection) . $this->getApplicationUrl();
3242
	}
3243
	public function getApplicationFilePath()
0 ignored issues
show
Coding Style introduced by
getApplicationFilePath uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
3244
	{
3245
		return realpath(isset($_SERVER['SCRIPT_FILENAME'])?$_SERVER['SCRIPT_FILENAME']:null);
3246
	}
3247
	public function getServerName()
0 ignored issues
show
Coding Style introduced by
getServerName uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
3248
	{
3249
		return isset($_SERVER['SERVER_NAME'])?$_SERVER['SERVER_NAME']:null;
3250
	}
3251
	public function getServerPort()
0 ignored issues
show
Coding Style introduced by
getServerPort uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
3252
	{
3253
		return isset($_SERVER['SERVER_PORT'])?$_SERVER['SERVER_PORT']:null;
3254
	}
3255
	public function getUrlReferrer()
0 ignored issues
show
Coding Style introduced by
getUrlReferrer uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
3256
	{
3257
		return isset($_SERVER['HTTP_REFERER'])?$_SERVER['HTTP_REFERER']:null;
3258
	}
3259
	public function getBrowser()
3260
	{
3261
		try
3262
		{
3263
			return get_browser();
3264
		}
3265
		catch(TPhpErrorException $e)
3266
		{
3267
			throw new TConfigurationException('httprequest_browscap_required');
3268
		}
3269
	}
3270
	public function getUserAgent()
0 ignored issues
show
Coding Style introduced by
getUserAgent uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
3271
	{
3272
		return isset($_SERVER['HTTP_USER_AGENT'])?$_SERVER['HTTP_USER_AGENT']:null;
3273
	}
3274
	public function getUserHostAddress()
0 ignored issues
show
Coding Style introduced by
getUserHostAddress uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
3275
	{
3276
		return isset($_SERVER['REMOTE_ADDR'])?$_SERVER['REMOTE_ADDR']:null;
3277
	}
3278
	public function getUserHost()
0 ignored issues
show
Coding Style introduced by
getUserHost uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
3279
	{
3280
		return isset($_SERVER['REMOTE_HOST'])?$_SERVER['REMOTE_HOST']:null;
3281
	}
3282
	public function getAcceptTypes()
0 ignored issues
show
Coding Style introduced by
getAcceptTypes uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
3283
	{
3284
				return isset($_SERVER['HTTP_ACCEPT'])?$_SERVER['HTTP_ACCEPT']:null;
3285
	}
3286
	public function getUserLanguages()
3287
	{
3288
		return Prado::getUserLanguages();
3289
	}
3290
	public function getEnableCookieValidation()
3291
	{
3292
		return $this->_enableCookieValidation;
3293
	}
3294
	public function setEnableCookieValidation($value)
3295
	{
3296
		$this->_enableCookieValidation=TPropertyValue::ensureBoolean($value);
3297
	}
3298
	public function getCgiFix()
3299
	{
3300
		return $this->_cgiFix;
3301
	}
3302
	public function setCgiFix($value)
3303
	{
3304
		$this->_cgiFix=TPropertyValue::ensureInteger($value);
3305
	}
3306
	public function getCookies()
0 ignored issues
show
Coding Style introduced by
getCookies uses the super-global variable $_COOKIE which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
3307
	{
3308
		if($this->_cookies===null)
3309
		{
3310
			$this->_cookies=new THttpCookieCollection;
3311
			if($this->getEnableCookieValidation())
3312
			{
3313
				$sm=$this->getApplication()->getSecurityManager();
3314
				foreach($_COOKIE as $key=>$value)
3315
				{
3316
					if(($value=$sm->validateData($value))!==false)
3317
						$this->_cookies->add(new THttpCookie($key,$value));
3318
				}
3319
			}
3320
			else
3321
			{
3322
				foreach($_COOKIE as $key=>$value)
3323
					$this->_cookies->add(new THttpCookie($key,$value));
3324
			}
3325
		}
3326
		return $this->_cookies;
3327
	}
3328
	public function getUploadedFiles()
0 ignored issues
show
Coding Style introduced by
getUploadedFiles uses the super-global variable $_FILES which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
3329
	{
3330
		return $_FILES;
3331
	}
3332
	public function getServerVariables()
0 ignored issues
show
Coding Style introduced by
getServerVariables uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
3333
	{
3334
		return $_SERVER;
3335
	}
3336
	public function getEnvironmentVariables()
0 ignored issues
show
Coding Style introduced by
getEnvironmentVariables uses the super-global variable $_ENV which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
3337
	{
3338
		return $_ENV;
3339
	}
3340
	public function constructUrl($serviceID,$serviceParam,$getItems=null,$encodeAmpersand=true,$encodeGetItems=true)
3341
	{
3342
		if ($this->_cookieOnly===null)
3343
				$this->_cookieOnly=(int)ini_get('session.use_cookies') && (int)ini_get('session.use_only_cookies');
3344
		$url=$this->getUrlManagerModule()->constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems);
3345
		if(defined('SID') && SID != '' && !$this->_cookieOnly)
3346
			return $url . (strpos($url,'?')===false? '?' : ($encodeAmpersand?'&amp;':'&')) . SID;
3347
		else
3348
			return $url;
3349
	}
3350
	protected function parseUrl()
3351
	{
3352
		return $this->getUrlManagerModule()->parseUrl();
3353
	}
3354
	public function resolveRequest($serviceIDs)
0 ignored issues
show
Coding Style introduced by
resolveRequest uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
resolveRequest uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
3355
	{
3356
		$getParams=$this->parseUrl();
3357
		foreach($getParams as $name=>$value)
3358
			$_GET[$name]=$value;
3359
		$this->_items=array_merge($_GET,$_POST);
3360
		$this->_requestResolved=true;
3361
		foreach($serviceIDs as $serviceID)
3362
		{
3363
			if($this->contains($serviceID))
3364
			{
3365
				$this->setServiceID($serviceID);
3366
				$this->setServiceParameter($this->itemAt($serviceID));
3367
				return $serviceID;
3368
			}
3369
		}
3370
		return null;
3371
	}
3372
	public function getRequestResolved()
3373
	{
3374
		return $this->_requestResolved;
3375
	}
3376
	public function getServiceID()
3377
	{
3378
		return $this->_serviceID;
3379
	}
3380
	public function setServiceID($value)
3381
	{
3382
		$this->_serviceID=$value;
3383
	}
3384
	public function getServiceParameter()
3385
	{
3386
		return $this->_serviceParam;
3387
	}
3388
	public function setServiceParameter($value)
3389
	{
3390
		$this->_serviceParam=$value;
3391
	}
3392
	public function getIterator()
3393
	{
3394
		return new ArrayIterator($this->_items);
3395
	}
3396
	public function getCount()
3397
	{
3398
		return count($this->_items);
3399
	}
3400
	public function count()
3401
	{
3402
		return $this->getCount();
3403
	}
3404
	public function getKeys()
3405
	{
3406
		return array_keys($this->_items);
3407
	}
3408
	public function itemAt($key)
3409
	{
3410
		return isset($this->_items[$key]) ? $this->_items[$key] : null;
3411
	}
3412
	public function add($key,$value)
3413
	{
3414
		$this->_items[$key]=$value;
3415
	}
3416
	public function remove($key)
3417
	{
3418
		if(isset($this->_items[$key]) || array_key_exists($key,$this->_items))
3419
		{
3420
			$value=$this->_items[$key];
3421
			unset($this->_items[$key]);
3422
			return $value;
3423
		}
3424
		else
3425
			return null;
3426
	}
3427
	public function clear()
3428
	{
3429
		foreach(array_keys($this->_items) as $key)
3430
			$this->remove($key);
3431
	}
3432
	public function contains($key)
3433
	{
3434
		return isset($this->_items[$key]) || array_key_exists($key,$this->_items);
3435
	}
3436
	public function toArray()
3437
	{
3438
		return $this->_items;
3439
	}
3440
	public function offsetExists($offset)
3441
	{
3442
		return $this->contains($offset);
3443
	}
3444
	public function offsetGet($offset)
3445
	{
3446
		return $this->itemAt($offset);
3447
	}
3448
	public function offsetSet($offset,$item)
3449
	{
3450
		$this->add($offset,$item);
3451
	}
3452
	public function offsetUnset($offset)
3453
	{
3454
		$this->remove($offset);
3455
	}
3456
}
3457
class THttpCookieCollection extends TList
3458
{
3459
	private $_o;
3460
	public function __construct($owner=null)
3461
	{
3462
		$this->_o=$owner;
3463
	}
3464
	public function insertAt($index,$item)
3465
	{
3466
		if($item instanceof THttpCookie)
3467
		{
3468
			parent::insertAt($index,$item);
3469
			if($this->_o instanceof THttpResponse)
3470
				$this->_o->addCookie($item);
3471
		}
3472
		else
3473
			throw new TInvalidDataTypeException('httpcookiecollection_httpcookie_required');
3474
	}
3475
	public function removeAt($index)
3476
	{
3477
		$item=parent::removeAt($index);
3478
		if($this->_o instanceof THttpResponse)
3479
			$this->_o->removeCookie($item);
3480
		return $item;
3481
	}
3482
	public function itemAt($index)
3483
	{
3484
		if(is_integer($index))
3485
			return parent::itemAt($index);
3486
		else
3487
			return $this->findCookieByName($index);
3488
	}
3489
	public function findCookieByName($name)
3490
	{
3491
		foreach($this as $cookie)
3492
			if($cookie->getName()===$name)
3493
				return $cookie;
3494
		return null;
3495
	}
3496
}
3497
class THttpCookie extends TComponent
3498
{
3499
	private $_domain='';
3500
	private $_name;
3501
	private $_value='';
3502
	private $_expire=0;
3503
	private $_path='/';
3504
	private $_secure=false;
3505
	private $_httpOnly=false;
3506
	public function __construct($name,$value)
3507
	{
3508
		$this->_name=$name;
3509
		$this->_value=$value;
3510
	}
3511
	public function getDomain()
3512
	{
3513
		return $this->_domain;
3514
	}
3515
	public function setDomain($value)
3516
	{
3517
		$this->_domain=$value;
3518
	}
3519
	public function getExpire()
3520
	{
3521
		return $this->_expire;
3522
	}
3523
	public function setExpire($value)
3524
	{
3525
		$this->_expire=TPropertyValue::ensureInteger($value);
3526
	}
3527
	public function getHttpOnly()
3528
	{
3529
		return $this->_httpOnly;
3530
	}
3531
	public function setHttpOnly($value)
3532
	{
3533
		$this->_httpOnly = TPropertyValue::ensureBoolean($value);
3534
	}
3535
	public function getName()
3536
	{
3537
		return $this->_name;
3538
	}
3539
	public function setName($value)
3540
	{
3541
		$this->_name=$value;
3542
	}
3543
	public function getValue()
3544
	{
3545
		return $this->_value;
3546
	}
3547
	public function setValue($value)
3548
	{
3549
		$this->_value=$value;
3550
	}
3551
	public function getPath()
3552
	{
3553
		return $this->_path;
3554
	}
3555
	public function setPath($value)
3556
	{
3557
		$this->_path=$value;
3558
	}
3559
	public function getSecure()
3560
	{
3561
		return $this->_secure;
3562
	}
3563
	public function setSecure($value)
3564
	{
3565
		$this->_secure=TPropertyValue::ensureBoolean($value);
3566
	}
3567
}
3568
class TUri extends TComponent
3569
{
3570
	private static $_defaultPort=array(
0 ignored issues
show
Unused Code introduced by
The property $_defaultPort is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
3571
		'ftp'=>21,
3572
		'gopher'=>70,
3573
		'http'=>80,
3574
		'https'=>443,
3575
		'news'=>119,
3576
		'nntp'=>119,
3577
		'wais'=>210,
3578
		'telnet'=>23
3579
	);
3580
	private $_scheme;
3581
	private $_host;
3582
	private $_port;
3583
	private $_user;
3584
	private $_pass;
3585
	private $_path;
3586
	private $_query;
3587
	private $_fragment;
3588
	private $_uri;
3589
	public function __construct($uri)
3590
	{
3591
		if(($ret=@parse_url($uri))!==false)
3592
		{
3593
						$this->_scheme=isset($ret['scheme'])?$ret['scheme']:'';
3594
			$this->_host=isset($ret['host'])?$ret['host']:'';
3595
			$this->_port=isset($ret['port'])?$ret['port']:'';
3596
			$this->_user=isset($ret['user'])?$ret['user']:'';
3597
			$this->_pass=isset($ret['pass'])?$ret['pass']:'';
3598
			$this->_path=isset($ret['path'])?$ret['path']:'';
3599
			$this->_query=isset($ret['query'])?$ret['query']:'';
3600
			$this->_fragment=isset($ret['fragment'])?$ret['fragment']:'';
3601
			$this->_uri=$uri;
3602
		}
3603
		else
3604
		{
3605
			throw new TInvalidDataValueException('uri_format_invalid',$uri);
3606
		}
3607
	}
3608
	public function getUri()
3609
	{
3610
		return $this->_uri;
3611
	}
3612
	public function getScheme()
3613
	{
3614
		return $this->_scheme;
3615
	}
3616
	public function getHost()
3617
	{
3618
		return $this->_host;
3619
	}
3620
	public function getPort()
3621
	{
3622
		return $this->_port;
3623
	}
3624
	public function getUser()
3625
	{
3626
		return $this->_user;
3627
	}
3628
	public function getPassword()
3629
	{
3630
		return $this->_pass;
3631
	}
3632
	public function getPath()
3633
	{
3634
		return $this->_path;
3635
	}
3636
	public function getQuery()
3637
	{
3638
		return $this->_query;
3639
	}
3640
	public function getFragment()
3641
	{
3642
		return $this->_fragment;
3643
	}
3644
}
3645
class THttpRequestUrlFormat extends TEnumerable
3646
{
3647
	const Get='Get';
3648
	const Path='Path';
3649
	const HiddenPath='HiddenPath';
3650
}
3651
class THttpResponseAdapter extends TApplicationComponent
3652
{
3653
	private $_response;
3654
	public function __construct($response)
3655
	{
3656
		$this->_response=$response;
3657
	}
3658
	public function getResponse()
3659
	{
3660
		return $this->_response;
3661
	}
3662
	public function flushContent()
3663
	{
3664
		$this->_response->flushContent();
3665
	}
3666
	public function httpRedirect($url)
3667
	{
3668
		$this->_response->httpRedirect($url);
3669
	}
3670
	public function createNewHtmlWriter($type, $writer)
3671
	{
3672
		return $this->_response->createNewHtmlWriter($type,$writer);
3673
	}
3674
}
3675
class THttpResponse extends TModule implements ITextWriter
3676
{
3677
	const DEFAULT_CONTENTTYPE	= 'text/html';
3678
	const DEFAULT_CHARSET		= 'UTF-8';
3679
	private static $HTTP_STATUS_CODES = array(
3680
		100 => 'Continue', 101 => 'Switching Protocols',
3681
		200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content',
3682
		300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect',
3683
		400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Time-out', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Large', 415 => 'Unsupported Media Type', 416 => 'Requested range not satisfiable', 417 => 'Expectation Failed',
3684
		500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported'
3685
	);
3686
	private $_bufferOutput=true;
3687
	private $_initialized=false;
3688
	private $_cookies=null;
3689
	private $_status=200;
3690
	private $_reason='OK';
3691
	private $_htmlWriterType='System.Web.UI.THtmlWriter';
3692
	private $_contentType=null;
3693
	private $_charset='';
3694
	private $_adapter;
3695
	private $_httpHeaderSent;
3696
	private $_contentTypeHeaderSent;
3697
	public function __destruct()
3698
	{
3699
					}
3700
	public function setAdapter(THttpResponseAdapter $adapter)
3701
	{
3702
		$this->_adapter=$adapter;
3703
	}
3704
	public function getAdapter()
3705
	{
3706
		return $this->_adapter;
3707
	}
3708
	public function getHasAdapter()
3709
	{
3710
		return $this->_adapter!==null;
3711
	}
3712
	public function init($config)
3713
	{
3714
		if($this->_bufferOutput)
3715
			ob_start();
3716
		$this->_initialized=true;
3717
		$this->getApplication()->setResponse($this);
3718
	}
3719
	public function getCacheExpire()
3720
	{
3721
		return session_cache_expire();
3722
	}
3723
	public function setCacheExpire($value)
3724
	{
3725
		session_cache_expire(TPropertyValue::ensureInteger($value));
3726
	}
3727
	public function getCacheControl()
3728
	{
3729
		return session_cache_limiter();
3730
	}
3731
	public function setCacheControl($value)
3732
	{
3733
		session_cache_limiter(TPropertyValue::ensureEnum($value,array('none','nocache','private','private_no_expire','public')));
3734
	}
3735
	public function setContentType($type)
3736
	{
3737
		if ($this->_contentTypeHeaderSent)
3738
			throw new Exception('Unable to alter content-type as it has been already sent');
3739
		$this->_contentType = $type;
3740
	}
3741
	public function getContentType()
3742
	{
3743
		return $this->_contentType;
3744
	}
3745
	public function getCharset()
3746
	{
3747
		return $this->_charset;
3748
	}
3749
	public function setCharset($charset)
3750
	{
3751
		$this->_charset = (strToLower($charset) === 'false') ? false : (string)$charset;
3752
	}
3753
	public function getBufferOutput()
3754
	{
3755
		return $this->_bufferOutput;
3756
	}
3757
	public function setBufferOutput($value)
3758
	{
3759
		if($this->_initialized)
3760
			throw new TInvalidOperationException('httpresponse_bufferoutput_unchangeable');
3761
		else
3762
			$this->_bufferOutput=TPropertyValue::ensureBoolean($value);
3763
	}
3764
	public function getStatusCode()
3765
	{
3766
		return $this->_status;
3767
	}
3768
	public function setStatusCode($status, $reason=null)
3769
	{
3770
		if ($this->_httpHeaderSent)
3771
			throw new Exception('Unable to alter response as HTTP header already sent');
3772
		$status=TPropertyValue::ensureInteger($status);
3773
		if(isset(self::$HTTP_STATUS_CODES[$status])) {
3774
			$this->_reason=self::$HTTP_STATUS_CODES[$status];
3775
		}else{
3776
			if($reason===null || $reason==='') {
3777
				throw new TInvalidDataValueException("response_status_reason_missing");
3778
			}
3779
			$reason=TPropertyValue::ensureString($reason);
3780
			if(strpos($reason, "\r")!=false || strpos($reason, "\n")!=false) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing strpos($reason, ' ') of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
Bug Best Practice introduced by
It seems like you are loosely comparing strpos($reason, ' ') of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
3781
				throw new TInvalidDataValueException("response_status_reason_barchars");
3782
			}
3783
			$this->_reason=$reason;
3784
		}
3785
		$this->_status=$status;
3786
	}
3787
	public function getStatusReason() {
3788
		return $this->_reason;
3789
	}
3790
	public function getCookies()
3791
	{
3792
		if($this->_cookies===null)
3793
			$this->_cookies=new THttpCookieCollection($this);
3794
		return $this->_cookies;
3795
	}
3796
	public function write($str)
3797
	{
3798
				if (!$this->_bufferOutput and !$this->_httpHeaderSent)
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
3799
			$this->ensureHeadersSent();
3800
		echo $str;
3801
	}
3802
	public function writeFile($fileName,$content=null,$mimeType=null,$headers=null,$forceDownload=true,$clientFileName=null,$fileSize=null)
3803
	{
3804
		static $defaultMimeTypes=array(
3805
			'css'=>'text/css',
3806
			'gif'=>'image/gif',
3807
			'png'=>'image/png',
3808
			'jpg'=>'image/jpeg',
3809
			'jpeg'=>'image/jpeg',
3810
			'htm'=>'text/html',
3811
			'html'=>'text/html',
3812
			'js'=>'javascript/js',
3813
			'pdf'=>'application/pdf',
3814
			'xls'=>'application/vnd.ms-excel',
3815
		);
3816
		if($mimeType===null)
3817
		{
3818
			$mimeType='text/plain';
3819
			if(function_exists('mime_content_type'))
3820
				$mimeType=mime_content_type($fileName);
3821
			else if(($ext=strrchr($fileName,'.'))!==false)
3822
			{
3823
				$ext=substr($ext,1);
3824
				if(isset($defaultMimeTypes[$ext]))
3825
					$mimeType=$defaultMimeTypes[$ext];
3826
			}
3827
		}
3828
		if($clientFileName===null)
3829
			$clientFileName=basename($fileName);
3830
		else
3831
			$clientFileName=basename($clientFileName);
3832
		if($fileSize===null || $fileSize < 0)
3833
			$fileSize = ($content===null?filesize($fileName):strlen($content));
3834
		$this->sendHttpHeader();
3835
		if(is_array($headers))
3836
		{
3837
			foreach($headers as $h)
3838
				header($h);
3839
		}
3840
		else
3841
		{
3842
			header('Pragma: public');
3843
			header('Expires: 0');
3844
			header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
3845
			header("Content-Type: $mimeType");
3846
			$this->_contentTypeHeaderSent = true;
3847
		}
3848
		header('Content-Length: '.$fileSize);
3849
		header("Content-Disposition: " . ($forceDownload ? 'attachment' : 'inline') . "; filename=\"$clientFileName\"");
3850
		header('Content-Transfer-Encoding: binary');
3851
		if($content===null)
3852
			readfile($fileName);
3853
		else
3854
			echo $content;
3855
	}
3856
	public function redirect($url)
3857
	{
3858
		if($this->getHasAdapter())
3859
			$this->_adapter->httpRedirect($url);
3860
		else
3861
			$this->httpRedirect($url);
3862
	}
3863
	public function httpRedirect($url)
3864
	{
3865
		$this->ensureHeadersSent();
3866
		if($url[0]==='/')
3867
			$url=$this->getRequest()->getBaseUrl().$url;
3868
		if ($this->_status >= 300 && $this->_status < 400)
3869
						header('Location: '.str_replace('&amp;','&',$url), true, $this->_status);
3870
		else
3871
			header('Location: '.str_replace('&amp;','&',$url));
3872
		if(!$this->getApplication()->getRequestCompleted())
3873
			$this->getApplication()->onEndRequest();
3874
		exit();
0 ignored issues
show
Coding Style Compatibility introduced by
The method httpRedirect() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
3875
	}
3876
	public function reload()
3877
	{
3878
		$this->redirect($this->getRequest()->getRequestUri());
3879
	}
3880
	public function flush($continueBuffering = true)
3881
	{
3882
		if($this->getHasAdapter())
3883
			$this->_adapter->flushContent($continueBuffering);
3884
		else
3885
			$this->flushContent($continueBuffering);
3886
	}
3887
	public function ensureHeadersSent()
3888
	{
3889
		$this->ensureHttpHeaderSent();
3890
		$this->ensureContentTypeHeaderSent();
3891
	}
3892
	public function flushContent($continueBuffering = true)
3893
	{
3894
		$this->ensureHeadersSent();
3895
		if($this->_bufferOutput)
3896
		{
3897
						if (ob_get_length()>0)
3898
			{
3899
				if (!$continueBuffering)
3900
				{
3901
					$this->_bufferOutput = false;
3902
					ob_end_flush();
3903
				}
3904
				else
3905
					ob_flush();
3906
				flush();
3907
			}
3908
		}
3909
		else
3910
			flush();
3911
	}
3912
	protected function ensureHttpHeaderSent()
3913
	{
3914
		if (!$this->_httpHeaderSent)
3915
			$this->sendHttpHeader();
3916
	}
3917
	protected function sendHttpHeader()
3918
	{
3919
		$protocol=$this->getRequest()->getHttpProtocolVersion();
3920
		if($this->getRequest()->getHttpProtocolVersion() === null)
3921
			$protocol='HTTP/1.1';
3922
		$phpSapiName = substr(php_sapi_name(), 0, 3);
3923
		$cgi = $phpSapiName == 'cgi' || $phpSapiName == 'fpm';
3924
		header(($cgi ? 'Status:' : $protocol).' '.$this->_status.' '.$this->_reason, true, TPropertyValue::ensureInteger($this->_status));
3925
		$this->_httpHeaderSent = true;
3926
	}
3927
	protected function ensureContentTypeHeaderSent()
3928
	{
3929
		if (!$this->_contentTypeHeaderSent)
3930
			$this->sendContentTypeHeader();
3931
	}
3932
	protected function sendContentTypeHeader()
3933
	{
3934
		$contentType=$this->_contentType===null?self::DEFAULT_CONTENTTYPE:$this->_contentType;
3935
		$charset=$this->getCharset();
3936
		if($charset === false) {
3937
			$this->appendHeader('Content-Type: '.$contentType);
3938
			return;
3939
		}
3940
		if($charset==='' && ($globalization=$this->getApplication()->getGlobalization(false))!==null)
3941
			$charset=$globalization->getCharset();
3942
		if($charset==='') $charset = self::DEFAULT_CHARSET;
3943
		$this->appendHeader('Content-Type: '.$contentType.';charset='.$charset);
3944
		$this->_contentTypeHeaderSent = true;
3945
	}
3946
	public function getContents()
3947
	{
3948
		return $this->_bufferOutput?ob_get_contents():'';
3949
	}
3950
	public function clear()
3951
	{
3952
		if($this->_bufferOutput)
3953
			ob_clean();
3954
	}
3955
	public function getHeaders($case=null)
3956
	{
3957
		$result = array();
3958
		$headers = headers_list();
3959
		foreach($headers as $header) {
3960
			$tmp = explode(':', $header);
3961
			$key = trim(array_shift($tmp));
3962
			$value = trim(implode(':', $tmp));
3963
			if(isset($result[$key]))
3964
				$result[$key] .= ', ' . $value;
3965
			else
3966
				$result[$key] = $value;
3967
		}
3968
		if($case !== null)
3969
			return array_change_key_case($result, $case);
3970
		return $result;
3971
	}
3972
	public function appendHeader($value, $replace=true)
3973
	{
3974
		header($value, $replace);
3975
	}
3976
	public function appendLog($message,$messageType=0,$destination='',$extraHeaders='')
3977
	{
3978
		error_log($message,$messageType,$destination,$extraHeaders);
3979
	}
3980
	public function addCookie($cookie)
3981
	{
3982
		$request=$this->getRequest();
3983
		if($request->getEnableCookieValidation())
3984
		{
3985
			$value=$this->getApplication()->getSecurityManager()->hashData($cookie->getValue());
3986
			setcookie(
3987
				$cookie->getName(),
3988
				$value,
3989
				$cookie->getExpire(),
3990
				$cookie->getPath(),
3991
				$cookie->getDomain(),
3992
				$cookie->getSecure(),
3993
				$cookie->getHttpOnly()
3994
			);
3995
		}
3996
		else {
3997
			setcookie(
3998
				$cookie->getName(),
3999
				$cookie->getValue(),
4000
				$cookie->getExpire(),
4001
				$cookie->getPath(),
4002
				$cookie->getDomain(),
4003
				$cookie->getSecure(),
4004
				$cookie->getHttpOnly()
4005
			);
4006
		}
4007
	}
4008
	public function removeCookie($cookie)
4009
	{
4010
		setcookie(
4011
			$cookie->getName(),
4012
			null,
4013
			0,
4014
			$cookie->getPath(),
4015
			$cookie->getDomain(),
4016
			$cookie->getSecure(),
4017
			$cookie->getHttpOnly()
4018
		);
4019
	}
4020
	public function getHtmlWriterType()
4021
	{
4022
		return $this->_htmlWriterType;
4023
	}
4024
	public function setHtmlWriterType($value)
4025
	{
4026
		$this->_htmlWriterType=$value;
4027
	}
4028
	public function createHtmlWriter($type=null)
4029
	{
4030
		if($type===null)
4031
			$type=$this->getHtmlWriterType();
4032
		if($this->getHasAdapter())
4033
			return $this->_adapter->createNewHtmlWriter($type, $this);
4034
		else
4035
			return $this->createNewHtmlWriter($type, $this);
4036
	}
4037
	public function createNewHtmlWriter($type, $writer)
4038
	{
4039
		return Prado::createComponent($type, $writer);
4040
	}
4041
}
4042
class THttpSession extends TApplicationComponent implements IteratorAggregate,ArrayAccess,Countable,IModule
0 ignored issues
show
Coding Style introduced by
Expected 1 space before "ArrayAccess"; 0 found
Loading history...
Coding Style introduced by
Expected 1 space before "Countable"; 0 found
Loading history...
Coding Style introduced by
Expected 1 space before "IModule"; 0 found
Loading history...
4043
{
4044
	private $_initialized=false;
4045
	private $_started=false;
4046
	private $_autoStart=false;
4047
	private $_cookie=null;
4048
	private $_id;
4049
	private $_customStorage=false;
4050
	public function getID()
4051
	{
4052
		return $this->_id;
4053
	}
4054
	public function setID($value)
4055
	{
4056
		$this->_id=$value;
4057
	}
4058
	public function init($config)
4059
	{
4060
		if($this->_autoStart)
4061
			$this->open();
4062
		$this->_initialized=true;
4063
		$this->getApplication()->setSession($this);
4064
		register_shutdown_function(array($this, "close"));
4065
	}
4066
	public function open()
4067
	{
4068
		if(!$this->_started)
4069
		{
4070
			if($this->_customStorage)
4071
				session_set_save_handler(array($this,'_open'),array($this,'_close'),array($this,'_read'),array($this,'_write'),array($this,'_destroy'),array($this,'_gc'));
4072
			if($this->_cookie!==null)
4073
				session_set_cookie_params($this->_cookie->getExpire(),$this->_cookie->getPath(),$this->_cookie->getDomain(),$this->_cookie->getSecure(),$this->_cookie->getHttpOnly());
4074
			if(ini_get('session.auto_start')!=='1')
4075
				session_start();
4076
			$this->_started=true;
4077
		}
4078
	}
4079
	public function close()
4080
	{
4081
		if($this->_started)
4082
		{
4083
			session_write_close();
4084
			$this->_started=false;
4085
		}
4086
	}
4087
	public function destroy()
4088
	{
4089
		if($this->_started)
4090
		{
4091
			session_destroy();
4092
			$this->_started=false;
4093
		}
4094
	}
4095
	public function regenerate($deleteOld=false)
4096
	{
4097
		$old = $this->getSessionID();
4098
		session_regenerate_id($deleteOld);
4099
		return $old;
4100
	}
4101
	public function getIsStarted()
4102
	{
4103
		return $this->_started;
4104
	}
4105
	public function getSessionID()
4106
	{
4107
		return session_id();
4108
	}
4109
	public function setSessionID($value)
4110
	{
4111
		if($this->_started)
4112
			throw new TInvalidOperationException('httpsession_sessionid_unchangeable');
4113
		else
4114
			session_id($value);
4115
	}
4116
	public function getSessionName()
4117
	{
4118
		return session_name();
4119
	}
4120
	public function setSessionName($value)
4121
	{
4122
		if($this->_started)
4123
			throw new TInvalidOperationException('httpsession_sessionname_unchangeable');
4124
		else if(ctype_alnum($value))
4125
			session_name($value);
4126
		else
4127
			throw new TInvalidDataValueException('httpsession_sessionname_invalid',$value);
4128
	}
4129
	public function getSavePath()
4130
	{
4131
		return session_save_path();
4132
	}
4133
	public function setSavePath($value)
4134
	{
4135
		if($this->_started)
4136
			throw new TInvalidOperationException('httpsession_savepath_unchangeable');
4137
		else if(is_dir($value))
4138
			session_save_path($value);
4139
		else
4140
			throw new TInvalidDataValueException('httpsession_savepath_invalid',$value);
4141
	}
4142
	public function getUseCustomStorage()
4143
	{
4144
		return $this->_customStorage;
4145
	}
4146
	public function setUseCustomStorage($value)
4147
	{
4148
		$this->_customStorage=TPropertyValue::ensureBoolean($value);
4149
	}
4150
	public function getCookie()
4151
	{
4152
		if($this->_cookie===null)
4153
			$this->_cookie=new THttpCookie($this->getSessionName(),$this->getSessionID());
4154
		return $this->_cookie;
4155
	}
4156
	public function getCookieMode()
4157
	{
4158
		if(ini_get('session.use_cookies')==='0')
4159
			return THttpSessionCookieMode::None;
4160
		else if(ini_get('session.use_only_cookies')==='0')
4161
			return THttpSessionCookieMode::Allow;
4162
		else
4163
			return THttpSessionCookieMode::Only;
4164
	}
4165
	public function setCookieMode($value)
4166
	{
4167
		if($this->_started)
4168
			throw new TInvalidOperationException('httpsession_cookiemode_unchangeable');
4169
		else
4170
		{
4171
			$value=TPropertyValue::ensureEnum($value,'THttpSessionCookieMode');
4172
			if($value===THttpSessionCookieMode::None) 
4173
      {
4174
				ini_set('session.use_cookies','0');
4175
			  ini_set('session.use_only_cookies','0');
4176
      }
4177
			else if($value===THttpSessionCookieMode::Allow)
4178
			{
4179
				ini_set('session.use_cookies','1');
4180
				ini_set('session.use_only_cookies','0');
4181
			}
4182
			else
4183
			{
4184
				ini_set('session.use_cookies','1');
4185
				ini_set('session.use_only_cookies','1');
4186
				ini_set('session.use_trans_sid', 0);
4187
			}
4188
		}
4189
	}
4190
	public function getAutoStart()
4191
	{
4192
		return $this->_autoStart;
4193
	}
4194
	public function setAutoStart($value)
4195
	{
4196
		if($this->_initialized)
4197
			throw new TInvalidOperationException('httpsession_autostart_unchangeable');
4198
		else
4199
			$this->_autoStart=TPropertyValue::ensureBoolean($value);
4200
	}
4201
	public function getGCProbability()
4202
	{
4203
		return TPropertyValue::ensureInteger(ini_get('session.gc_probability'));
4204
	}
4205
	public function setGCProbability($value)
4206
	{
4207
		if($this->_started)
4208
			throw new TInvalidOperationException('httpsession_gcprobability_unchangeable');
4209
		else
4210
		{
4211
			$value=TPropertyValue::ensureInteger($value);
4212
			if($value>=0 && $value<=100)
4213
			{
4214
				ini_set('session.gc_probability',$value);
4215
				ini_set('session.gc_divisor','100');
4216
			}
4217
			else
4218
				throw new TInvalidDataValueException('httpsession_gcprobability_invalid',$value);
4219
		}
4220
	}
4221
	public function getUseTransparentSessionID()
4222
	{
4223
		return ini_get('session.use_trans_sid')==='1';
4224
	}
4225
	public function setUseTransparentSessionID($value)
4226
	{
4227
		if($this->_started)
4228
			throw new TInvalidOperationException('httpsession_transid_unchangeable');
4229
		else
4230
		{
4231
			$value=TPropertyValue::ensureBoolean($value);
4232
			if ($value && $this->getCookieMode()==THttpSessionCookieMode::Only)
4233
					throw new TInvalidOperationException('httpsession_transid_cookieonly');
4234
			ini_set('session.use_trans_sid',$value?'1':'0');
4235
		}
4236
	}
4237
	public function getTimeout()
4238
	{
4239
		return TPropertyValue::ensureInteger(ini_get('session.gc_maxlifetime'));
4240
	}
4241
	public function setTimeout($value)
4242
	{
4243
		if($this->_started)
4244
			throw new TInvalidOperationException('httpsession_maxlifetime_unchangeable');
4245
		else
4246
			ini_set('session.gc_maxlifetime',$value);
4247
	}
4248
	public function _open($savePath,$sessionName)
4249
	{
4250
		return true;
4251
	}
4252
	public function _close()
4253
	{
4254
		return true;
4255
	}
4256
	public function _read($id)
4257
	{
4258
		return '';
4259
	}
4260
	public function _write($id,$data)
4261
	{
4262
		return true;
4263
	}
4264
	public function _destroy($id)
4265
	{
4266
		return true;
4267
	}
4268
	public function _gc($maxLifetime)
4269
	{
4270
		return true;
4271
	}
4272
	public function getIterator()
4273
	{
4274
		return new TSessionIterator;
4275
	}
4276
	public function getCount()
1 ignored issue
show
Coding Style introduced by
getCount uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
4277
	{
4278
		return count($_SESSION);
4279
	}
4280
	public function count()
4281
	{
4282
		return $this->getCount();
4283
	}
4284
	public function getKeys()
1 ignored issue
show
Coding Style introduced by
getKeys uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
4285
	{
4286
		return array_keys($_SESSION);
4287
	}
4288
	public function itemAt($key)
1 ignored issue
show
Coding Style introduced by
itemAt uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
4289
	{
4290
		return isset($_SESSION[$key]) ? $_SESSION[$key] : null;
4291
	}
4292
	public function add($key,$value)
1 ignored issue
show
Coding Style introduced by
add uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
4293
	{
4294
		$_SESSION[$key]=$value;
4295
	}
4296
	public function remove($key)
1 ignored issue
show
Coding Style introduced by
remove uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
4297
	{
4298
		if(isset($_SESSION[$key]))
4299
		{
4300
			$value=$_SESSION[$key];
4301
			unset($_SESSION[$key]);
4302
			return $value;
4303
		}
4304
		else
4305
			return null;
4306
	}
4307
	public function clear()
1 ignored issue
show
Coding Style introduced by
clear uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
4308
	{
4309
		foreach(array_keys($_SESSION) as $key)
4310
			unset($_SESSION[$key]);
4311
	}
4312
	public function contains($key)
1 ignored issue
show
Coding Style introduced by
contains uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
4313
	{
4314
		return isset($_SESSION[$key]);
4315
	}
4316
	public function toArray()
1 ignored issue
show
Coding Style introduced by
toArray uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
4317
	{
4318
		return $_SESSION;
4319
	}
4320
	public function offsetExists($offset)
1 ignored issue
show
Coding Style introduced by
offsetExists uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
4321
	{
4322
		return isset($_SESSION[$offset]);
4323
	}
4324
	public function offsetGet($offset)
1 ignored issue
show
Coding Style introduced by
offsetGet uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
4325
	{
4326
		return isset($_SESSION[$offset]) ? $_SESSION[$offset] : null;
4327
	}
4328
	public function offsetSet($offset,$item)
1 ignored issue
show
Coding Style introduced by
offsetSet uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
4329
	{
4330
		$_SESSION[$offset]=$item;
4331
	}
4332
	public function offsetUnset($offset)
1 ignored issue
show
Coding Style introduced by
offsetUnset uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
4333
	{
4334
		unset($_SESSION[$offset]);
4335
	}
4336
}
4337
class TSessionIterator implements Iterator
4338
{
4339
	private $_keys;
4340
	private $_key;
4341
	public function __construct()
1 ignored issue
show
Coding Style introduced by
__construct uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
4342
	{
4343
		$this->_keys=array_keys($_SESSION);
4344
	}
4345
	public function rewind()
4346
	{
4347
		$this->_key=reset($this->_keys);
4348
	}
4349
	public function key()
4350
	{
4351
		return $this->_key;
4352
	}
4353
	public function current()
1 ignored issue
show
Coding Style introduced by
current uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
4354
	{
4355
		return isset($_SESSION[$this->_key])?$_SESSION[$this->_key]:null;
4356
	}
4357
	public function next()
1 ignored issue
show
Coding Style introduced by
next uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
4358
	{
4359
		do
4360
		{
4361
			$this->_key=next($this->_keys);
4362
		}
4363
		while(!isset($_SESSION[$this->_key]) && $this->_key!==false);
4364
	}
4365
	public function valid()
4366
	{
4367
		return $this->_key!==false;
4368
	}
4369
}
4370
class THttpSessionCookieMode extends TEnumerable
4371
{
4372
	const None='None';
4373
	const Allow='Allow';
4374
	const Only='Only';
4375
}
4376
Prado::using('System.Web.UI.WebControls.*');
4377
class TAttributeCollection extends TMap
4378
{
4379
	private $_caseSensitive=false;
4380
	protected function _getZappableSleepProps(&$exprops)
4381
	{
4382
		parent::_getZappableSleepProps($exprops);
4383
		if ($this->_caseSensitive===false)
4384
			$exprops[] = "\0TAttributeCollection\0_caseSensitive";
4385
	}
4386
	public function __get($name)
4387
	{
4388
		return $this->contains($name)?$this->itemAt($name):parent::__get($name);
4389
	}
4390
	public function __set($name,$value)
4391
	{
4392
		$this->add($name,$value);
4393
	}
4394
	public function getCaseSensitive()
4395
	{
4396
		return $this->_caseSensitive;
4397
	}
4398
	public function setCaseSensitive($value)
4399
	{
4400
		$this->_caseSensitive=TPropertyValue::ensureBoolean($value);
4401
	}
4402
	public function itemAt($key)
4403
	{
4404
		return parent::itemAt($this->_caseSensitive?$key:strtolower($key));
4405
	}
4406
	public function add($key,$value)
4407
	{
4408
		parent::add($this->_caseSensitive?$key:strtolower($key),$value);
4409
	}
4410
	public function remove($key)
4411
	{
4412
		return parent::remove($this->_caseSensitive?$key:strtolower($key));
4413
	}
4414
	public function contains($key)
4415
	{
4416
		return parent::contains($this->_caseSensitive?$key:strtolower($key));
4417
	}
4418
	public function hasProperty($name)
4419
	{
4420
		return $this->contains($name) || parent::canGetProperty($name) || parent::canSetProperty($name);
4421
	}
4422
	public function canGetProperty($name)
4423
	{
4424
		return $this->contains($name) || parent::canGetProperty($name);
4425
	}
4426
	public function canSetProperty($name)
4427
	{
4428
		return true;
4429
	}
4430
}
4431
class TControlAdapter extends TApplicationComponent
4432
{
4433
	protected $_control;
4434
	public function __construct($control)
4435
	{
4436
		$this->_control=$control;
4437
	}
4438
	public function getControl()
4439
	{
4440
		return $this->_control;
4441
	}
4442
	public function getPage()
4443
	{
4444
		return $this->_control?$this->_control->getPage():null;
4445
	}
4446
	public function createChildControls()
4447
	{
4448
		$this->_control->createChildControls();
4449
	}
4450
	public function loadState()
4451
	{
4452
		$this->_control->loadState();
4453
	}
4454
	public function saveState()
4455
	{
4456
		$this->_control->saveState();
4457
	}
4458
	public function onInit($param)
4459
	{
4460
		$this->_control->onInit($param);
4461
	}
4462
	public function onLoad($param)
4463
	{
4464
		$this->_control->onLoad($param);
4465
	}
4466
	public function onPreRender($param)
4467
	{
4468
		$this->_control->onPreRender($param);
4469
	}
4470
	public function onUnload($param)
4471
	{
4472
		$this->_control->onUnload($param);
4473
	}
4474
	public function render($writer)
4475
	{
4476
		$this->_control->render($writer);
4477
	}
4478
	public function renderChildren($writer)
4479
	{
4480
		$this->_control->renderChildren($writer);
4481
	}
4482
}
4483
class TControl extends TApplicationComponent implements IRenderable, IBindable
4484
{
4485
	const ID_FORMAT='/^[a-zA-Z_]\\w*$/';
4486
	const ID_SEPARATOR='$';
4487
	const CLIENT_ID_SEPARATOR='_';
4488
	const AUTOMATIC_ID_PREFIX='ctl';
4489
	const CS_CONSTRUCTED=0;
4490
	const CS_CHILD_INITIALIZED=1;
4491
	const CS_INITIALIZED=2;
4492
	const CS_STATE_LOADED=3;
4493
	const CS_LOADED=4;
4494
	const CS_PRERENDERED=5;
4495
	const IS_ID_SET=0x01;
4496
	const IS_DISABLE_VIEWSTATE=0x02;
4497
	const IS_SKIN_APPLIED=0x04;
4498
	const IS_STYLESHEET_APPLIED=0x08;
4499
	const IS_DISABLE_THEMING=0x10;
4500
	const IS_CHILD_CREATED=0x20;
4501
	const IS_CREATING_CHILD=0x40;
4502
	const RF_CONTROLS=0;				const RF_CHILD_STATE=1;				const RF_NAMED_CONTROLS=2;			const RF_NAMED_CONTROLS_ID=3;		const RF_SKIN_ID=4;					const RF_DATA_BINDINGS=5;			const RF_EVENTS=6;					const RF_CONTROLSTATE=7;			const RF_NAMED_OBJECTS=8;			const RF_ADAPTER=9;					const RF_AUTO_BINDINGS=10;		
0 ignored issues
show
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
4503
	private $_id='';
4504
	private $_uid;
4505
	private $_parent;
4506
	private $_page;
4507
	private $_namingContainer;
4508
	private $_tplControl;
4509
	private $_viewState=array();
4510
	private $_tempState=array();
4511
	private $_trackViewState=true;
4512
	private $_stage=0;
4513
	private $_flags=0;
4514
	private $_rf=array();
4515
	public function __get($name)
4516
	{
4517
		if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
4518
			return $this->_rf[self::RF_NAMED_OBJECTS][$name];
4519
		else
4520
			return parent::__get($name);
4521
	}
4522
	public function getHasAdapter()
4523
	{
4524
		return isset($this->_rf[self::RF_ADAPTER]);
4525
	}
4526
	public function getAdapter()
4527
	{
4528
		return isset($this->_rf[self::RF_ADAPTER])?$this->_rf[self::RF_ADAPTER]:null;
4529
	}
4530
	public function setAdapter(TControlAdapter $adapter)
4531
	{
4532
		$this->_rf[self::RF_ADAPTER]=$adapter;
4533
	}
4534
	public function getParent()
4535
	{
4536
		return $this->_parent;
4537
	}
4538
	public function getNamingContainer()
4539
	{
4540
		if(!$this->_namingContainer && $this->_parent)
4541
		{
4542
			if($this->_parent instanceof INamingContainer)
4543
				$this->_namingContainer=$this->_parent;
4544
			else
4545
				$this->_namingContainer=$this->_parent->getNamingContainer();
4546
		}
4547
		return $this->_namingContainer;
4548
	}
4549
	public function getPage()
4550
	{
4551
		if(!$this->_page)
4552
		{
4553
			if($this->_parent)
4554
				$this->_page=$this->_parent->getPage();
4555
			else if($this->_tplControl)
4556
				$this->_page=$this->_tplControl->getPage();
4557
		}
4558
		return $this->_page;
4559
	}
4560
	public function setPage($page)
4561
	{
4562
		$this->_page=$page;
4563
	}
4564
	public function setTemplateControl($control)
4565
	{
4566
		$this->_tplControl=$control;
4567
	}
4568
	public function getTemplateControl()
4569
	{
4570
		if(!$this->_tplControl && $this->_parent)
4571
			$this->_tplControl=$this->_parent->getTemplateControl();
4572
		return $this->_tplControl;
4573
	}
4574
	public function getSourceTemplateControl()
4575
	{
4576
		$control=$this;
4577
		while(($control instanceof TControl) && ($control=$control->getTemplateControl())!==null)
4578
		{
4579
			if(($control instanceof TTemplateControl) && $control->getIsSourceTemplateControl())
4580
				return $control;
4581
		}
4582
		return $this->getPage();
4583
	}
4584
	protected function getControlStage()
4585
	{
4586
		return $this->_stage;
4587
	}
4588
	protected function setControlStage($value)
4589
	{
4590
		$this->_stage=$value;
4591
	}
4592
	public function getID($hideAutoID=true)
4593
	{
4594
		if($hideAutoID)
4595
			return ($this->_flags & self::IS_ID_SET) ? $this->_id : '';
4596
		else
4597
			return $this->_id;
4598
	}
4599
	public function setID($id)
4600
	{
4601
		if(!preg_match(self::ID_FORMAT,$id))
4602
			throw new TInvalidDataValueException('control_id_invalid',get_class($this),$id);
4603
		$this->_id=$id;
4604
		$this->_flags |= self::IS_ID_SET;
4605
		$this->clearCachedUniqueID($this instanceof INamingContainer);
4606
		if($this->_namingContainer)
4607
			$this->_namingContainer->clearNameTable();
4608
	}
4609
	public function getUniqueID()
4610
	{
4611
		if($this->_uid==='' || $this->_uid===null)			{
4612
			$this->_uid='';  			if($namingContainer=$this->getNamingContainer())
4613
			{
4614
				if($this->getPage()===$namingContainer)
4615
					return ($this->_uid=$this->_id);
4616
				else if(($prefix=$namingContainer->getUniqueID())==='')
4617
					return $this->_id;
4618
				else
4619
					return ($this->_uid=$prefix.self::ID_SEPARATOR.$this->_id);
4620
			}
4621
			else					return $this->_id;
4622
		}
4623
		else
4624
			return $this->_uid;
4625
	}
4626
	public function focus()
4627
	{
4628
		$this->getPage()->setFocus($this);
4629
	}
4630
	public function getClientID()
4631
	{
4632
		return strtr($this->getUniqueID(),self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
4633
	}
4634
	public static function convertUniqueIdToClientId($uniqueID)
4635
	{
4636
		return strtr($uniqueID,self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
4637
	}
4638
	public function getSkinID()
4639
	{
4640
		return isset($this->_rf[self::RF_SKIN_ID])?$this->_rf[self::RF_SKIN_ID]:'';
4641
	}
4642
	public function setSkinID($value)
4643
	{
4644
		if(($this->_flags & self::IS_SKIN_APPLIED) || $this->_stage>=self::CS_CHILD_INITIALIZED)
4645
			throw new TInvalidOperationException('control_skinid_unchangeable',get_class($this));
4646
		else
4647
			$this->_rf[self::RF_SKIN_ID]=$value;
4648
	}
4649
	public function getIsSkinApplied()
4650
	{
4651
		return ($this->_flags & self::IS_SKIN_APPLIED);
4652
	}
4653
	public function getEnableTheming()
4654
	{
4655
		if($this->_flags & self::IS_DISABLE_THEMING)
4656
			return false;
4657
		else
4658
			return $this->_parent?$this->_parent->getEnableTheming():true;
4659
	}
4660
	public function setEnableTheming($value)
4661
	{
4662
		if($this->_stage>=self::CS_CHILD_INITIALIZED)
4663
			throw new TInvalidOperationException('control_enabletheming_unchangeable',get_class($this),$this->getUniqueID());
4664
		else if(TPropertyValue::ensureBoolean($value))
4665
			$this->_flags &= ~self::IS_DISABLE_THEMING;
4666
		else
4667
			$this->_flags |= self::IS_DISABLE_THEMING;
4668
	}
4669
	public function getCustomData()
4670
	{
4671
		return $this->getViewState('CustomData',null);
4672
	}
4673
	public function setCustomData($value)
4674
	{
4675
		$this->setViewState('CustomData',$value,null);
4676
	}
4677
	public function getHasControls()
4678
	{
4679
		return isset($this->_rf[self::RF_CONTROLS]) && $this->_rf[self::RF_CONTROLS]->getCount()>0;
4680
	}
4681
	public function getControls()
4682
	{
4683
		if(!isset($this->_rf[self::RF_CONTROLS]))
4684
			$this->_rf[self::RF_CONTROLS]=$this->createControlCollection();
4685
		return $this->_rf[self::RF_CONTROLS];
4686
	}
4687
	protected function createControlCollection()
4688
	{
4689
		return $this->getAllowChildControls()?new TControlCollection($this):new TEmptyControlCollection($this);
4690
	}
4691
	public function getVisible($checkParents=true)
4692
	{
4693
		if($checkParents)
4694
		{
4695
			for($control=$this;$control;$control=$control->_parent)
4696
				if(!$control->getVisible(false))
4697
					return false;
4698
			return true;
4699
		}
4700
		else
4701
			return $this->getViewState('Visible',true);
4702
	}
4703
	public function setVisible($value)
4704
	{
4705
		$this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true);
4706
	}
4707
	public function getEnabled($checkParents=false)
4708
	{
4709
		if($checkParents)
4710
		{
4711
			for($control=$this;$control;$control=$control->_parent)
4712
				if(!$control->getViewState('Enabled',true))
4713
					return false;
4714
			return true;
4715
		}
4716
		else
4717
			return $this->getViewState('Enabled',true);
4718
	}
4719
	public function setEnabled($value)
4720
	{
4721
		$this->setViewState('Enabled',TPropertyValue::ensureBoolean($value),true);
4722
	}
4723
	public function getHasAttributes()
4724
	{
4725
		if($attributes=$this->getViewState('Attributes',null))
4726
			return $attributes->getCount()>0;
4727
		else
4728
			return false;
4729
	}
4730
	public function getAttributes()
4731
	{
4732
		if($attributes=$this->getViewState('Attributes',null))
4733
			return $attributes;
4734
		else
4735
		{
4736
			$attributes=new TAttributeCollection;
4737
			$this->setViewState('Attributes',$attributes,null);
4738
			return $attributes;
4739
		}
4740
	}
4741
	public function hasAttribute($name)
4742
	{
4743
		if($attributes=$this->getViewState('Attributes',null))
4744
			return $attributes->contains($name);
4745
		else
4746
			return false;
4747
	}
4748
	public function getAttribute($name)
4749
	{
4750
		if($attributes=$this->getViewState('Attributes',null))
4751
			return $attributes->itemAt($name);
4752
		else
4753
			return null;
4754
	}
4755
	public function setAttribute($name,$value)
4756
	{
4757
		$this->getAttributes()->add($name,$value);
4758
	}
4759
	public function removeAttribute($name)
4760
	{
4761
		if($attributes=$this->getViewState('Attributes',null))
4762
			return $attributes->remove($name);
4763
		else
4764
			return null;
4765
	}
4766
	public function getEnableViewState($checkParents=false)
4767
	{
4768
		if($checkParents)
4769
		{
4770
			for($control=$this;$control!==null;$control=$control->getParent())
4771
				if($control->_flags & self::IS_DISABLE_VIEWSTATE)
4772
					return false;
4773
			return true;
4774
		}
4775
		else
4776
			return !($this->_flags & self::IS_DISABLE_VIEWSTATE);
4777
	}
4778
	public function setEnableViewState($value)
4779
	{
4780
		if(TPropertyValue::ensureBoolean($value))
4781
			$this->_flags &= ~self::IS_DISABLE_VIEWSTATE;
4782
		else
4783
			$this->_flags |= self::IS_DISABLE_VIEWSTATE;
4784
	}
4785
	protected function getControlState($key,$defaultValue=null)
4786
	{
4787
		return isset($this->_rf[self::RF_CONTROLSTATE][$key])?$this->_rf[self::RF_CONTROLSTATE][$key]:$defaultValue;
4788
	}
4789
	protected function setControlState($key,$value,$defaultValue=null)
4790
	{
4791
		if($value===$defaultValue)
4792
			unset($this->_rf[self::RF_CONTROLSTATE][$key]);
4793
		else
4794
			$this->_rf[self::RF_CONTROLSTATE][$key]=$value;
4795
	}
4796
	protected function clearControlState($key)
4797
	{
4798
		unset($this->_rf[self::RF_CONTROLSTATE][$key]);
4799
	}
4800
	public function trackViewState($enabled)
4801
	{
4802
		$this->_trackViewState=TPropertyValue::ensureBoolean($enabled);
4803
	}
4804
	public function getViewState($key,$defaultValue=null)
4805
	{
4806
		if(isset($this->_viewState[$key]))
4807
			return $this->_viewState[$key]!==null?$this->_viewState[$key]:$defaultValue;
4808
		else if(isset($this->_tempState[$key]))
4809
		{
4810
			if(is_object($this->_tempState[$key]) && $this->_trackViewState)
4811
				$this->_viewState[$key]=$this->_tempState[$key];
4812
			return $this->_tempState[$key];
4813
		}
4814
		else
4815
			return $defaultValue;
4816
	}
4817
	public function setViewState($key,$value,$defaultValue=null)
4818
	{
4819
		if($this->_trackViewState)
4820
		{
4821
			unset($this->_tempState[$key]);
4822
			if($value===$defaultValue)
4823
				unset($this->_viewState[$key]);
4824
			else
4825
				$this->_viewState[$key]=$value;
4826
		}
4827
		else
4828
		{
4829
			unset($this->_viewState[$key]);
4830
			if($value===$defaultValue)
4831
				unset($this->_tempState[$key]);
4832
			else
4833
				$this->_tempState[$key]=$value;
4834
		}
4835
	}
4836
	public function clearViewState($key)
4837
	{
4838
		unset($this->_viewState[$key]);
4839
		unset($this->_tempState[$key]);
4840
	}
4841
	public function bindProperty($name,$expression)
4842
	{
4843
		$this->_rf[self::RF_DATA_BINDINGS][$name]=$expression;
4844
	}
4845
	public function unbindProperty($name)
4846
	{
4847
		unset($this->_rf[self::RF_DATA_BINDINGS][$name]);
4848
	}
4849
	public function autoBindProperty($name,$expression)
4850
	{
4851
		$this->_rf[self::RF_AUTO_BINDINGS][$name]=$expression;
4852
	}
4853
	public function dataBind()
4854
	{
4855
		$this->dataBindProperties();
4856
		$this->onDataBinding(null);
4857
		$this->dataBindChildren();
4858
	}
4859
	protected function dataBindProperties()
4860
	{
4861
		if(isset($this->_rf[self::RF_DATA_BINDINGS]))
4862
		{
4863
			if(($context=$this->getTemplateControl())===null)
4864
				$context=$this;
4865
			foreach($this->_rf[self::RF_DATA_BINDINGS] as $property=>$expression)
4866
				$this->setSubProperty($property,$context->evaluateExpression($expression));
4867
		}
4868
	}
4869
	protected function autoDataBindProperties()
4870
	{
4871
		if(isset($this->_rf[self::RF_AUTO_BINDINGS]))
4872
		{
4873
			if(($context=$this->getTemplateControl())===null)
4874
				$context=$this;
4875
			foreach($this->_rf[self::RF_AUTO_BINDINGS] as $property=>$expression)
4876
				$this->setSubProperty($property,$context->evaluateExpression($expression));
4877
		}
4878
	}
4879
	protected function dataBindChildren()
4880
	{
4881
		if(isset($this->_rf[self::RF_CONTROLS]))
4882
		{
4883
			foreach($this->_rf[self::RF_CONTROLS] as $control)
4884
				if($control instanceof IBindable)
4885
					$control->dataBind();
4886
		}
4887
	}
4888
	final protected function getChildControlsCreated()
4889
	{
4890
		return ($this->_flags & self::IS_CHILD_CREATED)!==0;
4891
	}
4892
	final protected function setChildControlsCreated($value)
4893
	{
4894
		if($value)
4895
			$this->_flags |= self::IS_CHILD_CREATED;
4896
		else
4897
		{
4898
			if($this->getHasControls() && ($this->_flags & self::IS_CHILD_CREATED))
4899
				$this->getControls()->clear();
4900
			$this->_flags &= ~self::IS_CHILD_CREATED;
4901
		}
4902
	}
4903
	public function ensureChildControls()
4904
	{
4905
		if(!($this->_flags & self::IS_CHILD_CREATED) && !($this->_flags & self::IS_CREATING_CHILD))
4906
		{
4907
			try
4908
			{
4909
				$this->_flags |= self::IS_CREATING_CHILD;
4910
				if(isset($this->_rf[self::RF_ADAPTER]))
4911
					$this->_rf[self::RF_ADAPTER]->createChildControls();
4912
				else
4913
					$this->createChildControls();
4914
				$this->_flags &= ~self::IS_CREATING_CHILD;
4915
				$this->_flags |= self::IS_CHILD_CREATED;
4916
			}
4917
			catch(Exception $e)
4918
			{
4919
				$this->_flags &= ~self::IS_CREATING_CHILD;
4920
				$this->_flags |= self::IS_CHILD_CREATED;
4921
				throw $e;
4922
			}
4923
		}
4924
	}
4925
	public function createChildControls()
4926
	{
4927
	}
4928
	public function findControl($id)
4929
	{
4930
		$id=strtr($id,'.',self::ID_SEPARATOR);
4931
		$container=($this instanceof INamingContainer)?$this:$this->getNamingContainer();
4932
		if(!$container || !$container->getHasControls())
4933
			return null;
4934
		if(!isset($container->_rf[self::RF_NAMED_CONTROLS]))
4935
		{
4936
			$container->_rf[self::RF_NAMED_CONTROLS]=array();
4937
			$container->fillNameTable($container,$container->_rf[self::RF_CONTROLS]);
4938
		}
4939
		if(($pos=strpos($id,self::ID_SEPARATOR))===false)
4940
			return isset($container->_rf[self::RF_NAMED_CONTROLS][$id])?$container->_rf[self::RF_NAMED_CONTROLS][$id]:null;
4941
		else
4942
		{
4943
			$cid=substr($id,0,$pos);
4944
			$sid=substr($id,$pos+1);
4945
			if(isset($container->_rf[self::RF_NAMED_CONTROLS][$cid]))
4946
				return $container->_rf[self::RF_NAMED_CONTROLS][$cid]->findControl($sid);
4947
			else
4948
				return null;
4949
		}
4950
	}
4951
	public function findControlsByType($type,$strict=true)
4952
	{
4953
		$controls=array();
4954
		if($this->getHasControls())
4955
		{
4956
			foreach($this->_rf[self::RF_CONTROLS] as $control)
4957
			{
4958
				if(is_object($control) && (get_class($control)===$type || (!$strict && ($control instanceof $type))))
4959
					$controls[]=$control;
4960
				if(($control instanceof TControl) && $control->getHasControls())
4961
					$controls=array_merge($controls,$control->findControlsByType($type,$strict));
4962
			}
4963
		}
4964
		return $controls;
4965
	}
4966
	public function findControlsByID($id)
4967
	{
4968
		$controls=array();
4969
		if($this->getHasControls())
4970
		{
4971
			foreach($this->_rf[self::RF_CONTROLS] as $control)
4972
			{
4973
				if($control instanceof TControl)
4974
				{
4975
					if($control->_id===$id)
4976
						$controls[]=$control;
4977
					$controls=array_merge($controls,$control->findControlsByID($id));
4978
				}
4979
			}
4980
		}
4981
		return $controls;
4982
	}
4983
	public function clearNamingContainer()
4984
	{
4985
		unset($this->_rf[self::RF_NAMED_CONTROLS_ID]);
4986
		$this->clearNameTable();
4987
	}
4988
	public function registerObject($name,$object)
4989
	{
4990
		if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
4991
			throw new TInvalidOperationException('control_object_reregistered',$name);
4992
		$this->_rf[self::RF_NAMED_OBJECTS][$name]=$object;
4993
	}
4994
	public function unregisterObject($name)
4995
	{
4996
		unset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
4997
	}
4998
	public function isObjectRegistered($name)
4999
	{
5000
		return isset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
5001
	}
5002
	public function getHasChildInitialized()
5003
	{
5004
		return $this->getControlStage() >= self::CS_CHILD_INITIALIZED;
5005
	}
5006
	public function getHasInitialized()
5007
	{
5008
		return $this->getControlStage() >= self::CS_INITIALIZED;
5009
	}
5010
	public function getHasLoadedPostData()
5011
	{
5012
		return $this->getControlStage() >= self::CS_STATE_LOADED;
5013
	}
5014
	public function getHasLoaded()
5015
	{
5016
		return $this->getControlStage() >= self::CS_LOADED;
5017
	}
5018
	public function getHasPreRendered()
5019
	{
5020
		return $this->getControlStage() >= self::CS_PRERENDERED;
5021
	}
5022
	public function getRegisteredObject($name)
5023
	{
5024
		return isset($this->_rf[self::RF_NAMED_OBJECTS][$name])?$this->_rf[self::RF_NAMED_OBJECTS][$name]:null;
5025
	}
5026
	public function getAllowChildControls()
5027
	{
5028
		return true;
5029
	}
5030
	public function addParsedObject($object)
5031
	{
5032
		$this->getControls()->add($object);
5033
	}
5034
	final protected function clearChildState()
5035
	{
5036
		unset($this->_rf[self::RF_CHILD_STATE]);
5037
	}
5038
	final protected function isDescendentOf($ancestor)
5039
	{
5040
		$control=$this;
5041
		while($control!==$ancestor && $control->_parent)
5042
			$control=$control->_parent;
5043
		return $control===$ancestor;
5044
	}
5045
	public function addedControl($control)
5046
	{
5047
		if($control->_parent)
5048
			$control->_parent->getControls()->remove($control);
5049
		$control->_parent=$this;
5050
		$control->_page=$this->getPage();
5051
		$namingContainer=($this instanceof INamingContainer)?$this:$this->_namingContainer;
5052
		if($namingContainer)
5053
		{
5054
			$control->_namingContainer=$namingContainer;
5055
			if($control->_id==='')
5056
				$control->generateAutomaticID();
5057
			else
5058
				$namingContainer->clearNameTable();
0 ignored issues
show
Bug introduced by
The method clearNameTable does only exist in TControl, but not in INamingContainer.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
5059
			$control->clearCachedUniqueID($control instanceof INamingContainer);
5060
		}
5061
		if($this->_stage>=self::CS_CHILD_INITIALIZED)
5062
		{
5063
			$control->initRecursive($namingContainer);
5064
			if($this->_stage>=self::CS_STATE_LOADED)
5065
			{
5066
				if(isset($this->_rf[self::RF_CHILD_STATE][$control->_id]))
5067
				{
5068
					$state=$this->_rf[self::RF_CHILD_STATE][$control->_id];
5069
					unset($this->_rf[self::RF_CHILD_STATE][$control->_id]);
5070
				}
5071
				else
5072
					$state=null;
5073
				$control->loadStateRecursive($state,!($this->_flags & self::IS_DISABLE_VIEWSTATE));
5074
				if($this->_stage>=self::CS_LOADED)
5075
				{
5076
					$control->loadRecursive();
5077
					if($this->_stage>=self::CS_PRERENDERED)
5078
						$control->preRenderRecursive();
5079
				}
5080
			}
5081
		}
5082
	}
5083
	public function removedControl($control)
5084
	{
5085
		if($this->_namingContainer)
5086
			$this->_namingContainer->clearNameTable();
5087
		$control->unloadRecursive();
5088
		$control->_parent=null;
5089
		$control->_page=null;
5090
		$control->_namingContainer=null;
5091
		$control->_tplControl=null;
5092
				if(!($control->_flags & self::IS_ID_SET))
5093
			$control->_id='';
5094
		else
5095
			unset($this->_rf[self::RF_NAMED_OBJECTS][$control->_id]);
5096
		$control->clearCachedUniqueID(true);
5097
	}
5098
	protected function initRecursive($namingContainer=null)
5099
	{
5100
		$this->ensureChildControls();
5101
		if($this->getHasControls())
5102
		{
5103
			if($this instanceof INamingContainer)
5104
				$namingContainer=$this;
5105
			$page=$this->getPage();
5106
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5107
			{
5108
				if($control instanceof TControl)
5109
				{
5110
					$control->_namingContainer=$namingContainer;
5111
					$control->_page=$page;
5112
					if($control->_id==='' && $namingContainer)
5113
						$control->generateAutomaticID();
5114
					$control->initRecursive($namingContainer);
5115
				}
5116
			}
5117
		}
5118
		if($this->_stage<self::CS_INITIALIZED)
5119
		{
5120
			$this->_stage=self::CS_CHILD_INITIALIZED;
5121
			if(($page=$this->getPage()) && $this->getEnableTheming() && !($this->_flags & self::IS_SKIN_APPLIED))
5122
			{
5123
				$page->applyControlSkin($this);
5124
				$this->_flags |= self::IS_SKIN_APPLIED;
5125
			}
5126
			if(isset($this->_rf[self::RF_ADAPTER]))
5127
				$this->_rf[self::RF_ADAPTER]->onInit(null);
5128
			else
5129
				$this->onInit(null);
5130
			$this->_stage=self::CS_INITIALIZED;
5131
		}
5132
	}
5133
	protected function loadRecursive()
5134
	{
5135
		if($this->_stage<self::CS_LOADED)
5136
		{
5137
			if(isset($this->_rf[self::RF_ADAPTER]))
5138
				$this->_rf[self::RF_ADAPTER]->onLoad(null);
5139
			else
5140
				$this->onLoad(null);
5141
		}
5142
		if($this->getHasControls())
5143
		{
5144
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5145
			{
5146
				if($control instanceof TControl)
5147
					$control->loadRecursive();
5148
			}
5149
		}
5150
		if($this->_stage<self::CS_LOADED)
5151
			$this->_stage=self::CS_LOADED;
5152
	}
5153
	protected function preRenderRecursive()
5154
	{
5155
		$this->autoDataBindProperties();
5156
		if($this->getVisible(false))
5157
		{
5158
			if(isset($this->_rf[self::RF_ADAPTER]))
5159
				$this->_rf[self::RF_ADAPTER]->onPreRender(null);
5160
			else
5161
				$this->onPreRender(null);
5162
			if($this->getHasControls())
5163
			{
5164
				foreach($this->_rf[self::RF_CONTROLS] as $control)
5165
				{
5166
					if($control instanceof TControl)
5167
						$control->preRenderRecursive();
5168
					else if($control instanceof TCompositeLiteral)
5169
						$control->evaluateDynamicContent();
5170
				}
5171
			}
5172
		}
5173
		$this->_stage=self::CS_PRERENDERED;
5174
	}
5175
	protected function unloadRecursive()
5176
	{
5177
		if(!($this->_flags & self::IS_ID_SET))
5178
			$this->_id='';
5179
		if($this->getHasControls())
5180
		{
5181
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5182
				if($control instanceof TControl)
5183
					$control->unloadRecursive();
5184
		}
5185
		if(isset($this->_rf[self::RF_ADAPTER]))
5186
			$this->_rf[self::RF_ADAPTER]->onUnload(null);
5187
		else
5188
			$this->onUnload(null);
5189
	}
5190
	public function onInit($param)
5191
	{
5192
		$this->raiseEvent('OnInit',$this,$param);
5193
	}
5194
	public function onLoad($param)
5195
	{
5196
		$this->raiseEvent('OnLoad',$this,$param);
5197
	}
5198
	public function onDataBinding($param)
5199
	{
5200
		$this->raiseEvent('OnDataBinding',$this,$param);
5201
	}
5202
	public function onUnload($param)
5203
	{
5204
		$this->raiseEvent('OnUnload',$this,$param);
5205
	}
5206
	public function onPreRender($param)
5207
	{
5208
		$this->raiseEvent('OnPreRender',$this,$param);
5209
	}
5210
	protected function raiseBubbleEvent($sender,$param)
5211
	{
5212
		$control=$this;
5213
		while($control=$control->_parent)
5214
		{
5215
			if($control->bubbleEvent($sender,$param))
5216
				break;
5217
		}
5218
	}
5219
	public function bubbleEvent($sender,$param)
5220
	{
5221
		return false;
5222
	}
5223
	public function broadcastEvent($name,$sender,$param)
5224
	{
5225
		$rootControl=(($page=$this->getPage())===null)?$this:$page;
5226
		$rootControl->broadcastEventInternal($name,$sender,new TBroadcastEventParameter($name,$param));
5227
	}
5228
	private function broadcastEventInternal($name,$sender,$param)
5229
	{
5230
		if($this->hasEvent($name))
5231
			$this->raiseEvent($name,$sender,$param->getParameter());
5232
		if($this instanceof IBroadcastEventReceiver)
5233
			$this->broadcastEventReceived($sender,$param);
5234
		if($this->getHasControls())
5235
		{
5236
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5237
			{
5238
				if($control instanceof TControl)
5239
					$control->broadcastEventInternal($name,$sender,$param);
5240
			}
5241
		}
5242
	}
5243
	protected function traverseChildControls($param,$preCallback=null,$postCallback=null)
5244
	{
5245
		if($preCallback!==null)
5246
			call_user_func($preCallback,$this,$param);
5247
		if($this->getHasControls())
5248
		{
5249
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5250
			{
5251
				if($control instanceof TControl)
5252
				{
5253
					$control->traverseChildControls($param,$preCallback,$postCallback);
5254
				}
5255
			}
5256
		}
5257
		if($postCallback!==null)
5258
			call_user_func($postCallback,$this,$param);
5259
	}
5260
	public function renderControl($writer)
5261
	{
5262
		if($this instanceof IActiveControl || $this->getVisible(false))
5263
		{
5264
			if(isset($this->_rf[self::RF_ADAPTER]))
5265
				$this->_rf[self::RF_ADAPTER]->render($writer);
5266
			else
5267
				$this->render($writer);
5268
		}
5269
	}
5270
	public function render($writer)
5271
	{
5272
		$this->renderChildren($writer);
5273
	}
5274
	public function renderChildren($writer)
5275
	{
5276
		if($this->getHasControls())
5277
		{
5278
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5279
			{
5280
				if(is_string($control))
5281
					$writer->write($control);
5282
				else if($control instanceof TControl)
5283
					$control->renderControl($writer);
5284
				else if($control instanceof IRenderable)
5285
					$control->render($writer);
5286
			}
5287
		}
5288
	}
5289
	public function saveState()
5290
	{
5291
	}
5292
	public function loadState()
5293
	{
5294
	}
5295
	protected function loadStateRecursive(&$state,$needViewState=true)
5296
	{
5297
		if(is_array($state))
5298
		{
5299
									$needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
5300
			if(isset($state[1]))
5301
			{
5302
				$this->_rf[self::RF_CONTROLSTATE]=&$state[1];
5303
				unset($state[1]);
5304
			}
5305
			else
5306
				unset($this->_rf[self::RF_CONTROLSTATE]);
5307
			if($needViewState)
5308
			{
5309
				if(isset($state[0]))
5310
					$this->_viewState=&$state[0];
5311
				else
5312
					$this->_viewState=array();
5313
			}
5314
			unset($state[0]);
5315
			if($this->getHasControls())
5316
			{
5317
				foreach($this->_rf[self::RF_CONTROLS] as $control)
5318
				{
5319
					if($control instanceof TControl)
5320
					{
5321
						if(isset($state[$control->_id]))
5322
						{
5323
							$control->loadStateRecursive($state[$control->_id],$needViewState);
5324
							unset($state[$control->_id]);
5325
						}
5326
					}
5327
				}
5328
			}
5329
			if(!empty($state))
5330
				$this->_rf[self::RF_CHILD_STATE]=&$state;
5331
		}
5332
		$this->_stage=self::CS_STATE_LOADED;
5333
		if(isset($this->_rf[self::RF_ADAPTER]))
5334
			$this->_rf[self::RF_ADAPTER]->loadState();
5335
		else
5336
			$this->loadState();
5337
	}
5338
	protected function &saveStateRecursive($needViewState=true)
5339
	{
5340
		if(isset($this->_rf[self::RF_ADAPTER]))
5341
			$this->_rf[self::RF_ADAPTER]->saveState();
5342
		else
5343
			$this->saveState();
5344
		$needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
5345
		$state=array();
5346
		if($this->getHasControls())
5347
		{
5348
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5349
			{
5350
				if($control instanceof TControl)
5351
				{
5352
					if(count($tmp = &$control->saveStateRecursive($needViewState)))
5353
						$state[$control->_id]=$tmp;
5354
				}
5355
			}
5356
		}
5357
		if($needViewState && !empty($this->_viewState))
5358
			$state[0]=&$this->_viewState;
5359
		if(isset($this->_rf[self::RF_CONTROLSTATE]))
5360
			$state[1]=&$this->_rf[self::RF_CONTROLSTATE];
5361
		return $state;
5362
	}
5363
	public function applyStyleSheetSkin($page)
5364
	{
5365
		if($page && !($this->_flags & self::IS_STYLESHEET_APPLIED))
5366
		{
5367
			$page->applyControlStyleSheet($this);
5368
			$this->_flags |= self::IS_STYLESHEET_APPLIED;
5369
		}
5370
		else if($this->_flags & self::IS_STYLESHEET_APPLIED)
5371
			throw new TInvalidOperationException('control_stylesheet_applied',get_class($this));
5372
	}
5373
	private function clearCachedUniqueID($recursive)
5374
	{
5375
		if($recursive && $this->_uid!==null && isset($this->_rf[self::RF_CONTROLS]))
5376
		{
5377
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5378
				if($control instanceof TControl)
5379
					$control->clearCachedUniqueID($recursive);
5380
		}
5381
		$this->_uid=null;
5382
	}
5383
	private function generateAutomaticID()
5384
	{
5385
		$this->_flags &= ~self::IS_ID_SET;
5386
		if(!isset($this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]))
0 ignored issues
show
Bug introduced by
Accessing _rf on the interface INamingContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
5387
			$this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]=0;
0 ignored issues
show
Bug introduced by
Accessing _rf on the interface INamingContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
5388
		$id=$this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]++;
0 ignored issues
show
Bug introduced by
Accessing _rf on the interface INamingContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
5389
		$this->_id=self::AUTOMATIC_ID_PREFIX . $id;
5390
		$this->_namingContainer->clearNameTable();
5391
	}
5392
	private function clearNameTable()
5393
	{
5394
		unset($this->_rf[self::RF_NAMED_CONTROLS]);
5395
	}
5396
	private function fillNameTable($container,$controls)
5397
	{
5398
		foreach($controls as $control)
5399
		{
5400
			if($control instanceof TControl)
5401
			{
5402
				if($control->_id!=='')
5403
				{
5404
					if(isset($container->_rf[self::RF_NAMED_CONTROLS][$control->_id]))
5405
						throw new TInvalidDataValueException('control_id_nonunique',get_class($control),$control->_id);
5406
					else
5407
						$container->_rf[self::RF_NAMED_CONTROLS][$control->_id]=$control;
5408
				}
5409
				if(!($control instanceof INamingContainer) && $control->getHasControls())
5410
					$this->fillNameTable($container,$control->_rf[self::RF_CONTROLS]);
5411
			}
5412
		}
5413
	}
5414
}
5415
class TControlCollection extends TList
5416
{
5417
	private $_o;
5418
	public function __construct(TControl $owner,$readOnly=false)
5419
	{
5420
		$this->_o=$owner;
5421
		parent::__construct(null,$readOnly);
5422
	}
5423
	protected function getOwner()
5424
	{
5425
		return $this->_o;
5426
	}
5427
	public function insertAt($index,$item)
5428
	{
5429
		if($item instanceof TControl)
5430
		{
5431
			parent::insertAt($index,$item);
5432
			$this->_o->addedControl($item);
5433
		}
5434
		else if(is_string($item) || ($item instanceof IRenderable))
5435
			parent::insertAt($index,$item);
5436
		else
5437
			throw new TInvalidDataTypeException('controlcollection_control_required');
5438
	}
5439
	public function removeAt($index)
5440
	{
5441
		$item=parent::removeAt($index);
5442
		if($item instanceof TControl)
5443
			$this->_o->removedControl($item);
5444
		return $item;
5445
	}
5446
	public function clear()
5447
	{
5448
		parent::clear();
5449
		if($this->_o instanceof INamingContainer)
5450
			$this->_o->clearNamingContainer();
5451
	}
5452
}
5453
class TEmptyControlCollection extends TControlCollection
5454
{
5455
	public function __construct(TControl $owner)
5456
	{
5457
		parent::__construct($owner,true);
5458
	}
5459
	public function insertAt($index,$item)
5460
	{
5461
		if(!is_string($item))  			parent::insertAt($index,$item);  	}
5462
}
5463
interface INamingContainer
5464
{
5465
}
5466
interface IPostBackEventHandler
5467
{
5468
	public function raisePostBackEvent($param);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
5469
}
5470
interface IPostBackDataHandler
5471
{
5472
	public function loadPostData($key,$values);
5473
	public function raisePostDataChangedEvent();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
5474
	public function getDataChanged();
5475
}
5476
interface IValidator
5477
{
5478
	public function validate();
5479
	public function getIsValid();
5480
	public function setIsValid($value);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
5481
	public function getErrorMessage();
5482
	public function setErrorMessage($value);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
5483
}
5484
interface IValidatable
5485
{
5486
	public function getValidationPropertyValue();
5487
	public function getIsValid();
5488
	public function setIsValid($value);
5489
}
5490
interface IBroadcastEventReceiver
5491
{
5492
	public function broadcastEventReceived($sender,$param);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
5493
}
5494
interface ITheme
5495
{
5496
	public function applySkin($control);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
5497
}
5498
interface ITemplate
5499
{
5500
	public function instantiateIn($parent);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
5501
}
5502
interface IButtonControl
5503
{
5504
	public function getText();
5505
	public function setText($value);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
5506
	public function getCausesValidation();
5507
	public function setCausesValidation($value);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
5508
	public function getCommandName();
5509
	public function setCommandName($value);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
5510
	public function getCommandParameter();
5511
	public function setCommandParameter($value);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
5512
	public function getValidationGroup();
5513
	public function setValidationGroup($value);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
5514
	public function onClick($param);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
5515
	public function onCommand($param);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
5516
	public function setIsDefaultButton($value);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
5517
	public function getIsDefaultButton();
5518
}
5519
interface ISurroundable
5520
{
5521
	public function getSurroundingTag();
5522
	public function getSurroundingTagID();
5523
}
5524
class TBroadcastEventParameter extends TEventParameter
5525
{
5526
	private $_name;
5527
	private $_param;
5528
	public function __construct($name='',$parameter=null)
5529
	{
5530
		$this->_name=$name;
5531
		$this->_param=$parameter;
5532
	}
5533
	public function getName()
5534
	{
5535
		return $this->_name;
5536
	}
5537
	public function setName($value)
5538
	{
5539
		$this->_name=$value;
5540
	}
5541
	public function getParameter()
5542
	{
5543
		return $this->_param;
5544
	}
5545
	public function setParameter($value)
5546
	{
5547
		$this->_param=$value;
5548
	}
5549
}
5550
class TCommandEventParameter extends TEventParameter
5551
{
5552
	private $_name;
5553
	private $_param;
5554
	public function __construct($name='',$parameter='')
5555
	{
5556
		$this->_name=$name;
5557
		$this->_param=$parameter;
5558
	}
5559
	public function getCommandName()
5560
	{
5561
		return $this->_name;
5562
	}
5563
	public function getCommandParameter()
5564
	{
5565
		return $this->_param;
5566
	}
5567
}
5568
class TCompositeLiteral extends TComponent implements IRenderable, IBindable
5569
{
5570
	const TYPE_EXPRESSION=0;
5571
	const TYPE_STATEMENTS=1;
5572
	const TYPE_DATABINDING=2;
5573
	private $_container=null;
5574
	private $_items=array();
5575
	private $_expressions=array();
5576
	private $_statements=array();
5577
	private $_bindings=array();
5578
	public function __construct($items)
5579
	{
5580
		$this->_items=array();
5581
		$this->_expressions=array();
5582
		$this->_statements=array();
5583
		foreach($items as $id=>$item)
5584
		{
5585
			if(is_array($item))
5586
			{
5587
				if($item[0]===self::TYPE_EXPRESSION)
5588
					$this->_expressions[$id]=$item[1];
5589
				else if($item[0]===self::TYPE_STATEMENTS)
5590
					$this->_statements[$id]=$item[1];
5591
				else if($item[0]===self::TYPE_DATABINDING)
5592
					$this->_bindings[$id]=$item[1];
5593
				$this->_items[$id]='';
5594
			}
5595
			else
5596
				$this->_items[$id]=$item;
5597
		}
5598
	}
5599
	public function getContainer()
5600
	{
5601
		return $this->_container;
5602
	}
5603
	public function setContainer(TComponent $value)
5604
	{
5605
		$this->_container=$value;
5606
	}
5607
	public function evaluateDynamicContent()
5608
	{
5609
		$context=$this->_container===null?$this:$this->_container;
5610
		foreach($this->_expressions as $id=>$expression)
5611
			$this->_items[$id]=$context->evaluateExpression($expression);
5612
		foreach($this->_statements as $id=>$statement)
5613
			$this->_items[$id]=$context->evaluateStatements($statement);
5614
	}
5615
	public function dataBind()
5616
	{
5617
		$context=$this->_container===null?$this:$this->_container;
5618
		foreach($this->_bindings as $id=>$binding)
5619
			$this->_items[$id]=$context->evaluateExpression($binding);
5620
	}
5621
	public function render($writer)
5622
	{
5623
		$writer->write(implode('',$this->_items));
5624
	}
5625
}
5626
class TFont extends TComponent
5627
{
5628
	const IS_BOLD=0x01;
5629
	const IS_ITALIC=0x02;
5630
	const IS_OVERLINE=0x04;
5631
	const IS_STRIKEOUT=0x08;
5632
	const IS_UNDERLINE=0x10;
5633
	const IS_SET_BOLD=0x01000;
5634
	const IS_SET_ITALIC=0x02000;
5635
	const IS_SET_OVERLINE=0x04000;
5636
	const IS_SET_STRIKEOUT=0x08000;
5637
	const IS_SET_UNDERLINE=0x10000;
5638
	const IS_SET_SIZE=0x20000;
5639
	const IS_SET_NAME=0x40000;
5640
	private $_flags=0;
5641
	private $_name='';
5642
	private $_size='';
5643
	protected function _getZappableSleepProps(&$exprops)
5644
	{
5645
		parent::_getZappableSleepProps($exprops);
5646
		if ($this->_flags===0)
5647
			$exprops[] = "\0TFont\0_flags";
5648
		if ($this->_name==='')
5649
			$exprops[] = "\0TFont\0_name";
5650
		if ($this->_size==='')
5651
			$exprops[] = "\0TFont\0_size";
5652
	}
5653
	public function getBold()
5654
	{
5655
		return ($this->_flags & self::IS_BOLD)!==0;
5656
	}
5657
	public function setBold($value)
5658
	{
5659
		$this->_flags |= self::IS_SET_BOLD;
5660
		if(TPropertyValue::ensureBoolean($value))
5661
			$this->_flags |= self::IS_BOLD;
5662
		else
5663
			$this->_flags &= ~self::IS_BOLD;
5664
	}
5665
	public function getItalic()
5666
	{
5667
		return ($this->_flags & self::IS_ITALIC)!==0;
5668
	}
5669
	public function setItalic($value)
5670
	{
5671
		$this->_flags |= self::IS_SET_ITALIC;
5672
		if(TPropertyValue::ensureBoolean($value))
5673
			$this->_flags |= self::IS_ITALIC;
5674
		else
5675
			$this->_flags &= ~self::IS_ITALIC;
5676
	}
5677
	public function getOverline()
5678
	{
5679
		return ($this->_flags & self::IS_OVERLINE)!==0;
5680
	}
5681
	public function setOverline($value)
5682
	{
5683
		$this->_flags |= self::IS_SET_OVERLINE;
5684
		if(TPropertyValue::ensureBoolean($value))
5685
			$this->_flags |= self::IS_OVERLINE;
5686
		else
5687
			$this->_flags &= ~self::IS_OVERLINE;
5688
	}
5689
	public function getSize()
5690
	{
5691
		return $this->_size;
5692
	}
5693
	public function setSize($value)
5694
	{
5695
		$this->_flags |= self::IS_SET_SIZE;
5696
		$this->_size=$value;
5697
	}
5698
	public function getStrikeout()
5699
	{
5700
		return ($this->_flags & self::IS_STRIKEOUT)!==0;
5701
	}
5702
	public function setStrikeout($value)
5703
	{
5704
		$this->_flags |= self::IS_SET_STRIKEOUT;
5705
		if(TPropertyValue::ensureBoolean($value))
5706
			$this->_flags |= self::IS_STRIKEOUT;
5707
		else
5708
			$this->_flags &= ~self::IS_STRIKEOUT;
5709
	}
5710
	public function getUnderline()
5711
	{
5712
		return ($this->_flags & self::IS_UNDERLINE)!==0;
5713
	}
5714
	public function setUnderline($value)
5715
	{
5716
		$this->_flags |= self::IS_SET_UNDERLINE;
5717
		if(TPropertyValue::ensureBoolean($value))
5718
			$this->_flags |= self::IS_UNDERLINE;
5719
		else
5720
			$this->_flags &= ~self::IS_UNDERLINE;
5721
	}
5722
	public function getName()
5723
	{
5724
		return $this->_name;
5725
	}
5726
	public function setName($value)
5727
	{
5728
		$this->_flags |= self::IS_SET_NAME;
5729
		$this->_name=$value;
5730
	}
5731
	public function getIsEmpty()
5732
	{
5733
		return !$this->_flags;
5734
	}
5735
	public function reset()
5736
	{
5737
		$this->_flags=0;
5738
		$this->_name='';
5739
		$this->_size='';
5740
	}
5741
	public function mergeWith($font)
5742
	{
5743
		if($font===null || $font->_flags===0)
5744
			return;
5745
		if(!($this->_flags & self::IS_SET_BOLD) && ($font->_flags & self::IS_SET_BOLD))
5746
			$this->setBold($font->getBold());
5747
		if(!($this->_flags & self::IS_SET_ITALIC) && ($font->_flags & self::IS_SET_ITALIC))
5748
			$this->setItalic($font->getItalic());
5749
		if(!($this->_flags & self::IS_SET_OVERLINE) && ($font->_flags & self::IS_SET_OVERLINE))
5750
			$this->setOverline($font->getOverline());
5751
		if(!($this->_flags & self::IS_SET_STRIKEOUT) && ($font->_flags & self::IS_SET_STRIKEOUT))
5752
			$this->setStrikeout($font->getStrikeout());
5753
		if(!($this->_flags & self::IS_SET_UNDERLINE) && ($font->_flags & self::IS_SET_UNDERLINE))
5754
			$this->setUnderline($font->getUnderline());
5755
		if(!($this->_flags & self::IS_SET_SIZE) && ($font->_flags & self::IS_SET_SIZE))
5756
			$this->setSize($font->getSize());
5757
		if(!($this->_flags & self::IS_SET_NAME) && ($font->_flags & self::IS_SET_NAME))
5758
			$this->setName($font->getName());
5759
	}
5760
	public function copyFrom($font)
5761
	{
5762
		if($font===null || $font->_flags===0)
5763
			return;
5764
		if($font->_flags & self::IS_SET_BOLD)
5765
			$this->setBold($font->getBold());
5766
		if($font->_flags & self::IS_SET_ITALIC)
5767
			$this->setItalic($font->getItalic());
5768
		if($font->_flags & self::IS_SET_OVERLINE)
5769
			$this->setOverline($font->getOverline());
5770
		if($font->_flags & self::IS_SET_STRIKEOUT)
5771
			$this->setStrikeout($font->getStrikeout());
5772
		if($font->_flags & self::IS_SET_UNDERLINE)
5773
			$this->setUnderline($font->getUnderline());
5774
		if($font->_flags & self::IS_SET_SIZE)
5775
			$this->setSize($font->getSize());
5776
		if($font->_flags & self::IS_SET_NAME)
5777
			$this->setName($font->getName());
5778
	}
5779
	public function toString()
5780
	{
5781
		if($this->_flags===0)
5782
			return '';
5783
		$str='';
5784
		if($this->_flags & self::IS_SET_BOLD)
5785
			$str.='font-weight:'.(($this->_flags & self::IS_BOLD)?'bold;':'normal;');
5786
		if($this->_flags & self::IS_SET_ITALIC)
5787
			$str.='font-style:'.(($this->_flags & self::IS_ITALIC)?'italic;':'normal;');
5788
		$textDec='';
5789
		if($this->_flags & self::IS_UNDERLINE)
5790
			$textDec.='underline';
5791
		if($this->_flags & self::IS_OVERLINE)
5792
			$textDec.=' overline';
5793
		if($this->_flags & self::IS_STRIKEOUT)
5794
			$textDec.=' line-through';
5795
		$textDec=ltrim($textDec);
5796
		if($textDec!=='')
5797
			$str.='text-decoration:'.$textDec.';';
5798
		if($this->_size!=='')
5799
			$str.='font-size:'.$this->_size.';';
5800
		if($this->_name!=='')
5801
			$str.='font-family:'.$this->_name.';';
5802
		return $str;
5803
	}
5804
	public function addAttributesToRender($writer)
5805
	{
5806
		if($this->_flags===0)
5807
			return;
5808
		if($this->_flags & self::IS_SET_BOLD)
5809
			$writer->addStyleAttribute('font-weight',(($this->_flags & self::IS_BOLD)?'bold':'normal'));
5810
		if($this->_flags & self::IS_SET_ITALIC)
5811
			$writer->addStyleAttribute('font-style',(($this->_flags & self::IS_ITALIC)?'italic':'normal'));
5812
		$textDec='';
5813
		if($this->_flags & self::IS_UNDERLINE)
5814
			$textDec.='underline';
5815
		if($this->_flags & self::IS_OVERLINE)
5816
			$textDec.=' overline';
5817
		if($this->_flags & self::IS_STRIKEOUT)
5818
			$textDec.=' line-through';
5819
		$textDec=ltrim($textDec);
5820
		if($textDec!=='')
5821
			$writer->addStyleAttribute('text-decoration',$textDec);
5822
		if($this->_size!=='')
5823
			$writer->addStyleAttribute('font-size',$this->_size);
5824
		if($this->_name!=='')
5825
			$writer->addStyleAttribute('font-family',$this->_name);
5826
	}
5827
}
5828
class TStyle extends TComponent
5829
{
5830
	private $_fields=array();
5831
	private $_font=null;
5832
	private $_class=null;
5833
	private $_customStyle=null;
5834
	private $_displayStyle='Fixed';
5835
	protected function _getZappableSleepProps(&$exprops)
5836
	{
5837
		parent::_getZappableSleepProps($exprops);
5838
		if ($this->_fields===array())
5839
			$exprops[] = "\0TStyle\0_fields";
5840
		if($this->_font===null)
5841
			$exprops[] = "\0TStyle\0_font";
5842
		if($this->_class===null)
5843
			$exprops[] = "\0TStyle\0_class";
5844
		if ($this->_customStyle===null)
5845
			$exprops[] = "\0TStyle\0_customStyle";
5846
		if ($this->_displayStyle==='Fixed')
5847
			$exprops[] = "\0TStyle\0_displayStyle";
5848
	}
5849
	public function __construct($style=null)
5850
	{
5851
		if($style!==null)
5852
			$this->copyFrom($style);
5853
	}
5854
	public function __clone()
5855
	{
5856
		if($this->_font!==null)
5857
			$this->_font = clone($this->_font);
5858
	}
5859
	public function getBackColor()
5860
	{
5861
		return isset($this->_fields['background-color'])?$this->_fields['background-color']:'';
5862
	}
5863
	public function setBackColor($value)
5864
	{
5865
		if(trim($value)==='')
5866
			unset($this->_fields['background-color']);
5867
		else
5868
			$this->_fields['background-color']=$value;
5869
	}
5870
	public function getBorderColor()
5871
	{
5872
		return isset($this->_fields['border-color'])?$this->_fields['border-color']:'';
5873
	}
5874
	public function setBorderColor($value)
5875
	{
5876
		if(trim($value)==='')
5877
			unset($this->_fields['border-color']);
5878
		else
5879
			$this->_fields['border-color']=$value;
5880
	}
5881
	public function getBorderStyle()
5882
	{
5883
		return isset($this->_fields['border-style'])?$this->_fields['border-style']:'';
5884
	}
5885
	public function setBorderStyle($value)
5886
	{
5887
		if(trim($value)==='')
5888
			unset($this->_fields['border-style']);
5889
		else
5890
			$this->_fields['border-style']=$value;
5891
	}
5892
	public function getBorderWidth()
5893
	{
5894
		return isset($this->_fields['border-width'])?$this->_fields['border-width']:'';
5895
	}
5896
	public function setBorderWidth($value)
5897
	{
5898
		if(trim($value)==='')
5899
			unset($this->_fields['border-width']);
5900
		else
5901
			$this->_fields['border-width']=$value;
5902
	}
5903
	public function getCssClass()
5904
	{
5905
		return $this->_class===null?'':$this->_class;
5906
	}
5907
	public function hasCssClass()
5908
	{
5909
		return ($this->_class!==null);
5910
	}
5911
	public function setCssClass($value)
5912
	{
5913
		$this->_class=$value;
5914
	}
5915
	public function getFont()
5916
	{
5917
		if($this->_font===null)
5918
			$this->_font=new TFont;
5919
		return $this->_font;
5920
	}
5921
	public function hasFont()
5922
	{
5923
		return $this->_font !== null;
5924
	}
5925
	public function setDisplayStyle($value)
5926
	{
5927
		$this->_displayStyle = TPropertyValue::ensureEnum($value, 'TDisplayStyle');
5928
		switch($this->_displayStyle)
5929
		{
5930
			case TDisplayStyle::None:
5931
				$this->_fields['display'] = 'none';
5932
				break;
5933
			case TDisplayStyle::Dynamic:
5934
				$this->_fields['display'] = ''; 				break;
0 ignored issues
show
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
5935
			case TDisplayStyle::Fixed:
5936
				$this->_fields['visibility'] = 'visible';
5937
				break;
5938
			case TDisplayStyle::Hidden:
5939
				$this->_fields['visibility'] = 'hidden';
5940
				break;
5941
		}
5942
	}
5943
	public function getDisplayStyle()
5944
	{
5945
		return $this->_displayStyle;
5946
	}
5947
	public function getForeColor()
5948
	{
5949
		return isset($this->_fields['color'])?$this->_fields['color']:'';
5950
	}
5951
	public function setForeColor($value)
5952
	{
5953
		if(trim($value)==='')
5954
			unset($this->_fields['color']);
5955
		else
5956
			$this->_fields['color']=$value;
5957
	}
5958
	public function getHeight()
5959
	{
5960
		return isset($this->_fields['height'])?$this->_fields['height']:'';
5961
	}
5962
	public function setHeight($value)
5963
	{
5964
		if(trim($value)==='')
5965
			unset($this->_fields['height']);
5966
		else
5967
			$this->_fields['height']=$value;
5968
	}
5969
	public function getCustomStyle()
5970
	{
5971
		return $this->_customStyle===null?'':$this->_customStyle;
5972
	}
5973
	public function setCustomStyle($value)
5974
	{
5975
		$this->_customStyle=$value;
5976
	}
5977
	public function getStyleField($name)
5978
	{
5979
		return isset($this->_fields[$name])?$this->_fields[$name]:'';
5980
	}
5981
	public function setStyleField($name,$value)
5982
	{
5983
		$this->_fields[$name]=$value;
5984
	}
5985
	public function clearStyleField($name)
5986
	{
5987
		unset($this->_fields[$name]);
5988
	}
5989
	public function hasStyleField($name)
5990
	{
5991
		return isset($this->_fields[$name]);
5992
	}
5993
	public function getWidth()
5994
	{
5995
		return isset($this->_fields['width'])?$this->_fields['width']:'';
5996
	}
5997
	public function setWidth($value)
5998
	{
5999
		$this->_fields['width']=$value;
6000
	}
6001
	public function reset()
6002
	{
6003
		$this->_fields=array();
6004
		$this->_font=null;
6005
		$this->_class=null;
6006
		$this->_customStyle=null;
6007
	}
6008
	public function copyFrom($style)
6009
	{
6010
		if($style instanceof TStyle)
6011
		{
6012
			$this->_fields=array_merge($this->_fields,$style->_fields);
6013
			if($style->_class!==null)
6014
				$this->_class=$style->_class;
6015
			if($style->_customStyle!==null)
6016
				$this->_customStyle=$style->_customStyle;
6017
			if($style->_font!==null)
6018
				$this->getFont()->copyFrom($style->_font);
6019
		}
6020
	}
6021
	public function mergeWith($style)
6022
	{
6023
		if($style instanceof TStyle)
6024
		{
6025
			$this->_fields=array_merge($style->_fields,$this->_fields);
6026
			if($this->_class===null)
6027
				$this->_class=$style->_class;
6028
			if($this->_customStyle===null)
6029
				$this->_customStyle=$style->_customStyle;
6030
			if($style->_font!==null)
6031
				$this->getFont()->mergeWith($style->_font);
6032
		}
6033
	}
6034
	public function addAttributesToRender($writer)
6035
	{
6036
		if($this->_customStyle!==null)
6037
		{
6038
			foreach(explode(';',$this->_customStyle) as $style)
6039
			{
6040
				$arr=explode(':',$style,2);
6041
				if(isset($arr[1]) && trim($arr[0])!=='')
6042
					$writer->addStyleAttribute(trim($arr[0]),trim($arr[1]));
6043
			}
6044
		}
6045
		$writer->addStyleAttributes($this->_fields);
6046
		if($this->_font!==null)
6047
			$this->_font->addAttributesToRender($writer);
6048
		if($this->_class!==null)
6049
			$writer->addAttribute('class',$this->_class);
6050
	}
6051
	public function getStyleFields()
6052
	{
6053
		return $this->_fields;
6054
	}
6055
}
6056
class TDisplayStyle extends TEnumerable
6057
{
6058
	const None='None';
6059
	const Dynamic='Dynamic';
6060
	const Fixed='Fixed';
6061
	const Hidden='Hidden';
6062
}
6063
class TTableStyle extends TStyle
6064
{
6065
	private $_backImageUrl=null;
6066
	private $_horizontalAlign=null;
6067
	private $_cellPadding=null;
6068
	private $_cellSpacing=null;
6069
	private $_gridLines=null;
6070
	private $_borderCollapse=null;
6071
	protected function _getZappableSleepProps(&$exprops)
6072
	{
6073
		parent::_getZappableSleepProps($exprops);
6074
		if ($this->_backImageUrl===null)
6075
			$exprops[] = "\0TTableStyle\0_backImageUrl";
6076
		if ($this->_horizontalAlign===null)
6077
			$exprops[] = "\0TTableStyle\0_horizontalAlign";
6078
		if ($this->_cellPadding===null)
6079
			$exprops[] = "\0TTableStyle\0_cellPadding";
6080
		if ($this->_cellSpacing===null)
6081
			$exprops[] = "\0TTableStyle\0_cellSpacing";
6082
		if ($this->_gridLines===null)
6083
			$exprops[] = "\0TTableStyle\0_gridLines";
6084
		if ($this->_borderCollapse===null)
6085
			$exprops[] = "\0TTableStyle\0_borderCollapse";
6086
	}
6087
	public function reset()
6088
	{
6089
		$this->_backImageUrl=null;
6090
		$this->_horizontalAlign=null;
6091
		$this->_cellPadding=null;
6092
		$this->_cellSpacing=null;
6093
		$this->_gridLines=null;
6094
		$this->_borderCollapse=null;
6095
	}
6096
	public function copyFrom($style)
6097
	{
6098
		parent::copyFrom($style);
6099
		if($style instanceof TTableStyle)
6100
		{
6101
			if($style->_backImageUrl!==null)
6102
				$this->_backImageUrl=$style->_backImageUrl;
6103
			if($style->_horizontalAlign!==null)
6104
				$this->_horizontalAlign=$style->_horizontalAlign;
6105
			if($style->_cellPadding!==null)
6106
				$this->_cellPadding=$style->_cellPadding;
6107
			if($style->_cellSpacing!==null)
6108
				$this->_cellSpacing=$style->_cellSpacing;
6109
			if($style->_gridLines!==null)
6110
				$this->_gridLines=$style->_gridLines;
6111
			if($style->_borderCollapse!==null)
6112
				$this->_borderCollapse=$style->_borderCollapse;
6113
		}
6114
	}
6115
	public function mergeWith($style)
6116
	{
6117
		parent::mergeWith($style);
6118
		if($style instanceof TTableStyle)
6119
		{
6120
			if($this->_backImageUrl===null && $style->_backImageUrl!==null)
6121
				$this->_backImageUrl=$style->_backImageUrl;
6122
			if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
6123
				$this->_horizontalAlign=$style->_horizontalAlign;
6124
			if($this->_cellPadding===null && $style->_cellPadding!==null)
6125
				$this->_cellPadding=$style->_cellPadding;
6126
			if($this->_cellSpacing===null && $style->_cellSpacing!==null)
6127
				$this->_cellSpacing=$style->_cellSpacing;
6128
			if($this->_gridLines===null && $style->_gridLines!==null)
6129
				$this->_gridLines=$style->_gridLines;
6130
			if($this->_borderCollapse===null && $style->_borderCollapse!==null)
6131
				$this->_borderCollapse=$style->_borderCollapse;
6132
		}
6133
	}
6134
	public function addAttributesToRender($writer)
6135
	{
6136
		if(($url=trim($this->getBackImageUrl()))!=='')
6137
			$writer->addStyleAttribute('background-image','url('.$url.')');
6138
		if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
6139
			$writer->addStyleAttribute('text-align',strtolower($horizontalAlign));
6140
		if(($cellPadding=$this->getCellPadding())>=0)
6141
			$writer->addAttribute('cellpadding',"$cellPadding");
6142
		if(($cellSpacing=$this->getCellSpacing())>=0)
6143
			$writer->addAttribute('cellspacing',"$cellSpacing");
6144
		if($this->getBorderCollapse())
6145
			$writer->addStyleAttribute('border-collapse','collapse');
6146
		switch($this->getGridLines())
6147
		{
6148
			case TTableGridLines::Horizontal : $writer->addAttribute('rules','rows'); break;
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
6149
			case TTableGridLines::Vertical : $writer->addAttribute('rules','cols'); break;
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
6150
			case TTableGridLines::Both : $writer->addAttribute('rules','all'); break;
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
6151
		}
6152
		parent::addAttributesToRender($writer);
6153
	}
6154
	public function getBackImageUrl()
6155
	{
6156
		return $this->_backImageUrl===null?'':$this->_backImageUrl;
6157
	}
6158
	public function setBackImageUrl($value)
6159
	{
6160
		$this->_backImageUrl=$value;
6161
	}
6162
	public function getHorizontalAlign()
6163
	{
6164
		return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
6165
	}
6166
	public function setHorizontalAlign($value)
6167
	{
6168
		$this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
6169
	}
6170
	public function getCellPadding()
6171
	{
6172
		return $this->_cellPadding===null?-1:$this->_cellPadding;
6173
	}
6174
	public function setCellPadding($value)
6175
	{
6176
		if(($this->_cellPadding=TPropertyValue::ensureInteger($value))<-1)
6177
			throw new TInvalidDataValueException('tablestyle_cellpadding_invalid');
6178
	}
6179
	public function getCellSpacing()
6180
	{
6181
		return $this->_cellSpacing===null?-1:$this->_cellSpacing;
6182
	}
6183
	public function setCellSpacing($value)
6184
	{
6185
		if(($this->_cellSpacing=TPropertyValue::ensureInteger($value))<-1)
6186
			throw new TInvalidDataValueException('tablestyle_cellspacing_invalid');
6187
	}
6188
	public function getGridLines()
6189
	{
6190
		return $this->_gridLines===null?TTableGridLines::None:$this->_gridLines;
6191
	}
6192
	public function setGridLines($value)
6193
	{
6194
		$this->_gridLines=TPropertyValue::ensureEnum($value,'TTableGridLines');
6195
	}
6196
	public function getBorderCollapse()
6197
	{
6198
		return $this->_borderCollapse===null?false:$this->_borderCollapse;
6199
	}
6200
	public function setBorderCollapse($value)
6201
	{
6202
		$this->_borderCollapse=TPropertyValue::ensureBoolean($value);
6203
	}
6204
}
6205
class TTableItemStyle extends TStyle
6206
{
6207
	private $_horizontalAlign=null;
6208
	private $_verticalAlign=null;
6209
	private $_wrap=null;
6210
	protected function _getZappableSleepProps(&$exprops)
6211
	{
6212
		parent::_getZappableSleepProps($exprops);
6213
		if ($this->_horizontalAlign===null)
6214
			$exprops[] = "\0TTableItemStyle\0_horizontalAlign";
6215
		if ($this->_verticalAlign===null)
6216
			$exprops[] = "\0TTableItemStyle\0_verticalAlign";
6217
		if ($this->_wrap===null)
6218
			$exprops[] = "\0TTableItemStyle\0_wrap";
6219
	}
6220
	public function reset()
6221
	{
6222
		parent::reset();
6223
		$this->_verticalAlign=null;
6224
		$this->_horizontalAlign=null;
6225
		$this->_wrap=null;
6226
	}
6227
	public function copyFrom($style)
6228
	{
6229
		parent::copyFrom($style);
6230
		if($style instanceof TTableItemStyle)
6231
		{
6232
			if($this->_verticalAlign===null && $style->_verticalAlign!==null)
6233
				$this->_verticalAlign=$style->_verticalAlign;
6234
			if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
6235
				$this->_horizontalAlign=$style->_horizontalAlign;
6236
			if($this->_wrap===null && $style->_wrap!==null)
6237
				$this->_wrap=$style->_wrap;
6238
		}
6239
	}
6240
	public function mergeWith($style)
6241
	{
6242
		parent::mergeWith($style);
6243
		if($style instanceof TTableItemStyle)
6244
		{
6245
			if($style->_verticalAlign!==null)
6246
				$this->_verticalAlign=$style->_verticalAlign;
6247
			if($style->_horizontalAlign!==null)
6248
				$this->_horizontalAlign=$style->_horizontalAlign;
6249
			if($style->_wrap!==null)
6250
				$this->_wrap=$style->_wrap;
6251
		}
6252
	}
6253
	public function addAttributesToRender($writer)
6254
	{
6255
		if(!$this->getWrap())
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->getWrap() of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
6256
			$writer->addStyleAttribute('white-space','nowrap');
6257
		if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
6258
			$writer->addAttribute('align',strtolower($horizontalAlign));
6259
		if(($verticalAlign=$this->getVerticalAlign())!==TVerticalAlign::NotSet)
6260
			$writer->addAttribute('valign',strtolower($verticalAlign));
6261
		parent::addAttributesToRender($writer);
6262
	}
6263
	public function getHorizontalAlign()
6264
	{
6265
		return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
6266
	}
6267
	public function setHorizontalAlign($value)
6268
	{
6269
		$this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
6270
	}
6271
	public function getVerticalAlign()
6272
	{
6273
		return $this->_verticalAlign===null?TVerticalAlign::NotSet:$this->_verticalAlign;
6274
	}
6275
	public function setVerticalAlign($value)
6276
	{
6277
		$this->_verticalAlign=TPropertyValue::ensureEnum($value,'TVerticalAlign');
6278
	}
6279
	public function getWrap()
6280
	{
6281
		return $this->_wrap===null?true:$this->_wrap;
6282
	}
6283
	public function setWrap($value)
6284
	{
6285
		$this->_wrap=TPropertyValue::ensureBoolean($value);
6286
	}
6287
}
6288
class THorizontalAlign extends TEnumerable
6289
{
6290
	const NotSet='NotSet';
6291
	const Left='Left';
6292
	const Right='Right';
6293
	const Center='Center';
6294
	const Justify='Justify';
6295
}
6296
class TVerticalAlign extends TEnumerable
6297
{
6298
	const NotSet='NotSet';
6299
	const Top='Top';
6300
	const Bottom='Bottom';
6301
	const Middle='Middle';
6302
}
6303
class TTableGridLines extends TEnumerable
6304
{
6305
	const None='None';
6306
	const Horizontal='Horizontal';
6307
	const Vertical='Vertical';
6308
	const Both='Both';
6309
}
6310
class TWebControlAdapter extends TControlAdapter
6311
{
6312
	public function render($writer)
6313
	{
6314
		$this->renderBeginTag($writer);
6315
		$this->renderContents($writer);
6316
		$this->renderEndTag($writer);
6317
	}
6318
	public function renderBeginTag($writer)
6319
	{
6320
		$this->getControl()->renderBeginTag($writer);
6321
	}
6322
	public function renderContents($writer)
6323
	{
6324
		$this->getControl()->renderContents($writer);
6325
	}
6326
	public function renderEndTag($writer)
6327
	{
6328
		$this->getControl()->renderEndTag($writer);
6329
	}
6330
}
6331
class TWebControlDecorator extends TComponent {
6332
	private $_internalonly;
6333
	private $_usestate = false;
6334
	private $_control;
6335
	private $_outercontrol;
6336
	private $_addedTemplateDecoration=false;
6337
	private $_pretagtext = '';
6338
	private $_precontentstext = '';
6339
	private $_postcontentstext = '';
6340
	private $_posttagtext = '';
6341
	private $_pretagtemplate;
6342
	private $_precontentstemplate;
6343
	private $_postcontentstemplate;
6344
	private $_posttagtemplate;
6345
	public function __construct($control, $onlyinternal = false) {
6346
		$this->_control = $control;
6347
		$this->_internalonly = $onlyinternal;
6348
	}
6349
	public function getUseState()
6350
	{
6351
		return $this->_usestate;
6352
	}
6353
	public function setUseState($value)
6354
	{
6355
		$this->_usestate = TPropertyValue::ensureBoolean($value);
6356
	}
6357
	public function getPreTagText() {
6358
		return $this->_pretagtext;
6359
	}
6360
	public function setPreTagText($value) {
6361
		if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
6362
			$this->_pretagtext = TPropertyValue::ensureString($value);
6363
	}
6364
	public function getPreContentsText() {
6365
		return $this->_precontentstext;
6366
	}
6367
	public function setPreContentsText($value) {
6368
		if(!$this->_control->getIsSkinApplied())
6369
			$this->_precontentstext = TPropertyValue::ensureString($value);
6370
	}
6371
	public function getPostContentsText() {
6372
		return $this->_postcontentstext;
6373
	}
6374
	public function setPostContentsText($value) {
6375
		if(!$this->_control->getIsSkinApplied())
6376
			$this->_postcontentstext = TPropertyValue::ensureString($value);
6377
	}
6378
	public function getPostTagText() {
6379
		return $this->_posttagtext;
6380
	}
6381
	public function setPostTagText($value) {
6382
		if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
6383
			$this->_posttagtext = TPropertyValue::ensureString($value);
6384
	}
6385
	public function getPreTagTemplate() {
6386
		return $this->_pretagtemplate;
6387
	}
6388
	public function setPreTagTemplate($value) {
6389
		if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
6390
			$this->_pretagtemplate = $value;
6391
	}
6392
	public function getPreContentsTemplate() {
6393
		return $this->_precontentstemplate;
6394
	}
6395
	public function setPreContentsTemplate($value) {
6396
		if(!$this->_control->getIsSkinApplied())
6397
			$this->_precontentstemplate = $value;
6398
	}
6399
	public function getPostContentsTemplate() {
6400
		return $this->_postcontentstemplate;
6401
	}
6402
	public function setPostContentsTemplate($value) {
6403
		if(!$this->_control->getIsSkinApplied())
6404
			$this->_postcontentstemplate = $value;
6405
	}
6406
	public function getPostTagTemplate() {
6407
		return $this->_posttagtemplate;
6408
	}
6409
	public function setPostTagTemplate($value) {
6410
		if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
6411
			$this->_posttagtemplate = $value;
6412
	}
6413
	public function instantiate($outercontrol = null) {
6414
		if($this->getPreTagTemplate() || $this->getPreContentsTemplate() ||
6415
			$this->getPostContentsTemplate() || $this->getPostTagTemplate()) {
6416
			$this->_outercontrol = $outercontrol;
6417
			if($this->getUseState())
6418
				$this->ensureTemplateDecoration();
6419
			else
6420
				$this->_control->getPage()->onSaveStateComplete[] = array($this, 'ensureTemplateDecoration');
6421
		}
6422
	}
6423
	public function ensureTemplateDecoration($sender=null, $param=null) {
6424
		$control = $this->_control;
6425
		$outercontrol = $this->_outercontrol;
6426
		if($outercontrol === null)
6427
			$outercontrol = $control;
6428
		if($this->_addedTemplateDecoration)
6429
			return $this->_addedTemplateDecoration;
6430
		$this->_addedTemplateDecoration = true;
6431
		if($this->getPreContentsTemplate())
6432
		{
6433
			$precontents = Prado::createComponent('TCompositeControl');
6434
			$this->getPreContentsTemplate()->instantiateIn($precontents);
6435
			$control->getControls()->insertAt(0, $precontents);
6436
		}
6437
		if($this->getPostContentsTemplate())
6438
		{
6439
			$postcontents = Prado::createComponent('TCompositeControl');
6440
			$this->getPostContentsTemplate()->instantiateIn($postcontents);
6441
			$control->getControls()->add($postcontents);
6442
		}
6443
		if(!$outercontrol->getParent())
6444
			return $this->_addedTemplateDecoration;
6445
		if($this->getPreTagTemplate())
6446
		{
6447
			$pretag = Prado::createComponent('TCompositeControl');
6448
			$this->getPreTagTemplate()->instantiateIn($pretag);
6449
			$outercontrol->getParent()->getControls()->insertBefore($outercontrol, $pretag);
6450
		}
6451
		if($this->getPostTagTemplate())
6452
		{
6453
			$posttag = Prado::createComponent('TCompositeControl');
6454
			$this->getPostTagTemplate()->instantiateIn($posttag);
6455
			$outercontrol->getParent()->getControls()->insertAfter($outercontrol, $posttag);
6456
		}
6457
		return true;
6458
	}
6459
	public function renderPreTagText($writer) {
6460
		$writer->write($this->getPreTagText());
6461
	}
6462
	public function renderPreContentsText($writer) {
6463
		$writer->write($this->getPreContentsText());
6464
	}
6465
	public function renderPostContentsText($writer) {
6466
		$writer->write($this->getPostContentsText());
6467
	}
6468
	public function renderPostTagText($writer) {
6469
		$writer->write($this->getPostTagText());
6470
	}
6471
}
6472
class TWebControl extends TControl implements IStyleable
6473
{
6474
	private $_ensureid=false;
6475
	protected $_decorator;
6476
	public function setEnsureId($value)
6477
	{
6478
		$this->_ensureid |= TPropertyValue::ensureBoolean($value);
6479
	}
6480
	public function getEnsureId()
6481
	{
6482
		return $this->_ensureid;
6483
	}
6484
	public function getDecorator($create=true)
6485
	{
6486
		if($create && !$this->_decorator)
6487
			$this->_decorator = Prado::createComponent('TWebControlDecorator', $this);
6488
		return $this->_decorator;
6489
	}
6490
	public function copyBaseAttributes(TWebControl $control)
6491
	{
6492
		$this->setAccessKey($control->getAccessKey());
6493
		$this->setToolTip($control->getToolTip());
6494
		$this->setTabIndex($control->getTabIndex());
6495
		if(!$control->getEnabled())
6496
			$this->setEnabled(false);
6497
		if($control->getHasAttributes())
6498
			$this->getAttributes()->copyFrom($control->getAttributes());
6499
	}
6500
	public function getAccessKey()
6501
	{
6502
		return $this->getViewState('AccessKey','');
6503
	}
6504
	public function setAccessKey($value)
6505
	{
6506
		if(strlen($value)>1)
6507
			throw new TInvalidDataValueException('webcontrol_accesskey_invalid',get_class($this),$value);
6508
		$this->setViewState('AccessKey',$value,'');
6509
	}
6510
	public function getBackColor()
6511
	{
6512
		if($style=$this->getViewState('Style',null))
6513
			return $style->getBackColor();
6514
		else
6515
			return '';
6516
	}
6517
	public function setBackColor($value)
6518
	{
6519
		$this->getStyle()->setBackColor($value);
6520
	}
6521
	public function getBorderColor()
6522
	{
6523
		if($style=$this->getViewState('Style',null))
6524
			return $style->getBorderColor();
6525
		else
6526
			return '';
6527
	}
6528
	public function setBorderColor($value)
6529
	{
6530
		$this->getStyle()->setBorderColor($value);
6531
	}
6532
	public function getBorderStyle()
6533
	{
6534
		if($style=$this->getViewState('Style',null))
6535
			return $style->getBorderStyle();
6536
		else
6537
			return '';
6538
	}
6539
	public function setBorderStyle($value)
6540
	{
6541
		$this->getStyle()->setBorderStyle($value);
6542
	}
6543
	public function getBorderWidth()
6544
	{
6545
		if($style=$this->getViewState('Style',null))
6546
			return $style->getBorderWidth();
6547
		else
6548
			return '';
6549
	}
6550
	public function setBorderWidth($value)
6551
	{
6552
		$this->getStyle()->setBorderWidth($value);
6553
	}
6554
	public function getFont()
6555
	{
6556
		return $this->getStyle()->getFont();
6557
	}
6558
	public function getForeColor()
6559
	{
6560
		if($style=$this->getViewState('Style',null))
6561
			return $style->getForeColor();
6562
		else
6563
			return '';
6564
	}
6565
	public function setForeColor($value)
6566
	{
6567
		$this->getStyle()->setForeColor($value);
6568
	}
6569
	public function getHeight()
6570
	{
6571
		if($style=$this->getViewState('Style',null))
6572
			return $style->getHeight();
6573
		else
6574
			return '';
6575
	}
6576
	public function setDisplay($value)
6577
	{
6578
		$this->getStyle()->setDisplayStyle($value);
6579
	}
6580
	public function getDisplay()
6581
	{
6582
		return $this->getStyle()->getDisplayStyle();
6583
	}
6584
	public function setCssClass($value)
6585
	{
6586
		$this->getStyle()->setCssClass($value);
6587
	}
6588
	public function getCssClass()
6589
	{
6590
		if($style=$this->getViewState('Style',null))
6591
			return $style->getCssClass();
6592
		else
6593
			return '';
6594
	}
6595
	public function setHeight($value)
6596
	{
6597
		$this->getStyle()->setHeight($value);
6598
	}
6599
	public function getHasStyle()
6600
	{
6601
		return $this->getViewState('Style',null)!==null;
6602
	}
6603
	protected function createStyle()
6604
	{
6605
		return new TStyle;
6606
	}
6607
	public function getStyle()
6608
	{
6609
		if($style=$this->getViewState('Style',null))
6610
			return $style;
6611
		else
6612
		{
6613
			$style=$this->createStyle();
6614
			$this->setViewState('Style',$style,null);
6615
			return $style;
6616
		}
6617
	}
6618
	public function setStyle($value)
6619
	{
6620
		if(is_string($value))
6621
			$this->getStyle()->setCustomStyle($value);
6622
		else
6623
			throw new TInvalidDataValueException('webcontrol_style_invalid',get_class($this));
6624
	}
6625
	public function clearStyle()
6626
	{
6627
		$this->clearViewState('Style');
6628
	}
6629
	public function getTabIndex()
6630
	{
6631
		return $this->getViewState('TabIndex',0);
6632
	}
6633
	public function setTabIndex($value)
6634
	{
6635
		$this->setViewState('TabIndex',TPropertyValue::ensureInteger($value),0);
6636
	}
6637
	protected function getTagName()
6638
	{
6639
		return 'span';
6640
	}
6641
	public function getToolTip()
6642
	{
6643
		return $this->getViewState('ToolTip','');
6644
	}
6645
	public function setToolTip($value)
6646
	{
6647
		$this->setViewState('ToolTip',$value,'');
6648
	}
6649
	public function getWidth()
6650
	{
6651
		if($style=$this->getViewState('Style',null))
6652
			return $style->getWidth();
6653
		else
6654
			return '';
6655
	}
6656
	public function setWidth($value)
6657
	{
6658
		$this->getStyle()->setWidth($value);
6659
	}
6660
	public function onPreRender($param) {
6661
		if($decorator = $this->getDecorator(false))
6662
			$decorator->instantiate();
6663
		parent::onPreRender($param);
6664
	}
6665
	protected function addAttributesToRender($writer)
6666
	{
6667
		if($this->getID()!=='' || $this->getEnsureId())
6668
			$writer->addAttribute('id',$this->getClientID());
6669
		if(($accessKey=$this->getAccessKey())!=='')
6670
			$writer->addAttribute('accesskey',$accessKey);
6671
		if(!$this->getEnabled())
6672
			$writer->addAttribute('disabled','disabled');
6673
		if(($tabIndex=$this->getTabIndex())>0)
6674
			$writer->addAttribute('tabindex',"$tabIndex");
6675
		if(($toolTip=$this->getToolTip())!=='')
6676
			$writer->addAttribute('title',$toolTip);
6677
		if($style=$this->getViewState('Style',null))
6678
			$style->addAttributesToRender($writer);
6679
		if($this->getHasAttributes())
6680
		{
6681
			foreach($this->getAttributes() as $name=>$value)
6682
				$writer->addAttribute($name,$value);
6683
		}
6684
	}
6685
	public function render($writer)
6686
	{
6687
		$this->renderBeginTag($writer);
6688
		$this->renderContents($writer);
6689
		$this->renderEndTag($writer);
6690
	}
6691
	public function renderBeginTag($writer)
6692
	{
6693
		if($decorator = $this->getDecorator(false)) {
6694
			$decorator->renderPreTagText($writer);
6695
			$this->addAttributesToRender($writer);
6696
			$writer->renderBeginTag($this->getTagName());
6697
			$decorator->renderPreContentsText($writer);
6698
		} else {
6699
			$this->addAttributesToRender($writer);
6700
			$writer->renderBeginTag($this->getTagName());
6701
		}
6702
	}
6703
	public function renderContents($writer)
6704
	{
6705
		parent::renderChildren($writer);
6706
	}
6707
	public function renderEndTag($writer)
6708
	{
6709
		if($decorator = $this->getDecorator(false)) {
6710
			$decorator->renderPostContentsText($writer);
6711
			$writer->renderEndTag();
6712
			$decorator->renderPostTagText($writer);
6713
		} else
6714
			$writer->renderEndTag($writer);
6715
	}
6716
}
6717
class TCompositeControl extends TControl implements INamingContainer
6718
{
6719
	protected function initRecursive($namingContainer=null)
6720
	{
6721
		$this->ensureChildControls();
6722
		parent::initRecursive($namingContainer);
6723
	}
6724
}
6725
class TTemplateControl extends TCompositeControl
6726
{
6727
	const EXT_TEMPLATE='.tpl';
6728
	private static $_template=array();
6729
	private $_localTemplate=null;
6730
	private $_master=null;
6731
	private $_masterClass='';
6732
	private $_contents=array();
6733
	private $_placeholders=array();
6734
	public function getTemplate()
6735
	{
6736
		if($this->_localTemplate===null)
6737
		{
6738
			$class=get_class($this);
6739
			if(!isset(self::$_template[$class]))
6740
				self::$_template[$class]=$this->loadTemplate();
6741
			return self::$_template[$class];
6742
		}
6743
		else
6744
			return $this->_localTemplate;
6745
	}
6746
	public function setTemplate($value)
6747
	{
6748
		$this->_localTemplate=$value;
6749
	}
6750
	public function getIsSourceTemplateControl()
6751
	{
6752
		if(($template=$this->getTemplate())!==null)
6753
			return $template->getIsSourceTemplate();
6754
		else
6755
			return false;
6756
	}
6757
	public function getTemplateDirectory()
6758
	{
6759
		if(($template=$this->getTemplate())!==null)
6760
			return $template->getContextPath();
6761
		else
6762
			return '';
6763
	}
6764
	protected function loadTemplate()
6765
	{
6766
		$template=$this->getService()->getTemplateManager()->getTemplateByClassName(get_class($this));
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface IService as the method getTemplateManager() does only exist in the following implementations of said interface: TPageService, TWsatService.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
6767
		return $template;
6768
	}
6769
	public function createChildControls()
6770
	{
6771
		if($tpl=$this->getTemplate())
6772
		{
6773
			foreach($tpl->getDirective() as $name=>$value)
6774
			{
6775
				if(is_string($value))
6776
					$this->setSubProperty($name,$value);
6777
				else
6778
					throw new TConfigurationException('templatecontrol_directive_invalid',get_class($this),$name);
6779
			}
6780
			$tpl->instantiateIn($this);
6781
		}
6782
	}
6783
	public function registerContent($id,TContent $object)
6784
	{
6785
		if(isset($this->_contents[$id]))
6786
			throw new TConfigurationException('templatecontrol_contentid_duplicated',$id);
6787
		else
6788
			$this->_contents[$id]=$object;
6789
	}
6790
	public function registerContentPlaceHolder($id,TContentPlaceHolder $object)
6791
	{
6792
		if(isset($this->_placeholders[$id]))
6793
			throw new TConfigurationException('templatecontrol_placeholderid_duplicated',$id);
6794
		else
6795
			$this->_placeholders[$id]=$object;
6796
	}
6797
	public function getMasterClass()
6798
	{
6799
		return $this->_masterClass;
6800
	}
6801
	public function setMasterClass($value)
6802
	{
6803
		$this->_masterClass=$value;
6804
	}
6805
	public function getMaster()
6806
	{
6807
		return $this->_master;
6808
	}
6809
	public function injectContent($id,$content)
6810
	{
6811
		if(isset($this->_placeholders[$id]))
6812
		{
6813
			$placeholder=$this->_placeholders[$id];
6814
			$controls=$placeholder->getParent()->getControls();
6815
			$loc=$controls->remove($placeholder);
6816
			$controls->insertAt($loc,$content);
6817
		}
6818
		else
6819
			throw new TConfigurationException('templatecontrol_placeholder_inexistent',$id);
6820
	}
6821
	protected function initRecursive($namingContainer=null)
6822
	{
6823
		$this->ensureChildControls();
6824
		if($this->_masterClass!=='')
6825
		{
6826
			$master=Prado::createComponent($this->_masterClass);
6827
			if(!($master instanceof TTemplateControl))
6828
				throw new TInvalidDataValueException('templatecontrol_mastercontrol_invalid');
6829
			$this->_master=$master;
6830
			$this->getControls()->clear();
6831
			$this->getControls()->add($master);
6832
			$master->ensureChildControls();
6833
			foreach($this->_contents as $id=>$content)
6834
				$master->injectContent($id,$content);
6835
		}
6836
		else if(!empty($this->_contents))
6837
			throw new TConfigurationException('templatecontrol_mastercontrol_required',get_class($this));
6838
		parent::initRecursive($namingContainer);
6839
	}
6840
        public function tryToUpdateView($arObj, $throwExceptions = false)
6841
        {
6842
                $objAttrs = get_class_vars(get_class($arObj));
6843
                foreach (array_keys($objAttrs) as $key)
6844
                {
6845
                        try
6846
                        {
6847
                                if ($key != "RELATIONS")
6848
                                {
6849
                                        $control = $this->{$key};
6850
                                        if ($control instanceof TTextBox)
6851
                                                $control->Text = $arObj->{$key};
6852
                                        elseif ($control instanceof TCheckBox)
6853
                                                $control->Checked = (boolean) $arObj->{$key};
6854
                                        elseif ($control instanceof TDatePicker)
6855
                                                $control->Date = $arObj->{$key};
6856
                                }
6857
                                else
6858
                                {
6859
                                        foreach ($objAttrs["RELATIONS"] as $relKey => $relValues)
6860
                                        {
6861
                                                $relControl = $this->{$relKey};
6862
                                                switch ($relValues[0])
6863
                                                {
6864
                                                        case TActiveRecord::BELONGS_TO:
6865
                                                        case TActiveRecord::HAS_ONE:
6866
                                                                $relControl->Text = $arObj->{$relKey};
6867
                                                                break;
6868
                                                        case TActiveRecord::HAS_MANY:
6869
                                                                if ($relControl instanceof TListControl)
6870
                                                                {
6871
                                                                        $relControl->DataSource = $arObj->{$relKey};
0 ignored issues
show
Bug introduced by
The property DataSource does not seem to exist. Did you mean _dataSource?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
6872
                                                                        $relControl->dataBind();
6873
                                                                }
6874
                                                                break;
6875
                                                }
6876
                                        }
6877
                                        break;
6878
                                }
6879
                        } 
6880
                        catch (Exception $ex)
6881
                        {
6882
                                if ($throwExceptions)
6883
                                        throw $ex;
6884
                        }
6885
                }
6886
        }
6887
        public function tryToUpdateAR($arObj, $throwExceptions = false)
6888
        {
6889
                $objAttrs = get_class_vars(get_class($arObj));
6890
                foreach (array_keys($objAttrs) as $key)
6891
                {
6892
                        try
6893
                        {
6894
                                if ($key == "RELATIONS")
6895
                                        break;
6896
                                $control = $this->{$key};
6897
                                if ($control instanceof TTextBox)
6898
                                        $arObj->{$key} = $control->Text;
6899
                                elseif ($control instanceof TCheckBox)
6900
                                        $arObj->{$key} = $control->Checked;
6901
                                elseif ($control instanceof TDatePicker)
6902
                                        $arObj->{$key} = $control->Date;
6903
                        } 
6904
                        catch (Exception $ex)
0 ignored issues
show
Unused Code introduced by
catch (\Exception $ex) {... throw $ex; } } does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
6905
                        {
6906
                                if ($throwExceptions)
0 ignored issues
show
Bug introduced by
The variable $throwExceptions seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
6907
                                        throw $ex;
6908
                        }
6909
                }
6910
        }
6911
}
6912
class TForm extends TControl
6913
{
6914
	public function onInit($param)
6915
	{
6916
		parent::onInit($param);
6917
		$this->getPage()->setForm($this);
6918
	}
6919
	protected function addAttributesToRender($writer)
6920
	{
6921
		$writer->addAttribute('id',$this->getClientID());
6922
		$writer->addAttribute('method',$this->getMethod());
6923
		$uri=$this->getRequest()->getRequestURI();
6924
		$writer->addAttribute('action',str_replace('&','&amp;',str_replace('&amp;','&',$uri)));
6925
		if(($enctype=$this->getEnctype())!=='')
6926
			$writer->addAttribute('enctype',$enctype);
6927
		$attributes=$this->getAttributes();
6928
		$attributes->remove('action');
6929
		$writer->addAttributes($attributes);
6930
		if(($butt=$this->getDefaultButton())!=='')
6931
		{
6932
			if(($button=$this->findControl($butt))!==null)
6933
				$this->getPage()->getClientScript()->registerDefaultButton($this, $button);
6934
			else
6935
				throw new TInvalidDataValueException('form_defaultbutton_invalid',$butt);
6936
		}
6937
	}
6938
	public function render($writer)
6939
	{
6940
		$page=$this->getPage();
6941
		$this->addAttributesToRender($writer);
6942
		$writer->renderBeginTag('form');
6943
		$cs=$page->getClientScript();
6944
		if($page->getClientSupportsJavaScript())
6945
		{
6946
			$cs->renderHiddenFieldsBegin($writer);
6947
			$cs->renderScriptFilesBegin($writer);
6948
			$cs->renderBeginScripts($writer);
6949
 			$page->beginFormRender($writer);
6950
 			$this->renderChildren($writer);
6951
			$cs->renderHiddenFieldsEnd($writer);
6952
 			$page->endFormRender($writer);
6953
			$cs->renderScriptFilesEnd($writer);
6954
			$cs->renderEndScripts($writer);
6955
		}
6956
		else
6957
		{
6958
			$cs->renderHiddenFieldsBegin($writer);
6959
			$page->beginFormRender($writer);
6960
			$this->renderChildren($writer);
6961
			$page->endFormRender($writer);
6962
			$cs->renderHiddenFieldsEnd($writer);
6963
		}
6964
		$writer->renderEndTag();
6965
	}
6966
	public function getDefaultButton()
6967
	{
6968
		return $this->getViewState('DefaultButton','');
6969
	}
6970
	public function setDefaultButton($value)
6971
	{
6972
		$this->setViewState('DefaultButton',$value,'');
6973
	}
6974
	public function getMethod()
6975
	{
6976
		return $this->getViewState('Method','post');
6977
	}
6978
	public function setMethod($value)
6979
	{
6980
		$this->setViewState('Method',TPropertyValue::ensureEnum($value,'post','get'),'post');
6981
	}
6982
	public function getEnctype()
6983
	{
6984
		return $this->getViewState('Enctype','');
6985
	}
6986
	public function setEnctype($value)
6987
	{
6988
		$this->setViewState('Enctype',$value,'');
6989
	}
6990
	public function getName()
6991
	{
6992
		return $this->getUniqueID();
6993
	}
6994
}
6995
class TClientScriptManager extends TApplicationComponent
6996
{
6997
	const SCRIPT_PATH='Web/Javascripts/source';
6998
	const PACKAGES_FILE='Web/Javascripts/packages.php';
6999
	private $_page;
7000
	private $_hiddenFields=array();
7001
	private $_beginScripts=array();
7002
	private $_endScripts=array();
7003
	private $_scriptFiles=array();
7004
	private $_headScriptFiles=array();
7005
	private $_headScripts=array();
7006
	private $_styleSheetFiles=array();
7007
	private $_styleSheets=array();
7008
	private $_registeredPradoScripts=array();
7009
	private static $_pradoScripts;
7010
	private static $_pradoPackages;
7011
	private $_renderedHiddenFields;
7012
	private $_renderedScriptFiles=array();
7013
	private $_expandedPradoScripts;
7014
	public function __construct(TPage $owner)
7015
	{
7016
		$this->_page=$owner;
7017
	}
7018
	public function getRequiresHead()
7019
	{
7020
		return count($this->_styleSheetFiles) || count($this->_styleSheets)
7021
			|| count($this->_headScriptFiles) || count($this->_headScripts);
7022
	}
7023
	public static function getPradoPackages()
7024
	{
7025
		return self::$_pradoPackages;
7026
	}
7027
	public static function getPradoScripts()
7028
	{
7029
		return self::$_pradoScripts;
7030
	}
7031
	public function registerPradoScript($name)
7032
	{
7033
		$this->registerPradoScriptInternal($name);
7034
		$params=func_get_args();
7035
		$this->_page->registerCachingAction('Page.ClientScript','registerPradoScript',$params);
7036
	}
7037
	protected function registerPradoScriptInternal($name)
7038
	{
7039
				if(!isset($this->_registeredPradoScripts[$name]))
7040
		{
7041
			if(self::$_pradoScripts === null)
7042
			{
7043
				$packageFile = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::PACKAGES_FILE;
7044
				list($packages,$deps)= include($packageFile);
7045
				self::$_pradoScripts = $deps;
7046
				self::$_pradoPackages = $packages;
7047
			}
7048
			if (isset(self::$_pradoScripts[$name]))
7049
				$this->_registeredPradoScripts[$name]=true;
7050
			else
7051
				throw new TInvalidOperationException('csmanager_pradoscript_invalid',$name);
7052
			if(($packages=array_keys($this->_registeredPradoScripts))!==array())
7053
			{
7054
				$base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
7055
				list($path,$baseUrl)=$this->getPackagePathUrl($base);
7056
				$packagesUrl=array();
7057
				$isDebug=$this->getApplication()->getMode()===TApplicationMode::Debug;
7058
				foreach ($packages as $p)
7059
				{
7060
					foreach (self::$_pradoScripts[$p] as $dep)
7061
					{
7062
						foreach (self::$_pradoPackages[$dep] as $script)
7063
						if (!isset($this->_expandedPradoScripts[$script]))
7064
						{
7065
							$this->_expandedPradoScripts[$script] = true;
7066
							if($isDebug)
7067
							{
7068
								if (!in_array($url=$baseUrl.'/'.$script,$packagesUrl))
7069
									$packagesUrl[]=$url;
7070
							} else {
7071
								if (!in_array($url=$baseUrl.'/min/'.$script,$packagesUrl))
7072
								{
7073
									if(!is_file($filePath=$path.'/min/'.$script))
7074
									{
7075
										$dirPath=dirname($filePath);
7076
										if(!is_dir($dirPath))
7077
											mkdir($dirPath, PRADO_CHMOD, true);
7078
										file_put_contents($filePath, TJavaScript::JSMin(file_get_contents($base.'/'.$script)));
7079
										chmod($filePath, PRADO_CHMOD);
7080
									}
7081
									$packagesUrl[]=$url;
7082
								}
7083
							}
7084
						}
7085
					}
7086
				}
7087
				foreach($packagesUrl as $url)
7088
					$this->registerScriptFile($url,$url);
7089
			}
7090
		}
7091
	}
7092
	public function getPradoScriptAssetUrl()
7093
	{
7094
		$base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
7095
		$assets = Prado::getApplication()->getAssetManager();
7096
		return $assets->getPublishedUrl($base);
7097
	}
7098
	public function getScriptUrls()
7099
	{
7100
		$scripts = array_values($this->_headScriptFiles);
7101
		$scripts = array_merge($scripts, array_values($this->_scriptFiles));
7102
		$scripts = array_unique($scripts);
7103
		return $scripts;
7104
	}
7105
	protected function getPackagePathUrl($base)
7106
	{
7107
		$assets = Prado::getApplication()->getAssetManager();
7108
		if(strpos($base, $assets->getBaseUrl())===false)
7109
		{
7110
			if(($dir = Prado::getPathOfNameSpace($base)) !== null) {
7111
				$base = $dir;
7112
			}
7113
			return array($assets->getPublishedPath($base), $assets->publishFilePath($base));
7114
		}
7115
		else
7116
		{
7117
			return array($assets->getBasePath().str_replace($assets->getBaseUrl(),'',$base), $base);
7118
		}
7119
	}
7120
	public function getCallbackReference(ICallbackEventHandler $callbackHandler, $options=null)
7121
	{
7122
		$options = !is_array($options) ? array() : $options;
7123
		$class = new ReflectionClass($callbackHandler);
0 ignored issues
show
Unused Code introduced by
$class is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
7124
		$clientSide = $callbackHandler->getActiveControl()->getClientSide();
7125
		$options = array_merge($options, $clientSide->getOptions()->toArray());
7126
		$optionString = TJavaScript::encode($options);
7127
		$this->registerPradoScriptInternal('ajax');
7128
		$id = $callbackHandler->getUniqueID();
7129
		return "new Prado.CallbackRequest('{$id}',{$optionString})";
7130
	}
7131
	public function registerCallbackControl($class, $options)
7132
	{
7133
		$optionString=TJavaScript::encode($options);
7134
		$code="new {$class}({$optionString});";
7135
		$this->_endScripts[sprintf('%08X', crc32($code))]=$code;
7136
		$this->registerPradoScriptInternal('ajax');
7137
		$params=func_get_args();
7138
		$this->_page->registerCachingAction('Page.ClientScript','registerCallbackControl',$params);
7139
	}
7140
	public function registerPostBackControl($class,$options)
7141
	{
7142
		if($class === null) {
7143
			return;
7144
		}
7145
		if(!isset($options['FormID']) && ($form=$this->_page->getForm())!==null)
7146
			$options['FormID']=$form->getClientID();
7147
		$optionString=TJavaScript::encode($options);
7148
		$code="new {$class}({$optionString});";
7149
		$this->_endScripts[sprintf('%08X', crc32($code))]=$code;
7150
		$this->registerPradoScriptInternal('prado');
7151
		$params=func_get_args();
7152
		$this->_page->registerCachingAction('Page.ClientScript','registerPostBackControl',$params);
7153
	}
7154
	public function registerDefaultButton($panel, $button)
7155
	{
7156
		$panelID=is_string($panel)?$panel:$panel->getUniqueID();
7157
		if(is_string($button))
7158
			$buttonID=$button;
7159
		else
7160
		{
7161
			$button->setIsDefaultButton(true);
7162
			$buttonID=$button->getUniqueID();
7163
		}
7164
		$options = TJavaScript::encode($this->getDefaultButtonOptions($panelID, $buttonID));
7165
		$code = "new Prado.WebUI.DefaultButton($options);";
7166
		$this->_endScripts['prado:'.$panelID]=$code;
7167
		$this->registerPradoScriptInternal('prado');
7168
		$params=array($panelID,$buttonID);
7169
		$this->_page->registerCachingAction('Page.ClientScript','registerDefaultButton',$params);
7170
	}
7171
	protected function getDefaultButtonOptions($panelID, $buttonID)
7172
	{
7173
		$options['ID'] = TControl::convertUniqueIdToClientId($panelID);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$options was never initialized. Although not strictly required by PHP, it is generally a good practice to add $options = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
7174
		$options['Panel'] = TControl::convertUniqueIdToClientId($panelID);
7175
		$options['Target'] = TControl::convertUniqueIdToClientId($buttonID);
7176
		$options['EventTarget'] = $buttonID;
7177
		$options['Event'] = 'click';
7178
		return $options;
7179
	}
7180
	public function registerFocusControl($target)
7181
	{
7182
		$this->registerPradoScriptInternal('jquery');
7183
		if($target instanceof TControl)
7184
			$target=$target->getClientID();
7185
		$this->_endScripts['prado:focus'] = 'jQuery(\'#'.$target.'\').focus();';
7186
		$params=func_get_args();
7187
		$this->_page->registerCachingAction('Page.ClientScript','registerFocusControl',$params);
7188
	}
7189
	public function registerStyleSheetFile($key,$url,$media='')
7190
	{
7191
		if($media==='')
7192
			$this->_styleSheetFiles[$key]=$url;
7193
		else
7194
			$this->_styleSheetFiles[$key]=array($url,$media);
7195
		$params=func_get_args();
7196
		$this->_page->registerCachingAction('Page.ClientScript','registerStyleSheetFile',$params);
7197
	}
7198
	public function registerStyleSheet($key,$css,$media='')
7199
	{
7200
		$this->_styleSheets[$key]=$css;
7201
		$params=func_get_args();
7202
		$this->_page->registerCachingAction('Page.ClientScript','registerStyleSheet',$params);
7203
	}
7204
	public function getStyleSheetUrls()
7205
	{
7206
		$stylesheets = array_values(
7207
			array_map(function($e) {
7208
				return is_array($e) ? $e[0] : $e;
7209
			}, $this->_styleSheetFiles)
7210
		);
7211
		foreach(Prado::getApplication()->getAssetManager()->getPublished() as $path=>$url)
7212
			if (substr($url,strlen($url)-4)=='.css')
7213
				$stylesheets[] = $url;
7214
		$stylesheets = array_unique($stylesheets);
7215
		return $stylesheets;
7216
	}
7217
	public function getStyleSheetCodes()
7218
	{
7219
		return array_unique(array_values($this->_styleSheets));
7220
	}
7221
	public function registerHeadScriptFile($key,$url)
7222
	{
7223
		$this->checkIfNotInRender();
7224
		$this->_headScriptFiles[$key]=$url;
7225
		$params=func_get_args();
7226
		$this->_page->registerCachingAction('Page.ClientScript','registerHeadScriptFile',$params);
7227
	}
7228
	public function registerHeadScript($key,$script)
7229
	{
7230
		$this->checkIfNotInRender();
7231
		$this->_headScripts[$key]=$script;
7232
		$params=func_get_args();
7233
		$this->_page->registerCachingAction('Page.ClientScript','registerHeadScript',$params);
7234
	}
7235
	public function registerScriptFile($key, $url)
7236
	{
7237
		$this->_scriptFiles[$key]=$url;
7238
		$params=func_get_args();
7239
		$this->_page->registerCachingAction('Page.ClientScript','registerScriptFile',$params);
7240
	}
7241
	public function registerBeginScript($key,$script)
7242
	{
7243
		$this->checkIfNotInRender();
7244
		$this->_beginScripts[$key]=$script;
7245
		$params=func_get_args();
7246
		$this->_page->registerCachingAction('Page.ClientScript','registerBeginScript',$params);
7247
	}
7248
	public function registerEndScript($key,$script)
7249
	{
7250
		$this->_endScripts[$key]=$script;
7251
		$params=func_get_args();
7252
		$this->_page->registerCachingAction('Page.ClientScript','registerEndScript',$params);
7253
	}
7254
	public function registerHiddenField($name,$value)
7255
	{
7256
		$this->_hiddenFields[$name]=$value;
7257
		$params=func_get_args();
7258
		$this->_page->registerCachingAction('Page.ClientScript','registerHiddenField',$params);
7259
	}
7260
	public function isStyleSheetFileRegistered($key)
7261
	{
7262
		return isset($this->_styleSheetFiles[$key]);
7263
	}
7264
	public function isStyleSheetRegistered($key)
7265
	{
7266
		return isset($this->_styleSheets[$key]);
7267
	}
7268
	public function isHeadScriptFileRegistered($key)
7269
	{
7270
		return isset($this->_headScriptFiles[$key]);
7271
	}
7272
	public function isHeadScriptRegistered($key)
7273
	{
7274
		return isset($this->_headScripts[$key]);
7275
	}
7276
	public function isScriptFileRegistered($key)
7277
	{
7278
		return isset($this->_scriptFiles[$key]);
7279
	}
7280
	public function isBeginScriptRegistered($key)
7281
	{
7282
		return isset($this->_beginScripts[$key]);
7283
	}
7284
	public function isEndScriptRegistered($key)
7285
	{
7286
		return isset($this->_endScripts[$key]);
7287
	}
7288
	public function hasEndScripts()
7289
	{
7290
		return count($this->_endScripts) > 0;
7291
	}
7292
	public function hasBeginScripts()
7293
	{
7294
		return count($this->_beginScripts) > 0;
7295
	}
7296
	public function isHiddenFieldRegistered($key)
7297
	{
7298
		return isset($this->_hiddenFields[$key]);
7299
	}
7300
	public function renderStyleSheetFiles($writer)
7301
	{
7302
		$str='';
7303
		foreach($this->_styleSheetFiles as $url)
7304
		{
7305
			if(is_array($url))
7306
				$str.="<link rel=\"stylesheet\" type=\"text/css\" media=\"{$url[1]}\" href=\"".THttpUtility::htmlEncode($url[0])."\" />\n";
7307
			else
7308
				$str.="<link rel=\"stylesheet\" type=\"text/css\" href=\"".THttpUtility::htmlEncode($url)."\" />\n";
7309
		}
7310
		$writer->write($str);
7311
	}
7312
	public function renderStyleSheets($writer)
7313
	{
7314
		if(count($this->_styleSheets))
7315
			$writer->write("<style type=\"text/css\">\n/*<![CDATA[*/\n".implode("\n",$this->_styleSheets)."\n/*]]>*/\n</style>\n");
7316
	}
7317
	public function renderHeadScriptFiles($writer)
7318
	{
7319
		$this->renderScriptFiles($writer,$this->_headScriptFiles);
7320
	}
7321
	public function renderHeadScripts($writer)
7322
	{
7323
		$writer->write(TJavaScript::renderScriptBlocks($this->_headScripts));
7324
	}
7325
	public function renderScriptFilesBegin($writer)
7326
	{
7327
		$this->renderAllPendingScriptFiles($writer);
7328
	}
7329
	public function renderScriptFilesEnd($writer)
7330
	{
7331
		$this->renderAllPendingScriptFiles($writer);
7332
	}
7333
	public function markScriptFileAsRendered($url)
7334
	{
7335
		$this->_renderedScriptFiles[$url] = $url;
7336
		$params=func_get_args();
7337
		$this->_page->registerCachingAction('Page.ClientScript','markScriptFileAsRendered',$params);
7338
	}
7339
	protected function renderScriptFiles($writer, Array $scripts)
7340
	{
7341
		foreach($scripts as $script)
7342
		{
7343
			$writer->write(TJavaScript::renderScriptFile($script));
7344
			$this->markScriptFileAsRendered($script);
7345
		}
7346
	}
7347
	protected function getRenderedScriptFiles()
7348
	{
7349
		return $this->_renderedScriptFiles;
7350
	}
7351
	public function renderAllPendingScriptFiles($writer)
7352
	{
7353
		if(!empty($this->_scriptFiles))
7354
		{
7355
			$addedScripts = array_diff($this->_scriptFiles,$this->getRenderedScriptFiles());
7356
			$this->renderScriptFiles($writer,$addedScripts);
7357
		}
7358
	}
7359
	public function renderBeginScripts($writer)
7360
	{
7361
		$writer->write(TJavaScript::renderScriptBlocks($this->_beginScripts));
7362
	}
7363
	public function renderEndScripts($writer)
7364
	{
7365
		$writer->write(TJavaScript::renderScriptBlocks($this->_endScripts));
7366
	}
7367
	public function renderBeginScriptsCallback($writer)
7368
	{
7369
		$writer->write(TJavaScript::renderScriptBlocksCallback($this->_beginScripts));
7370
	}
7371
	public function renderEndScriptsCallback($writer)
7372
	{
7373
		$writer->write(TJavaScript::renderScriptBlocksCallback($this->_endScripts));
7374
	}
7375
	public function renderHiddenFieldsBegin($writer)
7376
	{
7377
		$this->renderHiddenFieldsInt($writer,true);
7378
	}
7379
	public function renderHiddenFieldsEnd($writer)
7380
	{
7381
		$this->renderHiddenFieldsInt($writer,false);
7382
	}
7383
	public function flushScriptFiles($writer, $control=null)
7384
	{
7385
		if(!$this->_page->getIsCallback())
7386
		{
7387
			$this->_page->ensureRenderInForm($control);
7388
			$this->renderAllPendingScriptFiles($writer);
7389
		}
7390
	}
7391
	protected function renderHiddenFieldsInt($writer, $initial)
7392
 	{
7393
		if ($initial) $this->_renderedHiddenFields = array();
7394
		$str='';
7395
		foreach($this->_hiddenFields as $name=>$value)
7396
		{
7397
			if (in_array($name,$this->_renderedHiddenFields)) continue;
7398
			$id=strtr($name,':','_');
7399
			if(is_array($value))
7400
			{
7401
				foreach($value as $v)
7402
					$str.='<input type="hidden" name="'.$name.'[]" id="'.$id.'" value="'.THttpUtility::htmlEncode($value)."\" />\n";
7403
			}
7404
			else
7405
			{
7406
				$str.='<input type="hidden" name="'.$name.'" id="'.$id.'" value="'.THttpUtility::htmlEncode($value)."\" />\n";
7407
			}
7408
			$this->_renderedHiddenFields[] = $name;
7409
		}
7410
		if($str!=='')
7411
			$writer->write("<div style=\"visibility:hidden;\">\n".$str."</div>\n");
7412
	}
7413
	public function getHiddenFields()
7414
	{
7415
		return $this->_hiddenFields;
7416
	}
7417
	protected function checkIfNotInRender()
7418
	{
7419
		if ($form = $this->_page->InFormRender)
0 ignored issues
show
Bug introduced by
The property InFormRender does not seem to exist. Did you mean _inFormRender?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
Unused Code introduced by
$form is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
7420
			throw new Exception('Operation invalid when page is already rendering');
7421
	}
7422
}
7423
abstract class TClientSideOptions extends TComponent
7424
{
7425
	private $_options;
7426
	protected function setFunction($name, $code)
7427
	{
7428
		if(!TJavaScript::isJsLiteral($code))
7429
			$code = TJavaScript::quoteJsLiteral($this->ensureFunction($code));
7430
		$this->setOption($name, $code);
7431
	}
7432
	protected function getOption($name)
7433
	{
7434
		if ($this->_options)
7435
			return $this->_options->itemAt($name);
7436
		else
7437
			return null;
7438
	}
7439
	protected function setOption($name, $value)
7440
	{
7441
		$this->getOptions()->add($name, $value);
7442
	}
7443
	public function getOptions()
7444
	{
7445
		if (!$this->_options)
7446
			$this->_options = Prado::createComponent('System.Collections.TMap');
7447
		return $this->_options;
7448
	}
7449
	protected function ensureFunction($javascript)
7450
	{
7451
		return "function(sender, parameter){ {$javascript} }";
7452
	}
7453
}
7454
class TPage extends TTemplateControl
7455
{
7456
	const FIELD_POSTBACK_TARGET='PRADO_POSTBACK_TARGET';
7457
	const FIELD_POSTBACK_PARAMETER='PRADO_POSTBACK_PARAMETER';
7458
	const FIELD_LASTFOCUS='PRADO_LASTFOCUS';
7459
	const FIELD_PAGESTATE='PRADO_PAGESTATE';
7460
	const FIELD_CALLBACK_TARGET='PRADO_CALLBACK_TARGET';
7461
	const FIELD_CALLBACK_PARAMETER='PRADO_CALLBACK_PARAMETER';
7462
	private static $_systemPostFields=array(
7463
		'PRADO_POSTBACK_TARGET'=>true,
7464
		'PRADO_POSTBACK_PARAMETER'=>true,
7465
		'PRADO_LASTFOCUS'=>true,
7466
		'PRADO_PAGESTATE'=>true,
7467
		'PRADO_CALLBACK_TARGET'=>true,
7468
		'PRADO_CALLBACK_PARAMETER'=>true
7469
	);
7470
	private $_form;
7471
	private $_head;
7472
	private $_validators=array();
7473
	private $_validated=false;
7474
	private $_theme;
7475
	private $_title;
7476
	private $_styleSheet;
7477
	private $_clientScript;
7478
	protected $_postData;
7479
	protected $_restPostData;
7480
	protected $_controlsPostDataChanged=array();
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $_controlsPostDataChanged exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
7481
	protected $_controlsRequiringPostData=array();
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $_controlsRequiringPostData exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
7482
	protected $_controlsRegisteredForPostData=array();
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $_controlsRegisteredForPostData exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
7483
	private $_postBackEventTarget;
7484
	private $_postBackEventParameter;
7485
	protected $_formRendered=false;
7486
	protected $_inFormRender=false;
7487
	private $_focus;
7488
	private $_pagePath='';
7489
	private $_enableStateValidation=true;
7490
	private $_enableStateEncryption=false;
7491
	private $_enableStateCompression=true;
7492
	private $_statePersisterClass='System.Web.UI.TPageStatePersister';
7493
	private $_statePersister;
7494
	private $_cachingStack;
7495
	private $_clientState='';
7496
	protected $_isLoadingPostData=false;
7497
	private $_enableJavaScript=true;
7498
	private $_writer;
7499
	public function __construct()
7500
	{
7501
		$this->setPage($this);
7502
	}
7503
	public function run($writer)
7504
	{
7505
		$this->_writer = $writer;
7506
		$this->determinePostBackMode();
7507
		if($this->getIsPostBack())
7508
		{
7509
			if($this->getIsCallback())
7510
				$this->processCallbackRequest($writer);
7511
			else
7512
				$this->processPostBackRequest($writer);
7513
		}
7514
		else
7515
			$this->processNormalRequest($writer);
7516
		$this->_writer = null;
7517
	}
7518
	protected function processNormalRequest($writer)
7519
	{
7520
		$this->onPreInit(null);
7521
		$this->initRecursive();
7522
		$this->onInitComplete(null);
7523
		$this->onPreLoad(null);
7524
		$this->loadRecursive();
7525
		$this->onLoadComplete(null);
7526
		$this->preRenderRecursive();
7527
		$this->onPreRenderComplete(null);
7528
		$this->savePageState();
7529
		$this->onSaveStateComplete(null);
7530
		$this->renderControl($writer);
7531
		$this->unloadRecursive();
7532
	}
7533
	protected function processPostBackRequest($writer)
7534
	{
7535
		$this->onPreInit(null);
7536
		$this->initRecursive();
7537
		$this->onInitComplete(null);
7538
		$this->_restPostData=new TMap;
7539
		$this->loadPageState();
7540
		$this->processPostData($this->_postData,true);
7541
		$this->onPreLoad(null);
7542
		$this->loadRecursive();
7543
		$this->processPostData($this->_restPostData,false);
7544
		$this->raiseChangedEvents();
7545
		$this->raisePostBackEvent();
7546
		$this->onLoadComplete(null);
7547
		$this->preRenderRecursive();
7548
		$this->onPreRenderComplete(null);
7549
		$this->savePageState();
7550
		$this->onSaveStateComplete(null);
7551
		$this->renderControl($writer);
7552
		$this->unloadRecursive();
7553
	}
7554
	protected static function decodeUTF8($data, $enc)
7555
	{
7556
		if(is_array($data))
7557
		{
7558
			foreach($data as $k=>$v)
7559
				$data[$k]=self::decodeUTF8($v, $enc);
7560
			return $data;
7561
		} elseif(is_string($data)) {
7562
			return iconv('UTF-8',$enc.'//IGNORE',$data);
7563
		} else {
7564
			return $data;
7565
		}
7566
	}
7567
	protected function processCallbackRequest($writer)
7568
	{
7569
		Prado::using('System.Web.UI.ActiveControls.TActivePageAdapter');
7570
		Prado::using('System.Web.UI.JuiControls.TJuiControlOptions');
7571
		$this->setAdapter(new TActivePageAdapter($this));
7572
        $callbackEventParameter = $this->getRequest()->itemAt(TPage::FIELD_CALLBACK_PARAMETER);
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $callbackEventParameter exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
7573
        if(strlen($callbackEventParameter) > 0)
7574
            $this->_postData[TPage::FIELD_CALLBACK_PARAMETER]=TJavaScript::jsonDecode((string)$callbackEventParameter);
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
7575
                if (($g=$this->getApplication()->getGlobalization(false))!==null &&
7576
            strtoupper($enc=$g->getCharset())!='UTF-8')
7577
                foreach ($this->_postData as $k=>$v)
7578
                	$this->_postData[$k]=self::decodeUTF8($v, $enc);
7579
		$this->onPreInit(null);
7580
		$this->initRecursive();
7581
		$this->onInitComplete(null);
7582
		$this->_restPostData=new TMap;
7583
		$this->loadPageState();
7584
		$this->processPostData($this->_postData,true);
7585
		$this->onPreLoad(null);
7586
		$this->loadRecursive();
7587
		$this->processPostData($this->_restPostData,false);
7588
		$this->raiseChangedEvents();
7589
		$this->getAdapter()->processCallbackEvent($writer);
7590
		$this->onLoadComplete(null);
7591
		$this->preRenderRecursive();
7592
		$this->onPreRenderComplete(null);
7593
		$this->savePageState();
7594
		$this->onSaveStateComplete(null);
7595
		$this->getAdapter()->renderCallbackResponse($writer);
7596
		$this->unloadRecursive();
7597
	}
7598
	public function getCallbackClient()
7599
	{
7600
		if($this->getAdapter() !== null)
7601
			return $this->getAdapter()->getCallbackClientHandler();
7602
		else
7603
			return new TCallbackClientScript();
7604
	}
7605
	public function setCallbackClient($client)
7606
	{
7607
		$this->getAdapter()->setCallbackClientHandler($client);
7608
	}
7609
	public function getCallbackEventTarget()
7610
	{
7611
		return $this->getAdapter()->getCallbackEventTarget();
7612
	}
7613
	public function setCallbackEventTarget(TControl $control)
7614
	{
7615
		$this->getAdapter()->setCallbackEventTarget($control);
7616
	}
7617
	public function getCallbackEventParameter()
7618
	{
7619
		return $this->getAdapter()->getCallbackEventParameter();
7620
	}
7621
	public function setCallbackEventParameter($value)
7622
	{
7623
		$this->getAdapter()->setCallbackEventParameter($value);
7624
	}
7625
	public function getForm()
7626
	{
7627
		return $this->_form;
7628
	}
7629
	public function setForm(TForm $form)
7630
	{
7631
		if($this->_form===null)
7632
			$this->_form=$form;
7633
		else
7634
			throw new TInvalidOperationException('page_form_duplicated');
7635
	}
7636
	public function getValidators($validationGroup=null)
7637
	{
7638
		if(!$this->_validators)
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->_validators of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
7639
			$this->_validators=new TList;
0 ignored issues
show
Documentation Bug introduced by
It seems like new \TList() of type object<TList> is incompatible with the declared type array of property $_validators.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
7640
		if(empty($validationGroup) === true)
7641
			return $this->_validators;
7642
		else
7643
		{
7644
			$list=new TList;
7645
			foreach($this->_validators as $validator)
7646
				if($validator->getValidationGroup()===$validationGroup)
7647
					$list->add($validator);
7648
			return $list;
7649
		}
7650
	}
7651
	public function validate($validationGroup=null)
7652
	{
7653
		$this->_validated=true;
7654
		if($this->_validators && $this->_validators->getCount())
0 ignored issues
show
Bug introduced by
The method getCount cannot be called on $this->_validators (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
Bug Best Practice introduced by
The expression $this->_validators of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
7655
		{
7656
			if($validationGroup===null)
7657
			{
7658
				foreach($this->_validators as $validator)
7659
					$validator->validate();
7660
			}
7661
			else
7662
			{
7663
				foreach($this->_validators as $validator)
7664
				{
7665
					if($validator->getValidationGroup()===$validationGroup)
7666
						$validator->validate();
7667
				}
7668
			}
7669
		}
7670
	}
7671
	public function getIsValid()
7672
	{
7673
		if($this->_validated)
7674
		{
7675
			if($this->_validators && $this->_validators->getCount())
0 ignored issues
show
Bug introduced by
The method getCount cannot be called on $this->_validators (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
Bug Best Practice introduced by
The expression $this->_validators of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
7676
			{
7677
				foreach($this->_validators as $validator)
7678
					if(!$validator->getIsValid())
7679
						return false;
7680
			}
7681
			return true;
7682
		}
7683
		else
7684
			throw new TInvalidOperationException('page_isvalid_unknown');
7685
	}
7686
	public function getTheme()
7687
	{
7688
		if(is_string($this->_theme))
7689
			$this->_theme=$this->getService()->getThemeManager()->getTheme($this->_theme);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface IService as the method getThemeManager() does only exist in the following implementations of said interface: TPageService, TWsatService.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
7690
		return $this->_theme;
7691
	}
7692
	public function setTheme($value)
7693
	{
7694
		$this->_theme=empty($value)?null:$value;
7695
	}
7696
	public function getStyleSheetTheme()
7697
	{
7698
		if(is_string($this->_styleSheet))
7699
			$this->_styleSheet=$this->getService()->getThemeManager()->getTheme($this->_styleSheet);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface IService as the method getThemeManager() does only exist in the following implementations of said interface: TPageService, TWsatService.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
7700
		return $this->_styleSheet;
7701
	}
7702
	public function setStyleSheetTheme($value)
7703
	{
7704
		$this->_styleSheet=empty($value)?null:$value;
7705
	}
7706
	public function applyControlSkin($control)
7707
	{
7708
		if(($theme=$this->getTheme())!==null)
7709
			$theme->applySkin($control);
7710
	}
7711
	public function applyControlStyleSheet($control)
7712
	{
7713
		if(($theme=$this->getStyleSheetTheme())!==null)
7714
			$theme->applySkin($control);
7715
	}
7716
	public function getClientScript()
7717
	{
7718
		if(!$this->_clientScript) {
7719
			$className = $classPath = $this->getService()->getClientScriptManagerClass();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface IService as the method getClientScriptManagerClass() does only exist in the following implementations of said interface: TPageService, TWsatService.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
7720
			Prado::using($className);
7721
			if(($pos=strrpos($className,'.'))!==false)
7722
				$className=substr($className,$pos+1);
7723
 			if(!class_exists($className,false) || ($className!=='TClientScriptManager' && !is_subclass_of($className,'TClientScriptManager')))
7724
				throw new THttpException(404,'page_csmanagerclass_invalid',$classPath);
7725
			$this->_clientScript=new $className($this);
7726
		}
7727
		return $this->_clientScript;
7728
	}
7729
	public function onPreInit($param)
7730
	{
7731
		$this->raiseEvent('OnPreInit',$this,$param);
7732
	}
7733
	public function onInitComplete($param)
7734
	{
7735
		$this->raiseEvent('OnInitComplete',$this,$param);
7736
	}
7737
	public function onPreLoad($param)
7738
	{
7739
		$this->raiseEvent('OnPreLoad',$this,$param);
7740
	}
7741
	public function onLoadComplete($param)
7742
	{
7743
		$this->raiseEvent('OnLoadComplete',$this,$param);
7744
	}
7745
	public function onPreRenderComplete($param)
7746
	{
7747
		$this->raiseEvent('OnPreRenderComplete',$this,$param);
7748
		$cs=$this->getClientScript();
7749
		$theme=$this->getTheme();
7750
		if($theme instanceof ITheme)
7751
		{
7752
			foreach($theme->getStyleSheetFiles() as $url)
7753
				$cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
7754
			foreach($theme->getJavaScriptFiles() as $url)
7755
				$cs->registerHeadScriptFile($url,$url);
7756
		}
7757
		$styleSheet=$this->getStyleSheetTheme();
7758
		if($styleSheet instanceof ITheme)
7759
		{
7760
			foreach($styleSheet->getStyleSheetFiles() as $url)
7761
				$cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
7762
			foreach($styleSheet->getJavaScriptFiles() as $url)
7763
				$cs->registerHeadScriptFile($url,$url);
7764
		}
7765
		if($cs->getRequiresHead() && $this->getHead()===null)
7766
			throw new TConfigurationException('page_head_required');
7767
	}
7768
	private function getCssMediaType($url)
7769
	{
7770
		$segs=explode('.',basename($url));
7771
		if(isset($segs[2]))
7772
			return $segs[count($segs)-2];
7773
		else
7774
			return '';
7775
	}
7776
	public function onSaveStateComplete($param)
7777
	{
7778
		$this->raiseEvent('OnSaveStateComplete',$this,$param);
7779
	}
7780
	private function determinePostBackMode()
7781
	{
7782
		$postData=$this->getRequest();
7783
		if($postData->contains(self::FIELD_PAGESTATE) || $postData->contains(self::FIELD_POSTBACK_TARGET))
7784
			$this->_postData=$postData;
7785
	}
7786
	public function getIsPostBack()
7787
	{
7788
		return $this->_postData!==null;
7789
	}
7790
	public function getIsCallback()
7791
	{
7792
		return $this->getIsPostBack() && $this->getRequest()->contains(self::FIELD_CALLBACK_TARGET);
7793
	}
7794
	public function saveState()
7795
	{
7796
		parent::saveState();
7797
		$this->setViewState('ControlsRequiringPostBack',$this->_controlsRegisteredForPostData,array());
7798
	}
7799
	public function loadState()
7800
	{
7801
		parent::loadState();
7802
		$this->_controlsRequiringPostData=$this->getViewState('ControlsRequiringPostBack',array());
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getViewState('Con...ringPostBack', array()) of type * is incompatible with the declared type array of property $_controlsRequiringPostData.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
7803
	}
7804
	protected function loadPageState()
7805
	{
7806
		$state=$this->getStatePersister()->load();
7807
		$this->loadStateRecursive($state,$this->getEnableViewState());
7808
	}
7809
	protected function savePageState()
7810
	{
7811
		$state=&$this->saveStateRecursive($this->getEnableViewState());
7812
		$this->getStatePersister()->save($state);
7813
	}
7814
	protected function isSystemPostField($field)
7815
	{
7816
		return isset(self::$_systemPostFields[$field]);
7817
	}
7818
	public function registerRequiresPostData($control)
7819
	{
7820
		$id=is_string($control)?$control:$control->getUniqueID();
7821
		$this->_controlsRegisteredForPostData[$id]=true;
7822
		$params=func_get_args();
0 ignored issues
show
Unused Code introduced by
$params is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
7823
		foreach($this->getCachingStack() as $item)
7824
			$item->registerAction('Page','registerRequiresPostData',array($id));
7825
	}
7826
	public function getPostBackEventTarget()
7827
	{
7828
		if($this->_postBackEventTarget===null && $this->_postData!==null)
7829
		{
7830
			$eventTarget=$this->_postData->itemAt(self::FIELD_POSTBACK_TARGET);
0 ignored issues
show
Bug introduced by
The method itemAt cannot be called on $this->_postData (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
7831
			if(!empty($eventTarget))
7832
				$this->_postBackEventTarget=$this->findControl($eventTarget);
7833
		}
7834
		return $this->_postBackEventTarget;
7835
	}
7836
	public function setPostBackEventTarget(TControl $control)
7837
	{
7838
		$this->_postBackEventTarget=$control;
7839
	}
7840
	public function getPostBackEventParameter()
7841
	{
7842
		if($this->_postBackEventParameter===null && $this->_postData!==null)
7843
		{
7844
			if(($this->_postBackEventParameter=$this->_postData->itemAt(self::FIELD_POSTBACK_PARAMETER))===null)
0 ignored issues
show
Bug introduced by
The method itemAt cannot be called on $this->_postData (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
7845
				$this->_postBackEventParameter='';
7846
		}
7847
		return $this->_postBackEventParameter;
7848
	}
7849
	public function setPostBackEventParameter($value)
7850
	{
7851
		$this->_postBackEventParameter=$value;
7852
	}
7853
	protected function processPostData($postData,$beforeLoad)
7854
	{
7855
		$this->_isLoadingPostData=true;
7856
		if($beforeLoad)
7857
			$this->_restPostData=new TMap;
7858
		foreach($postData as $key=>$value)
7859
		{
7860
			if($this->isSystemPostField($key))
7861
				continue;
7862
			else if($control=$this->findControl($key))
7863
			{
7864
				if($control instanceof IPostBackDataHandler)
7865
				{
7866
					if($control->loadPostData($key,$postData))
7867
						$this->_controlsPostDataChanged[]=$control;
7868
				}
7869
				else if($control instanceof IPostBackEventHandler &&
7870
					empty($this->_postData[self::FIELD_POSTBACK_TARGET]))
7871
				{
7872
					$this->_postData->add(self::FIELD_POSTBACK_TARGET,$key);  				}
7873
				unset($this->_controlsRequiringPostData[$key]);
7874
			}
7875
			else if($beforeLoad)
7876
				$this->_restPostData->add($key,$value);
7877
		}
7878
		foreach($this->_controlsRequiringPostData as $key=>$value)
7879
		{
7880
			if($control=$this->findControl($key))
7881
			{
7882
				if($control instanceof IPostBackDataHandler)
7883
				{
7884
					if($control->loadPostData($key,$this->_postData))
7885
						$this->_controlsPostDataChanged[]=$control;
7886
				}
7887
				else
7888
					throw new TInvalidDataValueException('page_postbackcontrol_invalid',$key);
7889
				unset($this->_controlsRequiringPostData[$key]);
7890
			}
7891
		}
7892
		$this->_isLoadingPostData=false;
7893
	}
7894
	public function getIsLoadingPostData()
7895
	{
7896
		return $this->_isLoadingPostData;
7897
	}
7898
	protected function raiseChangedEvents()
7899
	{
7900
		foreach($this->_controlsPostDataChanged as $control)
7901
			$control->raisePostDataChangedEvent();
7902
	}
7903
	protected function raisePostBackEvent()
7904
	{
7905
		if(($postBackHandler=$this->getPostBackEventTarget())===null)
7906
			$this->validate();
7907
		else if($postBackHandler instanceof IPostBackEventHandler)
7908
			$postBackHandler->raisePostBackEvent($this->getPostBackEventParameter());
7909
	}
7910
	public function getInFormRender()
7911
	{
7912
		return $this->_inFormRender;
7913
	}
7914
	public function ensureRenderInForm($control)
7915
	{
7916
		if(!$this->getIsCallback() && !$this->_inFormRender)
7917
			throw new TConfigurationException('page_control_outofform',get_class($control), $control ? $control->getUniqueID() : null);
7918
	}
7919
	public function beginFormRender($writer)
7920
	{
7921
		if($this->_formRendered)
7922
			throw new TConfigurationException('page_form_duplicated');
7923
		$this->_formRendered=true;
7924
		$this->getClientScript()->registerHiddenField(self::FIELD_PAGESTATE,$this->getClientState());
7925
		$this->_inFormRender=true;
7926
	}
7927
	public function endFormRender($writer)
7928
	{
7929
		if($this->_focus)
7930
		{
7931
			if(($this->_focus instanceof TControl) && $this->_focus->getVisible(true))
7932
				$focus=$this->_focus->getClientID();
7933
			else
7934
				$focus=$this->_focus;
7935
			$this->getClientScript()->registerFocusControl($focus);
7936
		}
7937
		else if($this->_postData && ($lastFocus=$this->_postData->itemAt(self::FIELD_LASTFOCUS))!==null)
0 ignored issues
show
Bug introduced by
The method itemAt cannot be called on $this->_postData (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
Bug Best Practice introduced by
The expression $this->_postData of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
7938
			$this->getClientScript()->registerFocusControl($lastFocus);
7939
		$this->_inFormRender=false;
7940
	}
7941
	public function setFocus($value)
7942
	{
7943
		$this->_focus=$value;
7944
	}
7945
	public function getClientSupportsJavaScript()
7946
	{
7947
		return $this->_enableJavaScript;
7948
	}
7949
	public function setClientSupportsJavaScript($value)
7950
	{
7951
		$this->_enableJavaScript=TPropertyValue::ensureBoolean($value);
7952
	}
7953
	public function getHead()
7954
	{
7955
		return $this->_head;
7956
	}
7957
	public function setHead(THead $value)
7958
	{
7959
		if($this->_head)
7960
			throw new TInvalidOperationException('page_head_duplicated');
7961
		$this->_head=$value;
7962
		if($this->_title!==null)
7963
		{
7964
			$this->_head->setTitle($this->_title);
7965
			$this->_title=null;
7966
		}
7967
	}
7968
	public function getTitle()
7969
	{
7970
		if($this->_head)
7971
			return $this->_head->getTitle();
7972
		else
7973
			return $this->_title===null ? '' : $this->_title;
7974
	}
7975
	public function setTitle($value)
7976
	{
7977
		if($this->_head)
7978
			$this->_head->setTitle($value);
7979
		else
7980
			$this->_title=$value;
7981
	}
7982
	public function getClientState()
7983
	{
7984
		return $this->_clientState;
7985
	}
7986
	public function setClientState($state)
7987
	{
7988
		$this->_clientState=$state;
7989
	}
7990
	public function getRequestClientState()
7991
	{
7992
		return $this->getRequest()->itemAt(self::FIELD_PAGESTATE);
7993
	}
7994
	public function getStatePersisterClass()
7995
	{
7996
		return $this->_statePersisterClass;
7997
	}
7998
	public function setStatePersisterClass($value)
7999
	{
8000
		$this->_statePersisterClass=$value;
8001
	}
8002
	public function getStatePersister()
8003
	{
8004
		if($this->_statePersister===null)
8005
		{
8006
			$this->_statePersister=Prado::createComponent($this->_statePersisterClass);
8007
			if(!($this->_statePersister instanceof IPageStatePersister))
8008
				throw new TInvalidDataTypeException('page_statepersister_invalid');
8009
			$this->_statePersister->setPage($this);
8010
		}
8011
		return $this->_statePersister;
8012
	}
8013
	public function getEnableStateValidation()
8014
	{
8015
		return $this->_enableStateValidation;
8016
	}
8017
	public function setEnableStateValidation($value)
8018
	{
8019
		$this->_enableStateValidation=TPropertyValue::ensureBoolean($value);
8020
	}
8021
	public function getEnableStateEncryption()
8022
	{
8023
		return $this->_enableStateEncryption;
8024
	}
8025
	public function setEnableStateEncryption($value)
8026
	{
8027
		$this->_enableStateEncryption=TPropertyValue::ensureBoolean($value);
8028
	}
8029
	public function getEnableStateCompression()
8030
	{
8031
		return $this->_enableStateCompression;
8032
	}
8033
	public function setEnableStateCompression($value)
8034
	{
8035
		$this->_enableStateCompression=TPropertyValue::ensureBoolean($value);
8036
	}
8037
	public function getPagePath()
8038
	{
8039
		return $this->_pagePath;
8040
	}
8041
	public function setPagePath($value)
8042
	{
8043
		$this->_pagePath=$value;
8044
	}
8045
	public function registerCachingAction($context,$funcName,$funcParams)
8046
	{
8047
		if($this->_cachingStack)
8048
		{
8049
			foreach($this->_cachingStack as $cache)
8050
				$cache->registerAction($context,$funcName,$funcParams);
8051
		}
8052
	}
8053
	public function getCachingStack()
8054
	{
8055
		if(!$this->_cachingStack)
8056
			$this->_cachingStack=new TStack;
8057
		return $this->_cachingStack;
8058
	}
8059
	public function flushWriter()
8060
	{
8061
		if ($this->_writer)
8062
			$this->Response->write($this->_writer->flush());
8063
	}
8064
}
8065
interface IPageStatePersister
8066
{
8067
	public function getPage();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
8068
	public function setPage(TPage $page);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
8069
	public function save($state);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
8070
	public function load();
8071
}
8072
class TPageStateFormatter
8073
{
8074
	public static function serialize($page,$data)
8075
	{
8076
		$sm=$page->getApplication()->getSecurityManager();
8077
		if($page->getEnableStateValidation())
8078
			$str=$sm->hashData(serialize($data));
8079
		else
8080
			$str=serialize($data);
8081
		if($page->getEnableStateCompression() && extension_loaded('zlib'))
8082
			$str=gzcompress($str);
8083
		if($page->getEnableStateEncryption())
8084
			$str=$sm->encrypt($str);
8085
		return base64_encode($str);
8086
	}
8087
	public static function unserialize($page,$data)
8088
	{
8089
		$str=base64_decode($data);
8090
		if($str==='')
8091
			return null;
8092
		if($str!==false)
8093
		{
8094
			$sm=$page->getApplication()->getSecurityManager();
8095
			if($page->getEnableStateEncryption())
8096
				$str=$sm->decrypt($str);
8097
			if($page->getEnableStateCompression() && extension_loaded('zlib'))
8098
				$str=@gzuncompress($str);
8099
			if($page->getEnableStateValidation())
8100
			{
8101
				if(($str=$sm->validateData($str))!==false)
8102
					return unserialize($str);
8103
			}
8104
			else
8105
				return unserialize($str);
8106
		}
8107
		return null;
8108
	}
8109
}
8110
class TOutputCache extends TControl implements INamingContainer
8111
{
8112
	const CACHE_ID_PREFIX='prado:outputcache';
8113
	private $_cacheModuleID='';
8114
	private $_dataCached=false;
8115
	private $_cacheAvailable=false;
8116
	private $_cacheChecked=false;
8117
	private $_cacheKey=null;
8118
	private $_duration=60;
8119
	private $_cache=null;
8120
	private $_contents;
8121
	private $_state;
8122
	private $_actions=array();
8123
	private $_varyByParam='';
8124
	private $_keyPrefix='';
8125
	private $_varyBySession=false;
8126
	private $_cachePostBack=false;
8127
	private $_cacheTime=0;
8128
	public function getAllowChildControls()
8129
	{
8130
		$this->determineCacheability();
8131
		return !$this->_dataCached;
8132
	}
8133
	private function determineCacheability()
8134
	{
8135
		if(!$this->_cacheChecked)
8136
		{
8137
			$this->_cacheChecked=true;
8138
			if($this->_duration>0 && ($this->_cachePostBack || !$this->getPage()->getIsPostBack()))
8139
			{
8140
				if($this->_cacheModuleID!=='')
8141
				{
8142
					$this->_cache=$this->getApplication()->getModule($this->_cacheModuleID);
8143
					if(!($this->_cache instanceof ICache))
8144
						throw new TConfigurationException('outputcache_cachemoduleid_invalid',$this->_cacheModuleID);
8145
				}
8146
				else
8147
					$this->_cache=$this->getApplication()->getCache();
8148
				if($this->_cache!==null)
8149
				{
8150
					$this->_cacheAvailable=true;
8151
					$data=$this->_cache->get($this->getCacheKey());
8152
					if(is_array($data))
8153
					{
8154
						$param=new TOutputCacheCheckDependencyEventParameter;
8155
						$param->setCacheTime(isset($data[3])?$data[3]:0);
8156
						$this->onCheckDependency($param);
8157
						$this->_dataCached=$param->getIsValid();
8158
					}
8159
					else
8160
						$this->_dataCached=false;
8161
					if($this->_dataCached)
8162
						list($this->_contents,$this->_state,$this->_actions,$this->_cacheTime)=$data;
8163
				}
8164
			}
8165
		}
8166
	}
8167
	protected function initRecursive($namingContainer=null)
8168
	{
8169
		if($this->_cacheAvailable && !$this->_dataCached)
8170
		{
8171
			$stack=$this->getPage()->getCachingStack();
8172
			$stack->push($this);
8173
			parent::initRecursive($namingContainer);
8174
			$stack->pop();
8175
		}
8176
		else
8177
			parent::initRecursive($namingContainer);
8178
	}
8179
	protected function loadRecursive()
8180
	{
8181
		if($this->_cacheAvailable && !$this->_dataCached)
8182
		{
8183
			$stack=$this->getPage()->getCachingStack();
8184
			$stack->push($this);
8185
			parent::loadRecursive();
8186
			$stack->pop();
8187
		}
8188
		else
8189
		{
8190
			if($this->_dataCached)
8191
				$this->performActions();
8192
			parent::loadRecursive();
8193
		}
8194
	}
8195
	private function performActions()
8196
	{
8197
		$page=$this->getPage();
8198
		$cs=$page->getClientScript();
8199
		foreach($this->_actions as $action)
8200
		{
8201
			if($action[0]==='Page.ClientScript')
8202
				call_user_func_array(array($cs,$action[1]),$action[2]);
8203
			else if($action[0]==='Page')
8204
				call_user_func_array(array($page,$action[1]),$action[2]);
8205
			else
8206
				call_user_func_array(array($this->getSubProperty($action[0]),$action[1]),$action[2]);
8207
		}
8208
	}
8209
	protected function preRenderRecursive()
8210
	{
8211
		if($this->_cacheAvailable && !$this->_dataCached)
8212
		{
8213
			$stack=$this->getPage()->getCachingStack();
8214
			$stack->push($this);
8215
			parent::preRenderRecursive();
8216
			$stack->pop();
8217
		}
8218
		else
8219
			parent::preRenderRecursive();
8220
	}
8221
	protected function loadStateRecursive(&$state,$needViewState=true)
8222
	{
8223
		$st=unserialize($state);
8224
		parent::loadStateRecursive($st,$needViewState);
8225
	}
8226
	protected function &saveStateRecursive($needViewState=true)
8227
	{
8228
		if($this->_dataCached)
8229
			return $this->_state;
8230
		else
8231
		{
8232
			$st=parent::saveStateRecursive($needViewState);
8233
						$this->_state=serialize($st);
8234
			return $this->_state;
8235
		}
8236
	}
8237
	public function registerAction($context,$funcName,$funcParams)
8238
	{
8239
		$this->_actions[]=array($context,$funcName,$funcParams);
8240
	}
8241
	public function getCacheKey()
8242
	{
8243
		if($this->_cacheKey===null)
8244
			$this->_cacheKey=$this->calculateCacheKey();
8245
		return $this->_cacheKey;
8246
	}
8247
	protected function calculateCacheKey()
8248
	{
8249
		$key=$this->getBaseCacheKey();
8250
		if($this->_varyBySession)
8251
			$key.=$this->getSession()->getSessionID();
8252
		if($this->_varyByParam!=='')
8253
		{
8254
			$params=array();
8255
			$request=$this->getRequest();
8256
			foreach(explode(',',$this->_varyByParam) as $name)
8257
			{
8258
				$name=trim($name);
8259
				$params[$name]=$request->itemAt($name);
8260
			}
8261
			$key.=serialize($params);
8262
		}
8263
		$param=new TOutputCacheCalculateKeyEventParameter;
8264
		$this->onCalculateKey($param);
8265
		$key.=$param->getCacheKey();
8266
		return $key;
8267
	}
8268
	protected function getBaseCacheKey()
8269
	{
8270
		return self::CACHE_ID_PREFIX.$this->_keyPrefix.$this->getPage()->getPagePath().$this->getUniqueID();
8271
	}
8272
	public function getCacheModuleID()
8273
	{
8274
		return $this->_cacheModuleID;
8275
	}
8276
	public function setCacheModuleID($value)
8277
	{
8278
		$this->_cacheModuleID=$value;
8279
	}
8280
	public function setCacheKeyPrefix($value)
8281
	{
8282
		$this->_keyPrefix=$value;
8283
	}
8284
	public function getCacheTime()
8285
	{
8286
		return $this->_cacheTime;
8287
	}
8288
	protected function getCacheDependency()
8289
	{
8290
		return null;
8291
	}
8292
	public function getContentCached()
8293
	{
8294
		return $this->_dataCached;
8295
	}
8296
	public function getDuration()
8297
	{
8298
		return $this->_duration;
8299
	}
8300
	public function setDuration($value)
8301
	{
8302
		if(($value=TPropertyValue::ensureInteger($value))<0)
8303
			throw new TInvalidDataValueException('outputcache_duration_invalid',get_class($this));
8304
		$this->_duration=$value;
8305
	}
8306
	public function getVaryByParam()
8307
	{
8308
		return $this->_varyByParam;
8309
	}
8310
	public function setVaryByParam($value)
8311
	{
8312
		$this->_varyByParam=trim($value);
8313
	}
8314
	public function getVaryBySession()
8315
	{
8316
		return $this->_varyBySession;
8317
	}
8318
	public function setVaryBySession($value)
8319
	{
8320
		$this->_varyBySession=TPropertyValue::ensureBoolean($value);
8321
	}
8322
	public function getCachingPostBack()
8323
	{
8324
		return $this->_cachePostBack;
8325
	}
8326
	public function setCachingPostBack($value)
8327
	{
8328
		$this->_cachePostBack=TPropertyValue::ensureBoolean($value);
8329
	}
8330
	public function onCheckDependency($param)
8331
	{
8332
		$this->raiseEvent('OnCheckDependency',$this,$param);
8333
	}
8334
	public function onCalculateKey($param)
8335
	{
8336
		$this->raiseEvent('OnCalculateKey',$this,$param);
8337
	}
8338
	public function render($writer)
8339
	{
8340
		if($this->_dataCached)
8341
			$writer->write($this->_contents);
8342
		else if($this->_cacheAvailable)
8343
		{
8344
			$textwriter = new TTextWriter();
8345
			$multiwriter = new TOutputCacheTextWriterMulti(array($writer->getWriter(),$textwriter));
8346
			$htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), $multiwriter);
8347
			$stack=$this->getPage()->getCachingStack();
8348
			$stack->push($this);
8349
			parent::render($htmlWriter);
8350
			$stack->pop();
8351
			$content=$textwriter->flush();
8352
			$data=array($content,$this->_state,$this->_actions,time());
8353
			$this->_cache->set($this->getCacheKey(),$data,$this->getDuration(),$this->getCacheDependency());
0 ignored issues
show
Bug introduced by
The method set does only exist in ICache, but not in IModule.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
8354
		}
8355
		else
8356
			parent::render($writer);
8357
	}
8358
}
8359
class TOutputCacheCheckDependencyEventParameter extends TEventParameter
8360
{
8361
	private $_isValid=true;
8362
	private $_cacheTime=0;
8363
	public function getIsValid()
8364
	{
8365
		return $this->_isValid;
8366
	}
8367
	public function setIsValid($value)
8368
	{
8369
		$this->_isValid=TPropertyValue::ensureBoolean($value);
8370
	}
8371
	public function getCacheTime()
8372
	{
8373
		return $this->_cacheTime;
8374
	}
8375
	public function setCacheTime($value)
8376
	{
8377
		$this->_cacheTime=TPropertyValue::ensureInteger($value);
8378
	}
8379
}
8380
class TOutputCacheCalculateKeyEventParameter extends TEventParameter
8381
{
8382
	private $_cacheKey='';
8383
	public function getCacheKey()
8384
	{
8385
		return $this->_cacheKey;
8386
	}
8387
	public function setCacheKey($value)
8388
	{
8389
		$this->_cacheKey=TPropertyValue::ensureString($value);
8390
	}
8391
}
8392
class TOutputCacheTextWriterMulti extends TTextWriter
8393
{
8394
	protected $_writers;
8395
	public function __construct(Array $writers)
8396
	{
8397
				$this->_writers = $writers;
8398
	}
8399
	public function write($s)
8400
	{
8401
		foreach($this->_writers as $writer)
8402
			$writer->write($s);
8403
	}
8404
	public function flush()
8405
	{
8406
		foreach($this->_writers as $writer)
8407
			$s = $writer->flush();
8408
		return $s;
0 ignored issues
show
Bug introduced by
The variable $s does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
8409
	}
8410
}
8411
class TTemplateManager extends TModule
8412
{
8413
	const TEMPLATE_FILE_EXT='.tpl';
8414
	const TEMPLATE_CACHE_PREFIX='prado:template:';
8415
	public function init($config)
8416
	{
8417
		$this->getService()->setTemplateManager($this);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface IService as the method setTemplateManager() does only exist in the following implementations of said interface: TPageService, TWsatService.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
8418
	}
8419
	public function getTemplateByClassName($className)
8420
	{
8421
		$class=new ReflectionClass($className);
8422
		$tplFile=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$className.self::TEMPLATE_FILE_EXT;
8423
		return $this->getTemplateByFileName($tplFile);
8424
	}
8425
	public function getTemplateByFileName($fileName)
8426
	{
8427
		if(($fileName=$this->getLocalizedTemplate($fileName))!==null)
8428
		{
8429
			if(($cache=$this->getApplication()->getCache())===null)
8430
				return new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
8431
			else
8432
			{
8433
				$array=$cache->get(self::TEMPLATE_CACHE_PREFIX.$fileName);
8434
				if(is_array($array))
8435
				{
8436
					list($template,$timestamps)=$array;
8437
					if($this->getApplication()->getMode()===TApplicationMode::Performance)
8438
						return $template;
8439
					$cacheValid=true;
8440
					foreach($timestamps as $tplFile=>$timestamp)
8441
					{
8442
						if(!is_file($tplFile) || filemtime($tplFile)>$timestamp)
8443
						{
8444
							$cacheValid=false;
8445
							break;
8446
						}
8447
					}
8448
					if($cacheValid)
8449
						return $template;
8450
				}
8451
				$template=new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
8452
				$includedFiles=$template->getIncludedFiles();
8453
				$timestamps=array();
8454
				$timestamps[$fileName]=filemtime($fileName);
8455
				foreach($includedFiles as $includedFile)
8456
					$timestamps[$includedFile]=filemtime($includedFile);
8457
				$cache->set(self::TEMPLATE_CACHE_PREFIX.$fileName,array($template,$timestamps));
8458
				return $template;
8459
			}
8460
		}
8461
		else
8462
			return null;
8463
	}
8464
	protected function getLocalizedTemplate($filename)
8465
	{
8466
		if(($app=$this->getApplication()->getGlobalization(false))===null)
8467
			return is_file($filename)?$filename:null;
8468
		foreach($app->getLocalizedResource($filename) as $file)
8469
		{
8470
			if(($file=realpath($file))!==false && is_file($file))
8471
				return $file;
8472
		}
8473
		return null;
8474
	}
8475
}
8476
class TTemplate extends TApplicationComponent implements ITemplate
8477
{
8478
	const REGEX_RULES='/<!--.*?--!>|<!---.*?--->|<\/?com:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/?>|<\/?prop:([\w\.]+)\s*>|<%@\s*((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?")*)\s*%>|<%[%#~\/\\$=\\[](.*?)%>|<prop:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/>/msS';
8479
	const CONFIG_DATABIND=0;
8480
	const CONFIG_EXPRESSION=1;
8481
	const CONFIG_ASSET=2;
8482
	const CONFIG_PARAMETER=3;
8483
	const CONFIG_LOCALIZATION=4;
8484
	const CONFIG_TEMPLATE=5;
8485
	private $_tpl=array();
8486
	private $_directive=array();
8487
	private $_contextPath;
8488
	private $_tplFile=null;
8489
	private $_startingLine=0;
8490
	private $_content;
8491
	private $_sourceTemplate=true;
8492
	private $_hashCode='';
8493
	private $_tplControl=null;
8494
	private $_includedFiles=array();
8495
	private $_includeAtLine=array();
8496
	private $_includeLines=array();
8497
	public function __construct($template,$contextPath,$tplFile=null,$startingLine=0,$sourceTemplate=true)
8498
	{
8499
		$this->_sourceTemplate=$sourceTemplate;
8500
		$this->_contextPath=$contextPath;
8501
		$this->_tplFile=$tplFile;
8502
		$this->_startingLine=$startingLine;
8503
		$this->_content=$template;
8504
		$this->_hashCode=md5($template);
8505
		$this->parse($template);
8506
		$this->_content=null; 	}
8507
	public function getTemplateFile()
8508
	{
8509
		return $this->_tplFile;
8510
	}
8511
	public function getIsSourceTemplate()
8512
	{
8513
		return $this->_sourceTemplate;
8514
	}
8515
	public function getContextPath()
8516
	{
8517
		return $this->_contextPath;
8518
	}
8519
	public function getDirective()
8520
	{
8521
		return $this->_directive;
8522
	}
8523
	public function getHashCode()
8524
	{
8525
		return $this->_hashCode;
8526
	}
8527
	public function &getItems()
8528
	{
8529
		return $this->_tpl;
8530
	}
8531
	public function instantiateIn($tplControl,$parentControl=null)
8532
	{
8533
		$this->_tplControl=$tplControl;
8534
		if($parentControl===null)
8535
			$parentControl=$tplControl;
8536
		if(($page=$tplControl->getPage())===null)
8537
			$page=$this->getService()->getRequestedPage();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface IService as the method getRequestedPage() does only exist in the following implementations of said interface: TPageService, TWsatService.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
8538
		$controls=array();
8539
		$directChildren=array();
8540
		foreach($this->_tpl as $key=>$object)
8541
		{
8542
			if($object[0]===-1)
8543
				$parent=$parentControl;
8544
			else if(isset($controls[$object[0]]))
8545
				$parent=$controls[$object[0]];
8546
			else
8547
				continue;
8548
			if(isset($object[2]))				{
8549
				$component=Prado::createComponent($object[1]);
8550
				$properties=&$object[2];
8551
				if($component instanceof TControl)
8552
				{
8553
					if($component instanceof TOutputCache)
8554
						$component->setCacheKeyPrefix($this->_hashCode.$key);
8555
					$component->setTemplateControl($tplControl);
8556
					if(isset($properties['id']))
8557
					{
8558
						if(is_array($properties['id']))
8559
							$properties['id']=$component->evaluateExpression($properties['id'][1]);
8560
						$tplControl->registerObject($properties['id'],$component);
8561
					}
8562
					if(isset($properties['skinid']))
8563
					{
8564
						if(is_array($properties['skinid']))
8565
							$component->setSkinID($component->evaluateExpression($properties['skinid'][1]));
8566
						else
8567
							$component->setSkinID($properties['skinid']);
8568
						unset($properties['skinid']);
8569
					}
8570
					$component->trackViewState(false);
8571
					$component->applyStyleSheetSkin($page);
8572
					foreach($properties as $name=>$value)
8573
						$this->configureControl($component,$name,$value);
8574
					$component->trackViewState(true);
8575
					if($parent===$parentControl)
8576
						$directChildren[]=$component;
8577
					else
8578
						$component->createdOnTemplate($parent);
8579
					if($component->getAllowChildControls())
8580
						$controls[$key]=$component;
8581
				}
8582
				else if($component instanceof TComponent)
8583
				{
8584
					$controls[$key]=$component;
8585
					if(isset($properties['id']))
8586
					{
8587
						if(is_array($properties['id']))
8588
							$properties['id']=$component->evaluateExpression($properties['id'][1]);
8589
						$tplControl->registerObject($properties['id'],$component);
8590
						if(!$component->hasProperty('id'))
8591
							unset($properties['id']);
8592
					}
8593
					foreach($properties as $name=>$value)
8594
						$this->configureComponent($component,$name,$value);
8595
					if($parent===$parentControl)
8596
						$directChildren[]=$component;
8597
					else
8598
						$component->createdOnTemplate($parent);
8599
				}
8600
			}
8601
			else
8602
			{
8603
				if($object[1] instanceof TCompositeLiteral)
8604
				{
8605
										$o=clone $object[1];
8606
					$o->setContainer($tplControl);
8607
					if($parent===$parentControl)
8608
						$directChildren[]=$o;
8609
					else
8610
						$parent->addParsedObject($o);
8611
				}
8612
				else
8613
				{
8614
					if($parent===$parentControl)
8615
						$directChildren[]=$object[1];
8616
					else
8617
						$parent->addParsedObject($object[1]);
8618
				}
8619
			}
8620
		}
8621
								foreach($directChildren as $control)
8622
		{
8623
			if($control instanceof TComponent)
8624
				$control->createdOnTemplate($parentControl);
8625
			else
8626
				$parentControl->addParsedObject($control);
8627
		}
8628
	}
8629
	protected function configureControl($control,$name,$value)
8630
	{
8631
		if(strncasecmp($name,'on',2)===0)					$this->configureEvent($control,$name,$value,$control);
8632
		else if(($pos=strrpos($name,'.'))===false)				$this->configureProperty($control,$name,$value);
8633
		else				$this->configureSubProperty($control,$name,$value);
8634
	}
8635
	protected function configureComponent($component,$name,$value)
8636
	{
8637
		if(strpos($name,'.')===false)				$this->configureProperty($component,$name,$value);
8638
		else				$this->configureSubProperty($component,$name,$value);
8639
	}
8640
	protected function configureEvent($control,$name,$value,$contextControl)
8641
	{
8642
		if(strpos($value,'.')===false)
8643
			$control->attachEventHandler($name,array($contextControl,'TemplateControl.'.$value));
8644
		else
8645
			$control->attachEventHandler($name,array($contextControl,$value));
8646
	}
8647
	protected function configureProperty($component,$name,$value)
8648
	{
8649
		if(is_array($value))
8650
		{
8651
			switch($value[0])
8652
			{
8653
				case self::CONFIG_DATABIND:
8654
					$component->bindProperty($name,$value[1]);
8655
					break;
8656
				case self::CONFIG_EXPRESSION:
8657
					if($component instanceof TControl)
8658
						$component->autoBindProperty($name,$value[1]);
8659
					else
8660
					{
8661
						$setter='set'.$name;
8662
						$component->$setter($this->_tplControl->evaluateExpression($value[1]));
8663
					}
8664
					break;
8665
				case self::CONFIG_TEMPLATE:
8666
					$setter='set'.$name;
8667
					$component->$setter($value[1]);
8668
					break;
8669
				case self::CONFIG_ASSET:							$setter='set'.$name;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
8670
					$url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
8671
					$component->$setter($url);
8672
					break;
8673
				case self::CONFIG_PARAMETER:							$setter='set'.$name;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
8674
					$component->$setter($this->getApplication()->getParameters()->itemAt($value[1]));
8675
					break;
8676
				case self::CONFIG_LOCALIZATION:
8677
					$setter='set'.$name;
8678
					$component->$setter(Prado::localize($value[1]));
8679
					break;
8680
				default:						throw new TConfigurationException('template_tag_unexpected',$name,$value[1]);
0 ignored issues
show
Coding Style introduced by
The default body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a default statement must start on the line immediately following the statement.

switch ($expr) {
    default:
        doSomething(); //right
        break;
}


switch ($expr) {
    default:

        doSomething(); //wrong
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
8681
					break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
8682
			}
8683
		}
8684
		else
8685
		{
8686
			if (substr($name,0,2)=='js')
8687
				if ($value and !($value instanceof TJavaScriptLiteral))
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
8688
					$value = new TJavaScriptLiteral($value);
8689
			$setter='set'.$name;
8690
			$component->$setter($value);
8691
		}
8692
	}
8693
	protected function configureSubProperty($component,$name,$value)
8694
	{
8695
		if(is_array($value))
8696
		{
8697
			switch($value[0])
8698
			{
8699
				case self::CONFIG_DATABIND:							$component->bindProperty($name,$value[1]);
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
8700
					break;
8701
				case self::CONFIG_EXPRESSION:							if($component instanceof TControl)
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
8702
						$component->autoBindProperty($name,$value[1]);
8703
					else
8704
						$component->setSubProperty($name,$this->_tplControl->evaluateExpression($value[1]));
8705
					break;
8706
				case self::CONFIG_TEMPLATE:
8707
					$component->setSubProperty($name,$value[1]);
8708
					break;
8709
				case self::CONFIG_ASSET:							$url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
8710
					$component->setSubProperty($name,$url);
8711
					break;
8712
				case self::CONFIG_PARAMETER:							$component->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
8713
					break;
8714
				case self::CONFIG_LOCALIZATION:
8715
					$component->setSubProperty($name,Prado::localize($value[1]));
8716
					break;
8717
				default:						throw new TConfigurationException('template_tag_unexpected',$name,$value[1]);
0 ignored issues
show
Coding Style introduced by
The default body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a default statement must start on the line immediately following the statement.

switch ($expr) {
    default:
        doSomething(); //right
        break;
}


switch ($expr) {
    default:

        doSomething(); //wrong
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
8718
					break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
8719
			}
8720
		}
8721
		else
8722
			$component->setSubProperty($name,$value);
8723
	}
8724
	protected function parse($input)
8725
	{
8726
		$input=$this->preprocess($input);
8727
		$tpl=&$this->_tpl;
8728
		$n=preg_match_all(self::REGEX_RULES,$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
8729
		$expectPropEnd=false;
8730
		$textStart=0;
8731
				$stack=array();
8732
		$container=-1;
8733
		$matchEnd=0;
8734
		$c=0;
8735
		$this->_directive=null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $_directive.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
8736
		try
8737
		{
8738
			for($i=0;$i<$n;++$i)
8739
			{
8740
				$match=&$matches[$i];
8741
				$str=$match[0][0];
8742
				$matchStart=$match[0][1];
8743
				$matchEnd=$matchStart+strlen($str)-1;
8744
				if(strpos($str,'<com:')===0)					{
8745
					if($expectPropEnd)
8746
						continue;
8747
					if($matchStart>$textStart)
8748
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8749
					$textStart=$matchEnd+1;
8750
					$type=$match[1][0];
8751
					$attributes=$this->parseAttributes($match[2][0],$match[2][1]);
8752
					$this->validateAttributes($type,$attributes);
8753
					$tpl[$c++]=array($container,$type,$attributes);
8754
					if($str[strlen($str)-2]!=='/')  					{
8755
						$stack[] = $type;
8756
						$container=$c-1;
8757
					}
8758
				}
8759
				else if(strpos($str,'</com:')===0)					{
8760
					if($expectPropEnd)
8761
						continue;
8762
					if($matchStart>$textStart)
8763
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8764
					$textStart=$matchEnd+1;
8765
					$type=$match[1][0];
8766
					if(empty($stack))
8767
						throw new TConfigurationException('template_closingtag_unexpected',"</com:$type>");
8768
					$name=array_pop($stack);
8769
					if($name!==$type)
8770
					{
8771
						$tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
8772
						throw new TConfigurationException('template_closingtag_expected',$tag);
8773
					}
8774
					$container=$tpl[$container][0];
8775
				}
8776
				else if(strpos($str,'<%@')===0)					{
8777
					if($expectPropEnd)
8778
						continue;
8779
					if($matchStart>$textStart)
8780
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8781
					$textStart=$matchEnd+1;
8782
					if(isset($tpl[0]) || $this->_directive!==null)
8783
						throw new TConfigurationException('template_directive_nonunique');
8784
					$this->_directive=$this->parseAttributes($match[4][0],$match[4][1]);
8785
				}
8786
				else if(strpos($str,'<%')===0)					{
8787
					if($expectPropEnd)
8788
						continue;
8789
					if($matchStart>$textStart)
8790
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8791
					$textStart=$matchEnd+1;
8792
					$literal=trim($match[5][0]);
8793
					if($str[2]==='=')							$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,$literal));
8794
					else if($str[2]==='%')  						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_STATEMENTS,$literal));
8795
					else if($str[2]==='#')
8796
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_DATABINDING,$literal));
8797
					else if($str[2]==='$')
8798
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->getApplication()->getParameters()->itemAt('$literal')"));
8799
					else if($str[2]==='~')
8800
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->publishFilePath('$this->_contextPath/$literal')"));
8801
					else if($str[2]==='/')
8802
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"rtrim(dirname(\$this->getApplication()->getRequest()->getApplicationUrl()), '/').'/$literal'"));
8803
					else if($str[2]==='[')
8804
					{
8805
						$literal=strtr(trim(substr($literal,0,strlen($literal)-1)),array("'"=>"\'","\\"=>"\\\\"));
8806
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"Prado::localize('$literal')"));
8807
					}
8808
				}
8809
				else if(strpos($str,'<prop:')===0)					{
8810
					if(strrpos($str,'/>')===strlen($str)-2)  					{
8811
						if($expectPropEnd)
8812
							continue;
8813
						if($matchStart>$textStart)
8814
							$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8815
						$textStart=$matchEnd+1;
8816
						$prop=strtolower($match[6][0]);
8817
						$attrs=$this->parseAttributes($match[7][0],$match[7][1]);
8818
						$attributes=array();
8819
						foreach($attrs as $name=>$value)
8820
							$attributes[$prop.'.'.$name]=$value;
8821
						$type=$tpl[$container][1];
8822
						$this->validateAttributes($type,$attributes);
8823
						foreach($attributes as $name=>$value)
8824
						{
8825
							if(isset($tpl[$container][2][$name]))
8826
								throw new TConfigurationException('template_property_duplicated',$name);
8827
							$tpl[$container][2][$name]=$value;
8828
						}
8829
					}
8830
					else  					{
8831
						$prop=strtolower($match[3][0]);
8832
						$stack[] = '@'.$prop;
8833
						if(!$expectPropEnd)
8834
						{
8835
							if($matchStart>$textStart)
8836
								$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8837
							$textStart=$matchEnd+1;
8838
							$expectPropEnd=true;
8839
						}
8840
					}
8841
				}
8842
				else if(strpos($str,'</prop:')===0)					{
8843
					$prop=strtolower($match[3][0]);
8844
					if(empty($stack))
8845
						throw new TConfigurationException('template_closingtag_unexpected',"</prop:$prop>");
8846
					$name=array_pop($stack);
8847
					if($name!=='@'.$prop)
8848
					{
8849
						$tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
8850
						throw new TConfigurationException('template_closingtag_expected',$tag);
8851
					}
8852
					if(($last=count($stack))<1 || $stack[$last-1][0]!=='@')
8853
					{
8854
						if($matchStart>$textStart)
8855
						{
8856
							$value=substr($input,$textStart,$matchStart-$textStart);
8857
							if(substr($prop,-8,8)==='template')
8858
								$value=$this->parseTemplateProperty($value,$textStart);
8859
							else
8860
								$value=$this->parseAttribute($value);
8861
							if($container>=0)
8862
							{
8863
								$type=$tpl[$container][1];
8864
								$this->validateAttributes($type,array($prop=>$value));
8865
								if(isset($tpl[$container][2][$prop]))
8866
									throw new TConfigurationException('template_property_duplicated',$prop);
8867
								$tpl[$container][2][$prop]=$value;
8868
							}
8869
							else									$this->_directive[$prop]=$value;
8870
							$textStart=$matchEnd+1;
8871
						}
8872
						$expectPropEnd=false;
8873
					}
8874
				}
8875
				else if(strpos($str,'<!--')===0)					{
8876
					if($expectPropEnd)
8877
						throw new TConfigurationException('template_comments_forbidden');
8878
					if($matchStart>$textStart)
8879
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8880
					$textStart=$matchEnd+1;
8881
				}
8882
				else
8883
					throw new TConfigurationException('template_matching_unexpected',$match);
8884
			}
8885
			if(!empty($stack))
8886
			{
8887
				$name=array_pop($stack);
8888
				$tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
8889
				throw new TConfigurationException('template_closingtag_expected',$tag);
8890
			}
8891
			if($textStart<strlen($input))
8892
				$tpl[$c++]=array($container,substr($input,$textStart));
8893
		}
8894
		catch(Exception $e)
8895
		{
8896
			if(($e instanceof TException) && ($e instanceof TTemplateException))
8897
				throw $e;
8898
			if($matchEnd===0)
8899
				$line=$this->_startingLine+1;
8900
			else
8901
				$line=$this->_startingLine+count(explode("\n",substr($input,0,$matchEnd+1)));
8902
			$this->handleException($e,$line,$input);
8903
		}
8904
		if($this->_directive===null)
8905
			$this->_directive=array();
8906
				$objects=array();
8907
		$parent=null;
8908
		$merged=array();
8909
		foreach($tpl as $id=>$object)
8910
		{
8911
			if(isset($object[2]) || $object[0]!==$parent)
8912
			{
8913
				if($parent!==null)
8914
				{
8915
					if(count($merged[1])===1 && is_string($merged[1][0]))
8916
						$objects[$id-1]=array($merged[0],$merged[1][0]);
8917
					else
8918
						$objects[$id-1]=array($merged[0],new TCompositeLiteral($merged[1]));
8919
				}
8920
				if(isset($object[2]))
8921
				{
8922
					$parent=null;
8923
					$objects[$id]=$object;
8924
				}
8925
				else
8926
				{
8927
					$parent=$object[0];
8928
					$merged=array($parent,array($object[1]));
8929
				}
8930
			}
8931
			else
8932
				$merged[1][]=$object[1];
8933
		}
8934
		if($parent!==null)
8935
		{
8936
			if(count($merged[1])===1 && is_string($merged[1][0]))
8937
				$objects[$id]=array($merged[0],$merged[1][0]);
0 ignored issues
show
Bug introduced by
The variable $id seems to be defined by a foreach iteration on line 8909. Are you sure the iterator is never empty, otherwise this variable is not defined?

It seems like you are relying on a variable being defined by an iteration:

foreach ($a as $b) {
}

// $b is defined here only if $a has elements, for example if $a is array()
// then $b would not be defined here. To avoid that, we recommend to set a
// default value for $b.


// Better
$b = 0; // or whatever default makes sense in your context
foreach ($a as $b) {
}

// $b is now guaranteed to be defined here.
Loading history...
8938
			else
8939
				$objects[$id]=array($merged[0],new TCompositeLiteral($merged[1]));
8940
		}
8941
		$tpl=$objects;
8942
		return $objects;
8943
	}
8944
	protected function parseAttributes($str,$offset)
8945
	{
8946
		if($str==='')
8947
			return array();
8948
		$pattern='/([\w\.\-]+)\s*=\s*(\'.*?\'|".*?"|<%.*?%>)/msS';
8949
		$attributes=array();
8950
		$n=preg_match_all($pattern,$str,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
8951
		for($i=0;$i<$n;++$i)
8952
		{
8953
			$match=&$matches[$i];
8954
			$name=strtolower($match[1][0]);
8955
			if(isset($attributes[$name]))
8956
				throw new TConfigurationException('template_property_duplicated',$name);
8957
			$value=$match[2][0];
8958
			if(substr($name,-8,8)==='template')
8959
			{
8960
				if($value[0]==='\'' || $value[0]==='"')
8961
					$attributes[$name]=$this->parseTemplateProperty(substr($value,1,strlen($value)-2),$match[2][1]+1);
8962
				else
8963
					$attributes[$name]=$this->parseTemplateProperty($value,$match[2][1]);
8964
			}
8965
			else
8966
			{
8967
				if($value[0]==='\'' || $value[0]==='"')
8968
					$attributes[$name]=$this->parseAttribute(substr($value,1,strlen($value)-2));
8969
				else
8970
					$attributes[$name]=$this->parseAttribute($value);
8971
			}
8972
		}
8973
		return $attributes;
8974
	}
8975
	protected function parseTemplateProperty($content,$offset)
8976
	{
8977
		$line=$this->_startingLine+count(explode("\n",substr($this->_content,0,$offset)))-1;
8978
		return array(self::CONFIG_TEMPLATE,new TTemplate($content,$this->_contextPath,$this->_tplFile,$line,false));
8979
	}
8980
	protected function parseAttribute($value)
8981
	{
8982
		if(($n=preg_match_all('/<%[#=].*?%>/msS',$value,$matches,PREG_OFFSET_CAPTURE))>0)
8983
		{
8984
			$isDataBind=false;
8985
			$textStart=0;
8986
			$expr='';
8987
			for($i=0;$i<$n;++$i)
8988
			{
8989
				$match=$matches[0][$i];
8990
				$token=$match[0];
8991
				$offset=$match[1];
8992
				$length=strlen($token);
8993
				if($token[2]==='#')
8994
					$isDataBind=true;
8995
				if($offset>$textStart)
8996
					$expr.=".'".strtr(substr($value,$textStart,$offset-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
8997
				$expr.='.('.substr($token,3,$length-5).')';
8998
				$textStart=$offset+$length;
8999
			}
9000
			$length=strlen($value);
9001
			if($length>$textStart)
9002
				$expr.=".'".strtr(substr($value,$textStart,$length-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
9003
			if($isDataBind)
9004
				return array(self::CONFIG_DATABIND,ltrim($expr,'.'));
9005
			else
9006
				return array(self::CONFIG_EXPRESSION,ltrim($expr,'.'));
9007
		}
9008
		else if(preg_match('/\\s*(<%~.*?%>|<%\\$.*?%>|<%\\[.*?\\]%>|<%\/.*?%>)\\s*/msS',$value,$matches) && $matches[0]===$value)
9009
		{
9010
			$value=$matches[1];
9011
			if($value[2]==='~')
9012
				return array(self::CONFIG_ASSET,trim(substr($value,3,strlen($value)-5)));
9013
			elseif($value[2]==='[')
9014
				return array(self::CONFIG_LOCALIZATION,trim(substr($value,3,strlen($value)-6)));
9015
			elseif($value[2]==='$')
9016
				return array(self::CONFIG_PARAMETER,trim(substr($value,3,strlen($value)-5)));
9017
			elseif($value[2]==='/') {
9018
				$literal = trim(substr($value,3,strlen($value)-5));
9019
				return array(self::CONFIG_EXPRESSION,"rtrim(dirname(\$this->getApplication()->getRequest()->getApplicationUrl()), '/').'/$literal'");
9020
			}
9021
		}
9022
		else
9023
			return $value;
9024
	}
9025
	protected function validateAttributes($type,$attributes)
9026
	{
9027
		Prado::using($type);
9028
		if(($pos=strrpos($type,'.'))!==false)
9029
			$className=substr($type,$pos+1);
9030
		else
9031
			$className=$type;
9032
		$class=new ReflectionClass($className);
9033
		if(is_subclass_of($className,'TControl') || $className==='TControl')
9034
		{
9035
			foreach($attributes as $name=>$att)
9036
			{
9037
				if(($pos=strpos($name,'.'))!==false)
9038
				{
9039
										$subname=substr($name,0,$pos);
9040
					if(!$class->hasMethod('get'.$subname))
9041
						throw new TConfigurationException('template_property_unknown',$type,$subname);
9042
				}
9043
				else if(strncasecmp($name,'on',2)===0)
9044
				{
9045
										if(!$class->hasMethod($name))
9046
						throw new TConfigurationException('template_event_unknown',$type,$name);
9047
					else if(!is_string($att))
9048
						throw new TConfigurationException('template_eventhandler_invalid',$type,$name);
9049
				}
9050
				else
9051
				{
9052
										if (! ($class->hasMethod('set'.$name) || $class->hasMethod('setjs'.$name) || $this->isClassBehaviorMethod($class,'set'.$name)) )
9053
					{
9054
						if ($class->hasMethod('get'.$name) || $class->hasMethod('getjs'.$name))
9055
							throw new TConfigurationException('template_property_readonly',$type,$name);
9056
						else
9057
							throw new TConfigurationException('template_property_unknown',$type,$name);
9058
					}
9059
					else if(is_array($att) && $att[0]!==self::CONFIG_EXPRESSION)
9060
					{
9061
						if(strcasecmp($name,'id')===0)
9062
							throw new TConfigurationException('template_controlid_invalid',$type);
9063
						else if(strcasecmp($name,'skinid')===0)
9064
							throw new TConfigurationException('template_controlskinid_invalid',$type);
9065
					}
9066
				}
9067
			}
9068
		}
9069
		else if(is_subclass_of($className,'TComponent') || $className==='TComponent')
9070
		{
9071
			foreach($attributes as $name=>$att)
9072
			{
9073
				if(is_array($att) && ($att[0]===self::CONFIG_DATABIND))
9074
					throw new TConfigurationException('template_databind_forbidden',$type,$name);
9075
				if(($pos=strpos($name,'.'))!==false)
9076
				{
9077
										$subname=substr($name,0,$pos);
9078
					if(!$class->hasMethod('get'.$subname))
9079
						throw new TConfigurationException('template_property_unknown',$type,$subname);
9080
				}
9081
				else if(strncasecmp($name,'on',2)===0)
9082
					throw new TConfigurationException('template_event_forbidden',$type,$name);
9083
				else
9084
				{
9085
										if(strcasecmp($name,'id')!==0 && !($class->hasMethod('set'.$name) || $this->isClassBehaviorMethod($class,'set'.$name)))
9086
					{
9087
						if($class->hasMethod('get'.$name))
9088
							throw new TConfigurationException('template_property_readonly',$type,$name);
9089
						else
9090
							throw new TConfigurationException('template_property_unknown',$type,$name);
9091
					}
9092
				}
9093
			}
9094
		}
9095
		else
9096
			throw new TConfigurationException('template_component_required',$type);
9097
	}
9098
	public function getIncludedFiles()
9099
	{
9100
		return $this->_includedFiles;
9101
	}
9102
	protected function handleException($e,$line,$input=null)
9103
	{
9104
		$srcFile=$this->_tplFile;
9105
		if(($n=count($this->_includedFiles))>0) 		{
9106
			for($i=$n-1;$i>=0;--$i)
9107
			{
9108
				if($this->_includeAtLine[$i]<=$line)
9109
				{
9110
					if($line<$this->_includeAtLine[$i]+$this->_includeLines[$i])
9111
					{
9112
						$line=$line-$this->_includeAtLine[$i]+1;
9113
						$srcFile=$this->_includedFiles[$i];
9114
						break;
9115
					}
9116
					else
9117
						$line=$line-$this->_includeLines[$i]+1;
9118
				}
9119
			}
9120
		}
9121
		$exception=new TTemplateException('template_format_invalid',$e->getMessage());
9122
		$exception->setLineNumber($line);
9123
		if(!empty($srcFile))
9124
			$exception->setTemplateFile($srcFile);
9125
		else
9126
			$exception->setTemplateSource($input);
9127
		throw $exception;
9128
	}
9129
	protected function preprocess($input)
9130
	{
9131
		if($n=preg_match_all('/<%include(.*?)%>/',$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE))
9132
		{
9133
			for($i=0;$i<$n;++$i)
9134
			{
9135
				$filePath=Prado::getPathOfNamespace(trim($matches[$i][1][0]),TTemplateManager::TEMPLATE_FILE_EXT);
9136
				if($filePath!==null && is_file($filePath))
9137
					$this->_includedFiles[]=$filePath;
9138
				else
9139
				{
9140
					$errorLine=count(explode("\n",substr($input,0,$matches[$i][0][1]+1)));
9141
					$this->handleException(new TConfigurationException('template_include_invalid',trim($matches[$i][1][0])),$errorLine,$input);
9142
				}
9143
			}
9144
			$base=0;
9145
			for($i=0;$i<$n;++$i)
9146
			{
9147
				$ext=file_get_contents($this->_includedFiles[$i]);
9148
				$length=strlen($matches[$i][0][0]);
9149
				$offset=$base+$matches[$i][0][1];
9150
				$this->_includeAtLine[$i]=count(explode("\n",substr($input,0,$offset)));
9151
				$this->_includeLines[$i]=count(explode("\n",$ext));
9152
				$input=substr_replace($input,$ext,$offset,$length);
9153
				$base+=strlen($ext)-$length;
9154
			}
9155
		}
9156
		return $input;
9157
	}
9158
	protected function isClassBehaviorMethod(ReflectionClass $class,$method)
9159
	{
9160
	  $component=new ReflectionClass('TComponent');
9161
	  $behaviors=$component->getStaticProperties();
9162
	  if(!isset($behaviors['_um']))
9163
	    return false;
9164
	  foreach($behaviors['_um'] as $name=>$list)
0 ignored issues
show
Bug introduced by
The expression $behaviors['_um'] of type string is not traversable.
Loading history...
9165
	  {
9166
	    if(strtolower($class->getShortName())!==$name && !$class->isSubclassOf($name)) continue;
9167
	    foreach($list as $param)
9168
	    {
9169
	      if(method_exists($param->getBehavior(),$method))
9170
	        return true;
9171
	    }
9172
	  }
9173
	  return false;
9174
	}
9175
}
9176
class TThemeManager extends TModule
9177
{
9178
	const DEFAULT_BASEPATH='themes';
9179
	const DEFAULT_THEMECLASS = 'TTheme';
9180
	private $_themeClass=self::DEFAULT_THEMECLASS;
9181
	private $_initialized=false;
9182
	private $_basePath=null;
9183
	private $_baseUrl=null;
9184
	public function init($config)
9185
	{
9186
		$this->_initialized=true;
9187
		$service=$this->getService();
9188
		if($service instanceof TPageService)
9189
			$service->setThemeManager($this);
9190
		else
9191
			throw new TConfigurationException('thememanager_service_unavailable');
9192
	}
9193
	public function getTheme($name)
9194
	{
9195
		$themePath=$this->getBasePath().DIRECTORY_SEPARATOR.$name;
9196
		$themeUrl=rtrim($this->getBaseUrl(),'/').'/'.$name;
9197
		return Prado::createComponent($this->getThemeClass(), $themePath, $themeUrl);
9198
	}
9199
	public function setThemeClass($class) {
9200
		$this->_themeClass = $class===null ? self::DEFAULT_THEMECLASS : (string)$class;
9201
	}
9202
	public function getThemeClass() {
9203
		return $this->_themeClass;
9204
	}
9205
	public function getAvailableThemes()
9206
	{
9207
		$themes=array();
9208
		$basePath=$this->getBasePath();
9209
		$folder=@opendir($basePath);
9210
		while($file=@readdir($folder))
9211
		{
9212
			if($file!=='.' && $file!=='..' && $file!=='.svn' && is_dir($basePath.DIRECTORY_SEPARATOR.$file))
9213
				$themes[]=$file;
9214
		}
9215
		closedir($folder);
9216
		return $themes;
9217
	}
9218
	public function getBasePath()
9219
	{
9220
		if($this->_basePath===null)
9221
		{
9222
			$this->_basePath=dirname($this->getRequest()->getApplicationFilePath()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
9223
			if(($basePath=realpath($this->_basePath))===false || !is_dir($basePath))
9224
				throw new TConfigurationException('thememanager_basepath_invalid2',$this->_basePath);
9225
			$this->_basePath=$basePath;
9226
		}
9227
		return $this->_basePath;
9228
	}
9229
	public function setBasePath($value)
9230
	{
9231
		if($this->_initialized)
9232
			throw new TInvalidOperationException('thememanager_basepath_unchangeable');
9233
		else
9234
		{
9235
			$this->_basePath=Prado::getPathOfNamespace($value);
9236
			if($this->_basePath===null || !is_dir($this->_basePath))
9237
				throw new TInvalidDataValueException('thememanager_basepath_invalid',$value);
9238
		}
9239
	}
9240
	public function getBaseUrl()
9241
	{
9242
		if($this->_baseUrl===null)
9243
		{
9244
			$appPath=dirname($this->getRequest()->getApplicationFilePath());
9245
			$basePath=$this->getBasePath();
9246
			if(strpos($basePath,$appPath)===false)
9247
				throw new TConfigurationException('thememanager_baseurl_required');
9248
			$appUrl=rtrim(dirname($this->getRequest()->getApplicationUrl()),'/\\');
9249
			$this->_baseUrl=$appUrl.strtr(substr($basePath,strlen($appPath)),'\\','/');
9250
		}
9251
		return $this->_baseUrl;
9252
	}
9253
	public function setBaseUrl($value)
9254
	{
9255
		$this->_baseUrl=rtrim($value,'/');
9256
	}
9257
}
9258
class TTheme extends TApplicationComponent implements ITheme
9259
{
9260
	const THEME_CACHE_PREFIX='prado:theme:';
9261
	const SKIN_FILE_EXT='.skin';
9262
	private $_themePath;
9263
	private $_themeUrl;
9264
	private $_skins=null;
9265
	private $_name='';
9266
	private $_cssFiles=array();
9267
	private $_jsFiles=array();
9268
	public function __construct($themePath,$themeUrl)
9269
	{
9270
		$this->_themeUrl=$themeUrl;
9271
		$this->_themePath=realpath($themePath);
9272
		$this->_name=basename($themePath);
9273
		$cacheValid=false;
9274
				if(($cache=$this->getApplication()->getCache())!==null)
9275
		{
9276
			$array=$cache->get(self::THEME_CACHE_PREFIX.$themePath);
9277
			if(is_array($array))
9278
			{
9279
				list($skins,$cssFiles,$jsFiles,$timestamp)=$array;
9280
				if($this->getApplication()->getMode()!==TApplicationMode::Performance)
9281
				{
9282
					if(($dir=opendir($themePath))===false)
9283
						throw new TIOException('theme_path_inexistent',$themePath);
9284
					$cacheValid=true;
9285
					while(($file=readdir($dir))!==false)
9286
					{
9287
						if($file==='.' || $file==='..')
9288
							continue;
9289
						else if(basename($file,'.css')!==$file)
9290
							$this->_cssFiles[]=$themeUrl.'/'.$file;
9291
						else if(basename($file,'.js')!==$file)
9292
							$this->_jsFiles[]=$themeUrl.'/'.$file;
9293
						else if(basename($file,self::SKIN_FILE_EXT)!==$file && filemtime($themePath.DIRECTORY_SEPARATOR.$file)>$timestamp)
9294
						{
9295
							$cacheValid=false;
9296
							break;
9297
						}
9298
					}
9299
					closedir($dir);
9300
					if($cacheValid)
9301
						$this->_skins=$skins;
9302
				}
9303
				else
9304
				{
9305
					$cacheValid=true;
9306
					$this->_cssFiles=$cssFiles;
9307
					$this->_jsFiles=$jsFiles;
9308
					$this->_skins=$skins;
9309
				}
9310
			}
9311
		}
9312
		if(!$cacheValid)
9313
		{
9314
			$this->_cssFiles=array();
9315
			$this->_jsFiles=array();
9316
			$this->_skins=array();
9317
			if(($dir=opendir($themePath))===false)
9318
				throw new TIOException('theme_path_inexistent',$themePath);
9319
			while(($file=readdir($dir))!==false)
9320
			{
9321
				if($file==='.' || $file==='..')
9322
					continue;
9323
				else if(basename($file,'.css')!==$file)
9324
					$this->_cssFiles[]=$themeUrl.'/'.$file;
9325
				else if(basename($file,'.js')!==$file)
9326
					$this->_jsFiles[]=$themeUrl.'/'.$file;
9327
				else if(basename($file,self::SKIN_FILE_EXT)!==$file)
9328
				{
9329
					$template=new TTemplate(file_get_contents($themePath.'/'.$file),$themePath,$themePath.'/'.$file);
9330
					foreach($template->getItems() as $skin)
9331
					{
9332
						if(!isset($skin[2]))  							continue;
9333
						else if($skin[0]!==-1)
9334
							throw new TConfigurationException('theme_control_nested',$skin[1],dirname($themePath));
9335
						$type=$skin[1];
9336
						$id=isset($skin[2]['skinid'])?$skin[2]['skinid']:0;
9337
						unset($skin[2]['skinid']);
9338
						if(isset($this->_skins[$type][$id]))
9339
							throw new TConfigurationException('theme_skinid_duplicated',$type,$id,dirname($themePath));
9340
						$this->_skins[$type][$id]=$skin[2];
9341
					}
9342
				}
9343
			}
9344
			closedir($dir);
9345
			sort($this->_cssFiles);
9346
			sort($this->_jsFiles);
9347
			if($cache!==null)
9348
				$cache->set(self::THEME_CACHE_PREFIX.$themePath,array($this->_skins,$this->_cssFiles,$this->_jsFiles,time()));
9349
		}
9350
	}
9351
	public function getName()
9352
	{
9353
		return $this->_name;
9354
	}
9355
	protected function setName($value)
9356
	{
9357
		$this->_name = $value;
9358
	}
9359
	public function getBaseUrl()
9360
	{
9361
		return $this->_themeUrl;
9362
	}
9363
	protected function setBaseUrl($value)
9364
	{
9365
		$this->_themeUrl=rtrim($value,'/');
9366
	}
9367
	public function getBasePath()
9368
	{
9369
		return $this->_themePath;
9370
	}
9371
	protected function setBasePath($value)
9372
	{
9373
		$this->_themePath=$value;
9374
	}
9375
	public function getSkins()
9376
	{
9377
		return $this->_skins;
9378
	}
9379
	protected function setSkins($value)
9380
	{
9381
		$this->_skins = $value;
9382
	}
9383
	public function applySkin($control)
9384
	{
9385
		$type=get_class($control);
9386
		if(($id=$control->getSkinID())==='')
9387
			$id=0;
9388
		if(isset($this->_skins[$type][$id]))
9389
		{
9390
			foreach($this->_skins[$type][$id] as $name=>$value)
9391
			{
9392
				if(is_array($value))
9393
				{
9394
					switch($value[0])
9395
					{
9396
						case TTemplate::CONFIG_EXPRESSION:
9397
							$value=$this->evaluateExpression($value[1]);
9398
							break;
9399
						case TTemplate::CONFIG_ASSET:
9400
							$value=$this->_themeUrl.'/'.ltrim($value[1],'/');
9401
							break;
9402
						case TTemplate::CONFIG_DATABIND:
9403
							$control->bindProperty($name,$value[1]);
9404
							break;
9405
						case TTemplate::CONFIG_PARAMETER:
9406
							$control->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
9407
							break;
9408
						case TTemplate::CONFIG_TEMPLATE:
9409
							$control->setSubProperty($name,$value[1]);
9410
							break;
9411
						case TTemplate::CONFIG_LOCALIZATION:
9412
							$control->setSubProperty($name,Prado::localize($value[1]));
9413
							break;
9414
						default:
9415
							throw new TConfigurationException('theme_tag_unexpected',$name,$value[0]);
9416
							break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
9417
					}
9418
				}
9419
				if(!is_array($value))
9420
				{
9421
					if(strpos($name,'.')===false)						{
9422
						if($control->hasProperty($name))
9423
						{
9424
							if($control->canSetProperty($name))
9425
							{
9426
								$setter='set'.$name;
9427
								$control->$setter($value);
9428
							}
9429
							else
9430
								throw new TConfigurationException('theme_property_readonly',$type,$name);
9431
						}
9432
						else
9433
							throw new TConfigurationException('theme_property_undefined',$type,$name);
9434
					}
9435
					else							$control->setSubProperty($name,$value);
9436
				}
9437
			}
9438
			return true;
9439
		}
9440
		else
9441
			return false;
9442
	}
9443
	public function getStyleSheetFiles()
9444
	{
9445
		return $this->_cssFiles;
9446
	}
9447
	protected function setStyleSheetFiles($value)
9448
	{
9449
		$this->_cssFiles=$value;
9450
	}
9451
	public function getJavaScriptFiles()
9452
	{
9453
		return $this->_jsFiles;
9454
	}
9455
	protected function setJavaScriptFiles($value)
9456
	{
9457
		$this->_jsFiles=$value;
9458
	}
9459
}
9460
class TPageService extends TService
9461
{
9462
	const CONFIG_FILE_XML='config.xml';
9463
	const CONFIG_FILE_PHP='config.php';
9464
	const DEFAULT_BASEPATH='Pages';
9465
	const FALLBACK_BASEPATH='pages';
9466
	const CONFIG_CACHE_PREFIX='prado:pageservice:';
9467
	const PAGE_FILE_EXT='.page';
9468
	private $_basePath=null;
9469
	private $_basePageClass='TPage';
9470
	private $_clientScriptManagerClass='System.Web.UI.TClientScriptManager';
9471
	private $_defaultPage='Home';
9472
	private $_pagePath=null;
9473
	private $_page=null;
9474
	private $_properties=array();
9475
	private $_initialized=false;
9476
	private $_themeManager=null;
9477
	private $_templateManager=null;
9478
	public function init($config)
9479
	{
9480
		$pageConfig=$this->loadPageConfig($config);
9481
		$this->initPageContext($pageConfig);
9482
		$this->_initialized=true;
9483
	}
9484
	protected function initPageContext($pageConfig)
9485
	{
9486
		$application=$this->getApplication();
9487
		foreach($pageConfig->getApplicationConfigurations() as $appConfig)
9488
			$application->applyConfiguration($appConfig);
9489
		$this->applyConfiguration($pageConfig);
9490
	}
9491
	protected function applyConfiguration($config)
9492
	{
9493
				$this->_properties=array_merge($this->_properties, $config->getProperties());
9494
		$this->getApplication()->getAuthorizationRules()->mergeWith($config->getRules());
9495
		$pagePath=$this->getRequestedPagePath();
9496
				foreach($config->getExternalConfigurations() as $filePath=>$params)
9497
		{
9498
			list($configPagePath,$condition)=$params;
9499
			if($condition!==true)
9500
				$condition=$this->evaluateExpression($condition);
9501
			if($condition)
9502
			{
9503
				if(($path=Prado::getPathOfNamespace($filePath,Prado::getApplication()->getConfigurationFileExt()))===null || !is_file($path))
9504
					throw new TConfigurationException('pageservice_includefile_invalid',$filePath);
9505
				$c=new TPageConfiguration($pagePath);
9506
				$c->loadFromFile($path,$configPagePath);
9507
				$this->applyConfiguration($c);
9508
			}
9509
		}
9510
	}
9511
	protected function determineRequestedPagePath()
9512
	{
9513
		$pagePath=$this->getRequest()->getServiceParameter();
9514
		if(empty($pagePath))
9515
			$pagePath=$this->getDefaultPage();
9516
		return $pagePath;
9517
	}
9518
	protected function loadPageConfig($config)
9519
	{
9520
		$application=$this->getApplication();
9521
		$pagePath=$this->getRequestedPagePath();
9522
		if(($cache=$application->getCache())===null)
9523
		{
9524
			$pageConfig=new TPageConfiguration($pagePath);
9525
			if($config!==null)
9526
			{
9527
				if($application->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
9528
					$pageConfig->loadPageConfigurationFromPhp($config,$application->getBasePath(),'');
9529
				else
9530
					$pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),'');
9531
			}
9532
			$pageConfig->loadFromFiles($this->getBasePath());
9533
		}
9534
		else
9535
		{
9536
			$configCached=true;
9537
			$currentTimestamp=array();
9538
			$arr=$cache->get(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath);
9539
			if(is_array($arr))
9540
			{
9541
				list($pageConfig,$timestamps)=$arr;
9542
				if($application->getMode()!==TApplicationMode::Performance)
9543
				{
9544
					foreach($timestamps as $fileName=>$timestamp)
9545
					{
9546
						if($fileName===0) 						{
9547
							$appConfigFile=$application->getConfigurationFile();
9548
							$currentTimestamp[0]=$appConfigFile===null?0:@filemtime($appConfigFile);
9549
							if($currentTimestamp[0]>$timestamp || ($timestamp>0 && !$currentTimestamp[0]))
9550
								$configCached=false;
9551
						}
9552
						else
9553
						{
9554
							$currentTimestamp[$fileName]=@filemtime($fileName);
9555
							if($currentTimestamp[$fileName]>$timestamp || ($timestamp>0 && !$currentTimestamp[$fileName]))
9556
								$configCached=false;
9557
						}
9558
					}
9559
				}
9560
			}
9561
			else
9562
			{
9563
				$configCached=false;
9564
				$paths=explode('.',$pagePath);
9565
				$configPath=$this->getBasePath();
9566
				$fileName = $this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP
9567
					? self::CONFIG_FILE_PHP
9568
					: self::CONFIG_FILE_XML;
9569
				foreach($paths as $path)
9570
				{
9571
					$configFile=$configPath.DIRECTORY_SEPARATOR.$fileName;
9572
					$currentTimestamp[$configFile]=@filemtime($configFile);
9573
					$configPath.=DIRECTORY_SEPARATOR.$path;
9574
				}
9575
				$appConfigFile=$application->getConfigurationFile();
9576
				$currentTimestamp[0]=$appConfigFile===null?0:@filemtime($appConfigFile);
9577
			}
9578
			if(!$configCached)
9579
			{
9580
				$pageConfig=new TPageConfiguration($pagePath);
9581
				if($config!==null)
9582
				{
9583
					if($application->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
9584
						$pageConfig->loadPageConfigurationFromPhp($config,$application->getBasePath(),'');
9585
					else
9586
						$pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),'');
9587
				}
9588
				$pageConfig->loadFromFiles($this->getBasePath());
9589
				$cache->set(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath,array($pageConfig,$currentTimestamp));
9590
			}
9591
		}
9592
		return $pageConfig;
0 ignored issues
show
Bug introduced by
The variable $pageConfig does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
9593
	}
9594
	public function getTemplateManager()
9595
	{
9596
		if(!$this->_templateManager)
9597
		{
9598
			$this->_templateManager=new TTemplateManager;
9599
			$this->_templateManager->init(null);
9600
		}
9601
		return $this->_templateManager;
9602
	}
9603
	public function setTemplateManager(TTemplateManager $value)
9604
	{
9605
		$this->_templateManager=$value;
9606
	}
9607
	public function getThemeManager()
9608
	{
9609
		if(!$this->_themeManager)
9610
		{
9611
			$this->_themeManager=new TThemeManager;
9612
			$this->_themeManager->init(null);
9613
		}
9614
		return $this->_themeManager;
9615
	}
9616
	public function setThemeManager(TThemeManager $value)
9617
	{
9618
		$this->_themeManager=$value;
9619
	}
9620
	public function getRequestedPagePath()
9621
	{
9622
		if($this->_pagePath===null)
9623
		{
9624
			$this->_pagePath=strtr($this->determineRequestedPagePath(),'/\\','..');
9625
			if(empty($this->_pagePath))
9626
				throw new THttpException(404,'pageservice_page_required');
9627
		}
9628
		return $this->_pagePath;
9629
	}
9630
	public function getRequestedPage()
9631
	{
9632
		return $this->_page;
9633
	}
9634
	public function getDefaultPage()
9635
	{
9636
		return $this->_defaultPage;
9637
	}
9638
	public function setDefaultPage($value)
9639
	{
9640
		if($this->_initialized)
9641
			throw new TInvalidOperationException('pageservice_defaultpage_unchangeable');
9642
		else
9643
			$this->_defaultPage=$value;
9644
	}
9645
	public function getDefaultPageUrl()
9646
	{
9647
		return $this->constructUrl($this->getDefaultPage());
9648
	}
9649
	public function getBasePath()
9650
	{
9651
		if($this->_basePath===null)
9652
		{
9653
			$basePath=$this->getApplication()->getBasePath().DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
9654
			if(($this->_basePath=realpath($basePath))===false || !is_dir($this->_basePath))
9655
			{
9656
				$basePath=$this->getApplication()->getBasePath().DIRECTORY_SEPARATOR.self::FALLBACK_BASEPATH;
9657
				if(($this->_basePath=realpath($basePath))===false || !is_dir($this->_basePath))
9658
					throw new TConfigurationException('pageservice_basepath_invalid',$basePath);
9659
			}
9660
		}
9661
		return $this->_basePath;
9662
	}
9663
	public function setBasePath($value)
9664
	{
9665
		if($this->_initialized)
9666
			throw new TInvalidOperationException('pageservice_basepath_unchangeable');
9667
		else if(($path=Prado::getPathOfNamespace($value))===null || !is_dir($path))
9668
			throw new TConfigurationException('pageservice_basepath_invalid',$value);
9669
		$this->_basePath=realpath($path);
9670
	}
9671
	public function setBasePageClass($value)
9672
	{
9673
		$this->_basePageClass=$value;
9674
	}
9675
	public function getBasePageClass()
9676
	{
9677
		return $this->_basePageClass;
9678
	}
9679
	public function setClientScriptManagerClass($value)
9680
	{
9681
		$this->_clientScriptManagerClass=$value;
9682
	}
9683
	public function getClientScriptManagerClass()
9684
	{
9685
		return $this->_clientScriptManagerClass;
9686
	}
9687
	public function run()
9688
	{
9689
		$this->_page=$this->createPage($this->getRequestedPagePath());
9690
		$this->runPage($this->_page,$this->_properties);
9691
	}
9692
	protected function createPage($pagePath)
9693
	{
9694
		$path=$this->getBasePath().DIRECTORY_SEPARATOR.strtr($pagePath,'.',DIRECTORY_SEPARATOR);
9695
		$hasTemplateFile=is_file($path.self::PAGE_FILE_EXT);
9696
		$hasClassFile=is_file($path.Prado::CLASS_FILE_EXT);
9697
		if(!$hasTemplateFile && !$hasClassFile)
9698
			throw new THttpException(404,'pageservice_page_unknown',$pagePath);
9699
		if($hasClassFile)
9700
		{
9701
			$className=basename($path);
9702
			if(!class_exists($className,false))
9703
				include_once($path.Prado::CLASS_FILE_EXT);
9704
		}
9705
		else
9706
		{
9707
			$className=$this->getBasePageClass();
9708
			Prado::using($className);
9709
			if(($pos=strrpos($className,'.'))!==false)
9710
				$className=substr($className,$pos+1);
9711
		}
9712
 		if(!class_exists($className,false) || ($className!=='TPage' && !is_subclass_of($className,'TPage')))
9713
			throw new THttpException(404,'pageservice_page_unknown',$pagePath);
9714
		$page=Prado::createComponent($className);
9715
		$page->setPagePath($pagePath);
9716
		if($hasTemplateFile)
9717
			$page->setTemplate($this->getTemplateManager()->getTemplateByFileName($path.self::PAGE_FILE_EXT));
9718
		return $page;
9719
	}
9720
	protected function runPage($page,$properties)
9721
	{
9722
		foreach($properties as $name=>$value)
9723
			$page->setSubProperty($name,$value);
9724
		$page->run($this->getResponse()->createHtmlWriter());
9725
	}
9726
	public function constructUrl($pagePath,$getParams=null,$encodeAmpersand=true,$encodeGetItems=true)
9727
	{
9728
		return $this->getRequest()->constructUrl($this->getID(),$pagePath,$getParams,$encodeAmpersand,$encodeGetItems);
9729
	}
9730
}
9731
class TPageConfiguration extends TComponent
9732
{
9733
	private $_appConfigs=array();
9734
	private $_properties=array();
9735
	private $_rules=array();
9736
	private $_includes=array();
9737
	private $_pagePath='';
9738
	public function __construct($pagePath)
9739
	{
9740
		$this->_pagePath=$pagePath;
9741
	}
9742
	public function getExternalConfigurations()
9743
	{
9744
		return $this->_includes;
9745
	}
9746
	public function getProperties()
9747
	{
9748
		return $this->_properties;
9749
	}
9750
	public function getRules()
9751
	{
9752
		return $this->_rules;
9753
	}
9754
	public function getApplicationConfigurations()
9755
	{
9756
		return $this->_appConfigs;
9757
	}
9758
	public function loadFromFiles($basePath)
9759
	{
9760
		$paths=explode('.',$this->_pagePath);
9761
		$page=array_pop($paths);
0 ignored issues
show
Unused Code introduced by
$page is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
9762
		$path=$basePath;
9763
		$configPagePath='';
9764
		$fileName = Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP
9765
			? TPageService::CONFIG_FILE_PHP
9766
			: TPageService::CONFIG_FILE_XML;
9767
		foreach($paths as $p)
9768
		{
9769
			$this->loadFromFile($path.DIRECTORY_SEPARATOR.$fileName,$configPagePath);
9770
			$path.=DIRECTORY_SEPARATOR.$p;
9771
			if($configPagePath==='')
9772
				$configPagePath=$p;
9773
			else
9774
				$configPagePath.='.'.$p;
9775
		}
9776
		$this->loadFromFile($path.DIRECTORY_SEPARATOR.$fileName,$configPagePath);
9777
		$this->_rules=new TAuthorizationRuleCollection($this->_rules);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \TAuthorizationRuleCollection($this->_rules) of type object<TAuthorizationRuleCollection> is incompatible with the declared type array of property $_rules.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
9778
	}
9779
	public function loadFromFile($fname,$configPagePath)
9780
	{
9781
		if(empty($fname) || !is_file($fname))
9782
			return;
9783
		if(Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
9784
		{
9785
			$fcontent = include $fname;
9786
			$this->loadFromPhp($fcontent,dirname($fname),$configPagePath);
9787
		}
9788
		else
9789
		{
9790
			$dom=new TXmlDocument;
9791
			if($dom->loadFromFile($fname))
9792
				$this->loadFromXml($dom,dirname($fname),$configPagePath);
9793
			else
9794
				throw new TConfigurationException('pageserviceconf_file_invalid',$fname);
9795
		}
9796
	}
9797
	public function loadFromPhp($config,$configPath,$configPagePath)
9798
	{
9799
		$this->loadApplicationConfigurationFromPhp($config,$configPath);
9800
		$this->loadPageConfigurationFromPhp($config,$configPath,$configPagePath);
9801
	}
9802
	public function loadFromXml($dom,$configPath,$configPagePath)
9803
	{
9804
		$this->loadApplicationConfigurationFromXml($dom,$configPath);
9805
		$this->loadPageConfigurationFromXml($dom,$configPath,$configPagePath);
9806
	}
9807
	public function loadApplicationConfigurationFromPhp($config,$configPath)
9808
	{
9809
		$appConfig=new TApplicationConfiguration;
9810
		$appConfig->loadFromPhp($config,$configPath);
9811
		$this->_appConfigs[]=$appConfig;
9812
	}
9813
	public function loadApplicationConfigurationFromXml($dom,$configPath)
9814
	{
9815
		$appConfig=new TApplicationConfiguration;
9816
		$appConfig->loadFromXml($dom,$configPath);
9817
		$this->_appConfigs[]=$appConfig;
9818
	}
9819
	public function loadPageConfigurationFromPhp($config, $configPath, $configPagePath)
9820
	{
9821
				if(isset($config['authorization']) && is_array($config['authorization']))
9822
		{
9823
			$rules = array();
9824
			foreach($config['authorization'] as $authorization)
9825
			{
9826
				$patterns=isset($authorization['pages'])?$authorization['pages']:'';
9827
				$ruleApplies=false;
9828
				if(empty($patterns) || trim($patterns)==='*') 					$ruleApplies=true;
9829
				else
9830
				{
9831
					foreach(explode(',',$patterns) as $pattern)
9832
					{
9833
						if(($pattern=trim($pattern))!=='')
9834
						{
9835
														if($configPagePath!=='')  								$pattern=$configPagePath.'.'.$pattern;
9836
							if(strcasecmp($pattern,$this->_pagePath)===0)
9837
							{
9838
								$ruleApplies=true;
9839
								break;
9840
							}
9841
							if($pattern[strlen($pattern)-1]==='*') 							{
9842
								if(strncasecmp($this->_pagePath,$pattern,strlen($pattern)-1)===0)
9843
								{
9844
									$ruleApplies=true;
9845
									break;
9846
								}
9847
							}
9848
						}
9849
					}
9850
				}
9851
				if($ruleApplies)
9852
				{
9853
					$action = isset($authorization['action'])?$authorization['action']:'';
9854
					$users = isset($authorization['users'])?$authorization['users']:'';
9855
					$roles = isset($authorization['roles'])?$authorization['roles']:'';
9856
					$verb = isset($authorization['verb'])?$authorization['verb']:'';
9857
					$ips = isset($authorization['ips'])?$authorization['ips']:'';
9858
					$rules[]=new TAuthorizationRule($action,$users,$roles,$verb,$ips);
9859
				}
9860
			}
9861
			$this->_rules=array_merge($rules,$this->_rules);
9862
		}
9863
				if(isset($config['pages']) && is_array($config['pages']))
9864
		{
9865
			if(isset($config['pages']['properties']))
9866
			{
9867
				$this->_properties = array_merge($this->_properties, $config['pages']['properties']);
9868
				unset($config['pages']['properties']);
9869
			}
9870
			foreach($config['pages'] as $id => $page)
9871
			{
9872
				$properties = array();
9873
				if(isset($page['properties']))
9874
				{
9875
					$properties=$page['properties'];
9876
					unset($page['properties']);
9877
				}
9878
				$matching=false;
9879
				$id=($configPagePath==='')?$id:$configPagePath.'.'.$id;
9880
				if(strcasecmp($id,$this->_pagePath)===0)
9881
					$matching=true;
9882
				else if($id[strlen($id)-1]==='*') 					$matching=strncasecmp($this->_pagePath,$id,strlen($id)-1)===0;
9883
				if($matching)
9884
					$this->_properties=array_merge($this->_properties,$properties);
9885
			}
9886
		}
9887
				if(isset($config['includes']) && is_array($config['includes']))
9888
		{
9889
			foreach($config['includes'] as $include)
9890
			{
9891
				$when = isset($include['when'])?true:false;
9892
				if(!isset($include['file']))
9893
					throw new TConfigurationException('pageserviceconf_includefile_required');
9894
				$filePath = $include['file'];
9895
				if(isset($this->_includes[$filePath]))
9896
					$this->_includes[$filePath]=array($configPagePath,'('.$this->_includes[$filePath][1].') || ('.$when.')');
9897
				else
9898
					$this->_includes[$filePath]=array($configPagePath,$when);
9899
			}
9900
		}
9901
	}
9902
	public function loadPageConfigurationFromXml($dom,$configPath,$configPagePath)
9903
	{
9904
				if(($authorizationNode=$dom->getElementByTagName('authorization'))!==null)
9905
		{
9906
			$rules=array();
9907
			foreach($authorizationNode->getElements() as $node)
9908
			{
9909
				$patterns=$node->getAttribute('pages');
9910
				$ruleApplies=false;
9911
				if(empty($patterns) || trim($patterns)==='*') 					$ruleApplies=true;
9912
				else
9913
				{
9914
					foreach(explode(',',$patterns) as $pattern)
9915
					{
9916
						if(($pattern=trim($pattern))!=='')
9917
						{
9918
														if($configPagePath!=='')  								$pattern=$configPagePath.'.'.$pattern;
9919
							if(strcasecmp($pattern,$this->_pagePath)===0)
9920
							{
9921
								$ruleApplies=true;
9922
								break;
9923
							}
9924
							if($pattern[strlen($pattern)-1]==='*') 							{
9925
								if(strncasecmp($this->_pagePath,$pattern,strlen($pattern)-1)===0)
9926
								{
9927
									$ruleApplies=true;
9928
									break;
9929
								}
9930
							}
9931
						}
9932
					}
9933
				}
9934
				if($ruleApplies)
9935
					$rules[]=new TAuthorizationRule($node->getTagName(),$node->getAttribute('users'),$node->getAttribute('roles'),$node->getAttribute('verb'),$node->getAttribute('ips'));
9936
			}
9937
			$this->_rules=array_merge($rules,$this->_rules);
9938
		}
9939
				if(($pagesNode=$dom->getElementByTagName('pages'))!==null)
9940
		{
9941
			$this->_properties=array_merge($this->_properties,$pagesNode->getAttributes()->toArray());
9942
						foreach($pagesNode->getElementsByTagName('page') as $node)
9943
			{
9944
				$properties=$node->getAttributes();
9945
				$id=$properties->remove('id');
9946
				if(empty($id))
9947
					throw new TConfigurationException('pageserviceconf_page_invalid',$configPath);
9948
				$matching=false;
9949
				$id=($configPagePath==='')?$id:$configPagePath.'.'.$id;
9950
				if(strcasecmp($id,$this->_pagePath)===0)
9951
					$matching=true;
9952
				else if($id[strlen($id)-1]==='*') 					$matching=strncasecmp($this->_pagePath,$id,strlen($id)-1)===0;
9953
				if($matching)
9954
					$this->_properties=array_merge($this->_properties,$properties->toArray());
9955
			}
9956
		}
9957
				foreach($dom->getElementsByTagName('include') as $node)
9958
		{
9959
			if(($when=$node->getAttribute('when'))===null)
9960
				$when=true;
9961
			if(($filePath=$node->getAttribute('file'))===null)
9962
				throw new TConfigurationException('pageserviceconf_includefile_required');
9963
			if(isset($this->_includes[$filePath]))
9964
				$this->_includes[$filePath]=array($configPagePath,'('.$this->_includes[$filePath][1].') || ('.$when.')');
9965
			else
9966
				$this->_includes[$filePath]=array($configPagePath,$when);
9967
		}
9968
	}
9969
}
9970
class TAssetManager extends TModule
9971
{
9972
	const DEFAULT_BASEPATH='assets';
9973
	private $_basePath=null;
9974
	private $_baseUrl=null;
9975
	private $_checkTimestamp=false;
0 ignored issues
show
Unused Code introduced by
The property $_checkTimestamp is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
9976
	private $_application;
0 ignored issues
show
Unused Code introduced by
The property $_application is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
9977
	private $_published=array();
9978
	private $_initialized=false;
9979
	public function init($config)
9980
	{
9981
		$application=$this->getApplication();
9982
		if($this->_basePath===null)
9983
			$this->_basePath=dirname($application->getRequest()->getApplicationFilePath()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
9984
		if(!is_writable($this->_basePath) || !is_dir($this->_basePath))
9985
			throw new TConfigurationException('assetmanager_basepath_invalid',$this->_basePath);
9986
		if($this->_baseUrl===null)
9987
			$this->_baseUrl=rtrim(dirname($application->getRequest()->getApplicationUrl()),'/\\').'/'.self::DEFAULT_BASEPATH;
9988
		$application->setAssetManager($this);
9989
		$this->_initialized=true;
9990
	}
9991
	public function getBasePath()
9992
	{
9993
		return $this->_basePath;
9994
	}
9995
	public function setBasePath($value)
9996
	{
9997
		if($this->_initialized)
9998
			throw new TInvalidOperationException('assetmanager_basepath_unchangeable');
9999
		else
10000
		{
10001
			$this->_basePath=Prado::getPathOfNamespace($value);
10002
			if($this->_basePath===null || !is_dir($this->_basePath) || !is_writable($this->_basePath))
10003
				throw new TInvalidDataValueException('assetmanager_basepath_invalid',$value);
10004
		}
10005
	}
10006
	public function getBaseUrl()
10007
	{
10008
		return $this->_baseUrl;
10009
	}
10010
	public function setBaseUrl($value)
10011
	{
10012
		if($this->_initialized)
10013
			throw new TInvalidOperationException('assetmanager_baseurl_unchangeable');
10014
		else
10015
			$this->_baseUrl=rtrim($value,'/');
10016
	}
10017
	public function publishFilePath($path,$checkTimestamp=false)
10018
	{
10019
		if(isset($this->_published[$path]))
10020
			return $this->_published[$path];
10021
		else if(empty($path) || ($fullpath=realpath($path))===false)
10022
			throw new TInvalidDataValueException('assetmanager_filepath_invalid',$path);
10023
		else if(is_file($fullpath))
10024
		{
10025
			$dir=$this->hash(dirname($fullpath));
10026
			$fileName=basename($fullpath);
10027
			$dst=$this->_basePath.DIRECTORY_SEPARATOR.$dir;
10028
			if(!is_file($dst.DIRECTORY_SEPARATOR.$fileName) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
10029
				$this->copyFile($fullpath,$dst);
10030
			return $this->_published[$path]=$this->_baseUrl.'/'.$dir.'/'.$fileName;
10031
		}
10032
		else
10033
		{
10034
			$dir=$this->hash($fullpath);
10035
			if(!is_dir($this->_basePath.DIRECTORY_SEPARATOR.$dir) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
10036
			{
10037
				$this->copyDirectory($fullpath,$this->_basePath.DIRECTORY_SEPARATOR.$dir);
10038
			}
10039
			return $this->_published[$path]=$this->_baseUrl.'/'.$dir;
10040
		}
10041
	}
10042
	public function getPublished()
10043
	{
10044
		return $this->_published;
10045
	}
10046
	protected function setPublished($values=array())
10047
	{
10048
		$this->_published = $values;
10049
	}
10050
	public function getPublishedPath($path)
10051
	{
10052
		$path=realpath($path);
10053
		if(is_file($path))
10054
			return $this->_basePath.DIRECTORY_SEPARATOR.$this->hash(dirname($path)).DIRECTORY_SEPARATOR.basename($path);
10055
		else
10056
			return $this->_basePath.DIRECTORY_SEPARATOR.$this->hash($path);
10057
	}
10058
	public function getPublishedUrl($path)
10059
	{
10060
		$path=realpath($path);
10061
		if(is_file($path))
10062
			return $this->_baseUrl.'/'.$this->hash(dirname($path)).'/'.basename($path);
10063
		else
10064
			return $this->_baseUrl.'/'.$this->hash($path);
10065
	}
10066
	protected function hash($dir)
10067
	{
10068
		return sprintf('%x',crc32($dir.Prado::getVersion()));
10069
	}
10070
	protected function copyFile($src,$dst)
10071
	{
10072
		if(!is_dir($dst))
10073
		{
10074
			@mkdir($dst);
10075
			@chmod($dst, PRADO_CHMOD);
10076
		}
10077
		$dstFile=$dst.DIRECTORY_SEPARATOR.basename($src);
10078
		if(@filemtime($dstFile)<@filemtime($src))
10079
		{
10080
			@copy($src,$dstFile);
10081
		}
10082
	}
10083
	public function copyDirectory($src,$dst)
10084
	{
10085
		if(!is_dir($dst))
10086
		{
10087
			@mkdir($dst);
10088
			@chmod($dst, PRADO_CHMOD);
10089
		}
10090
		if($folder=@opendir($src))
10091
		{
10092
			while($file=@readdir($folder))
10093
			{
10094
				if($file==='.' || $file==='..' || $file==='.svn')
10095
					continue;
10096
				else if(is_file($src.DIRECTORY_SEPARATOR.$file))
10097
				{
10098
					if(@filemtime($dst.DIRECTORY_SEPARATOR.$file)<@filemtime($src.DIRECTORY_SEPARATOR.$file))
10099
					{
10100
						@copy($src.DIRECTORY_SEPARATOR.$file,$dst.DIRECTORY_SEPARATOR.$file);
10101
						@chmod($dst.DIRECTORY_SEPARATOR.$file, PRADO_CHMOD);
10102
					}
10103
				}
10104
				else
10105
					$this->copyDirectory($src.DIRECTORY_SEPARATOR.$file,$dst.DIRECTORY_SEPARATOR.$file);
10106
			}
10107
			closedir($folder);
10108
		} else {
10109
			throw new TInvalidDataValueException('assetmanager_source_directory_invalid', $src);
10110
		}
10111
	}
10112
	public function publishTarFile($tarfile, $md5sum, $checkTimestamp=false)
10113
	{
10114
		if(isset($this->_published[$md5sum]))
10115
			return $this->_published[$md5sum];
10116
		else if(($fullpath=realpath($md5sum))===false || !is_file($fullpath))
10117
			throw new TInvalidDataValueException('assetmanager_tarchecksum_invalid',$md5sum);
10118
		else
10119
		{
10120
			$dir=$this->hash(dirname($fullpath));
10121
			$fileName=basename($fullpath);
10122
			$dst=$this->_basePath.DIRECTORY_SEPARATOR.$dir;
10123
			if(!is_file($dst.DIRECTORY_SEPARATOR.$fileName) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
10124
			{
10125
				if(@filemtime($dst.DIRECTORY_SEPARATOR.$fileName)<@filemtime($fullpath))
10126
				{
10127
					$this->copyFile($fullpath,$dst);
10128
					$this->deployTarFile($tarfile,$dst);
10129
				}
10130
			}
10131
			return $this->_published[$md5sum]=$this->_baseUrl.'/'.$dir;
10132
		}
10133
	}
10134
	protected function deployTarFile($path,$destination)
10135
	{
10136
		if(($fullpath=realpath($path))===false || !is_file($fullpath))
10137
			throw new TIOException('assetmanager_tarfile_invalid',$path);
10138
		else
10139
		{
10140
			Prado::using('System.IO.TTarFileExtractor');
10141
			$tar = new TTarFileExtractor($fullpath);
10142
			return $tar->extract($destination);
10143
		}
10144
	}
10145
}
10146
class TGlobalization extends TModule
10147
{
10148
	private $_defaultCharset = 'UTF-8';
10149
	private $_defaultCulture = 'en';
10150
	private $_charset=null;
10151
	private $_culture=null;
10152
	private $_translation;
10153
	private $_translateDefaultCulture=true;
10154
	public function init($config)
10155
	{
10156
		if($this->_charset===null)
10157
			$this->_charset=$this->getDefaultCharset();
10158
		if($this->_culture===null)
10159
			$this->_culture=$this->getDefaultCulture();
10160
		if($config!==null)
10161
		{
10162
			if($this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
10163
				$translation = isset($config['translate'])?$config['translate']:null;
10164
			else
10165
			{
10166
				$t = $config->getElementByTagName('translation');
10167
				$translation = ($t)?$t->getAttributes():null;
10168
			}
10169
			if($translation)
10170
				$this->setTranslationConfiguration($translation);
10171
		}
10172
		$this->getApplication()->setGlobalization($this);
10173
	}
10174
	public function getTranslateDefaultCulture()
10175
	{
10176
		return $this->_translateDefaultCulture;
10177
	}
10178
	public function setTranslateDefaultCulture($value)
10179
	{
10180
		$this->_translateDefaultCulture = TPropertyValue::ensureBoolean($value);
10181
	}
10182
	public function getDefaultCulture()
10183
	{
10184
		return $this->_defaultCulture;
10185
	}
10186
	public function setDefaultCulture($culture)
10187
	{
10188
		$this->_defaultCulture = str_replace('-','_',$culture);
10189
	}
10190
	public function getDefaultCharset()
10191
	{
10192
		return $this->_defaultCharset;
10193
	}
10194
	public function setDefaultCharset($charset)
10195
	{
10196
		$this->_defaultCharset = $charset;
10197
	}
10198
	public function getCulture()
10199
	{
10200
		return $this->_culture;
10201
	}
10202
	public function setCulture($culture)
10203
	{
10204
		$this->_culture = str_replace('-','_',$culture);
10205
	}
10206
	public function getCharset()
10207
	{
10208
		return $this->_charset;
10209
	}
10210
	public function setCharset($charset)
10211
	{
10212
		$this->_charset = $charset;
10213
	}
10214
	public function getTranslationConfiguration()
10215
	{
10216
		return (!$this->_translateDefaultCulture && ($this->getDefaultCulture() == $this->getCulture()))
10217
			? null
10218
			: $this->_translation;
10219
	}
10220
	protected function setTranslationConfiguration($config)
10221
	{
10222
		if($config['type'] == 'XLIFF' || $config['type'] == 'gettext')
10223
		{
10224
			if($config['source'])
10225
			{
10226
				$config['source'] = Prado::getPathOfNamespace($config['source']);
10227
				if(!is_dir($config['source']))
10228
				{
10229
					if(@mkdir($config['source'])===false)
10230
					throw new TConfigurationException('globalization_source_path_failed',
10231
						$config['source']);
10232
					chmod($config['source'], PRADO_CHMOD); 				}
10233
			}
10234
			else
10235
			{
10236
				throw new TConfigurationException("invalid source dir '{$config['source']}'");
10237
			}
10238
		}
10239
		if($config['cache'])
10240
		{
10241
			$config['cache'] = $this->getApplication()->getRunTimePath().'/i18n';
10242
			if(!is_dir($config['cache']))
10243
			{
10244
				if(@mkdir($config['cache'])===false)
10245
					throw new TConfigurationException('globalization_cache_path_failed',
10246
						$config['cache']);
10247
				chmod($config['cache'], PRADO_CHMOD); 			}
10248
		}
10249
		$this->_translation = $config;
10250
	}
10251
	public function getTranslationCatalogue()
10252
	{
10253
		return $this->_translation['catalogue'];
10254
	}
10255
	public function setTranslationCatalogue($value)
10256
	{
10257
		$this->_translation['catalogue'] = $value;
10258
	}
10259
	public function getCultureVariants($culture=null)
10260
	{
10261
		if($culture===null) $culture = $this->getCulture();
10262
		$variants = explode('_', $culture);
10263
		$result = array();
10264
		for(; count($variants) > 0; array_pop($variants))
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
10265
			$result[] = implode('_', $variants);
10266
		return $result;
10267
	}
10268
	public function getLocalizedResource($file,$culture=null)
10269
	{
10270
		$files = array();
10271
		$variants = $this->getCultureVariants($culture);
10272
		$path = pathinfo($file);
10273
		foreach($variants as $variant)
10274
			$files[] = $path['dirname'].DIRECTORY_SEPARATOR.$variant.DIRECTORY_SEPARATOR.$path['basename'];
10275
		$filename = substr($path['basename'],0,strrpos($path['basename'],'.'));
10276
		foreach($variants as $variant)
10277
			$files[] = $path['dirname'].DIRECTORY_SEPARATOR.$filename.'.'.$variant.'.'.$path['extension'];
10278
		$files[] = $file;
10279
		return $files;
10280
	}
10281
}
10282
class TApplication extends TComponent
10283
{
10284
	const STATE_OFF='Off';
10285
	const STATE_DEBUG='Debug';
10286
	const STATE_NORMAL='Normal';
10287
	const STATE_PERFORMANCE='Performance';
10288
	const PAGE_SERVICE_ID='page';
10289
	const CONFIG_FILE_XML='application.xml';
10290
	const CONFIG_FILE_EXT_XML='.xml';
10291
	const CONFIG_TYPE_XML = 'xml';
10292
	const CONFIG_FILE_PHP='application.php';
10293
	const CONFIG_FILE_EXT_PHP='.php';
10294
	const CONFIG_TYPE_PHP = 'php';
10295
	const RUNTIME_PATH='runtime';
10296
	const CONFIGCACHE_FILE='config.cache';
10297
	const GLOBAL_FILE='global.cache';
10298
	private static $_steps=array(
10299
		'onBeginRequest',
10300
		'onLoadState',
10301
		'onLoadStateComplete',
10302
		'onAuthentication',
10303
		'onAuthenticationComplete',
10304
		'onAuthorization',
10305
		'onAuthorizationComplete',
10306
		'onPreRunService',
10307
		'runService',
10308
		'onSaveState',
10309
		'onSaveStateComplete',
10310
		'onPreFlushOutput',
10311
		'flushOutput'
10312
	);
10313
	private $_id;
10314
	private $_uniqueID;
10315
	private $_requestCompleted=false;
10316
	private $_step;
10317
	private $_services;
10318
	private $_service;
10319
	private $_modules=array();
10320
	private $_lazyModules=array();
10321
	private $_parameters;
10322
	private $_configFile;
10323
	private $_configFileExt;
10324
	private $_configType;
10325
	private $_basePath;
10326
	private $_runtimePath;
10327
	private $_stateChanged=false;
10328
	private $_globals=array();
10329
	private $_cacheFile;
10330
	private $_errorHandler;
10331
	private $_request;
10332
	private $_response;
10333
	private $_session;
10334
	private $_cache;
10335
	private $_statePersister;
10336
	private $_user;
10337
	private $_globalization;
10338
	private $_security;
10339
	private $_assetManager;
10340
	private $_authRules;
10341
	private $_mode=TApplicationMode::Debug;
10342
	private $_pageServiceID = self::PAGE_SERVICE_ID;
10343
	public function __construct($basePath='protected',$cacheConfig=true, $configType=self::CONFIG_TYPE_XML)
10344
	{
10345
				Prado::setApplication($this);
10346
		$this->setConfigurationType($configType);
10347
		$this->resolvePaths($basePath);
10348
		if($cacheConfig)
10349
			$this->_cacheFile=$this->_runtimePath.DIRECTORY_SEPARATOR.self::CONFIGCACHE_FILE;
10350
				$this->_uniqueID=md5($this->_runtimePath);
10351
		$this->_parameters=new TMap;
10352
		$this->_services=array($this->getPageServiceID()=>array('TPageService',array(),null));
10353
		Prado::setPathOfAlias('Application',$this->_basePath);
10354
	}
10355
	protected function resolvePaths($basePath)
10356
	{
10357
				if(empty($basePath) || ($basePath=realpath($basePath))===false)
10358
			throw new TConfigurationException('application_basepath_invalid',$basePath);
10359
		if(is_dir($basePath) && is_file($basePath.DIRECTORY_SEPARATOR.$this->getConfigurationFileName()))
10360
			$configFile=$basePath.DIRECTORY_SEPARATOR.$this->getConfigurationFileName();
10361
		else if(is_file($basePath))
10362
		{
10363
			$configFile=$basePath;
10364
			$basePath=dirname($configFile);
10365
		}
10366
		else
10367
			$configFile=null;
10368
				$runtimePath=$basePath.DIRECTORY_SEPARATOR.self::RUNTIME_PATH;
10369
		if(is_writable($runtimePath))
10370
		{
10371
			if($configFile!==null)
10372
			{
10373
				$runtimePath.=DIRECTORY_SEPARATOR.basename($configFile).'-'.Prado::getVersion();
10374
				if(!is_dir($runtimePath))
10375
				{
10376
					if(@mkdir($runtimePath)===false)
10377
						throw new TConfigurationException('application_runtimepath_failed',$runtimePath);
10378
					@chmod($runtimePath, PRADO_CHMOD); 				}
10379
				$this->setConfigurationFile($configFile);
10380
			}
10381
			$this->setBasePath($basePath);
10382
			$this->setRuntimePath($runtimePath);
10383
		}
10384
		else
10385
			throw new TConfigurationException('application_runtimepath_invalid',$runtimePath);
10386
	}
10387
	public function run()
10388
	{
10389
		try
10390
		{
10391
			$this->initApplication();
10392
			$n=count(self::$_steps);
10393
			$this->_step=0;
10394
			$this->_requestCompleted=false;
10395
			while($this->_step<$n)
10396
			{
10397
				if($this->_mode===self::STATE_OFF)
10398
					throw new THttpException(503,'application_unavailable');
10399
				if($this->_requestCompleted)
10400
					break;
10401
				$method=self::$_steps[$this->_step];
10402
				$this->$method();
10403
				$this->_step++;
10404
			}
10405
		}
10406
		catch(Exception $e)
10407
		{
10408
			$this->onError($e);
10409
		}
10410
		$this->onEndRequest();
10411
	}
10412
	public function completeRequest()
10413
	{
10414
		$this->_requestCompleted=true;
10415
	}
10416
	public function getRequestCompleted()
10417
	{
10418
		return $this->_requestCompleted;
10419
	}
10420
	public function getGlobalState($key,$defaultValue=null)
10421
	{
10422
		return isset($this->_globals[$key])?$this->_globals[$key]:$defaultValue;
10423
	}
10424
	public function setGlobalState($key,$value,$defaultValue=null,$forceSave=false)
10425
	{
10426
		$this->_stateChanged=true;
10427
		if($value===$defaultValue)
10428
			unset($this->_globals[$key]);
10429
		else
10430
			$this->_globals[$key]=$value;
10431
		if($forceSave)
10432
			$this->saveGlobals();
10433
	}
10434
	public function clearGlobalState($key)
10435
	{
10436
		$this->_stateChanged=true;
10437
		unset($this->_globals[$key]);
10438
	}
10439
	protected function loadGlobals()
10440
	{
10441
		$this->_globals=$this->getApplicationStatePersister()->load();
10442
	}
10443
	protected function saveGlobals()
10444
	{
10445
		if($this->_stateChanged)
10446
		{
10447
			$this->_stateChanged=false;
10448
			$this->getApplicationStatePersister()->save($this->_globals);
10449
		}
10450
	}
10451
	public function getID()
10452
	{
10453
		return $this->_id;
10454
	}
10455
	public function setID($value)
10456
	{
10457
		$this->_id=$value;
10458
	}
10459
	public function getPageServiceID()
10460
	{
10461
		return $this->_pageServiceID;
10462
	}
10463
	public function setPageServiceID($value)
10464
	{
10465
		$this->_pageServiceID=$value;
10466
	}
10467
	public function getUniqueID()
10468
	{
10469
		return $this->_uniqueID;
10470
	}
10471
	public function getMode()
10472
	{
10473
		return $this->_mode;
10474
	}
10475
	public function setMode($value)
10476
	{
10477
		$this->_mode=TPropertyValue::ensureEnum($value,'TApplicationMode');
10478
	}
10479
	public function getBasePath()
10480
	{
10481
		return $this->_basePath;
10482
	}
10483
	public function setBasePath($value)
10484
	{
10485
		$this->_basePath=$value;
10486
	}
10487
	public function getConfigurationFile()
10488
	{
10489
		return $this->_configFile;
10490
	}
10491
	public function setConfigurationFile($value)
10492
	{
10493
		$this->_configFile=$value;
10494
	}
10495
	public function getConfigurationType()
10496
	{
10497
		return $this->_configType;
10498
	}
10499
	public function setConfigurationType($value)
10500
	{
10501
		$this->_configType = $value;
10502
	}
10503
	public function getConfigurationFileExt()
10504
	{
10505
		if($this->_configFileExt===null)
10506
		{
10507
			switch($this->_configType)
10508
			{
10509
				case TApplication::CONFIG_TYPE_PHP:
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
10510
					$this->_configFileExt = TApplication::CONFIG_FILE_EXT_PHP;
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
10511
					break;
10512
				default:
10513
					$this->_configFileExt = TApplication::CONFIG_FILE_EXT_XML;
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
10514
			}
10515
		}
10516
		return $this->_configFileExt;
10517
	}
10518
	public function getConfigurationFileName()
10519
	{
10520
		static $fileName;
10521
		if($fileName == null)
10522
		{
10523
			switch($this->_configType)
10524
			{
10525
				case TApplication::CONFIG_TYPE_PHP:
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
10526
					$fileName = TApplication::CONFIG_FILE_PHP;
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
10527
					break;
10528
				default:
10529
					$fileName = TApplication::CONFIG_FILE_XML;
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
10530
			}
10531
		}
10532
		return $fileName;
10533
	}
10534
	public function getRuntimePath()
10535
	{
10536
		return $this->_runtimePath;
10537
	}
10538
	public function setRuntimePath($value)
10539
	{
10540
		$this->_runtimePath=$value;
10541
		if($this->_cacheFile)
10542
			$this->_cacheFile=$this->_runtimePath.DIRECTORY_SEPARATOR.self::CONFIGCACHE_FILE;
10543
				$this->_uniqueID=md5($this->_runtimePath);
10544
	}
10545
	public function getService()
10546
	{
10547
		return $this->_service;
10548
	}
10549
	public function setService($value)
10550
	{
10551
		$this->_service=$value;
10552
	}
10553
	public function setModule($id,IModule $module=null)
10554
	{
10555
		if(isset($this->_modules[$id]))
10556
			throw new TConfigurationException('application_moduleid_duplicated',$id);
10557
		else
10558
			$this->_modules[$id]=$module;
10559
	}
10560
	public function getModule($id)
10561
	{
10562
		if(!array_key_exists($id, $this->_modules))
10563
			return null;
10564
				if($this->_modules[$id]===null)
10565
		{
10566
			$module = $this->internalLoadModule($id, true);
10567
			$module[0]->init($module[1]);
10568
		}
10569
		return $this->_modules[$id];
10570
	}
10571
	public function getModules()
10572
	{
10573
		return $this->_modules;
10574
	}
10575
	public function getParameters()
10576
	{
10577
		return $this->_parameters;
10578
	}
10579
	public function getRequest()
10580
	{
10581
		if(!$this->_request)
10582
		{
10583
			$this->_request=new THttpRequest;
10584
			$this->_request->init(null);
10585
		}
10586
		return $this->_request;
10587
	}
10588
	public function setRequest(THttpRequest $request)
10589
	{
10590
		$this->_request=$request;
10591
	}
10592
	public function getResponse()
10593
	{
10594
		if(!$this->_response)
10595
		{
10596
			$this->_response=new THttpResponse;
10597
			$this->_response->init(null);
10598
		}
10599
		return $this->_response;
10600
	}
10601
	public function setResponse(THttpResponse $response)
10602
	{
10603
		$this->_response=$response;
10604
	}
10605
	public function getSession()
10606
	{
10607
		if(!$this->_session)
10608
		{
10609
			$this->_session=new THttpSession;
10610
			$this->_session->init(null);
10611
		}
10612
		return $this->_session;
10613
	}
10614
	public function setSession(THttpSession $session)
10615
	{
10616
		$this->_session=$session;
10617
	}
10618
	public function getErrorHandler()
10619
	{
10620
		if(!$this->_errorHandler)
10621
		{
10622
			$this->_errorHandler=new TErrorHandler;
10623
			$this->_errorHandler->init(null);
10624
		}
10625
		return $this->_errorHandler;
10626
	}
10627
	public function setErrorHandler(TErrorHandler $handler)
10628
	{
10629
		$this->_errorHandler=$handler;
10630
	}
10631
	public function getSecurityManager()
10632
	{
10633
		if(!$this->_security)
10634
		{
10635
			$this->_security=new TSecurityManager;
10636
			$this->_security->init(null);
10637
		}
10638
		return $this->_security;
10639
	}
10640
	public function setSecurityManager(TSecurityManager $sm)
10641
	{
10642
		$this->_security=$sm;
10643
	}
10644
	public function getAssetManager()
10645
	{
10646
		if(!$this->_assetManager)
10647
		{
10648
			$this->_assetManager=new TAssetManager;
10649
			$this->_assetManager->init(null);
10650
		}
10651
		return $this->_assetManager;
10652
	}
10653
	public function setAssetManager(TAssetManager $value)
10654
	{
10655
		$this->_assetManager=$value;
10656
	}
10657
	public function getApplicationStatePersister()
10658
	{
10659
		if(!$this->_statePersister)
10660
		{
10661
			$this->_statePersister=new TApplicationStatePersister;
10662
			$this->_statePersister->init(null);
10663
		}
10664
		return $this->_statePersister;
10665
	}
10666
	public function setApplicationStatePersister(IStatePersister $persister)
10667
	{
10668
		$this->_statePersister=$persister;
10669
	}
10670
	public function getCache()
10671
	{
10672
		return $this->_cache;
10673
	}
10674
	public function setCache(ICache $cache)
10675
	{
10676
		$this->_cache=$cache;
10677
	}
10678
	public function getUser()
10679
	{
10680
		return $this->_user;
10681
	}
10682
	public function setUser(IUser $user)
10683
	{
10684
		$this->_user=$user;
10685
	}
10686
	public function getGlobalization($createIfNotExists=true)
10687
	{
10688
		if($this->_globalization===null && $createIfNotExists)
10689
		{
10690
			$this->_globalization=new TGlobalization;
10691
			$this->_globalization->init(null);
10692
		}
10693
		return $this->_globalization;
10694
	}
10695
	public function setGlobalization(TGlobalization $glob)
10696
	{
10697
		$this->_globalization=$glob;
10698
	}
10699
	public function getAuthorizationRules()
10700
	{
10701
		if($this->_authRules===null)
10702
			$this->_authRules=new TAuthorizationRuleCollection;
10703
		return $this->_authRules;
10704
	}
10705
	protected function getApplicationConfigurationClass()
10706
	{
10707
		return 'TApplicationConfiguration';
10708
	}
10709
	protected function internalLoadModule($id, $force=false)
10710
	{
10711
		list($moduleClass, $initProperties, $configElement)=$this->_lazyModules[$id];
10712
		if(isset($initProperties['lazy']) && $initProperties['lazy'] && !$force)
10713
		{
10714
			$this->setModule($id, null);
10715
			return null;
10716
		}
10717
		$module=Prado::createComponent($moduleClass);
10718
		foreach($initProperties as $name=>$value)
10719
		{
10720
			if($name==='lazy') continue;
10721
			$module->setSubProperty($name,$value);
10722
		}
10723
		$this->setModule($id,$module);
10724
				$this->_lazyModules[$id]=null;
10725
		return array($module,$configElement);
10726
	}
10727
	public function applyConfiguration($config,$withinService=false)
10728
	{
10729
		if($config->getIsEmpty())
10730
			return;
10731
				foreach($config->getAliases() as $alias=>$path)
10732
			Prado::setPathOfAlias($alias,$path);
10733
		foreach($config->getUsings() as $using)
10734
			Prado::using($using);
10735
				if(!$withinService)
10736
		{
10737
			foreach($config->getProperties() as $name=>$value)
10738
				$this->setSubProperty($name,$value);
10739
		}
10740
		if(empty($this->_services))
10741
			$this->_services=array($this->getPageServiceID()=>array('TPageService',array(),null));
10742
				foreach($config->getParameters() as $id=>$parameter)
10743
		{
10744
			if(is_array($parameter))
10745
			{
10746
				$component=Prado::createComponent($parameter[0]);
10747
				foreach($parameter[1] as $name=>$value)
10748
					$component->setSubProperty($name,$value);
10749
				$this->_parameters->add($id,$component);
10750
			}
10751
			else
10752
				$this->_parameters->add($id,$parameter);
10753
		}
10754
				$modules=array();
10755
		foreach($config->getModules() as $id=>$moduleConfig)
10756
		{
10757
			if(!is_string($id))
10758
				$id='_module'.count($this->_lazyModules);
10759
			$this->_lazyModules[$id]=$moduleConfig;
10760
			if($module = $this->internalLoadModule($id))
10761
				$modules[]=$module;
10762
		}
10763
		foreach($modules as $module)
10764
			$module[0]->init($module[1]);
10765
				foreach($config->getServices() as $serviceID=>$serviceConfig)
10766
			$this->_services[$serviceID]=$serviceConfig;
10767
				foreach($config->getExternalConfigurations() as $filePath=>$condition)
10768
		{
10769
			if($condition!==true)
10770
				$condition=$this->evaluateExpression($condition);
10771
			if($condition)
10772
			{
10773
				if(($path=Prado::getPathOfNamespace($filePath,$this->getConfigurationFileExt()))===null || !is_file($path))
10774
					throw new TConfigurationException('application_includefile_invalid',$filePath);
10775
				$cn=$this->getApplicationConfigurationClass();
10776
				$c=new $cn;
10777
				$c->loadFromFile($path);
10778
				$this->applyConfiguration($c,$withinService);
10779
			}
10780
		}
10781
	}
10782
	protected function initApplication()
10783
	{
10784
		if($this->_configFile!==null)
10785
		{
10786
			if($this->_cacheFile===null || @filemtime($this->_cacheFile)<filemtime($this->_configFile))
10787
			{
10788
				$config=new TApplicationConfiguration;
10789
				$config->loadFromFile($this->_configFile);
10790
				if($this->_cacheFile!==null)
10791
					file_put_contents($this->_cacheFile,serialize($config),LOCK_EX);
10792
			}
10793
			else
10794
				$config=unserialize(file_get_contents($this->_cacheFile));
10795
			$this->applyConfiguration($config,false);
10796
		}
10797
		if(($serviceID=$this->getRequest()->resolveRequest(array_keys($this->_services)))===null)
10798
			$serviceID=$this->getPageServiceID();
10799
		$this->startService($serviceID);
10800
	}
10801
	public function startService($serviceID)
10802
	{
10803
		if(isset($this->_services[$serviceID]))
10804
		{
10805
			list($serviceClass,$initProperties,$configElement)=$this->_services[$serviceID];
10806
			$service=Prado::createComponent($serviceClass);
10807
			if(!($service instanceof IService))
10808
				throw new THttpException(500,'application_service_invalid',$serviceClass);
10809
			if(!$service->getEnabled())
10810
				throw new THttpException(500,'application_service_unavailable',$serviceClass);
10811
			$service->setID($serviceID);
10812
			$this->setService($service);
10813
			foreach($initProperties as $name=>$value)
10814
				$service->setSubProperty($name,$value);
10815
			if($configElement!==null)
10816
			{
10817
				$config=new TApplicationConfiguration;
10818
				if($this->getConfigurationType()==self::CONFIG_TYPE_PHP)
10819
					$config->loadFromPhp($configElement,$this->getBasePath());
10820
				else
10821
					$config->loadFromXml($configElement,$this->getBasePath());
10822
				$this->applyConfiguration($config,true);
10823
			}
10824
			$service->init($configElement);
10825
		}
10826
		else
10827
			throw new THttpException(500,'application_service_unknown',$serviceID);
10828
	}
10829
	public function onError($param)
10830
	{
10831
		Prado::log($param->getMessage(),TLogger::ERROR,'System.TApplication');
10832
		$this->raiseEvent('OnError',$this,$param);
10833
		$this->getErrorHandler()->handleError($this,$param);
10834
	}
10835
	public function onBeginRequest()
10836
	{
10837
		$this->raiseEvent('OnBeginRequest',$this,null);
10838
	}
10839
	public function onAuthentication()
10840
	{
10841
		$this->raiseEvent('OnAuthentication',$this,null);
10842
	}
10843
	public function onAuthenticationComplete()
10844
	{
10845
		$this->raiseEvent('OnAuthenticationComplete',$this,null);
10846
	}
10847
	public function onAuthorization()
10848
	{
10849
		$this->raiseEvent('OnAuthorization',$this,null);
10850
	}
10851
	public function onAuthorizationComplete()
10852
	{
10853
		$this->raiseEvent('OnAuthorizationComplete',$this,null);
10854
	}
10855
	public function onLoadState()
10856
	{
10857
		$this->loadGlobals();
10858
		$this->raiseEvent('OnLoadState',$this,null);
10859
	}
10860
	public function onLoadStateComplete()
10861
	{
10862
		$this->raiseEvent('OnLoadStateComplete',$this,null);
10863
	}
10864
	public function onPreRunService()
10865
	{
10866
		$this->raiseEvent('OnPreRunService',$this,null);
10867
	}
10868
	public function runService()
10869
	{
10870
		if($this->_service)
10871
			$this->_service->run();
10872
	}
10873
	public function onSaveState()
10874
	{
10875
		$this->raiseEvent('OnSaveState',$this,null);
10876
		$this->saveGlobals();
10877
	}
10878
	public function onSaveStateComplete()
10879
	{
10880
		$this->raiseEvent('OnSaveStateComplete',$this,null);
10881
	}
10882
	public function onPreFlushOutput()
10883
	{
10884
		$this->raiseEvent('OnPreFlushOutput',$this,null);
10885
	}
10886
	public function flushOutput($continueBuffering = true)
10887
	{
10888
		$this->getResponse()->flush($continueBuffering);
10889
	}
10890
	public function onEndRequest()
10891
	{
10892
		$this->flushOutput(false); 		$this->saveGlobals();  		$this->raiseEvent('OnEndRequest',$this,null);
0 ignored issues
show
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
10893
	}
10894
}
10895
class TApplicationMode extends TEnumerable
10896
{
10897
	const Off='Off';
10898
	const Debug='Debug';
10899
	const Normal='Normal';
10900
	const Performance='Performance';
10901
}
10902
class TApplicationConfiguration extends TComponent
10903
{
10904
	private $_properties=array();
10905
	private $_usings=array();
10906
	private $_aliases=array();
10907
	private $_modules=array();
10908
	private $_services=array();
10909
	private $_parameters=array();
10910
	private $_includes=array();
10911
	private $_empty=true;
10912
	public function loadFromFile($fname)
10913
	{
10914
		if(Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
10915
		{
10916
			$fcontent = include $fname;
10917
			$this->loadFromPhp($fcontent,dirname($fname));
10918
		}
10919
		else
10920
		{
10921
			$dom=new TXmlDocument;
10922
			$dom->loadFromFile($fname);
10923
			$this->loadFromXml($dom,dirname($fname));
10924
		}
10925
	}
10926
	public function getIsEmpty()
10927
	{
10928
		return $this->_empty;
10929
	}
10930
	public function loadFromPhp($config, $configPath)
10931
	{
10932
				if(isset($config['application']))
10933
		{
10934
			foreach($config['application'] as $name=>$value)
10935
			{
10936
				$this->_properties[$name]=$value;
10937
			}
10938
			$this->_empty = false;
10939
		}
10940
		if(isset($config['paths']) && is_array($config['paths']))
10941
			$this->loadPathsPhp($config['paths'],$configPath);
10942
		if(isset($config['modules']) && is_array($config['modules']))
10943
			$this->loadModulesPhp($config['modules'],$configPath);
10944
		if(isset($config['services']) && is_array($config['services']))
10945
			$this->loadServicesPhp($config['services'],$configPath);
10946
		if(isset($config['parameters']) && is_array($config['parameters']))
10947
			$this->loadParametersPhp($config['parameters'], $configPath);
10948
		if(isset($config['includes']) && is_array($config['includes']))
10949
			$this->loadExternalXml($config['includes'],$configPath);
10950
	}
10951
	public function loadFromXml($dom,$configPath)
10952
	{
10953
				foreach($dom->getAttributes() as $name=>$value)
10954
		{
10955
			$this->_properties[$name]=$value;
10956
			$this->_empty=false;
10957
		}
10958
		foreach($dom->getElements() as $element)
10959
		{
10960
			switch($element->getTagName())
10961
			{
10962
				case 'paths':
10963
					$this->loadPathsXml($element,$configPath);
10964
					break;
10965
				case 'modules':
10966
					$this->loadModulesXml($element,$configPath);
10967
					break;
10968
				case 'services':
10969
					$this->loadServicesXml($element,$configPath);
10970
					break;
10971
				case 'parameters':
10972
					$this->loadParametersXml($element,$configPath);
10973
					break;
10974
				case 'include':
10975
					$this->loadExternalXml($element,$configPath);
10976
					break;
10977
				default:
10978
										break;
10979
			}
10980
		}
10981
	}
10982
	protected function loadPathsPhp($pathsNode, $configPath)
10983
	{
10984
		if(isset($pathsNode['aliases']) && is_array($pathsNode['aliases']))
10985
		{
10986
			foreach($pathsNode['aliases'] as $id=>$path)
10987
			{
10988
				$path=str_replace('\\','/',$path);
10989
				if(preg_match('/^\\/|.:\\/|.:\\\\/',$path))						$p=realpath($path);
10990
				else
10991
					$p=realpath($configPath.DIRECTORY_SEPARATOR.$path);
10992
				if($p===false || !is_dir($p))
10993
					throw new TConfigurationException('appconfig_aliaspath_invalid',$id,$path);
10994
				if(isset($this->_aliases[$id]))
10995
					throw new TConfigurationException('appconfig_alias_redefined',$id);
10996
				$this->_aliases[$id]=$p;
10997
			}
10998
		}
10999
		if(isset($pathsNode['using']) && is_array($pathsNode['using']))
11000
		{
11001
			foreach($pathsNode['using'] as $namespace)
11002
			{
11003
				$this->_usings[] = $namespace;
11004
			}
11005
		}
11006
	}
11007
	protected function loadPathsXml($pathsNode,$configPath)
11008
	{
11009
		foreach($pathsNode->getElements() as $element)
11010
		{
11011
			switch($element->getTagName())
11012
			{
11013
				case 'alias':
0 ignored issues
show
Coding Style introduced by
CASE statements must be defined using a colon

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
11014
				{
11015
					if(($id=$element->getAttribute('id'))!==null && ($path=$element->getAttribute('path'))!==null)
11016
					{
11017
						$path=str_replace('\\','/',$path);
11018
						if(preg_match('/^\\/|.:\\/|.:\\\\/',$path))								$p=realpath($path);
11019
						else
11020
							$p=realpath($configPath.DIRECTORY_SEPARATOR.$path);
11021
						if($p===false || !is_dir($p))
11022
							throw new TConfigurationException('appconfig_aliaspath_invalid',$id,$path);
11023
						if(isset($this->_aliases[$id]))
11024
							throw new TConfigurationException('appconfig_alias_redefined',$id);
11025
						$this->_aliases[$id]=$p;
11026
					}
11027
					else
11028
						throw new TConfigurationException('appconfig_alias_invalid');
11029
					$this->_empty=false;
11030
					break;
11031
				}
11032
				case 'using':
0 ignored issues
show
Coding Style introduced by
CASE statements must be defined using a colon

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
11033
				{
11034
					if(($namespace=$element->getAttribute('namespace'))!==null)
11035
						$this->_usings[]=$namespace;
11036
					else
11037
						throw new TConfigurationException('appconfig_using_invalid');
11038
					$this->_empty=false;
11039
					break;
11040
				}
11041
				default:
11042
					throw new TConfigurationException('appconfig_paths_invalid',$element->getTagName());
11043
			}
11044
		}
11045
	}
11046
	protected function loadModulesPhp($modulesNode, $configPath)
11047
	{
11048
		foreach($modulesNode as $id=>$module)
11049
		{
11050
			if(!isset($module['class']))
11051
				throw new TConfigurationException('appconfig_moduletype_required',$id);
11052
			$type = $module['class'];
11053
			unset($module['class']);
11054
			$properties = array();
11055
			if(isset($module['properties']))
11056
			{
11057
				$properties = $module['properties'];
11058
				unset($module['properties']);
11059
			}
11060
			$properties['id'] = $id;
11061
			$this->_modules[$id]=array($type,$properties,$module);
11062
			$this->_empty=false;
11063
		}
11064
	}
11065
	protected function loadModulesXml($modulesNode,$configPath)
11066
	{
11067
		foreach($modulesNode->getElements() as $element)
11068
		{
11069
			if($element->getTagName()==='module')
11070
			{
11071
				$properties=$element->getAttributes();
11072
				$id=$properties->itemAt('id');
11073
				$type=$properties->remove('class');
11074
				if($type===null)
11075
					throw new TConfigurationException('appconfig_moduletype_required',$id);
11076
				$element->setParent(null);
11077
				if($id===null)
11078
					$this->_modules[]=array($type,$properties->toArray(),$element);
11079
				else
11080
					$this->_modules[$id]=array($type,$properties->toArray(),$element);
11081
				$this->_empty=false;
11082
			}
11083
			else
11084
				throw new TConfigurationException('appconfig_modules_invalid',$element->getTagName());
11085
		}
11086
	}
11087
	protected function loadServicesPhp($servicesNode,$configPath)
11088
	{
11089
		foreach($servicesNode as $id => $service)
11090
		{
11091
			if(!isset($service['class']))
11092
				throw new TConfigurationException('appconfig_servicetype_required');
11093
			$type = $service['class'];
11094
			$properties = isset($service['properties']) ? $service['properties'] : array();
11095
			unset($service['properties']);
11096
			$properties['id'] = $id;
11097
			$this->_services[$id] = array($type,$properties,$service);
11098
			$this->_empty = false;
11099
		}
11100
	}
11101
	protected function loadServicesXml($servicesNode,$configPath)
11102
	{
11103
		foreach($servicesNode->getElements() as $element)
11104
		{
11105
			if($element->getTagName()==='service')
11106
			{
11107
				$properties=$element->getAttributes();
11108
				if(($id=$properties->itemAt('id'))===null)
11109
					throw new TConfigurationException('appconfig_serviceid_required');
11110
				if(($type=$properties->remove('class'))===null)
11111
					throw new TConfigurationException('appconfig_servicetype_required',$id);
11112
				$element->setParent(null);
11113
				$this->_services[$id]=array($type,$properties->toArray(),$element);
11114
				$this->_empty=false;
11115
			}
11116
			else
11117
				throw new TConfigurationException('appconfig_services_invalid',$element->getTagName());
11118
		}
11119
	}
11120
	protected function loadParametersPhp($parametersNode,$configPath)
11121
	{
11122
		foreach($parametersNode as $id => $parameter)
11123
		{
11124
			if(is_array($parameter))
11125
			{
11126
				if(isset($parameter['class']))
11127
				{
11128
					$type = $parameter['class'];
11129
					unset($parameter['class']);
11130
					$properties = isset($service['properties']) ? $service['properties'] : array();
11131
					$properties['id'] = $id;
11132
					$this->_parameters[$id] = array($type,$properties);
11133
				}
11134
			}
11135
			else
11136
			{
11137
				$this->_parameters[$id] = $parameter;
11138
			}
11139
		}
11140
	}
11141
	protected function loadParametersXml($parametersNode,$configPath)
11142
	{
11143
		foreach($parametersNode->getElements() as $element)
11144
		{
11145
			if($element->getTagName()==='parameter')
11146
			{
11147
				$properties=$element->getAttributes();
11148
				if(($id=$properties->remove('id'))===null)
11149
					throw new TConfigurationException('appconfig_parameterid_required');
11150
				if(($type=$properties->remove('class'))===null)
11151
				{
11152
					if(($value=$properties->remove('value'))===null)
11153
						$this->_parameters[$id]=$element;
11154
					else
11155
						$this->_parameters[$id]=$value;
11156
				}
11157
				else
11158
					$this->_parameters[$id]=array($type,$properties->toArray());
11159
				$this->_empty=false;
11160
			}
11161
			else
11162
				throw new TConfigurationException('appconfig_parameters_invalid',$element->getTagName());
11163
		}
11164
	}
11165
	protected function loadExternalPhp($includeNode,$configPath)
11166
	{
11167
		foreach($includeNode as $include)
11168
		{
11169
			$when = isset($include['when'])?true:false;
11170
			if(!isset($include['file']))
11171
				throw new TConfigurationException('appconfig_includefile_required');
11172
			$filePath = $include['file'];
11173
			if(isset($this->_includes[$filePath]))
11174
				$this->_includes[$filePath]='('.$this->_includes[$filePath].') || ('.$when.')';
11175
			else
11176
				$$this->_includes[$filePath]=$when;
11177
			$this->_empty=false;
11178
		}
11179
	}
11180
	protected function loadExternalXml($includeNode,$configPath)
11181
	{
11182
		if(($when=$includeNode->getAttribute('when'))===null)
11183
			$when=true;
11184
		if(($filePath=$includeNode->getAttribute('file'))===null)
11185
			throw new TConfigurationException('appconfig_includefile_required');
11186
		if(isset($this->_includes[$filePath]))
11187
			$this->_includes[$filePath]='('.$this->_includes[$filePath].') || ('.$when.')';
11188
		else
11189
			$this->_includes[$filePath]=$when;
11190
		$this->_empty=false;
11191
	}
11192
	public function getProperties()
11193
	{
11194
		return $this->_properties;
11195
	}
11196
	public function getAliases()
11197
	{
11198
		return $this->_aliases;
11199
	}
11200
	public function getUsings()
11201
	{
11202
		return $this->_usings;
11203
	}
11204
	public function getModules()
11205
	{
11206
		return $this->_modules;
11207
	}
11208
	public function getServices()
11209
	{
11210
		return $this->_services;
11211
	}
11212
	public function getParameters()
11213
	{
11214
		return $this->_parameters;
11215
	}
11216
	public function getExternalConfigurations()
11217
	{
11218
		return $this->_includes;
11219
	}
11220
}
11221
class TApplicationStatePersister extends TModule implements IStatePersister
11222
{
11223
	const CACHE_NAME='prado:appstate';
11224
	public function init($config)
11225
	{
11226
		$this->getApplication()->setApplicationStatePersister($this);
11227
	}
11228
	protected function getStateFilePath()
11229
	{
11230
		return $this->getApplication()->getRuntimePath().'/global.cache';
11231
	}
11232
	public function load()
11233
	{
11234
		if(($cache=$this->getApplication()->getCache())!==null && ($value=$cache->get(self::CACHE_NAME))!==false)
11235
			return unserialize($value);
11236
		else
11237
		{
11238
			if(($content=@file_get_contents($this->getStateFilePath()))!==false)
11239
				return unserialize($content);
11240
			else
11241
				return null;
11242
		}
11243
	}
11244
	public function save($state)
11245
	{
11246
		$content=serialize($state);
11247
		$saveFile=true;
11248
		if(($cache=$this->getApplication()->getCache())!==null)
11249
		{
11250
			if($cache->get(self::CACHE_NAME)===$content)
11251
				$saveFile=false;
11252
			else
11253
				$cache->set(self::CACHE_NAME,$content);
11254
		}
11255
		if($saveFile)
11256
		{
11257
			$fileName=$this->getStateFilePath();
11258
			file_put_contents($fileName,$content,LOCK_EX);
11259
		}
11260
	}
11261
}
11262
class TShellApplication extends TApplication
11263
{
11264
	public function run()
11265
	{
11266
		$this->initApplication();
11267
	}
11268
}
11269
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...