Completed
Push — master ( 2c4901...f8799b )
by Fabio
10:54
created

TControl::loadRecursive()   B

Complexity

Conditions 7
Paths 12

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 12
nc 12
nop 0
dl 0
loc 20
rs 8.2222
c 0
b 0
f 0
1
<?php
2
/**
3
 * File Name: pradolite.php
4
 * Last Update: 2016/06/08 16:06:00
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.1';
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
		ini_set('display_errors', 0);
36
	}
37
	public static function autoload($className)
38
	{
39
		@include_once($className.self::CLASS_FILE_EXT);
40
	}
41
	public static function poweredByPrado($logoType=0)
42
	{
43
		$logoName=$logoType==1?'powered2':'powered';
44
		if(self::$_application!==null)
45
		{
46
			$am=self::$_application->getAssetManager();
47
			$url=$am->publishFilePath(self::getPathOfNamespace('System.'.$logoName,'.gif'));
48
		}
49
		else
50
			$url='http://pradosoft.github.io/docs/'.$logoName.'.gif';
51
		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>';
52
	}
53
	public static function phpErrorHandler($errno,$errstr,$errfile,$errline)
54
	{
55
		if(error_reporting() & $errno)
56
			throw new TPhpErrorException($errno,$errstr,$errfile,$errline);
57
	}
58
	public static function phpFatalErrorHandler()
59
	{
60
		$error = error_get_last();
61
		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...
62
			TPhpErrorException::isFatalError($error) &&
63
			error_reporting() & $error['type'])
64
		{
65
			self::exceptionHandler(new TPhpErrorException($error['type'],$error['message'],$error['file'],$error['line']));
66
		}
67
	}
68
	public static function exceptionHandler($exception)
69
	{
70
		if(self::$_application!==null && ($errorHandler=self::$_application->getErrorHandler())!==null)
71
		{
72
			$errorHandler->handleError(null,$exception);
73
		}
74
		else
75
		{
76
			echo $exception;
77
		}
78
		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...
79
	}
80
	public static function setApplication($application)
81
	{
82
		if(self::$_application!==null && !defined('PRADO_TEST_RUN'))
83
			throw new TInvalidOperationException('prado_application_singleton_required');
84
		self::$_application=$application;
85
	}
86
	public static function getApplication()
87
	{
88
		return self::$_application;
89
	}
90
	public static function getFrameworkPath()
91
	{
92
		return PRADO_DIR;
93
	}
94
	public static function createComponent($type)
95
	{
96
		if(!isset(self::$classExists[$type]))
97
			self::$classExists[$type] = class_exists($type, false);
98
		if( !isset(self::$_usings[$type]) && !self::$classExists[$type]) {
99
			self::using($type);
100
			self::$classExists[$type] = class_exists($type, false);
101
		}
102
		if( ($pos = strrpos($type, '.')) !== false)
103
			$type = substr($type,$pos+1);
104
		if(($n=func_num_args())>1)
105
		{
106
			$args = func_get_args();
107
			switch($n) {
108
				case 2:
109
					return new $type($args[1]);
110
				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...
111
				case 3:
112
					return new $type($args[1], $args[2]);
113
				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...
114
				case 4:
115
					return new $type($args[1], $args[2], $args[3]);
116
				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...
117
				case 5:
118
					return new $type($args[1], $args[2], $args[3], $args[4]);
119
				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...
120
				default:
121
					$s='$args[1]';
122
					for($i=2;$i<$n;++$i)
123
						$s.=",\$args[$i]";
124
					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...
125
					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...
126
				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...
127
			}
128
		}
129
		else
130
			return new $type;
131
	}
132
	public static function using($namespace,$checkClassExistence=true)
133
	{
134
		if(isset(self::$_usings[$namespace]) || class_exists($namespace,false))
135
			return;
136
		if(($pos=strrpos($namespace,'.'))===false)  		{
137
			try
138
			{
139
				include_once($namespace.self::CLASS_FILE_EXT);
140
			}
141
			catch(Exception $e)
142
			{
143
				if($checkClassExistence && !class_exists($namespace,false))
144
					throw new TInvalidOperationException('prado_component_unknown',$namespace,$e->getMessage());
145
				else
146
					throw $e;
147
			}
148
		}
149
		else if(($path=self::getPathOfNamespace($namespace,self::CLASS_FILE_EXT))!==null)
150
		{
151
			$className=substr($namespace,$pos+1);
152
			if($className==='*')  			{
153
				self::$_usings[$namespace]=$path;
154
				set_include_path(get_include_path().PATH_SEPARATOR.$path);
155
			}
156
			else  			{
157
				self::$_usings[$namespace]=$path;
158
				if(!$checkClassExistence || !class_exists($className,false))
159
				{
160
					try
161
					{
162
						include_once($path);
163
					}
164
					catch(Exception $e)
165
					{
166
						if($checkClassExistence && !class_exists($className,false))
167
							throw new TInvalidOperationException('prado_component_unknown',$className,$e->getMessage());
168
						else
169
							throw $e;
170
					}
171
				}
172
			}
173
		}
174
		else
175
			throw new TInvalidDataValueException('prado_using_invalid',$namespace);
176
	}
177
	public static function getPathOfNamespace($namespace, $ext='')
178
	{
179
		if(self::CLASS_FILE_EXT === $ext || empty($ext))
180
		{
181
			if(isset(self::$_usings[$namespace]))
182
				return self::$_usings[$namespace];
183
			if(isset(self::$_aliases[$namespace]))
184
				return self::$_aliases[$namespace];
185
		}
186
		$segs = explode('.',$namespace);
187
		$alias = array_shift($segs);
188
		if(null !== ($file = array_pop($segs)) && null !== ($root = self::getPathOfAlias($alias)))
189
			return rtrim($root.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR ,$segs),'/\\').(($file === '*') ? '' : DIRECTORY_SEPARATOR.$file.$ext);
190
		return null;
191
	}
192
	public static function getPathOfAlias($alias)
193
	{
194
		return isset(self::$_aliases[$alias])?self::$_aliases[$alias]:null;
195
	}
196
	protected static function getPathAliases()
197
	{
198
		return self::$_aliases;
199
	}
200
	public static function setPathOfAlias($alias,$path)
201
	{
202
		if(isset(self::$_aliases[$alias]) && !defined('PRADO_TEST_RUN'))
203
			throw new TInvalidOperationException('prado_alias_redefined',$alias);
204
		else if(($rp=realpath($path))!==false && is_dir($rp))
205
		{
206
			if(strpos($alias,'.')===false)
207
				self::$_aliases[$alias]=$rp;
208
			else
209
				throw new TInvalidDataValueException('prado_aliasname_invalid',$alias);
210
		}
211
		else
212
			throw new TInvalidDataValueException('prado_alias_invalid',$alias,$path);
213
	}
214
	public static function fatalError($msg)
215
	{
216
		echo '<h1>Fatal Error</h1>';
217
		echo '<p>'.$msg.'</p>';
218
		if(!function_exists('debug_backtrace'))
219
			return;
220
		echo '<h2>Debug Backtrace</h2>';
221
		echo '<pre>';
222
		$index=-1;
223
		foreach(debug_backtrace() as $t)
224
		{
225
			$index++;
226
			if($index==0)  				continue;
227
			echo '#'.$index.' ';
228
			if(isset($t['file']))
229
				echo basename($t['file']) . ':' . $t['line'];
230
			else
231
				 echo '<PHP inner-code>';
232
			echo ' -- ';
233
			if(isset($t['class']))
234
				echo $t['class'] . $t['type'];
235
			echo $t['function'] . '(';
236
			if(isset($t['args']) && sizeof($t['args']) > 0)
237
			{
238
				$count=0;
239
				foreach($t['args'] as $item)
240
				{
241
					if(is_string($item))
242
					{
243
						$str=htmlentities(str_replace("\r\n", "", $item), ENT_QUOTES);
244
						if (strlen($item) > 70)
245
							echo "'". substr($str, 0, 70) . "...'";
246
						else
247
							echo "'" . $str . "'";
248
					}
249
					else if (is_int($item) || is_float($item))
250
						echo $item;
251
					else if (is_object($item))
252
						echo get_class($item);
253
					else if (is_array($item))
254
						echo 'array(' . count($item) . ')';
255
					else if (is_bool($item))
256
						echo $item ? 'true' : 'false';
257
					else if ($item === null)
258
						echo 'NULL';
259
					else if (is_resource($item))
260
						echo get_resource_type($item);
261
					$count++;
262
					if (count($t['args']) > $count)
263
						echo ', ';
264
				}
265
			}
266
			echo ")\n";
267
		}
268
		echo '</pre>';
269
		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...
270
	}
271
	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...
272
	{
273
		static $languages=null;
274
		if($languages===null)
275
		{
276
			if(!isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
277
				$languages[0]='en';
278
			else
279
			{
280
				$languages=array();
281
				foreach(explode(',',$_SERVER['HTTP_ACCEPT_LANGUAGE']) as $language)
282
				{
283
					$array=explode(';q=',trim($language));
284
					$languages[trim($array[0])]=isset($array[1])?(float)$array[1]:1.0;
285
				}
286
				arsort($languages);
287
				$languages=array_keys($languages);
288
				if(empty($languages))
289
					$languages[0]='en';
290
			}
291
		}
292
		return $languages;
293
	}
294
	public static function getPreferredLanguage()
295
	{
296
		static $language=null;
297
		if($language===null)
298
		{
299
			$langs=Prado::getUserLanguages();
300
			$lang=explode('-',$langs[0]);
301
			if(empty($lang[0]) || !ctype_alpha($lang[0]))
302
				$language='en';
303
			else
304
				$language=$lang[0];
305
		}
306
		return $language;
307
	}
308
	public static function trace($msg,$category='Uncategorized',$ctl=null)
309
	{
310
		if(self::$_application && self::$_application->getMode()===TApplicationMode::Performance)
311
			return;
312
		if(!self::$_application || self::$_application->getMode()===TApplicationMode::Debug)
313
		{
314
			$trace=debug_backtrace();
315
			if(isset($trace[0]['file']) && isset($trace[0]['line']))
316
				$msg.=" (line {$trace[0]['line']}, {$trace[0]['file']})";
317
			$level=TLogger::DEBUG;
318
		}
319
		else
320
			$level=TLogger::INFO;
321
		self::log($msg,$level,$category,$ctl);
322
	}
323
	public static function log($msg,$level=TLogger::INFO,$category='Uncategorized',$ctl=null)
324
	{
325
		if(self::$_logger===null)
326
			self::$_logger=new TLogger;
327
		self::$_logger->log($msg,$level,$category,$ctl);
328
	}
329
	public static function getLogger()
330
	{
331
		if(self::$_logger===null)
332
			self::$_logger=new TLogger;
333
		return self::$_logger;
334
	}
335
	public static function varDump($var,$depth=10,$highlight=false)
336
	{
337
		Prado::using('System.Util.TVarDumper');
338
		return TVarDumper::dump($var,$depth,$highlight);
339
	}
340
	public static function localize($text, $parameters=array(), $catalogue=null, $charset=null)
341
	{
342
		Prado::using('System.I18N.Translation');
343
		$app = Prado::getApplication()->getGlobalization(false);
344
		$params = array();
345
		foreach($parameters as $key => $value)
346
			$params['{'.$key.'}'] = $value;
347
				if($app===null || ($config = $app->getTranslationConfiguration())===null)
348
			return strtr($text, $params);
349
		if ($catalogue===null)
350
			$catalogue=isset($config['catalogue'])?$config['catalogue']:'messages';
351
		Translation::init($catalogue);
352
				$appCharset = $app===null ? '' : $app->getCharset();
353
				$defaultCharset = ($app===null) ? 'UTF-8' : $app->getDefaultCharset();
354
				if(empty($charset)) $charset = $appCharset;
355
		if(empty($charset)) $charset = $defaultCharset;
356
		return Translation::formatter($catalogue)->format($text,$params,$catalogue,$charset);
357
	}
358
}
359
PradoBase::using('System.TComponent');
360
PradoBase::using('System.Exceptions.TException');
361
PradoBase::using('System.Util.TLogger');
362
if(!class_exists('Prado',false))
363
{
364
	class Prado extends PradoBase
365
	{
366
	}
367
}
368
spl_autoload_register(array('Prado','autoload'));
369
Prado::initErrorHandlers();
370
interface IModule
371
{
372
	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...
373
	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...
374
	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...
375
}
376
interface IService
377
{
378
	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...
379
	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...
380
	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...
381
	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...
382
	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...
383
	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...
384
}
385
interface ITextWriter
386
{
387
	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...
388
	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...
389
}
390
interface IUser
391
{
392
	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...
393
	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...
394
	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...
395
	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...
396
	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...
397
	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...
398
	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...
399
	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...
400
	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...
401
}
402
interface IStatePersister
403
{
404
	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...
405
	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...
406
}
407
interface ICache
408
{
409
	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...
410
	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...
411
	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...
412
	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...
413
	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...
414
}
415
interface ICacheDependency
416
{
417
	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...
418
}
419
interface IRenderable
420
{
421
	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...
422
}
423
interface IBindable
424
{
425
	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...
426
}
427
interface IStyleable
428
{
429
	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...
430
	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...
431
	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...
432
}
433
interface IActiveControl
434
{
435
	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...
436
}
437
interface ICallbackEventHandler
438
{
439
	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...
440
}
441
interface IDataRenderer
442
{
443
	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...
444
	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...
445
}
446
class TApplicationComponent extends TComponent
447
{
448
	public function getApplication()
449
	{
450
		return Prado::getApplication();
451
	}
452
	public function getService()
453
	{
454
		return Prado::getApplication()->getService();
455
	}
456
	public function getRequest()
457
	{
458
		return Prado::getApplication()->getRequest();
459
	}
460
	public function getResponse()
461
	{
462
		return Prado::getApplication()->getResponse();
463
	}
464
	public function getSession()
465
	{
466
		return Prado::getApplication()->getSession();
467
	}
468
	public function getUser()
469
	{
470
		return Prado::getApplication()->getUser();
471
	}
472
	public function publishAsset($assetPath,$className=null)
473
	{
474
		if($className===null)
475
			$className=get_class($this);
476
		$class=new ReflectionClass($className);
477
		$fullPath=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$assetPath;
478
		return $this->publishFilePath($fullPath);
479
	}
480
	public function publishFilePath($fullPath, $checkTimestamp=false)
481
	{
482
		return Prado::getApplication()->getAssetManager()->publishFilePath($fullPath, $checkTimestamp);
483
	}
484
}
485
abstract class TModule extends TApplicationComponent implements IModule
486
{
487
	private $_id;
488
	public function init($config)
489
	{
490
	}
491
	public function getID()
492
	{
493
		return $this->_id;
494
	}
495
	public function setID($value)
496
	{
497
		$this->_id=$value;
498
	}
499
}
500
abstract class TService extends TApplicationComponent implements IService
501
{
502
	private $_id;
503
	private $_enabled=true;
504
	public function init($config)
505
	{
506
	}
507
	public function getID()
508
	{
509
		return $this->_id;
510
	}
511
	public function setID($value)
512
	{
513
		$this->_id=$value;
514
	}
515
	public function getEnabled()
516
	{
517
		return $this->_enabled;
518
	}
519
	public function setEnabled($value)
520
	{
521
		$this->_enabled=TPropertyValue::ensureBoolean($value);
522
	}
523
	public function run()
524
	{
525
	}
526
}
527
class TErrorHandler extends TModule
528
{
529
	const ERROR_FILE_NAME='error';
530
	const EXCEPTION_FILE_NAME='exception';
531
	const SOURCE_LINES=12;
532
	private $_templatePath=null;
533
	public function init($config)
534
	{
535
		$this->getApplication()->setErrorHandler($this);
536
	}
537
	public function getErrorTemplatePath()
538
	{
539
		if($this->_templatePath===null)
540
			$this->_templatePath=Prado::getFrameworkPath().'/Exceptions/templates';
541
		return $this->_templatePath;
542
	}
543
	public function setErrorTemplatePath($value)
544
	{
545
		if(($templatePath=Prado::getPathOfNamespace($value))!==null && is_dir($templatePath))
546
			$this->_templatePath=$templatePath;
547
		else
548
			throw new TConfigurationException('errorhandler_errortemplatepath_invalid',$value);
549
	}
550
	public function handleError($sender,$param)
551
	{
552
		static $handling=false;
553
								restore_error_handler();
554
		restore_exception_handler();
555
				if($handling)
556
			$this->handleRecursiveError($param);
557
		else
558
		{
559
			$handling=true;
560
			if(($response=$this->getResponse())!==null)
561
				$response->clear();
562
			if(!headers_sent())
563
				header('Content-Type: text/html; charset=UTF-8');
564
			if($param instanceof THttpException)
565
				$this->handleExternalError($param->getStatusCode(),$param);
566
			else if($this->getApplication()->getMode()===TApplicationMode::Debug)
567
				$this->displayException($param);
568
			else
569
				$this->handleExternalError(500,$param);
570
		}
571
	}
572
	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...
573
	{
574
		$aRpl = array();
575
		if($exception !== null && $exception instanceof Exception)
576
		{
577
			$aTrace = $exception->getTrace();
578
			foreach($aTrace as $item)
579
			{
580
				if(isset($item['file']))
581
					$aRpl[dirname($item['file']) . DIRECTORY_SEPARATOR] = '<hidden>' . DIRECTORY_SEPARATOR;
582
			}
583
		}
584
		$aRpl[$_SERVER['DOCUMENT_ROOT']] = '${DocumentRoot}';
585
		$aRpl[str_replace('/', DIRECTORY_SEPARATOR, $_SERVER['DOCUMENT_ROOT'])] = '${DocumentRoot}';
586
		$aRpl[PRADO_DIR . DIRECTORY_SEPARATOR] = '${PradoFramework}' . DIRECTORY_SEPARATOR;
587
		if(isset($aRpl[DIRECTORY_SEPARATOR])) unset($aRpl[DIRECTORY_SEPARATOR]);
588
		$aRpl = array_reverse($aRpl, true);
589
		return str_replace(array_keys($aRpl), $aRpl, $value);
590
	}
591
	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...
592
	{
593
		if(!($exception instanceof THttpException))
594
			error_log($exception->__toString());
595
		$content=$this->getErrorTemplate($statusCode,$exception);
596
		$serverAdmin=isset($_SERVER['SERVER_ADMIN'])?$_SERVER['SERVER_ADMIN']:'';
597
		$isDebug = $this->getApplication()->getMode()===TApplicationMode::Debug;
598
		$errorMessage = $exception->getMessage();
599
		if($isDebug)
600
			$version=$_SERVER['SERVER_SOFTWARE'].' <a href="https://github.com/pradosoft/prado">PRADO</a>/'.Prado::getVersion();
601
		else
602
		{
603
			$version='';
604
			$errorMessage = self::hideSecurityRelated($errorMessage, $exception);
605
		}
606
		$tokens=array(
607
			'%%StatusCode%%' => "$statusCode",
608
			'%%ErrorMessage%%' => htmlspecialchars($errorMessage),
609
			'%%ServerAdmin%%' => $serverAdmin,
610
			'%%Version%%' => $version,
611
			'%%Time%%' => @strftime('%Y-%m-%d %H:%M',time())
612
		);
613
		$this->getApplication()->getResponse()->setStatusCode($statusCode, $isDebug ? $exception->getMessage() : null);
614
		echo strtr($content,$tokens);
615
	}
616
	protected function handleRecursiveError($exception)
617
	{
618
		if($this->getApplication()->getMode()===TApplicationMode::Debug)
619
		{
620
			echo "<html><head><title>Recursive Error</title></head>\n";
621
			echo "<body><h1>Recursive Error</h1>\n";
622
			echo "<pre>".$exception->__toString()."</pre>\n";
623
			echo "</body></html>";
624
		}
625
		else
626
		{
627
			error_log("Error happened while processing an existing error:\n".$exception->__toString());
628
			header('HTTP/1.0 500 Internal Error');
629
		}
630
	}
631
	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...
632
	{
633
		if(php_sapi_name()==='cli')
634
		{
635
			echo $exception->getMessage()."\n";
636
			echo $exception->getTraceAsString();
637
			return;
638
		}
639
		if($exception instanceof TTemplateException)
640
		{
641
			$fileName=$exception->getTemplateFile();
642
			$lines=empty($fileName)?explode("\n",$exception->getTemplateSource()):@file($fileName);
643
			$source=$this->getSourceCode($lines,$exception->getLineNumber());
644
			if($fileName==='')
645
				$fileName='---embedded template---';
646
			$errorLine=$exception->getLineNumber();
647
		}
648
		else
649
		{
650
			if(($trace=$this->getExactTrace($exception))!==null)
651
			{
652
				$fileName=$trace['file'];
653
				$errorLine=$trace['line'];
654
			}
655
			else
656
			{
657
				$fileName=$exception->getFile();
658
				$errorLine=$exception->getLine();
659
			}
660
			$source=$this->getSourceCode(@file($fileName),$errorLine);
661
		}
662
		if($this->getApplication()->getMode()===TApplicationMode::Debug)
663
			$version=$_SERVER['SERVER_SOFTWARE'].' <a href="https://github.com/pradosoft/prado">PRADO</a>/'.Prado::getVersion();
664
		else
665
			$version='';
666
		$tokens=array(
667
			'%%ErrorType%%' => get_class($exception),
668
			'%%ErrorMessage%%' => $this->addLink(htmlspecialchars($exception->getMessage())),
669
			'%%SourceFile%%' => htmlspecialchars($fileName).' ('.$errorLine.')',
670
			'%%SourceCode%%' => $source,
671
			'%%StackTrace%%' => htmlspecialchars($exception->getTraceAsString()),
672
			'%%Version%%' => $version,
673
			'%%Time%%' => @strftime('%Y-%m-%d %H:%M',time())
674
		);
675
		$content=$this->getExceptionTemplate($exception);
676
		echo strtr($content,$tokens);
677
	}
678
	protected function getExceptionTemplate($exception)
679
	{
680
		$lang=Prado::getPreferredLanguage();
681
		$exceptionFile=Prado::getFrameworkPath().'/Exceptions/templates/'.self::EXCEPTION_FILE_NAME.'-'.$lang.'.html';
682
		if(!is_file($exceptionFile))
683
			$exceptionFile=Prado::getFrameworkPath().'/Exceptions/templates/'.self::EXCEPTION_FILE_NAME.'.html';
684
		if(($content=@file_get_contents($exceptionFile))===false)
685
			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...
686
		return $content;
687
	}
688
	protected function getErrorTemplate($statusCode,$exception)
689
	{
690
		$base=$this->getErrorTemplatePath().DIRECTORY_SEPARATOR.self::ERROR_FILE_NAME;
691
		$lang=Prado::getPreferredLanguage();
692
		if(is_file("$base$statusCode-$lang.html"))
693
			$errorFile="$base$statusCode-$lang.html";
694
		else if(is_file("$base$statusCode.html"))
695
			$errorFile="$base$statusCode.html";
696
		else if(is_file("$base-$lang.html"))
697
			$errorFile="$base-$lang.html";
698
		else
699
			$errorFile="$base.html";
700
		if(($content=@file_get_contents($errorFile))===false)
701
			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...
702
		return $content;
703
	}
704
	private function getExactTrace($exception)
705
	{
706
		$trace=$exception->getTrace();
707
		$result=null;
708
						if($exception instanceof TPhpErrorException)
709
		{
710
			if(isset($trace[0]['file']))
711
				$result=$trace[0];
712
			elseif(isset($trace[1]))
713
				$result=$trace[1];
714
		}
715
		else if($exception instanceof TInvalidOperationException)
716
		{
717
						if(($result=$this->getPropertyAccessTrace($trace,'__get'))===null)
718
				$result=$this->getPropertyAccessTrace($trace,'__set');
719
		}
720
		if($result!==null && strpos($result['file'],': eval()\'d code')!==false)
721
			return null;
722
		return $result;
723
	}
724
	private function getPropertyAccessTrace($trace,$pattern)
725
	{
726
		$result=null;
727
		foreach($trace as $t)
728
		{
729
			if(isset($t['function']) && $t['function']===$pattern)
730
				$result=$t;
731
			else
732
				break;
733
		}
734
		return $result;
735
	}
736
	private function getSourceCode($lines,$errorLine)
737
	{
738
		$beginLine=$errorLine-self::SOURCE_LINES>=0?$errorLine-self::SOURCE_LINES:0;
739
		$endLine=$errorLine+self::SOURCE_LINES<=count($lines)?$errorLine+self::SOURCE_LINES:count($lines);
740
		$source='';
741
		for($i=$beginLine;$i<$endLine;++$i)
742
		{
743
			if($i===$errorLine-1)
744
			{
745
				$line=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",'    ',$lines[$i])));
746
				$source.="<div class=\"error\">".$line."</div>";
747
			}
748
			else
749
				$source.=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",'    ',$lines[$i])));
750
		}
751
		return $source;
752
	}
753
	private function addLink($message)
754
	{
755
		$baseUrl='http://pradosoft.github.io/docs/manual/class-';
756
		return preg_replace('/\b(T[A-Z]\w+)\b/',"<a href=\"$baseUrl\${1}\" target=\"_blank\">\${1}</a>",$message);
757
	}
758
}
759
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...
760
{
761
	private $_d=array();
762
	private $_c=0;
763
	private $_r=false;
764
	public function __construct($data=null,$readOnly=false)
765
	{
766
		if($data!==null)
767
			$this->copyFrom($data);
768
		$this->setReadOnly($readOnly);
769
	}
770
	public function getReadOnly()
771
	{
772
		return $this->_r;
773
	}
774
	protected function setReadOnly($value)
775
	{
776
		$this->_r=TPropertyValue::ensureBoolean($value);
777
	}
778
	public function getIterator()
779
	{
780
		return new ArrayIterator( $this->_d );
781
	}
782
	public function count()
783
	{
784
		return $this->getCount();
785
	}
786
	public function getCount()
787
	{
788
		return $this->_c;
789
	}
790
	public function itemAt($index)
791
	{
792
		if($index>=0 && $index<$this->_c)
793
			return $this->_d[$index];
794
		else
795
			throw new TInvalidDataValueException('list_index_invalid',$index);
796
	}
797
	public function add($item)
798
	{
799
		$this->insertAt($this->_c,$item);
800
		return $this->_c-1;
801
	}
802
	public function insertAt($index,$item)
803
	{
804
		if(!$this->_r)
805
		{
806
			if($index===$this->_c)
807
				$this->_d[$this->_c++]=$item;
808
			else if($index>=0 && $index<$this->_c)
809
			{
810
				array_splice($this->_d,$index,0,array($item));
811
				$this->_c++;
812
			}
813
			else
814
				throw new TInvalidDataValueException('list_index_invalid',$index);
815
		}
816
		else
817
			throw new TInvalidOperationException('list_readonly',get_class($this));
818
	}
819
	public function remove($item)
820
	{
821
		if(!$this->_r)
822
		{
823
			if(($index=$this->indexOf($item))>=0)
824
			{
825
				$this->removeAt($index);
826
				return $index;
827
			}
828
			else
829
				throw new TInvalidDataValueException('list_item_inexistent');
830
		}
831
		else
832
			throw new TInvalidOperationException('list_readonly',get_class($this));
833
	}
834
	public function removeAt($index)
835
	{
836
		if(!$this->_r)
837
		{
838
			if($index>=0 && $index<$this->_c)
839
			{
840
				$this->_c--;
841
				if($index===$this->_c)
842
					return array_pop($this->_d);
843
				else
844
				{
845
					$item=$this->_d[$index];
846
					array_splice($this->_d,$index,1);
847
					return $item;
848
				}
849
			}
850
			else
851
				throw new TInvalidDataValueException('list_index_invalid',$index);
852
		}
853
		else
854
			throw new TInvalidOperationException('list_readonly',get_class($this));
855
	}
856
	public function clear()
857
	{
858
		for($i=$this->_c-1;$i>=0;--$i)
859
			$this->removeAt($i);
860
	}
861
	public function contains($item)
862
	{
863
		return $this->indexOf($item)>=0;
864
	}
865
	public function indexOf($item)
866
	{
867
		if(($index=array_search($item,$this->_d,true))===false)
868
			return -1;
869
		else
870
			return $index;
871
	}
872
	public function insertBefore($baseitem, $item)
873
	{
874
		if(!$this->_r)
875
		{
876
			if(($index = $this->indexOf($baseitem)) == -1)
877
				throw new TInvalidDataValueException('list_item_inexistent');
878
			$this->insertAt($index, $item);
879
			return $index;
880
		}
881
		else
882
			throw new TInvalidOperationException('list_readonly',get_class($this));
883
	}
884
	public function insertAfter($baseitem, $item)
885
	{
886
		if(!$this->_r)
887
		{
888
			if(($index = $this->indexOf($baseitem)) == -1)
889
				throw new TInvalidDataValueException('list_item_inexistent');
890
			$this->insertAt($index + 1, $item);
891
			return $index + 1;
892
		}
893
		else
894
			throw new TInvalidOperationException('list_readonly',get_class($this));
895
	}
896
	public function toArray()
897
	{
898
		return $this->_d;
899
	}
900
	public function copyFrom($data)
901
	{
902
		if(is_array($data) || ($data instanceof Traversable))
903
		{
904
			if($this->_c>0)
905
				$this->clear();
906
			foreach($data as $item)
907
				$this->add($item);
908
		}
909
		else if($data!==null)
910
			throw new TInvalidDataTypeException('list_data_not_iterable');
911
	}
912
	public function mergeWith($data)
913
	{
914
		if(is_array($data) || ($data instanceof Traversable))
915
		{
916
			foreach($data as $item)
917
				$this->add($item);
918
		}
919
		else if($data!==null)
920
			throw new TInvalidDataTypeException('list_data_not_iterable');
921
	}
922
	public function offsetExists($offset)
923
	{
924
		return ($offset>=0 && $offset<$this->_c);
925
	}
926
	public function offsetGet($offset)
927
	{
928
		return $this->itemAt($offset);
929
	}
930
	public function offsetSet($offset,$item)
931
	{
932
		if($offset===null || $offset===$this->_c)
933
			$this->insertAt($this->_c,$item);
934
		else
935
		{
936
			$this->removeAt($offset);
937
			$this->insertAt($offset,$item);
938
		}
939
	}
940
	public function offsetUnset($offset)
941
	{
942
		$this->removeAt($offset);
943
	}
944
}
945
class TListIterator extends ArrayIterator
946
{
947
}
948
abstract class TCache extends TModule implements ICache, ArrayAccess
949
{
950
	private $_prefix=null;
951
	private $_primary=true;
952
	public function init($config)
953
	{
954
		if($this->_prefix===null)
955
			$this->_prefix=$this->getApplication()->getUniqueID();
956
		if($this->_primary)
957
		{
958
			if($this->getApplication()->getCache()===null)
959
				$this->getApplication()->setCache($this);
960
			else
961
				throw new TConfigurationException('cache_primary_duplicated',get_class($this));
962
		}
963
	}
964
	public function getPrimaryCache()
965
	{
966
		return $this->_primary;
967
	}
968
	public function setPrimaryCache($value)
969
	{
970
		$this->_primary=TPropertyValue::ensureBoolean($value);
971
	}
972
	public function getKeyPrefix()
973
	{
974
		return $this->_prefix;
975
	}
976
	public function setKeyPrefix($value)
977
	{
978
		$this->_prefix=$value;
979
	}
980
	protected function generateUniqueKey($key)
981
	{
982
		return md5($this->_prefix.$key);
983
	}
984
	public function get($id)
985
	{
986
		if(($data=$this->getValue($this->generateUniqueKey($id)))!==false)
987
		{
988
			if(!is_array($data))
989
				return false;
990
			if(!($data[1] instanceof ICacheDependency) || !$data[1]->getHasChanged())
991
				return $data[0];
992
		}
993
		return false;
994
	}
995
	public function set($id,$value,$expire=0,$dependency=null)
996
	{
997
		if(empty($value) && $expire === 0)
998
			$this->delete($id);
999
		else
1000
		{
1001
			$data=array($value,$dependency);
1002
			return $this->setValue($this->generateUniqueKey($id),$data,$expire);
1003
		}
1004
	}
1005
	public function add($id,$value,$expire=0,$dependency=null)
1006
	{
1007
		if(empty($value) && $expire === 0)
1008
			return false;
1009
		$data=array($value,$dependency);
1010
		return $this->addValue($this->generateUniqueKey($id),$data,$expire);
1011
	}
1012
	public function delete($id)
1013
	{
1014
		return $this->deleteValue($this->generateUniqueKey($id));
1015
	}
1016
	public function flush()
1017
	{
1018
		throw new TNotSupportedException('cache_flush_unsupported');
1019
	}
1020
	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...
1021
	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...
1022
	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...
1023
	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...
1024
	public function offsetExists($id)
1025
	{
1026
		return $this->get($id) !== false;
1027
	}
1028
	public function offsetGet($id)
1029
	{
1030
		return $this->get($id);
1031
	}
1032
	public function offsetSet($id, $value)
1033
	{
1034
		$this->set($id, $value);
1035
	}
1036
	public function offsetUnset($id)
1037
	{
1038
		$this->delete($id);
1039
	}
1040
}
1041
abstract class TCacheDependency extends TComponent implements ICacheDependency
1042
{
1043
}
1044
class TFileCacheDependency extends TCacheDependency
1045
{
1046
	private $_fileName;
1047
	private $_timestamp;
1048
	public function __construct($fileName)
1049
	{
1050
		$this->setFileName($fileName);
1051
	}
1052
	public function getFileName()
1053
	{
1054
		return $this->_fileName;
1055
	}
1056
	public function setFileName($value)
1057
	{
1058
		$this->_fileName=$value;
1059
		$this->_timestamp=@filemtime($value);
1060
	}
1061
	public function getTimestamp()
1062
	{
1063
		return $this->_timestamp;
1064
	}
1065
	public function getHasChanged()
1066
	{
1067
		return @filemtime($this->_fileName)!==$this->_timestamp;
1068
	}
1069
}
1070
class TDirectoryCacheDependency extends TCacheDependency
1071
{
1072
	private $_recursiveCheck=true;
1073
	private $_recursiveLevel=-1;
1074
	private $_timestamps;
1075
	private $_directory;
1076
	public function __construct($directory)
1077
	{
1078
		$this->setDirectory($directory);
1079
	}
1080
	public function getDirectory()
1081
	{
1082
		return $this->_directory;
1083
	}
1084
	public function setDirectory($directory)
1085
	{
1086
		if(($path=realpath($directory))===false || !is_dir($path))
1087
			throw new TInvalidDataValueException('directorycachedependency_directory_invalid',$directory);
1088
		$this->_directory=$path;
1089
		$this->_timestamps=$this->generateTimestamps($path);
1090
	}
1091
	public function getRecursiveCheck()
1092
	{
1093
		return $this->_recursiveCheck;
1094
	}
1095
	public function setRecursiveCheck($value)
1096
	{
1097
		$this->_recursiveCheck=TPropertyValue::ensureBoolean($value);
1098
	}
1099
	public function getRecursiveLevel()
1100
	{
1101
		return $this->_recursiveLevel;
1102
	}
1103
	public function setRecursiveLevel($value)
1104
	{
1105
		$this->_recursiveLevel=TPropertyValue::ensureInteger($value);
1106
	}
1107
	public function getHasChanged()
1108
	{
1109
		return $this->generateTimestamps($this->_directory)!=$this->_timestamps;
1110
	}
1111
	protected function validateFile($fileName)
1112
	{
1113
		return true;
1114
	}
1115
	protected function validateDirectory($directory)
1116
	{
1117
		return true;
1118
	}
1119
	protected function generateTimestamps($directory,$level=0)
1120
	{
1121
		if(($dir=opendir($directory))===false)
1122
			throw new TIOException('directorycachedependency_directory_invalid',$directory);
1123
		$timestamps=array();
1124
		while(($file=readdir($dir))!==false)
1125
		{
1126
			$path=$directory.DIRECTORY_SEPARATOR.$file;
1127
			if($file==='.' || $file==='..')
1128
				continue;
1129
			else if(is_dir($path))
1130
			{
1131
				if(($this->_recursiveLevel<0 || $level<$this->_recursiveLevel) && $this->validateDirectory($path))
1132
					$timestamps=array_merge($this->generateTimestamps($path,$level+1));
1133
			}
1134
			else if($this->validateFile($path))
1135
				$timestamps[$path]=filemtime($path);
1136
		}
1137
		closedir($dir);
1138
		return $timestamps;
1139
	}
1140
}
1141
class TGlobalStateCacheDependency extends TCacheDependency
1142
{
1143
	private $_stateName;
1144
	private $_stateValue;
1145
	public function __construct($name)
1146
	{
1147
		$this->setStateName($name);
1148
	}
1149
	public function getStateName()
1150
	{
1151
		return $this->_stateName;
1152
	}
1153
	public function setStateName($value)
1154
	{
1155
		$this->_stateName=$value;
1156
		$this->_stateValue=Prado::getApplication()->getGlobalState($value);
1157
	}
1158
	public function getHasChanged()
1159
	{
1160
		return $this->_stateValue!==Prado::getApplication()->getGlobalState($this->_stateName);
1161
	}
1162
}
1163
class TChainedCacheDependency extends TCacheDependency
1164
{
1165
	private $_dependencies=null;
1166
	public function getDependencies()
1167
	{
1168
		if($this->_dependencies===null)
1169
			$this->_dependencies=new TCacheDependencyList;
1170
		return $this->_dependencies;
1171
	}
1172
	public function getHasChanged()
1173
	{
1174
		if($this->_dependencies!==null)
1175
		{
1176
			foreach($this->_dependencies as $dependency)
1177
				if($dependency->getHasChanged())
1178
					return true;
1179
		}
1180
		return false;
1181
	}
1182
}
1183
class TApplicationStateCacheDependency extends TCacheDependency
1184
{
1185
	public function getHasChanged()
1186
	{
1187
		return Prado::getApplication()->getMode()!==TApplicationMode::Performance;
1188
	}
1189
}
1190
class TCacheDependencyList extends TList
1191
{
1192
	public function insertAt($index,$item)
1193
	{
1194
		if($item instanceof ICacheDependency)
1195
			parent::insertAt($index,$item);
1196
		else
1197
			throw new TInvalidDataTypeException('cachedependencylist_cachedependency_required');
1198
	}
1199
}
1200
class TTextWriter extends TComponent implements ITextWriter
1201
{
1202
	private $_str='';
1203
	public function flush()
1204
	{
1205
		$str=$this->_str;
1206
		$this->_str='';
1207
		return $str;
1208
	}
1209
	public function write($str)
1210
	{
1211
		$this->_str.=$str;
1212
	}
1213
	public function writeLine($str='')
1214
	{
1215
		$this->write($str."\n");
1216
	}
1217
}
1218
class TPriorityList extends TList
1219
{
1220
	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...
1221
	private $_o=false;
1222
	private $_fd=null;
1223
	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...
1224
	private $_dp=10;
1225
	private $_p=8;
1226
	public function __construct($data=null,$readOnly=false,$defaultPriority=10,$precision=8)
1227
	{
1228
		parent::__construct();
1229
		if($data!==null)
1230
			$this->copyFrom($data);
1231
		$this->setReadOnly($readOnly);
1232
		$this->setPrecision($precision);
1233
		$this->setDefaultPriority($defaultPriority);
1234
	}
1235
	public function count()
1236
	{
1237
		return $this->getCount();
1238
	}
1239
	public function getCount()
1240
	{
1241
		return $this->_c;
1242
	}
1243
	public function getPriorityCount($priority=null)
1244
	{
1245
		if($priority===null)
1246
			$priority=$this->getDefaultPriority();
1247
		$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1248
		if(!isset($this->_d[$priority]) || !is_array($this->_d[$priority]))
1249
			return false;
1250
		return count($this->_d[$priority]);
1251
	}
1252
	public function getDefaultPriority()
1253
	{
1254
		return $this->_dp;
1255
	}
1256
	protected function setDefaultPriority($value)
1257
	{
1258
		$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...
1259
	}
1260
	public function getPrecision()
1261
	{
1262
		return $this->_p;
1263
	}
1264
	protected function setPrecision($value)
1265
	{
1266
		$this->_p=TPropertyValue::ensureInteger($value);
1267
	}
1268
	public function getIterator()
1269
	{
1270
		return new ArrayIterator($this->flattenPriorities());
1271
	}
1272
	public function getPriorities()
1273
	{
1274
		$this->sortPriorities();
1275
		return array_keys($this->_d);
1276
	}
1277
	protected function sortPriorities() {
1278
		if(!$this->_o) {
1279
			ksort($this->_d,SORT_NUMERIC);
1280
			$this->_o=true;
1281
		}
1282
	}
1283
	protected function flattenPriorities() {
1284
		if(is_array($this->_fd))
1285
			return $this->_fd;
1286
		$this->sortPriorities();
1287
		$this->_fd=array();
1288
		foreach($this->_d as $priority => $itemsatpriority)
1289
			$this->_fd=array_merge($this->_fd,$itemsatpriority);
1290
		return $this->_fd;
1291
	}
1292
	public function itemAt($index)
1293
	{
1294
		if($index>=0&&$index<$this->getCount()) {
1295
			$arr=$this->flattenPriorities();
1296
			return $arr[$index];
1297
		} else
1298
			throw new TInvalidDataValueException('list_index_invalid',$index);
1299
	}
1300
	public function itemsAtPriority($priority=null)
1301
	{
1302
		if($priority===null)
1303
			$priority=$this->getDefaultPriority();
1304
		$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1305
		return isset($this->_d[$priority])?$this->_d[$priority]:null;
1306
	}
1307
	public function itemAtIndexInPriority($index,$priority=null)
1308
	{
1309
		if($priority===null)
1310
			$priority=$this->getDefaultPriority();
1311
		$priority=(string)round(TPropertyValue::ensureFloat($priority), $this->_p);
1312
		return !isset($this->_d[$priority])?false:(
1313
				isset($this->_d[$priority][$index])?$this->_d[$priority][$index]:false
1314
			);
1315
	}
1316
	public function add($item,$priority=null)
1317
	{
1318
		if($this->getReadOnly())
1319
			throw new TInvalidOperationException('list_readonly',get_class($this));
1320
		return $this->insertAtIndexInPriority($item,false,$priority,true);
1321
	}
1322
	public function insertAt($index,$item)
1323
	{
1324
		if($this->getReadOnly())
1325
			throw new TInvalidOperationException('list_readonly',get_class($this));
1326
		if(($priority=$this->priorityAt($index,true))!==false)
1327
			$this->insertAtIndexInPriority($item,$priority[1],$priority[0]);
1328
		else
1329
			throw new TInvalidDataValueException('list_index_invalid',$index);
1330
	}
1331
	public function insertAtIndexInPriority($item,$index=false,$priority=null,$preserveCache=false)
1332
	{
1333
		if($this->getReadOnly())
1334
			throw new TInvalidOperationException('list_readonly',get_class($this));
1335
		if($priority===null)
1336
			$priority=$this->getDefaultPriority();
1337
		$priority=(string)round(TPropertyValue::ensureFloat($priority), $this->_p);
1338
		if($preserveCache) {
1339
			$this->sortPriorities();
1340
			$cc=0;
1341
			foreach($this->_d as $prioritykey=>$items)
1342
				if($prioritykey>=$priority)
1343
					break;
1344
				else
1345
					$cc+=count($items);
1346
			if($index===false&&isset($this->_d[$priority])) {
1347
				$c=count($this->_d[$priority]);
1348
				$c+=$cc;
1349
				$this->_d[$priority][]=$item;
1350
			} else if(isset($this->_d[$priority])) {
1351
				$c=$index+$cc;
1352
				array_splice($this->_d[$priority],$index,0,array($item));
1353
			} else {
1354
				$c = $cc;
1355
				$this->_o = false;
1356
				$this->_d[$priority]=array($item);
1357
			}
1358
			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...
1359
		} else {
1360
			$c=null;
1361
			if($index===false&&isset($this->_d[$priority])) {
1362
				$cc=count($this->_d[$priority]);
1363
				$this->_d[$priority][]=$item;
1364
			} else if(isset($this->_d[$priority])) {
1365
				$cc=$index;
1366
				array_splice($this->_d[$priority],$index,0,array($item));
1367
			} else {
1368
				$cc=0;
1369
				$this->_o=false;
1370
				$this->_d[$priority]=array($item);
1371
			}
1372
			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...
1373
				array_splice($this->_fd,$cc,0,array($item));
1374
			else
1375
				$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...
1376
		}
1377
		$this->_c++;
1378
		return $c;
1379
	}
1380
	public function remove($item,$priority=false)
1381
	{
1382
		if($this->getReadOnly())
1383
			throw new TInvalidOperationException('list_readonly',get_class($this));
1384
		if(($p=$this->priorityOf($item,true))!==false)
1385
		{
1386
			if($priority!==false) {
1387
				if($priority===null)
1388
					$priority=$this->getDefaultPriority();
1389
				$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1390
				if($p[0]!=$priority)
1391
					throw new TInvalidDataValueException('list_item_inexistent');
1392
			}
1393
			$this->removeAtIndexInPriority($p[1],$p[0]);
1394
			return $p[2];
1395
		}
1396
		else
1397
			throw new TInvalidDataValueException('list_item_inexistent');
1398
	}
1399
	public function removeAt($index)
1400
	{
1401
		if($this->getReadOnly())
1402
			throw new TInvalidOperationException('list_readonly',get_class($this));
1403
		if(($priority=$this->priorityAt($index, true))!==false)
1404
			return $this->removeAtIndexInPriority($priority[1],$priority[0]);
1405
		throw new TInvalidDataValueException('list_index_invalid',$index);
1406
	}
1407
	public function removeAtIndexInPriority($index, $priority=null)
1408
	{
1409
		if($this->getReadOnly())
1410
			throw new TInvalidOperationException('list_readonly',get_class($this));
1411
		if($priority===null)
1412
			$priority=$this->getDefaultPriority();
1413
		$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1414
		if(!isset($this->_d[$priority])||$index<0||$index>=count($this->_d[$priority]))
1415
			throw new TInvalidDataValueException('list_item_inexistent');
1416
				$value=array_splice($this->_d[$priority],$index,1);
1417
		$value=$value[0];
1418
		if(!count($this->_d[$priority]))
1419
			unset($this->_d[$priority]);
1420
		$this->_c--;
1421
		$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...
1422
		return $value;
1423
	}
1424
	public function clear()
1425
	{
1426
		if($this->getReadOnly())
1427
			throw new TInvalidOperationException('list_readonly',get_class($this));
1428
		$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...
1429
		foreach($this->_d as $priority=>$items) {
1430
			for($index=count($items)-1;$index>=0;$index--)
1431
				$this->removeAtIndexInPriority($index,$priority);
1432
			unset($this->_d[$priority]);
1433
		}
1434
	}
1435
	public function contains($item)
1436
	{
1437
		return $this->indexOf($item)>=0;
1438
	}
1439
	public function indexOf($item)
1440
	{
1441
		if(($index=array_search($item,$this->flattenPriorities(),true))===false)
1442
			return -1;
1443
		else
1444
			return $index;
1445
	}
1446
	public function priorityOf($item,$withindex = false)
1447
	{
1448
		$this->sortPriorities();
1449
		$absindex = 0;
1450
		foreach($this->_d as $priority=>$items) {
1451
			if(($index=array_search($item,$items,true))!==false) {
1452
				$absindex+=$index;
1453
				return $withindex?array($priority,$index,$absindex,
1454
						'priority'=>$priority,'index'=>$index,'absindex'=>$absindex):$priority;
1455
			} else
1456
				$absindex+=count($items);
1457
		}
1458
		return false;
1459
	}
1460
	public function priorityAt($index,$withindex = false)
1461
	{
1462
		if($index<0||$index>=$this->getCount())
1463
			throw new TInvalidDataValueException('list_index_invalid',$index);
1464
		$absindex=$index;
1465
		$this->sortPriorities();
1466
		foreach($this->_d as $priority=>$items) {
1467
			if($index>=($c=count($items)))
1468
				$index-=$c;
1469
			else
1470
				return $withindex?array($priority,$index,$absindex,
1471
						'priority'=>$priority,'index'=>$index,'absindex'=>$absindex):$priority;
1472
		}
1473
		return false;
1474
	}
1475
	public function insertBefore($indexitem, $item)
1476
	{
1477
		if($this->getReadOnly())
1478
			throw new TInvalidOperationException('list_readonly',get_class($this));
1479
		if(($priority=$this->priorityOf($indexitem,true))===false)
1480
			throw new TInvalidDataValueException('list_item_inexistent');
1481
		$this->insertAtIndexInPriority($item,$priority[1],$priority[0]);
1482
		return $priority[2];
1483
	}
1484
	public function insertAfter($indexitem, $item)
1485
	{
1486
		if($this->getReadOnly())
1487
			throw new TInvalidOperationException('list_readonly',get_class($this));
1488
		if(($priority=$this->priorityOf($indexitem,true))===false)
1489
			throw new TInvalidDataValueException('list_item_inexistent');
1490
		$this->insertAtIndexInPriority($item,$priority[1]+1,$priority[0]);
1491
		return $priority[2]+1;
1492
	}
1493
	public function toArray()
1494
	{
1495
		return $this->flattenPriorities();
1496
	}
1497
	public function toPriorityArray()
1498
	{
1499
		$this->sortPriorities();
1500
		return $this->_d;
1501
	}
1502
	public function toArrayBelowPriority($priority,$inclusive=false)
1503
	{
1504
		$this->sortPriorities();
1505
		$items=array();
1506
		foreach($this->_d as $itemspriority=>$itemsatpriority)
1507
		{
1508
			if((!$inclusive&&$itemspriority>=$priority)||$itemspriority>$priority)
1509
				break;
1510
			$items=array_merge($items,$itemsatpriority);
1511
		}
1512
		return $items;
1513
	}
1514
	public function toArrayAbovePriority($priority,$inclusive=true)
1515
	{
1516
		$this->sortPriorities();
1517
		$items=array();
1518
		foreach($this->_d as $itemspriority=>$itemsatpriority)
1519
		{
1520
			if((!$inclusive&&$itemspriority<=$priority)||$itemspriority<$priority)
1521
				continue;
1522
			$items=array_merge($items,$itemsatpriority);
1523
		}
1524
		return $items;
1525
	}
1526
	public function copyFrom($data)
1527
	{
1528
		if($data instanceof TPriorityList)
1529
		{
1530
			if($this->getCount()>0)
1531
				$this->clear();
1532
			foreach($data->getPriorities() as $priority)
1533
			{
1534
				foreach($data->itemsAtPriority($priority) as $index=>$item)
1535
					$this->insertAtIndexInPriority($item,$index,$priority);
1536
			}
1537
		} else if(is_array($data)||$data instanceof Traversable) {
1538
			if($this->getCount()>0)
1539
				$this->clear();
1540
			foreach($data as $key=>$item)
1541
				$this->add($item);
1542
		} else if($data!==null)
1543
			throw new TInvalidDataTypeException('map_data_not_iterable');
1544
	}
1545
	public function mergeWith($data)
1546
	{
1547
		if($data instanceof TPriorityList)
1548
		{
1549
			foreach($data->getPriorities() as $priority)
1550
			{
1551
				foreach($data->itemsAtPriority($priority) as $index=>$item)
1552
					$this->insertAtIndexInPriority($item,false,$priority);
1553
			}
1554
		}
1555
		else if(is_array($data)||$data instanceof Traversable)
1556
		{
1557
			foreach($data as $priority=>$item)
1558
				$this->add($item);
1559
		}
1560
		else if($data!==null)
1561
			throw new TInvalidDataTypeException('map_data_not_iterable');
1562
	}
1563
	public function offsetExists($offset)
1564
	{
1565
		return ($offset>=0&&$offset<$this->getCount());
1566
	}
1567
	public function offsetGet($offset)
1568
	{
1569
		return $this->itemAt($offset);
1570
	}
1571
	public function offsetSet($offset,$item)
1572
	{
1573
		if($offset===null)
1574
			return $this->add($item);
1575
		if($offset===$this->getCount()) {
1576
			$priority=$this->priorityAt($offset-1,true);
1577
			$priority[1]++;
1578
		} else {
1579
			$priority=$this->priorityAt($offset,true);
1580
			$this->removeAtIndexInPriority($priority[1],$priority[0]);
1581
		}
1582
		$this->insertAtIndexInPriority($item,$priority[1],$priority[0]);
1583
	}
1584
	public function offsetUnset($offset)
1585
	{
1586
		$this->removeAt($offset);
1587
	}
1588
}
1589
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...
1590
{
1591
	private $_d=array();
1592
	private $_r=false;
1593
	protected function _getZappableSleepProps(&$exprops)
1594
	{
1595
		parent::_getZappableSleepProps($exprops);
1596
		if ($this->_d===array())
1597
			$exprops[] = "\0TMap\0_d";
1598
		if ($this->_r===false)
1599
			$exprops[] = "\0TMap\0_r";
1600
	}
1601
	public function __construct($data=null,$readOnly=false)
1602
	{
1603
		if($data!==null)
1604
			$this->copyFrom($data);
1605
		$this->setReadOnly($readOnly);
1606
	}
1607
	public function getReadOnly()
1608
	{
1609
		return $this->_r;
1610
	}
1611
	protected function setReadOnly($value)
1612
	{
1613
		$this->_r=TPropertyValue::ensureBoolean($value);
1614
	}
1615
	public function getIterator()
1616
	{
1617
		return new ArrayIterator( $this->_d );
1618
	}
1619
	public function count()
1620
	{
1621
		return $this->getCount();
1622
	}
1623
	public function getCount()
1624
	{
1625
		return count($this->_d);
1626
	}
1627
	public function getKeys()
1628
	{
1629
		return array_keys($this->_d);
1630
	}
1631
	public function itemAt($key)
1632
	{
1633
		return isset($this->_d[$key]) ? $this->_d[$key] : null;
1634
	}
1635
	public function add($key,$value)
1636
	{
1637
		if(!$this->_r)
1638
			$this->_d[$key]=$value;
1639
		else
1640
			throw new TInvalidOperationException('map_readonly',get_class($this));
1641
	}
1642
	public function remove($key)
1643
	{
1644
		if(!$this->_r)
1645
		{
1646
			if(isset($this->_d[$key]) || array_key_exists($key,$this->_d))
1647
			{
1648
				$value=$this->_d[$key];
1649
				unset($this->_d[$key]);
1650
				return $value;
1651
			}
1652
			else
1653
				return null;
1654
		}
1655
		else
1656
			throw new TInvalidOperationException('map_readonly',get_class($this));
1657
	}
1658
	public function clear()
1659
	{
1660
		foreach(array_keys($this->_d) as $key)
1661
			$this->remove($key);
1662
	}
1663
	public function contains($key)
1664
	{
1665
		return isset($this->_d[$key]) || array_key_exists($key,$this->_d);
1666
	}
1667
	public function toArray()
1668
	{
1669
		return $this->_d;
1670
	}
1671
	public function copyFrom($data)
1672
	{
1673
		if(is_array($data) || $data instanceof Traversable)
1674
		{
1675
			if($this->getCount()>0)
1676
				$this->clear();
1677
			foreach($data as $key=>$value)
1678
				$this->add($key,$value);
1679
		}
1680
		else if($data!==null)
1681
			throw new TInvalidDataTypeException('map_data_not_iterable');
1682
	}
1683
	public function mergeWith($data)
1684
	{
1685
		if(is_array($data) || $data instanceof Traversable)
1686
		{
1687
			foreach($data as $key=>$value)
1688
				$this->add($key,$value);
1689
		}
1690
		else if($data!==null)
1691
			throw new TInvalidDataTypeException('map_data_not_iterable');
1692
	}
1693
	public function offsetExists($offset)
1694
	{
1695
		return $this->contains($offset);
1696
	}
1697
	public function offsetGet($offset)
1698
	{
1699
		return $this->itemAt($offset);
1700
	}
1701
	public function offsetSet($offset,$item)
1702
	{
1703
		$this->add($offset,$item);
1704
	}
1705
	public function offsetUnset($offset)
1706
	{
1707
		$this->remove($offset);
1708
	}
1709
}
1710
class TMapIterator extends ArrayIterator
1711
{
1712
}
1713
class TPriorityMap extends TMap
1714
{
1715
	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...
1716
	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...
1717
	private $_o=false;
1718
	private $_fd=null;
1719
	private $_c=0;
1720
	private $_dp=10;
1721
	private $_p=8;
1722
	public function __construct($data=null,$readOnly=false,$defaultPriority=10,$precision=8)
1723
	{
1724
		if($data!==null)
1725
			$this->copyFrom($data);
1726
		$this->setReadOnly($readOnly);
1727
		$this->setPrecision($precision);
1728
		$this->setDefaultPriority($defaultPriority);
1729
	}
1730
	public function getReadOnly()
1731
	{
1732
		return $this->_r;
1733
	}
1734
	protected function setReadOnly($value)
1735
	{
1736
		$this->_r=TPropertyValue::ensureBoolean($value);
1737
	}
1738
	public function getDefaultPriority()
1739
	{
1740
		return $this->_dp;
1741
	}
1742
	protected function setDefaultPriority($value)
1743
	{
1744
		$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...
1745
	}
1746
	public function getPrecision()
1747
	{
1748
		return $this->_p;
1749
	}
1750
	protected function setPrecision($value)
1751
	{
1752
		$this->_p=TPropertyValue::ensureInteger($value);
1753
	}
1754
	public function getIterator()
1755
	{
1756
		return new ArrayIterator($this->flattenPriorities());
1757
	}
1758
	protected function sortPriorities() {
1759
		if(!$this->_o) {
1760
			ksort($this->_d, SORT_NUMERIC);
1761
			$this->_o=true;
1762
		}
1763
	}
1764
	protected function flattenPriorities() {
1765
		if(is_array($this->_fd))
1766
			return $this->_fd;
1767
		$this->sortPriorities();
1768
		$this->_fd = array();
1769
		foreach($this->_d as $priority => $itemsatpriority)
1770
			$this->_fd = array_merge($this->_fd, $itemsatpriority);
1771
		return $this->_fd;
1772
	}
1773
	public function count()
1774
	{
1775
		return $this->getCount();
1776
	}
1777
	public function getCount()
1778
	{
1779
		return $this->_c;
1780
	}
1781
	public function getPriorityCount($priority=null)
1782
	{
1783
		if($priority===null)
1784
			$priority=$this->getDefaultPriority();
1785
		$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1786
		if(!isset($this->_d[$priority])||!is_array($this->_d[$priority]))
1787
			return false;
1788
		return count($this->_d[$priority]);
1789
	}
1790
	public function getPriorities()
1791
	{
1792
		$this->sortPriorities();
1793
		return array_keys($this->_d);
1794
	}
1795
	public function getKeys()
1796
	{
1797
		return array_keys($this->flattenPriorities());
1798
	}
1799
	public function itemAt($key,$priority=false)
1800
	{
1801
		if($priority===false){
1802
			$map=$this->flattenPriorities();
1803
			return isset($map[$key])?$map[$key]:null;
1804
		} else {
1805
			if($priority===null)
1806
				$priority=$this->getDefaultPriority();
1807
			$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1808
			return (isset($this->_d[$priority])&&isset($this->_d[$priority][$key]))?$this->_d[$priority][$key]:null;
1809
		}
1810
	}
1811
	public function setPriorityAt($key,$priority=null)
1812
	{
1813
		if($priority===null)
1814
			$priority=$this->getDefaultPriority();
1815
		$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1816
		$oldpriority=$this->priorityAt($key);
1817
		if($oldpriority!==false&&$oldpriority!=$priority) {
1818
			$value=$this->remove($key,$oldpriority);
1819
			$this->add($key,$value,$priority);
1820
		}
1821
		return $oldpriority;
1822
	}
1823
	public function itemsAtPriority($priority=null)
1824
	{
1825
		if($priority===null)
1826
			$priority=$this->getDefaultPriority();
1827
		$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1828
		return isset($this->_d[$priority])?$this->_d[$priority]:null;
1829
	}
1830
	public function priorityOf($item)
1831
	{
1832
		$this->sortPriorities();
1833
		foreach($this->_d as $priority=>$items)
1834
			if(($index=array_search($item,$items,true))!==false)
1835
				return $priority;
1836
		return false;
1837
	}
1838
	public function priorityAt($key)
1839
	{
1840
		$this->sortPriorities();
1841
		foreach($this->_d as $priority=>$items)
1842
			if(array_key_exists($key,$items))
1843
				return $priority;
1844
		return false;
1845
	}
1846
	public function add($key,$value,$priority=null)
1847
	{
1848
		if($priority===null)
1849
			$priority=$this->getDefaultPriority();
1850
		$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1851
		if(!$this->_r)
1852
		{
1853
			foreach($this->_d as $innerpriority=>$items)
1854
				if(array_key_exists($key,$items))
1855
				{
1856
					unset($this->_d[$innerpriority][$key]);
1857
					$this->_c--;
1858
					if(count($this->_d[$innerpriority])===0)
1859
						unset($this->_d[$innerpriority]);
1860
				}
1861
			if(!isset($this->_d[$priority])) {
1862
				$this->_d[$priority]=array($key=>$value);
1863
				$this->_o=false;
1864
			}
1865
			else
1866
				$this->_d[$priority][$key]=$value;
1867
			$this->_c++;
1868
			$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...
1869
		}
1870
		else
1871
			throw new TInvalidOperationException('map_readonly',get_class($this));
1872
		return $priority;
1873
	}
1874
	public function remove($key,$priority=false)
1875
	{
1876
		if(!$this->_r)
1877
		{
1878
			if($priority===null)
1879
				$priority=$this->getDefaultPriority();
1880
			if($priority===false)
1881
			{
1882
				$this->sortPriorities();
1883
				foreach($this->_d as $priority=>$items)
1884
					if(array_key_exists($key,$items))
1885
					{
1886
						$value=$this->_d[$priority][$key];
1887
						unset($this->_d[$priority][$key]);
1888
						$this->_c--;
1889
						if(count($this->_d[$priority])===0)
1890
						{
1891
							unset($this->_d[$priority]);
1892
							$this->_o=false;
1893
						}
1894
						$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...
1895
						return $value;
1896
					}
1897
				return null;
1898
			}
1899
			else
1900
			{
1901
				$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1902
				if(isset($this->_d[$priority])&&(isset($this->_d[$priority][$key])||array_key_exists($key,$this->_d[$priority])))
1903
				{
1904
					$value=$this->_d[$priority][$key];
1905
					unset($this->_d[$priority][$key]);
1906
					$this->_c--;
1907
					if(count($this->_d[$priority])===0) {
1908
						unset($this->_d[$priority]);
1909
						$this->_o=false;
1910
					}
1911
					$this->_fd=null;
1912
					return $value;
1913
				}
1914
				else
1915
					return null;
1916
			}
1917
		}
1918
		else
1919
			throw new TInvalidOperationException('map_readonly',get_class($this));
1920
	}
1921
	public function clear()
1922
	{
1923
		foreach($this->_d as $priority=>$items)
1924
			foreach(array_keys($items) as $key)
1925
				$this->remove($key);
1926
	}
1927
	public function contains($key)
1928
	{
1929
		$map=$this->flattenPriorities();
1930
		return isset($map[$key])||array_key_exists($key,$map);
1931
	}
1932
	public function toArray()
1933
	{
1934
		return $this->flattenPriorities();
1935
	}
1936
	public function toArrayBelowPriority($priority,$inclusive=false)
1937
	{
1938
		$this->sortPriorities();
1939
		$items=array();
1940
		foreach($this->_d as $itemspriority=>$itemsatpriority)
1941
		{
1942
			if((!$inclusive&&$itemspriority>=$priority)||$itemspriority>$priority)
1943
				break;
1944
			$items=array_merge($items,$itemsatpriority);
1945
		}
1946
		return $items;
1947
	}
1948
	public function toArrayAbovePriority($priority,$inclusive=true)
1949
	{
1950
		$this->sortPriorities();
1951
		$items=array();
1952
		foreach($this->_d as $itemspriority=>$itemsatpriority)
1953
		{
1954
			if((!$inclusive&&$itemspriority<=$priority)||$itemspriority<$priority)
1955
				continue;
1956
			$items=array_merge($items,$itemsatpriority);
1957
		}
1958
		return $items;
1959
	}
1960
	public function copyFrom($data)
1961
	{
1962
		if($data instanceof TPriorityMap)
1963
		{
1964
			if($this->getCount()>0)
1965
				$this->clear();
1966
			foreach($data->getPriorities() as $priority) {
1967
				foreach($data->itemsAtPriority($priority) as $key => $value) {
1968
					$this->add($key,$value,$priority);
1969
				}
1970
			}
1971
		}
1972
		else if(is_array($data)||$data instanceof Traversable)
1973
		{
1974
			if($this->getCount()>0)
1975
				$this->clear();
1976
			foreach($data as $key=>$value)
1977
				$this->add($key,$value);
1978
		}
1979
		else if($data!==null)
1980
			throw new TInvalidDataTypeException('map_data_not_iterable');
1981
	}
1982
	public function mergeWith($data)
1983
	{
1984
		if($data instanceof TPriorityMap)
1985
		{
1986
			foreach($data->getPriorities() as $priority)
1987
			{
1988
				foreach($data->itemsAtPriority($priority) as $key => $value)
1989
					$this->add($key,$value,$priority);
1990
			}
1991
		}
1992
		else if(is_array($data)||$data instanceof Traversable)
1993
		{
1994
			foreach($data as $key=>$value)
1995
				$this->add($key,$value);
1996
		}
1997
		else if($data!==null)
1998
			throw new TInvalidDataTypeException('map_data_not_iterable');
1999
	}
2000
	public function offsetExists($offset)
2001
	{
2002
		return $this->contains($offset);
2003
	}
2004
	public function offsetGet($offset)
2005
	{
2006
		return $this->itemAt($offset);
2007
	}
2008
	public function offsetSet($offset,$item)
2009
	{
2010
		$this->add($offset,$item);
2011
	}
2012
	public function offsetUnset($offset)
2013
	{
2014
		$this->remove($offset);
2015
	}
2016
}
2017
class TStack extends TComponent implements IteratorAggregate,Countable
0 ignored issues
show
Coding Style introduced by
Expected 1 space before "Countable"; 0 found
Loading history...
2018
{
2019
	private $_d=array();
2020
	private $_c=0;
2021
	public function __construct($data=null)
2022
	{
2023
		if($data!==null)
2024
			$this->copyFrom($data);
2025
	}
2026
	public function toArray()
2027
	{
2028
		return $this->_d;
2029
	}
2030
	public function copyFrom($data)
2031
	{
2032
		if(is_array($data) || ($data instanceof Traversable))
2033
		{
2034
			$this->clear();
2035
			foreach($data as $item)
2036
			{
2037
				$this->_d[]=$item;
2038
				++$this->_c;
2039
			}
2040
		}
2041
		else if($data!==null)
2042
			throw new TInvalidDataTypeException('stack_data_not_iterable');
2043
	}
2044
	public function clear()
2045
	{
2046
		$this->_c=0;
2047
		$this->_d=array();
2048
	}
2049
	public function contains($item)
2050
	{
2051
		return array_search($item,$this->_d,true)!==false;
2052
	}
2053
	public function peek()
2054
	{
2055
		if($this->_c===0)
2056
			throw new TInvalidOperationException('stack_empty');
2057
		else
2058
			return $this->_d[$this->_c-1];
2059
	}
2060
	public function pop()
2061
	{
2062
		if($this->_c===0)
2063
			throw new TInvalidOperationException('stack_empty');
2064
		else
2065
		{
2066
			--$this->_c;
2067
			return array_pop($this->_d);
2068
		}
2069
	}
2070
	public function push($item)
2071
	{
2072
		++$this->_c;
2073
		$this->_d[] = $item;
2074
	}
2075
	public function getIterator()
2076
	{
2077
		return new ArrayIterator( $this->_d );
2078
	}
2079
	public function getCount()
2080
	{
2081
		return $this->_c;
2082
	}
2083
	public function count()
2084
	{
2085
		return $this->getCount();
2086
	}
2087
}
2088
class TStackIterator implements Iterator
2089
{
2090
	private $_d;
2091
	private $_i;
2092
	private $_c;
2093
	public function __construct(&$data)
2094
	{
2095
		$this->_d=&$data;
2096
		$this->_i=0;
2097
		$this->_c=count($this->_d);
2098
	}
2099
	public function rewind()
2100
	{
2101
		$this->_i=0;
2102
	}
2103
	public function key()
2104
	{
2105
		return $this->_i;
2106
	}
2107
	public function current()
2108
	{
2109
		return $this->_d[$this->_i];
2110
	}
2111
	public function next()
2112
	{
2113
		$this->_i++;
2114
	}
2115
	public function valid()
2116
	{
2117
		return $this->_i<$this->_c;
2118
	}
2119
}
2120
class TXmlElement extends TComponent
2121
{
2122
	private $_parent=null;
2123
	private $_tagName='unknown';
2124
	private $_value='';
2125
	private $_elements=null;
2126
	private $_attributes=null;
2127
	public function __construct($tagName)
2128
	{
2129
		$this->setTagName($tagName);
2130
	}
2131
	public function getParent()
2132
	{
2133
		return $this->_parent;
2134
	}
2135
	public function setParent($parent)
2136
	{
2137
		$this->_parent=$parent;
2138
	}
2139
	public function getTagName()
2140
	{
2141
		return $this->_tagName;
2142
	}
2143
	public function setTagName($tagName)
2144
	{
2145
		$this->_tagName=$tagName;
2146
	}
2147
	public function getValue()
2148
	{
2149
		return $this->_value;
2150
	}
2151
	public function setValue($value)
2152
	{
2153
		$this->_value=TPropertyValue::ensureString($value);
2154
	}
2155
	public function getHasElement()
2156
	{
2157
		return $this->_elements!==null && $this->_elements->getCount()>0;
2158
	}
2159
	public function getHasAttribute()
2160
	{
2161
		return $this->_attributes!==null && $this->_attributes->getCount()>0;
2162
	}
2163
	public function getAttribute($name)
2164
	{
2165
		if($this->_attributes!==null)
2166
			return $this->_attributes->itemAt($name);
2167
		else
2168
			return null;
2169
	}
2170
	public function setAttribute($name,$value)
2171
	{
2172
		$this->getAttributes()->add($name,TPropertyValue::ensureString($value));
2173
	}
2174
	public function getElements()
2175
	{
2176
		if(!$this->_elements)
2177
			$this->_elements=new TXmlElementList($this);
2178
		return $this->_elements;
2179
	}
2180
	public function getAttributes()
2181
	{
2182
		if(!$this->_attributes)
2183
			$this->_attributes=new TMap;
2184
		return $this->_attributes;
2185
	}
2186
	public function getElementByTagName($tagName)
2187
	{
2188
		if($this->_elements)
2189
		{
2190
			foreach($this->_elements as $element)
2191
				if($element->_tagName===$tagName)
2192
					return $element;
2193
		}
2194
		return null;
2195
	}
2196
	public function getElementsByTagName($tagName)
2197
	{
2198
		$list=new TList;
2199
		if($this->_elements)
2200
		{
2201
			foreach($this->_elements as $element)
2202
				if($element->_tagName===$tagName)
2203
					$list->add($element);
2204
		}
2205
		return $list;
2206
	}
2207
	public function toString($indent=0)
2208
	{
2209
		$attr='';
2210
		if($this->_attributes!==null)
2211
		{
2212
			foreach($this->_attributes as $name=>$value)
2213
			{
2214
				$value=$this->xmlEncode($value);
2215
				$attr.=" $name=\"$value\"";
2216
			}
2217
		}
2218
		$prefix=str_repeat(' ',$indent*4);
2219
		if($this->getHasElement())
2220
		{
2221
			$str=$prefix."<{$this->_tagName}$attr>\n";
2222
			foreach($this->getElements() as $element)
2223
				$str.=$element->toString($indent+1)."\n";
2224
			$str.=$prefix."</{$this->_tagName}>";
2225
			return $str;
2226
		}
2227
		else if(($value=$this->getValue())!=='')
2228
		{
2229
			$value=$this->xmlEncode($value);
2230
			return $prefix."<{$this->_tagName}$attr>$value</{$this->_tagName}>";
2231
		}
2232
		else
2233
			return $prefix."<{$this->_tagName}$attr />";
2234
	}
2235
	public function __toString()
2236
	{
2237
		return $this->toString();
2238
	}
2239
	private function xmlEncode($str)
2240
	{
2241
		return strtr($str,array(
2242
			'>'=>'&gt;',
2243
			'<'=>'&lt;',
2244
			'&'=>'&amp;',
2245
			'"'=>'&quot;',
2246
			"\r"=>'&#xD;',
2247
			"\t"=>'&#x9;',
2248
			"\n"=>'&#xA;'));
2249
	}
2250
}
2251
class TXmlDocument extends TXmlElement
2252
{
2253
	private $_version;
2254
	private $_encoding;
2255
	public function __construct($version='1.0',$encoding='')
2256
	{
2257
		parent::__construct('');
2258
		$this->setVersion($version);
2259
		$this->setEncoding($encoding);
2260
	}
2261
	public function getVersion()
2262
	{
2263
		return $this->_version;
2264
	}
2265
	public function setVersion($version)
2266
	{
2267
		$this->_version=$version;
2268
	}
2269
	public function getEncoding()
2270
	{
2271
		return $this->_encoding;
2272
	}
2273
	public function setEncoding($encoding)
2274
	{
2275
		$this->_encoding=$encoding;
2276
	}
2277
	public function loadFromFile($file)
2278
	{
2279
		if(($str=@file_get_contents($file))!==false)
2280
			return $this->loadFromString($str);
2281
		else
2282
			throw new TIOException('xmldocument_file_read_failed',$file);
2283
	}
2284
	public function loadFromString($string)
2285
	{
2286
				$doc=new DOMDocument();
2287
		if($doc->loadXML($string)===false)
2288
			return false;
2289
		$this->setEncoding($doc->encoding);
2290
		$this->setVersion($doc->xmlVersion);
2291
		$element=$doc->documentElement;
2292
		$this->setTagName($element->tagName);
2293
		$this->setValue($element->nodeValue);
2294
		$elements=$this->getElements();
2295
		$attributes=$this->getAttributes();
2296
		$elements->clear();
2297
		$attributes->clear();
2298
		static $bSimpleXml;
2299
		if($bSimpleXml === null)
2300
			$bSimpleXml = (boolean)function_exists('simplexml_load_string');
2301
		if($bSimpleXml)
2302
		{
2303
			$simpleDoc = simplexml_load_string($string);
2304
			$docNamespaces = $simpleDoc->getDocNamespaces(false);
2305
			$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...
2306
			foreach($docNamespaces as $prefix => $uri)
2307
			{
2308
 				if($prefix === '')
2309
   					$attributes->add('xmlns', $uri);
2310
   				else
2311
   					$attributes->add('xmlns:'.$prefix, $uri);
2312
			}
2313
		}
2314
		foreach($element->attributes as $name=>$attr)
2315
			$attributes->add(($attr->prefix === '' ? '' : $attr->prefix . ':') .$name,$attr->value);
2316
		foreach($element->childNodes as $child)
2317
		{
2318
			if($child instanceof DOMElement)
2319
				$elements->add($this->buildElement($child));
2320
		}
2321
		return true;
2322
	}
2323
	public function saveToFile($file)
2324
	{
2325
		if(($fw=fopen($file,'w'))!==false)
2326
		{
2327
			fwrite($fw,$this->saveToString());
2328
			fclose($fw);
2329
		}
2330
		else
2331
			throw new TIOException('xmldocument_file_write_failed',$file);
2332
	}
2333
	public function saveToString()
2334
	{
2335
		$version=empty($this->_version)?' version="1.0"':' version="'.$this->_version.'"';
2336
		$encoding=empty($this->_encoding)?'':' encoding="'.$this->_encoding.'"';
2337
		return "<?xml{$version}{$encoding}?>\n".$this->toString(0);
2338
	}
2339
	public function __toString()
2340
	{
2341
		return $this->saveToString();
2342
	}
2343
	protected function buildElement($node)
2344
	{
2345
		$element=new TXmlElement($node->tagName);
2346
		$element->setValue($node->nodeValue);
2347
		foreach($node->attributes as $name=>$attr)
2348
			$element->getAttributes()->add(($attr->prefix === '' ? '' : $attr->prefix . ':') . $name,$attr->value);
2349
		foreach($node->childNodes as $child)
2350
		{
2351
			if($child instanceof DOMElement)
2352
				$element->getElements()->add($this->buildElement($child));
2353
		}
2354
		return $element;
2355
	}
2356
}
2357
class TXmlElementList extends TList
2358
{
2359
	private $_o;
2360
	public function __construct(TXmlElement $owner)
2361
	{
2362
		$this->_o=$owner;
2363
	}
2364
	protected function getOwner()
2365
	{
2366
		return $this->_o;
2367
	}
2368
	public function insertAt($index,$item)
2369
	{
2370
		if($item instanceof TXmlElement)
2371
		{
2372
			parent::insertAt($index,$item);
2373
			if($item->getParent()!==null)
2374
				$item->getParent()->getElements()->remove($item);
2375
			$item->setParent($this->_o);
2376
		}
2377
		else
2378
			throw new TInvalidDataTypeException('xmlelementlist_xmlelement_required');
2379
	}
2380
	public function removeAt($index)
2381
	{
2382
		$item=parent::removeAt($index);
2383
		if($item instanceof TXmlElement)
2384
			$item->setParent(null);
2385
		return $item;
2386
	}
2387
}
2388
class TAuthorizationRule extends TComponent
2389
{
2390
	private $_action;
2391
	private $_users;
2392
	private $_roles;
2393
	private $_verb;
2394
	private $_ipRules;
2395
	private $_everyone;
2396
	private $_guest;
2397
	private $_authenticated;
2398
	public function __construct($action,$users,$roles,$verb='',$ipRules='')
2399
	{
2400
		$action=strtolower(trim($action));
2401
		if($action==='allow' || $action==='deny')
2402
			$this->_action=$action;
2403
		else
2404
			throw new TInvalidDataValueException('authorizationrule_action_invalid',$action);
2405
		$this->_users=array();
2406
		$this->_roles=array();
2407
		$this->_ipRules=array();
2408
		$this->_everyone=false;
2409
		$this->_guest=false;
2410
		$this->_authenticated=false;
2411
		if(trim($users)==='')
2412
			$users='*';
2413
		foreach(explode(',',$users) as $user)
2414
		{
2415
			if(($user=trim(strtolower($user)))!=='')
2416
			{
2417
				if($user==='*')
2418
				{
2419
					$this->_everyone=true;
2420
					break;
2421
				}
2422
				else if($user==='?')
2423
					$this->_guest=true;
2424
				else if($user==='@')
2425
					$this->_authenticated=true;
2426
				else
2427
					$this->_users[]=$user;
2428
			}
2429
		}
2430
		if(trim($roles)==='')
2431
			$roles='*';
2432
		foreach(explode(',',$roles) as $role)
2433
		{
2434
			if(($role=trim(strtolower($role)))!=='')
2435
				$this->_roles[]=$role;
2436
		}
2437
		if(($verb=trim(strtolower($verb)))==='')
2438
			$verb='*';
2439
		if($verb==='*' || $verb==='get' || $verb==='post')
2440
			$this->_verb=$verb;
2441
		else
2442
			throw new TInvalidDataValueException('authorizationrule_verb_invalid',$verb);
2443
		if(trim($ipRules)==='')
2444
			$ipRules='*';
2445
		foreach(explode(',',$ipRules) as $ipRule)
2446
		{
2447
			if(($ipRule=trim($ipRule))!=='')
2448
				$this->_ipRules[]=$ipRule;
2449
		}
2450
	}
2451
	public function getAction()
2452
	{
2453
		return $this->_action;
2454
	}
2455
	public function getUsers()
2456
	{
2457
		return $this->_users;
2458
	}
2459
	public function getRoles()
2460
	{
2461
		return $this->_roles;
2462
	}
2463
	public function getVerb()
2464
	{
2465
		return $this->_verb;
2466
	}
2467
	public function getIPRules()
2468
	{
2469
		return $this->_ipRules;
2470
	}
2471
	public function getGuestApplied()
2472
	{
2473
		return $this->_guest || $this->_everyone;
2474
	}
2475
	public function getEveryoneApplied()
2476
	{
2477
		return $this->_everyone;
2478
	}
2479
	public function getAuthenticatedApplied()
2480
	{
2481
		return $this->_authenticated || $this->_everyone;
2482
	}
2483
	public function isUserAllowed(IUser $user,$verb,$ip)
2484
	{
2485
		if($this->isVerbMatched($verb) && $this->isIpMatched($ip) && $this->isUserMatched($user) && $this->isRoleMatched($user))
2486
			return ($this->_action==='allow')?1:-1;
2487
		else
2488
			return 0;
2489
	}
2490
	private function isIpMatched($ip)
2491
	{
2492
		if(empty($this->_ipRules))
2493
			return 1;
2494
		foreach($this->_ipRules as $rule)
2495
		{
2496
			if($rule==='*' || $rule===$ip || (($pos=strpos($rule,'*'))!==false && strncmp($ip,$rule,$pos)===0))
2497
				return 1;
2498
		}
2499
		return 0;
2500
	}
2501
	private function isUserMatched($user)
2502
	{
2503
		return ($this->_everyone || ($this->_guest && $user->getIsGuest()) || ($this->_authenticated && !$user->getIsGuest()) || in_array(strtolower($user->getName()),$this->_users));
2504
	}
2505
	private function isRoleMatched($user)
2506
	{
2507
		foreach($this->_roles as $role)
2508
		{
2509
			if($role==='*' || $user->isInRole($role))
2510
				return true;
2511
		}
2512
		return false;
2513
	}
2514
	private function isVerbMatched($verb)
2515
	{
2516
		return ($this->_verb==='*' || strcasecmp($verb,$this->_verb)===0);
2517
	}
2518
}
2519
class TAuthorizationRuleCollection extends TList
2520
{
2521
	public function isUserAllowed($user,$verb,$ip)
2522
	{
2523
		if($user instanceof IUser)
2524
		{
2525
			$verb=strtolower(trim($verb));
2526
			foreach($this as $rule)
2527
			{
2528
				if(($decision=$rule->isUserAllowed($user,$verb,$ip))!==0)
2529
					return ($decision>0);
2530
			}
2531
			return true;
2532
		}
2533
		else
2534
			return false;
2535
	}
2536
	public function insertAt($index,$item)
2537
	{
2538
		if($item instanceof TAuthorizationRule)
2539
			parent::insertAt($index,$item);
2540
		else
2541
			throw new TInvalidDataTypeException('authorizationrulecollection_authorizationrule_required');
2542
	}
2543
}
2544
class TSecurityManager extends TModule
2545
{
2546
	const STATE_VALIDATION_KEY = 'prado:securitymanager:validationkey';
2547
	const STATE_ENCRYPTION_KEY = 'prado:securitymanager:encryptionkey';
2548
	private $_validationKey = null;
2549
	private $_encryptionKey = null;
2550
	private $_hashAlgorithm = 'sha1';
2551
	private $_cryptAlgorithm = 'rijndael-256';
2552
	private $_mbstring;
2553
	public function init($config)
2554
	{
2555
		$this->_mbstring=extension_loaded('mbstring');
2556
		$this->getApplication()->setSecurityManager($this);
2557
	}
2558
	protected function generateRandomKey()
2559
	{
2560
		return sprintf('%08x%08x%08x%08x',mt_rand(),mt_rand(),mt_rand(),mt_rand());
2561
	}
2562
	public function getValidationKey()
2563
	{
2564
		if(null === $this->_validationKey) {
2565
			if(null === ($this->_validationKey = $this->getApplication()->getGlobalState(self::STATE_VALIDATION_KEY))) {
2566
				$this->_validationKey = $this->generateRandomKey();
2567
				$this->getApplication()->setGlobalState(self::STATE_VALIDATION_KEY, $this->_validationKey, null, true);
2568
			}
2569
		}
2570
		return $this->_validationKey;
2571
	}
2572
	public function setValidationKey($value)
2573
	{
2574
		if('' === $value)
2575
			throw new TInvalidDataValueException('securitymanager_validationkey_invalid');
2576
		$this->_validationKey = $value;
2577
	}
2578
	public function getEncryptionKey()
2579
	{
2580
		if(null === $this->_encryptionKey) {
2581
			if(null === ($this->_encryptionKey = $this->getApplication()->getGlobalState(self::STATE_ENCRYPTION_KEY))) {
2582
				$this->_encryptionKey = $this->generateRandomKey();
2583
				$this->getApplication()->setGlobalState(self::STATE_ENCRYPTION_KEY, $this->_encryptionKey, null, true);
2584
			}
2585
		}
2586
		return $this->_encryptionKey;
2587
	}
2588
	public function setEncryptionKey($value)
2589
	{
2590
		if('' === $value)
2591
			throw new TInvalidDataValueException('securitymanager_encryptionkey_invalid');
2592
		$this->_encryptionKey = $value;
2593
	}
2594
	public function getValidation()
2595
	{
2596
		return $this->_hashAlgorithm;
2597
	}
2598
	public function getHashAlgorithm()
2599
	{
2600
		return $this->_hashAlgorithm;
2601
	}
2602
	public function setValidation($value)
2603
	{
2604
		$this->_hashAlgorithm = TPropertyValue::ensureEnum($value, 'TSecurityManagerValidationMode');
2605
	}
2606
	public function setHashAlgorithm($value)
2607
	{
2608
		$this->_hashAlgorithm = TPropertyValue::ensureString($value);
2609
	}
2610
	public function getEncryption()
2611
	{
2612
		if(is_string($this->_cryptAlgorithm))
2613
			return $this->_cryptAlgorithm;
2614
				return "3DES";
2615
	}
2616
	public function setEncryption($value)
2617
	{
2618
		$this->_cryptAlgorithm = $value;
2619
	}
2620
	public function getCryptAlgorithm()
2621
	{
2622
		return $this->_cryptAlgorithm;
2623
	}
2624
	public function setCryptAlgorithm($value)
2625
	{
2626
		$this->_cryptAlgorithm = $value;
2627
	}
2628
	public function encrypt($data)
2629
	{
2630
		$module=$this->openCryptModule();
2631
		$key = $this->substr(md5($this->getEncryptionKey()), 0, mcrypt_enc_get_key_size($module));
2632
		srand();
2633
		$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($module), MCRYPT_RAND);
2634
		mcrypt_generic_init($module, $key, $iv);
2635
		$encrypted = $iv.mcrypt_generic($module, $data);
2636
		mcrypt_generic_deinit($module);
2637
		mcrypt_module_close($module);
2638
		return $encrypted;
2639
	}
2640
	public function decrypt($data)
2641
	{
2642
		$module=$this->openCryptModule();
2643
		$key = $this->substr(md5($this->getEncryptionKey()), 0, mcrypt_enc_get_key_size($module));
2644
		$ivSize = mcrypt_enc_get_iv_size($module);
2645
		$iv = $this->substr($data, 0, $ivSize);
2646
		mcrypt_generic_init($module, $key, $iv);
2647
		$decrypted = mdecrypt_generic($module, $this->substr($data, $ivSize, $this->strlen($data)));
2648
		mcrypt_generic_deinit($module);
2649
		mcrypt_module_close($module);
2650
		return $decrypted;
2651
	}
2652
	protected function openCryptModule()
2653
	{
2654
		if(extension_loaded('mcrypt'))
2655
		{
2656
			if(is_array($this->_cryptAlgorithm))
2657
				$module=@call_user_func_array('mcrypt_module_open',$this->_cryptAlgorithm);
2658
			else
2659
				$module=@mcrypt_module_open($this->_cryptAlgorithm,'', MCRYPT_MODE_CBC,'');
2660
			if($module===false)
2661
				throw new TNotSupportedException('securitymanager_mcryptextension_initfailed');
2662
			return $module;
2663
		}
2664
		else
2665
			throw new TNotSupportedException('securitymanager_mcryptextension_required');
2666
	}
2667
	public function hashData($data)
2668
	{
2669
		$hmac = $this->computeHMAC($data);
2670
		return $hmac.$data;
2671
	}
2672
	public function validateData($data)
2673
	{
2674
		$len=$this->strlen($this->computeHMAC('test'));
2675
		if($this->strlen($data) < $len)
2676
			return false;
2677
		$hmac = $this->substr($data, 0, $len);
2678
		$data2=$this->substr($data, $len, $this->strlen($data));
2679
		return $hmac === $this->computeHMAC($data2) ? $data2 : false;
2680
	}
2681
	protected function computeHMAC($data)
2682
	{
2683
		$key = $this->getValidationKey();
2684
		if(function_exists('hash_hmac'))
2685
			return hash_hmac($this->_hashAlgorithm, $data, $key);
2686
		if(!strcasecmp($this->_hashAlgorithm,'sha1'))
2687
		{
2688
			$pack = 'H40';
2689
			$func = 'sha1';
2690
		} else {
2691
			$pack = 'H32';
2692
			$func = 'md5';
2693
		}
2694
		$key = str_pad($func($key), 64, chr(0));
2695
		return $func((str_repeat(chr(0x5C), 64) ^ substr($key, 0, 64)) . pack($pack, $func((str_repeat(chr(0x36), 64) ^ substr($key, 0, 64)) . $data)));
2696
	}
2697
	private function strlen($string)
2698
	{
2699
		return $this->_mbstring ? mb_strlen($string,'8bit') : strlen($string);
2700
	}
2701
	private function substr($string,$start,$length)
2702
	{
2703
		return $this->_mbstring ? mb_substr($string,$start,$length,'8bit') : substr($string,$start,$length);
2704
	}
2705
}
2706
class TSecurityManagerValidationMode extends TEnumerable
2707
{
2708
	const MD5 = 'MD5';
2709
	const SHA1 = 'SHA1';
2710
}
2711
class THttpUtility
2712
{
2713
	private static $_encodeTable=array('<'=>'&lt;','>'=>'&gt;','"'=>'&quot;');
2714
	private static $_decodeTable=array('&lt;'=>'<','&gt;'=>'>','&quot;'=>'"');
2715
	private static $_stripTable=array('&lt;'=>'','&gt;'=>'','&quot;'=>'');
2716
	public static function htmlEncode($s)
2717
	{
2718
		return strtr($s,self::$_encodeTable);
2719
	}
2720
	public static function htmlDecode($s)
2721
	{
2722
		return strtr($s,self::$_decodeTable);
2723
	}
2724
	public static function htmlStrip($s)
2725
	{
2726
		return strtr($s,self::$_stripTable);
2727
	}
2728
}
2729
class TJavaScript
2730
{
2731
	public static function renderScriptFiles($files)
2732
	{
2733
		$str='';
2734
		foreach($files as $file)
2735
			$str.= self::renderScriptFile($file);
2736
		return $str;
2737
	}
2738
	public static function renderScriptFile($file)
2739
	{
2740
		return '<script type="text/javascript" src="'.THttpUtility::htmlEncode($file)."\"></script>\n";
2741
	}
2742
	public static function renderScriptBlocks($scripts)
2743
	{
2744
		if(count($scripts))
2745
			return "<script type=\"text/javascript\">\n/*<![CDATA[*/\n".implode("\n",$scripts)."\n/*]]>*/\n</script>\n";
2746
		else
2747
			return '';
2748
	}
2749
	public static function renderScriptBlocksCallback($scripts)
2750
	{
2751
		if(count($scripts))
2752
			return implode("\n",$scripts)."\n";
2753
		else
2754
			return '';
2755
	}
2756
	public static function renderScriptBlock($script)
2757
	{
2758
		return "<script type=\"text/javascript\">\n/*<![CDATA[*/\n{$script}\n/*]]>*/\n</script>\n";
2759
	}
2760
	public static function quoteString($js)
2761
	{
2762
		return self::jsonEncode($js,JSON_HEX_QUOT | JSON_HEX_APOS | JSON_HEX_TAG);
2763
	}
2764
	public static function quoteJsLiteral($js)
2765
	{
2766
		if($js instanceof TJavaScriptLiteral)
2767
			return $js;
2768
		else
2769
			return new TJavaScriptLiteral($js);
2770
	}
2771
	public static function quoteFunction($js)
2772
	{
2773
		return self::quoteJsLiteral($js);
2774
	}
2775
	public static function isJsLiteral($js)
2776
	{
2777
		return ($js instanceof TJavaScriptLiteral);
2778
	}
2779
	public static function isFunction($js)
2780
	{
2781
		return self::isJsLiteral($js);
2782
	}
2783
	public static function encode($value,$toMap=true,$encodeEmptyStrings=false)
2784
	{
2785
		if(is_string($value))
2786
			return self::quoteString($value);
2787
		else if(is_bool($value))
2788
			return $value?'true':'false';
2789
		else if(is_array($value))
2790
		{
2791
			$results='';
2792
			if(($n=count($value))>0 && array_keys($value)!==range(0,$n-1))
2793
			{
2794
				foreach($value as $k=>$v)
2795
				{
2796
					if($v!=='' || $encodeEmptyStrings)
2797
					{
2798
						if($results!=='')
2799
							$results.=',';
2800
						$results.="'$k':".self::encode($v,$toMap,$encodeEmptyStrings);
2801
					}
2802
				}
2803
				return '{'.$results.'}';
2804
			}
2805
			else
2806
			{
2807
				foreach($value as $v)
2808
				{
2809
					if($v!=='' || $encodeEmptyStrings)
2810
					{
2811
						if($results!=='')
2812
							$results.=',';
2813
						$results.=self::encode($v,$toMap, $encodeEmptyStrings);
2814
					}
2815
				}
2816
				return '['.$results.']';
2817
			}
2818
		}
2819
		else if(is_integer($value))
2820
			return "$value";
2821
		else if(is_float($value))
2822
		{
2823
			switch($value)
2824
			{
2825
				case -INF:
2826
					return 'Number.NEGATIVE_INFINITY';
2827
					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...
2828
				case INF:
2829
					return 'Number.POSITIVE_INFINITY';
2830
					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...
2831
				default:
2832
					$locale=localeConv();
2833
					if($locale['decimal_point']=='.')
2834
						return "$value";
2835
					else
2836
						return str_replace($locale['decimal_point'], '.', "$value");
2837
					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...
2838
			}
2839
		}
2840
		else if(is_object($value))
2841
			if ($value instanceof TJavaScriptLiteral)
2842
				return $value->toJavaScriptLiteral();
2843
			else
2844
				return self::encode(get_object_vars($value),$toMap);
2845
		else if($value===null)
2846
			return 'null';
2847
		else
2848
			return '';
2849
	}
2850
	public static function jsonEncode($value, $options = 0)
2851
	{
2852
		if (($g=Prado::getApplication()->getGlobalization(false))!==null &&
2853
			strtoupper($enc=$g->getCharset())!='UTF-8') {
2854
			self::convertToUtf8($value, $enc);
2855
		}
2856
		$s = @json_encode($value,$options);
2857
		self::checkJsonError();
2858
		return $s;
2859
	}
2860
	private static function convertToUtf8(&$value, $sourceEncoding) {
2861
		if(is_string($value))
2862
			$value=iconv($sourceEncoding, 'UTF-8', $value);
2863
		else if (is_array($value))
2864
		{
2865
			foreach($value as &$element)
2866
				self::convertToUtf8($element, $sourceEncoding);
2867
		}
2868
	}
2869
	public static function jsonDecode($value, $assoc = false, $depth = 512)
2870
	{
2871
		$s= @json_decode($value, $assoc, $depth);
2872
		self::checkJsonError();
2873
		return $s;
2874
	}
2875
	private static function checkJsonError()
2876
	{
2877
		switch ($err = json_last_error())
2878
		{
2879
			case JSON_ERROR_NONE:
2880
				return;
2881
				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...
2882
			case JSON_ERROR_DEPTH:
2883
				$msg = 'Maximum stack depth exceeded';
2884
				break;
2885
			case JSON_ERROR_STATE_MISMATCH:
2886
				$msg = 'Underflow or the modes mismatch';
2887
				break;
2888
			case JSON_ERROR_CTRL_CHAR:
2889
				$msg = 'Unexpected control character found';
2890
				break;
2891
			case JSON_ERROR_SYNTAX:
2892
				$msg = 'Syntax error, malformed JSON';
2893
				break;
2894
			case JSON_ERROR_UTF8:
2895
				$msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
2896
				break;
2897
			default:
2898
				$msg = 'Unknown error';
2899
				break;
2900
		}
2901
		throw new Exception("JSON error ($err): $msg");
2902
	}
2903
	public static function JSMin($code)
2904
	{
2905
		Prado::using('System.Web.Javascripts.JSMin');
2906
		return JSMin::minify($code);
2907
	}
2908
}
2909
class TUrlManager extends TModule
2910
{
2911
	public function constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems)
2912
	{
2913
		$url=$serviceID.'='.urlencode($serviceParam);
2914
		$amp=$encodeAmpersand?'&amp;':'&';
2915
		$request=$this->getRequest();
2916
		if(is_array($getItems) || $getItems instanceof Traversable)
2917
		{
2918
			if($encodeGetItems)
2919
			{
2920
				foreach($getItems as $name=>$value)
2921
				{
2922
					if(is_array($value))
2923
					{
2924
						$name=urlencode($name.'[]');
2925
						foreach($value as $v)
2926
							$url.=$amp.$name.'='.urlencode($v);
2927
					}
2928
					else
2929
						$url.=$amp.urlencode($name).'='.urlencode($value);
2930
				}
2931
			}
2932
			else
2933
			{
2934
				foreach($getItems as $name=>$value)
2935
				{
2936
					if(is_array($value))
2937
					{
2938
						foreach($value as $v)
2939
							$url.=$amp.$name.'[]='.$v;
2940
					}
2941
					else
2942
						$url.=$amp.$name.'='.$value;
2943
				}
2944
			}
2945
		}
2946
		switch($request->getUrlFormat())
2947
		{
2948
			case THttpRequestUrlFormat::Path:
2949
				return $request->getApplicationUrl().'/'.strtr($url,array($amp=>'/','?'=>'/','='=>$request->getUrlParamSeparator()));
2950
			case THttpRequestUrlFormat::HiddenPath:
2951
				return rtrim(dirname($request->getApplicationUrl()), '/').'/'.strtr($url,array($amp=>'/','?'=>'/','='=>$request->getUrlParamSeparator()));
2952
			default:
2953
				return $request->getApplicationUrl().'?'.$url;
2954
		}
2955
	}
2956
	public function parseUrl()
2957
	{
2958
		$request=$this->getRequest();
2959
		$pathInfo=trim($request->getPathInfo(),'/');
2960
		if(($request->getUrlFormat()===THttpRequestUrlFormat::Path ||
2961
			$request->getUrlFormat()===THttpRequestUrlFormat::HiddenPath) &&
2962
			$pathInfo!=='')
2963
		{
2964
			$separator=$request->getUrlParamSeparator();
2965
			$paths=explode('/',$pathInfo);
2966
			$getVariables=array();
2967
			foreach($paths as $path)
2968
			{
2969
				if(($path=trim($path))!=='')
2970
				{
2971
					if(($pos=strpos($path,$separator))!==false)
2972
					{
2973
						$name=substr($path,0,$pos);
2974
						$value=substr($path,$pos+1);
2975
						if(($pos=strpos($name,'[]'))!==false)
2976
							$getVariables[substr($name,0,$pos)][]=$value;
2977
						else
2978
							$getVariables[$name]=$value;
2979
					}
2980
					else
2981
						$getVariables[$path]='';
2982
				}
2983
			}
2984
			return $getVariables;
2985
		}
2986
		else
2987
			return array();
2988
	}
2989
}
2990
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...
2991
{
2992
	const CGIFIX__PATH_INFO		= 1;
2993
	const CGIFIX__SCRIPT_NAME	= 2;
2994
	private $_urlManager=null;
2995
	private $_urlManagerID='';
2996
	private $_separator=',';
2997
	private $_serviceID=null;
2998
	private $_serviceParam=null;
2999
	private $_cookies=null;
3000
	private $_requestUri;
3001
	private $_pathInfo;
3002
	private $_cookieOnly=null;
3003
	private $_urlFormat=THttpRequestUrlFormat::Get;
3004
	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...
3005
	private $_requestResolved=false;
3006
	private $_enableCookieValidation=false;
3007
	private $_cgiFix=0;
3008
	private $_enableCache=false;
3009
	private $_url=null;
3010
	private $_id;
3011
	private $_items=array();
3012
	public function getID()
3013
	{
3014
		return $this->_id;
3015
	}
3016
	public function setID($value)
3017
	{
3018
		$this->_id=$value;
3019
	}
3020
	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...
3021
	{
3022
				if(php_sapi_name()==='cli')
3023
		{
3024
			$_SERVER['REMOTE_ADDR']='127.0.0.1';
3025
			$_SERVER['REQUEST_METHOD']='GET';
3026
			$_SERVER['SERVER_NAME']='localhost';
3027
			$_SERVER['SERVER_PORT']=80;
3028
			$_SERVER['HTTP_USER_AGENT']='';
3029
		}
3030
														if(isset($_SERVER['REQUEST_URI']))
3031
			$this->_requestUri=$_SERVER['REQUEST_URI'];
3032
		else  			$this->_requestUri=$_SERVER['SCRIPT_NAME'].(empty($_SERVER['QUERY_STRING'])?'':'?'.$_SERVER['QUERY_STRING']);
3033
		if($this->_cgiFix&self::CGIFIX__PATH_INFO && isset($_SERVER['ORIG_PATH_INFO']))
3034
			$this->_pathInfo=substr($_SERVER['ORIG_PATH_INFO'], strlen($_SERVER['SCRIPT_NAME']));
3035
		elseif(isset($_SERVER['PATH_INFO']))
3036
			$this->_pathInfo=$_SERVER['PATH_INFO'];
3037
		else if(strpos($_SERVER['PHP_SELF'],$_SERVER['SCRIPT_NAME'])===0 && $_SERVER['PHP_SELF']!==$_SERVER['SCRIPT_NAME'])
3038
			$this->_pathInfo=substr($_SERVER['PHP_SELF'],strlen($_SERVER['SCRIPT_NAME']));
3039
		else
3040
			$this->_pathInfo='';
3041
		if(get_magic_quotes_gpc())
3042
		{
3043
			if(isset($_GET))
3044
				$_GET=$this->stripSlashes($_GET);
3045
			if(isset($_POST))
3046
				$_POST=$this->stripSlashes($_POST);
3047
			if(isset($_REQUEST))
3048
				$_REQUEST=$this->stripSlashes($_REQUEST);
3049
			if(isset($_COOKIE))
3050
				$_COOKIE=$this->stripSlashes($_COOKIE);
3051
		}
3052
		$this->getApplication()->setRequest($this);
3053
	}
3054
	public function stripSlashes(&$data)
3055
	{
3056
		return is_array($data)?array_map(array($this,'stripSlashes'),$data):stripslashes($data);
3057
	}
3058
	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...
3059
	{
3060
		if($this->_url===null)
3061
		{
3062
			$secure=$this->getIsSecureConnection();
3063
			$url=$secure?'https://':'http://';
3064
			if(empty($_SERVER['HTTP_HOST']))
3065
			{
3066
				$url.=$_SERVER['SERVER_NAME'];
3067
				$port=$_SERVER['SERVER_PORT'];
3068
				if(($port!=80 && !$secure) || ($port!=443 && $secure))
3069
					$url.=':'.$port;
3070
			}
3071
			else
3072
				$url.=$_SERVER['HTTP_HOST'];
3073
			$url.=$this->getRequestUri();
3074
			$this->_url=new TUri($url);
3075
		}
3076
		return $this->_url;
3077
	}
3078
	public function setEnableCache($value)
3079
	{
3080
		$this->_enableCache = TPropertyValue::ensureBoolean($value);
3081
	}
3082
	public function getEnableCache()
3083
	{
3084
		return $this->_enableCache;
3085
	}
3086
	protected function getCacheKey()
3087
	{
3088
		return $this->getID();
3089
	}
3090
	protected function cacheUrlManager($manager)
3091
	{
3092
		if($this->getEnableCache())
3093
		{
3094
			$cache = $this->getApplication()->getCache();
3095
			if($cache !== null)
3096
			{
3097
				$dependencies = null;
3098
				if($this->getApplication()->getMode() !== TApplicationMode::Performance)
3099
					if ($manager instanceof TUrlMapping && $fn = $manager->getConfigFile())
3100
					{
3101
						$fn = Prado::getPathOfNamespace($fn,$this->getApplication()->getConfigurationFileExt());
3102
						$dependencies = new TFileCacheDependency($fn);
3103
					}
3104
				return $cache->set($this->getCacheKey(), $manager, 0, $dependencies);
3105
			}
3106
		}
3107
		return false;
3108
	}
3109
	protected function loadCachedUrlManager()
3110
	{
3111
		if($this->getEnableCache())
3112
		{
3113
			$cache = $this->getApplication()->getCache();
3114
			if($cache !== null)
3115
			{
3116
				$manager = $cache->get($this->getCacheKey());
3117
				if($manager instanceof TUrlManager)
3118
					return $manager;
3119
			}
3120
		}
3121
		return null;
3122
	}
3123
	public function getUrlManager()
3124
	{
3125
		return $this->_urlManagerID;
3126
	}
3127
	public function setUrlManager($value)
3128
	{
3129
		$this->_urlManagerID=$value;
3130
	}
3131
	public function getUrlManagerModule()
3132
	{
3133
		if($this->_urlManager===null)
3134
		{
3135
			if(($this->_urlManager = $this->loadCachedUrlManager())===null)
3136
			{
3137
				if(empty($this->_urlManagerID))
3138
				{
3139
					$this->_urlManager=new TUrlManager;
3140
					$this->_urlManager->init(null);
3141
				}
3142
				else
3143
				{
3144
					$this->_urlManager=$this->getApplication()->getModule($this->_urlManagerID);
3145
					if($this->_urlManager===null)
3146
						throw new TConfigurationException('httprequest_urlmanager_inexist',$this->_urlManagerID);
3147
					if(!($this->_urlManager instanceof TUrlManager))
3148
						throw new TConfigurationException('httprequest_urlmanager_invalid',$this->_urlManagerID);
3149
				}
3150
				$this->cacheUrlManager($this->_urlManager);
3151
			}
3152
		}
3153
		return $this->_urlManager;
3154
	}
3155
	public function getUrlFormat()
3156
	{
3157
		return $this->_urlFormat;
3158
	}
3159
	public function setUrlFormat($value)
3160
	{
3161
		$this->_urlFormat=TPropertyValue::ensureEnum($value,'THttpRequestUrlFormat');
3162
	}
3163
	public function getUrlParamSeparator()
3164
	{
3165
		return $this->_separator;
3166
	}
3167
	public function setUrlParamSeparator($value)
3168
	{
3169
		if(strlen($value)===1)
3170
			$this->_separator=$value;
3171
		else
3172
			throw new TInvalidDataValueException('httprequest_separator_invalid');
3173
	}
3174
	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...
3175
	{
3176
		return isset($_SERVER['REQUEST_METHOD'])?$_SERVER['REQUEST_METHOD']:null;
3177
	}
3178
	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...
3179
	{
3180
		if(!isset($_SERVER['CONTENT_TYPE']))
3181
			return null;
3182
		if($mimetypeOnly === true && ($_pos = strpos(';', $_SERVER['CONTENT_TYPE'])) !== false)
3183
			return substr($_SERVER['CONTENT_TYPE'], 0, $_pos);
3184
		return $_SERVER['CONTENT_TYPE'];
3185
	}
3186
	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...
3187
	{
3188
			return isset($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'],'off');
3189
	}
3190
	public function getPathInfo()
3191
	{
3192
		return $this->_pathInfo;
3193
	}
3194
	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...
3195
	{
3196
		return isset($_SERVER['QUERY_STRING'])?$_SERVER['QUERY_STRING']:null;
3197
	}
3198
	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...
3199
	{
3200
		return isset($_SERVER['SERVER_PROTOCOL'])?$_SERVER['SERVER_PROTOCOL']:null;
3201
	}
3202
	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...
3203
	{
3204
		static $result;
3205
		if($result === null && function_exists('apache_request_headers')) {
3206
			$result = apache_request_headers();
3207
		}
3208
		elseif($result === null) {
3209
			$result = array();
3210
			foreach($_SERVER as $key=>$value) {
3211
				if(strncasecmp($key, 'HTTP_', 5) !== 0) continue;
3212
					$key = str_replace(' ','-', ucwords(strtolower(str_replace('_',' ', substr($key, 5)))));
3213
					$result[$key] = $value;
3214
			}
3215
		}
3216
		if($case !== null)
3217
			return array_change_key_case($result, $case);
3218
		return $result;
3219
	}
3220
	public function getRequestUri()
3221
	{
3222
		return $this->_requestUri;
3223
	}
3224
	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...
3225
	{
3226
		$url=$this->getUrl();
3227
		$scheme=($forceSecureConnection)?"https": (($forceSecureConnection === null)?$url->getScheme():'http');
3228
		$host=$url->getHost();
3229
		if (($port=$url->getPort())) $host.=':'.$port;
3230
		return $scheme.'://'.$host;
3231
	}
3232
	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...
3233
	{
3234
		if($this->_cgiFix&self::CGIFIX__SCRIPT_NAME && isset($_SERVER['ORIG_SCRIPT_NAME']))
3235
			return $_SERVER['ORIG_SCRIPT_NAME'];
3236
		return isset($_SERVER['SCRIPT_NAME'])?$_SERVER['SCRIPT_NAME']:null;
3237
	}
3238
	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...
3239
	{
3240
		return $this->getBaseUrl($forceSecureConnection) . $this->getApplicationUrl();
3241
	}
3242
	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...
3243
	{
3244
		return realpath(isset($_SERVER['SCRIPT_FILENAME'])?$_SERVER['SCRIPT_FILENAME']:null);
3245
	}
3246
	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...
3247
	{
3248
		return isset($_SERVER['SERVER_NAME'])?$_SERVER['SERVER_NAME']:null;
3249
	}
3250
	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...
3251
	{
3252
		return isset($_SERVER['SERVER_PORT'])?$_SERVER['SERVER_PORT']:null;
3253
	}
3254
	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...
3255
	{
3256
		return isset($_SERVER['HTTP_REFERER'])?$_SERVER['HTTP_REFERER']:null;
3257
	}
3258
	public function getBrowser()
3259
	{
3260
		try
3261
		{
3262
			return get_browser();
3263
		}
3264
		catch(TPhpErrorException $e)
3265
		{
3266
			throw new TConfigurationException('httprequest_browscap_required');
3267
		}
3268
	}
3269
	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...
3270
	{
3271
		return isset($_SERVER['HTTP_USER_AGENT'])?$_SERVER['HTTP_USER_AGENT']:null;
3272
	}
3273
	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...
3274
	{
3275
		return isset($_SERVER['REMOTE_ADDR'])?$_SERVER['REMOTE_ADDR']:null;
3276
	}
3277
	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...
3278
	{
3279
		return isset($_SERVER['REMOTE_HOST'])?$_SERVER['REMOTE_HOST']:null;
3280
	}
3281
	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...
3282
	{
3283
				return isset($_SERVER['HTTP_ACCEPT'])?$_SERVER['HTTP_ACCEPT']:null;
3284
	}
3285
	public function getUserLanguages()
3286
	{
3287
		return Prado::getUserLanguages();
3288
	}
3289
	public function getEnableCookieValidation()
3290
	{
3291
		return $this->_enableCookieValidation;
3292
	}
3293
	public function setEnableCookieValidation($value)
3294
	{
3295
		$this->_enableCookieValidation=TPropertyValue::ensureBoolean($value);
3296
	}
3297
	public function getCgiFix()
3298
	{
3299
		return $this->_cgiFix;
3300
	}
3301
	public function setCgiFix($value)
3302
	{
3303
		$this->_cgiFix=TPropertyValue::ensureInteger($value);
3304
	}
3305
	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...
3306
	{
3307
		if($this->_cookies===null)
3308
		{
3309
			$this->_cookies=new THttpCookieCollection;
3310
			if($this->getEnableCookieValidation())
3311
			{
3312
				$sm=$this->getApplication()->getSecurityManager();
3313
				foreach($_COOKIE as $key=>$value)
3314
				{
3315
					if(($value=$sm->validateData($value))!==false)
3316
						$this->_cookies->add(new THttpCookie($key,$value));
3317
				}
3318
			}
3319
			else
3320
			{
3321
				foreach($_COOKIE as $key=>$value)
3322
					$this->_cookies->add(new THttpCookie($key,$value));
3323
			}
3324
		}
3325
		return $this->_cookies;
3326
	}
3327
	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...
3328
	{
3329
		return $_FILES;
3330
	}
3331
	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...
3332
	{
3333
		return $_SERVER;
3334
	}
3335
	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...
3336
	{
3337
		return $_ENV;
3338
	}
3339
	public function constructUrl($serviceID,$serviceParam,$getItems=null,$encodeAmpersand=true,$encodeGetItems=true)
3340
	{
3341
		if ($this->_cookieOnly===null)
3342
				$this->_cookieOnly=(int)ini_get('session.use_cookies') && (int)ini_get('session.use_only_cookies');
3343
		$url=$this->getUrlManagerModule()->constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems);
3344
		if(defined('SID') && SID != '' && !$this->_cookieOnly)
3345
			return $url . (strpos($url,'?')===false? '?' : ($encodeAmpersand?'&amp;':'&')) . SID;
3346
		else
3347
			return $url;
3348
	}
3349
	protected function parseUrl()
3350
	{
3351
		return $this->getUrlManagerModule()->parseUrl();
3352
	}
3353
	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...
3354
	{
3355
		$getParams=$this->parseUrl();
3356
		foreach($getParams as $name=>$value)
3357
			$_GET[$name]=$value;
3358
		$this->_items=array_merge($_GET,$_POST);
3359
		$this->_requestResolved=true;
3360
		foreach($serviceIDs as $serviceID)
3361
		{
3362
			if($this->contains($serviceID))
3363
			{
3364
				$this->setServiceID($serviceID);
3365
				$this->setServiceParameter($this->itemAt($serviceID));
3366
				return $serviceID;
3367
			}
3368
		}
3369
		return null;
3370
	}
3371
	public function getRequestResolved()
3372
	{
3373
		return $this->_requestResolved;
3374
	}
3375
	public function getServiceID()
3376
	{
3377
		return $this->_serviceID;
3378
	}
3379
	public function setServiceID($value)
3380
	{
3381
		$this->_serviceID=$value;
3382
	}
3383
	public function getServiceParameter()
3384
	{
3385
		return $this->_serviceParam;
3386
	}
3387
	public function setServiceParameter($value)
3388
	{
3389
		$this->_serviceParam=$value;
3390
	}
3391
	public function getIterator()
3392
	{
3393
		return new ArrayIterator($this->_items);
3394
	}
3395
	public function getCount()
3396
	{
3397
		return count($this->_items);
3398
	}
3399
	public function count()
3400
	{
3401
		return $this->getCount();
3402
	}
3403
	public function getKeys()
3404
	{
3405
		return array_keys($this->_items);
3406
	}
3407
	public function itemAt($key)
3408
	{
3409
		return isset($this->_items[$key]) ? $this->_items[$key] : null;
3410
	}
3411
	public function add($key,$value)
3412
	{
3413
		$this->_items[$key]=$value;
3414
	}
3415
	public function remove($key)
3416
	{
3417
		if(isset($this->_items[$key]) || array_key_exists($key,$this->_items))
3418
		{
3419
			$value=$this->_items[$key];
3420
			unset($this->_items[$key]);
3421
			return $value;
3422
		}
3423
		else
3424
			return null;
3425
	}
3426
	public function clear()
3427
	{
3428
		foreach(array_keys($this->_items) as $key)
3429
			$this->remove($key);
3430
	}
3431
	public function contains($key)
3432
	{
3433
		return isset($this->_items[$key]) || array_key_exists($key,$this->_items);
3434
	}
3435
	public function toArray()
3436
	{
3437
		return $this->_items;
3438
	}
3439
	public function offsetExists($offset)
3440
	{
3441
		return $this->contains($offset);
3442
	}
3443
	public function offsetGet($offset)
3444
	{
3445
		return $this->itemAt($offset);
3446
	}
3447
	public function offsetSet($offset,$item)
3448
	{
3449
		$this->add($offset,$item);
3450
	}
3451
	public function offsetUnset($offset)
3452
	{
3453
		$this->remove($offset);
3454
	}
3455
}
3456
class THttpCookieCollection extends TList
3457
{
3458
	private $_o;
3459
	public function __construct($owner=null)
3460
	{
3461
		$this->_o=$owner;
3462
	}
3463
	public function insertAt($index,$item)
3464
	{
3465
		if($item instanceof THttpCookie)
3466
		{
3467
			parent::insertAt($index,$item);
3468
			if($this->_o instanceof THttpResponse)
3469
				$this->_o->addCookie($item);
3470
		}
3471
		else
3472
			throw new TInvalidDataTypeException('httpcookiecollection_httpcookie_required');
3473
	}
3474
	public function removeAt($index)
3475
	{
3476
		$item=parent::removeAt($index);
3477
		if($this->_o instanceof THttpResponse)
3478
			$this->_o->removeCookie($item);
3479
		return $item;
3480
	}
3481
	public function itemAt($index)
3482
	{
3483
		if(is_integer($index))
3484
			return parent::itemAt($index);
3485
		else
3486
			return $this->findCookieByName($index);
3487
	}
3488
	public function findCookieByName($name)
3489
	{
3490
		foreach($this as $cookie)
3491
			if($cookie->getName()===$name)
3492
				return $cookie;
3493
		return null;
3494
	}
3495
}
3496
class THttpCookie extends TComponent
3497
{
3498
	private $_domain='';
3499
	private $_name;
3500
	private $_value='';
3501
	private $_expire=0;
3502
	private $_path='/';
3503
	private $_secure=false;
3504
	private $_httpOnly=false;
3505
	public function __construct($name,$value)
3506
	{
3507
		$this->_name=$name;
3508
		$this->_value=$value;
3509
	}
3510
	public function getDomain()
3511
	{
3512
		return $this->_domain;
3513
	}
3514
	public function setDomain($value)
3515
	{
3516
		$this->_domain=$value;
3517
	}
3518
	public function getExpire()
3519
	{
3520
		return $this->_expire;
3521
	}
3522
	public function setExpire($value)
3523
	{
3524
		$this->_expire=TPropertyValue::ensureInteger($value);
3525
	}
3526
	public function getHttpOnly()
3527
	{
3528
		return $this->_httpOnly;
3529
	}
3530
	public function setHttpOnly($value)
3531
	{
3532
		$this->_httpOnly = TPropertyValue::ensureBoolean($value);
3533
	}
3534
	public function getName()
3535
	{
3536
		return $this->_name;
3537
	}
3538
	public function setName($value)
3539
	{
3540
		$this->_name=$value;
3541
	}
3542
	public function getValue()
3543
	{
3544
		return $this->_value;
3545
	}
3546
	public function setValue($value)
3547
	{
3548
		$this->_value=$value;
3549
	}
3550
	public function getPath()
3551
	{
3552
		return $this->_path;
3553
	}
3554
	public function setPath($value)
3555
	{
3556
		$this->_path=$value;
3557
	}
3558
	public function getSecure()
3559
	{
3560
		return $this->_secure;
3561
	}
3562
	public function setSecure($value)
3563
	{
3564
		$this->_secure=TPropertyValue::ensureBoolean($value);
3565
	}
3566
}
3567
class TUri extends TComponent
3568
{
3569
	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...
3570
		'ftp'=>21,
3571
		'gopher'=>70,
3572
		'http'=>80,
3573
		'https'=>443,
3574
		'news'=>119,
3575
		'nntp'=>119,
3576
		'wais'=>210,
3577
		'telnet'=>23
3578
	);
3579
	private $_scheme;
3580
	private $_host;
3581
	private $_port;
3582
	private $_user;
3583
	private $_pass;
3584
	private $_path;
3585
	private $_query;
3586
	private $_fragment;
3587
	private $_uri;
3588
	public function __construct($uri)
3589
	{
3590
		if(($ret=@parse_url($uri))!==false)
3591
		{
3592
						$this->_scheme=isset($ret['scheme'])?$ret['scheme']:'';
3593
			$this->_host=isset($ret['host'])?$ret['host']:'';
3594
			$this->_port=isset($ret['port'])?$ret['port']:'';
3595
			$this->_user=isset($ret['user'])?$ret['user']:'';
3596
			$this->_pass=isset($ret['pass'])?$ret['pass']:'';
3597
			$this->_path=isset($ret['path'])?$ret['path']:'';
3598
			$this->_query=isset($ret['query'])?$ret['query']:'';
3599
			$this->_fragment=isset($ret['fragment'])?$ret['fragment']:'';
3600
			$this->_uri=$uri;
3601
		}
3602
		else
3603
		{
3604
			throw new TInvalidDataValueException('uri_format_invalid',$uri);
3605
		}
3606
	}
3607
	public function getUri()
3608
	{
3609
		return $this->_uri;
3610
	}
3611
	public function getScheme()
3612
	{
3613
		return $this->_scheme;
3614
	}
3615
	public function getHost()
3616
	{
3617
		return $this->_host;
3618
	}
3619
	public function getPort()
3620
	{
3621
		return $this->_port;
3622
	}
3623
	public function getUser()
3624
	{
3625
		return $this->_user;
3626
	}
3627
	public function getPassword()
3628
	{
3629
		return $this->_pass;
3630
	}
3631
	public function getPath()
3632
	{
3633
		return $this->_path;
3634
	}
3635
	public function getQuery()
3636
	{
3637
		return $this->_query;
3638
	}
3639
	public function getFragment()
3640
	{
3641
		return $this->_fragment;
3642
	}
3643
}
3644
class THttpRequestUrlFormat extends TEnumerable
3645
{
3646
	const Get='Get';
3647
	const Path='Path';
3648
	const HiddenPath='HiddenPath';
3649
}
3650
class THttpResponseAdapter extends TApplicationComponent
3651
{
3652
	private $_response;
3653
	public function __construct($response)
3654
	{
3655
		$this->_response=$response;
3656
	}
3657
	public function getResponse()
3658
	{
3659
		return $this->_response;
3660
	}
3661
	public function flushContent()
3662
	{
3663
		$this->_response->flushContent();
3664
	}
3665
	public function httpRedirect($url)
3666
	{
3667
		$this->_response->httpRedirect($url);
3668
	}
3669
	public function createNewHtmlWriter($type, $writer)
3670
	{
3671
		return $this->_response->createNewHtmlWriter($type,$writer);
3672
	}
3673
}
3674
class THttpResponse extends TModule implements ITextWriter
3675
{
3676
	const DEFAULT_CONTENTTYPE	= 'text/html';
3677
	const DEFAULT_CHARSET		= 'UTF-8';
3678
	private static $HTTP_STATUS_CODES = array(
3679
		100 => 'Continue', 101 => 'Switching Protocols',
3680
		200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content',
3681
		300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect',
3682
		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',
3683
		500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported'
3684
	);
3685
	private $_bufferOutput=true;
3686
	private $_initialized=false;
3687
	private $_cookies=null;
3688
	private $_status=200;
3689
	private $_reason='OK';
3690
	private $_htmlWriterType='System.Web.UI.THtmlWriter';
3691
	private $_contentType=null;
3692
	private $_charset='';
3693
	private $_adapter;
3694
	private $_httpHeaderSent;
3695
	private $_contentTypeHeaderSent;
3696
	public function __destruct()
3697
	{
3698
					}
3699
	public function setAdapter(THttpResponseAdapter $adapter)
3700
	{
3701
		$this->_adapter=$adapter;
3702
	}
3703
	public function getAdapter()
3704
	{
3705
		return $this->_adapter;
3706
	}
3707
	public function getHasAdapter()
3708
	{
3709
		return $this->_adapter!==null;
3710
	}
3711
	public function init($config)
3712
	{
3713
		if($this->_bufferOutput)
3714
			ob_start();
3715
		$this->_initialized=true;
3716
		$this->getApplication()->setResponse($this);
3717
	}
3718
	public function getCacheExpire()
3719
	{
3720
		return session_cache_expire();
3721
	}
3722
	public function setCacheExpire($value)
3723
	{
3724
		session_cache_expire(TPropertyValue::ensureInteger($value));
3725
	}
3726
	public function getCacheControl()
3727
	{
3728
		return session_cache_limiter();
3729
	}
3730
	public function setCacheControl($value)
3731
	{
3732
		session_cache_limiter(TPropertyValue::ensureEnum($value,array('none','nocache','private','private_no_expire','public')));
3733
	}
3734
	public function setContentType($type)
3735
	{
3736
		if ($this->_contentTypeHeaderSent)
3737
			throw new Exception('Unable to alter content-type as it has been already sent');
3738
		$this->_contentType = $type;
3739
	}
3740
	public function getContentType()
3741
	{
3742
		return $this->_contentType;
3743
	}
3744
	public function getCharset()
3745
	{
3746
		return $this->_charset;
3747
	}
3748
	public function setCharset($charset)
3749
	{
3750
		$this->_charset = (strToLower($charset) === 'false') ? false : (string)$charset;
3751
	}
3752
	public function getBufferOutput()
3753
	{
3754
		return $this->_bufferOutput;
3755
	}
3756
	public function setBufferOutput($value)
3757
	{
3758
		if($this->_initialized)
3759
			throw new TInvalidOperationException('httpresponse_bufferoutput_unchangeable');
3760
		else
3761
			$this->_bufferOutput=TPropertyValue::ensureBoolean($value);
3762
	}
3763
	public function getStatusCode()
3764
	{
3765
		return $this->_status;
3766
	}
3767
	public function setStatusCode($status, $reason=null)
3768
	{
3769
		if ($this->_httpHeaderSent)
3770
			throw new Exception('Unable to alter response as HTTP header already sent');
3771
		$status=TPropertyValue::ensureInteger($status);
3772
		if(isset(self::$HTTP_STATUS_CODES[$status])) {
3773
			$this->_reason=self::$HTTP_STATUS_CODES[$status];
3774
		}else{
3775
			if($reason===null || $reason==='') {
3776
				throw new TInvalidDataValueException("response_status_reason_missing");
3777
			}
3778
			$reason=TPropertyValue::ensureString($reason);
3779
			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...
3780
				throw new TInvalidDataValueException("response_status_reason_barchars");
3781
			}
3782
			$this->_reason=$reason;
3783
		}
3784
		$this->_status=$status;
3785
	}
3786
	public function getStatusReason() {
3787
		return $this->_reason;
3788
	}
3789
	public function getCookies()
3790
	{
3791
		if($this->_cookies===null)
3792
			$this->_cookies=new THttpCookieCollection($this);
3793
		return $this->_cookies;
3794
	}
3795
	public function write($str)
3796
	{
3797
				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...
3798
			$this->ensureHeadersSent();
3799
		echo $str;
3800
	}
3801
	public function writeFile($fileName,$content=null,$mimeType=null,$headers=null,$forceDownload=true,$clientFileName=null,$fileSize=null)
3802
	{
3803
		static $defaultMimeTypes=array(
3804
			'css'=>'text/css',
3805
			'gif'=>'image/gif',
3806
			'png'=>'image/png',
3807
			'jpg'=>'image/jpeg',
3808
			'jpeg'=>'image/jpeg',
3809
			'htm'=>'text/html',
3810
			'html'=>'text/html',
3811
			'js'=>'javascript/js',
3812
			'pdf'=>'application/pdf',
3813
			'xls'=>'application/vnd.ms-excel',
3814
		);
3815
		if($mimeType===null)
3816
		{
3817
			$mimeType='text/plain';
3818
			if(function_exists('mime_content_type'))
3819
				$mimeType=mime_content_type($fileName);
3820
			else if(($ext=strrchr($fileName,'.'))!==false)
3821
			{
3822
				$ext=substr($ext,1);
3823
				if(isset($defaultMimeTypes[$ext]))
3824
					$mimeType=$defaultMimeTypes[$ext];
3825
			}
3826
		}
3827
		if($clientFileName===null)
3828
			$clientFileName=basename($fileName);
3829
		else
3830
			$clientFileName=basename($clientFileName);
3831
		if($fileSize===null || $fileSize < 0)
3832
			$fileSize = ($content===null?filesize($fileName):strlen($content));
3833
		$this->sendHttpHeader();
3834
		if(is_array($headers))
3835
		{
3836
			foreach($headers as $h)
3837
				header($h);
3838
		}
3839
		else
3840
		{
3841
			header('Pragma: public');
3842
			header('Expires: 0');
3843
			header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
3844
			header("Content-Type: $mimeType");
3845
			$this->_contentTypeHeaderSent = true;
3846
		}
3847
		header('Content-Length: '.$fileSize);
3848
		header("Content-Disposition: " . ($forceDownload ? 'attachment' : 'inline') . "; filename=\"$clientFileName\"");
3849
		header('Content-Transfer-Encoding: binary');
3850
		if($content===null)
3851
			readfile($fileName);
3852
		else
3853
			echo $content;
3854
	}
3855
	public function redirect($url)
3856
	{
3857
		if($this->getHasAdapter())
3858
			$this->_adapter->httpRedirect($url);
3859
		else
3860
			$this->httpRedirect($url);
3861
	}
3862
	public function httpRedirect($url)
3863
	{
3864
		$this->ensureHeadersSent();
3865
		if($url[0]==='/')
3866
			$url=$this->getRequest()->getBaseUrl().$url;
3867
		if ($this->_status >= 300 && $this->_status < 400)
3868
						header('Location: '.str_replace('&amp;','&',$url), true, $this->_status);
3869
		else
3870
			header('Location: '.str_replace('&amp;','&',$url));
3871
		if(!$this->getApplication()->getRequestCompleted())
3872
			$this->getApplication()->onEndRequest();
3873
		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...
3874
	}
3875
	public function reload()
3876
	{
3877
		$this->redirect($this->getRequest()->getRequestUri());
3878
	}
3879
	public function flush($continueBuffering = true)
3880
	{
3881
		if($this->getHasAdapter())
3882
			$this->_adapter->flushContent($continueBuffering);
3883
		else
3884
			$this->flushContent($continueBuffering);
3885
	}
3886
	public function ensureHeadersSent()
3887
	{
3888
		$this->ensureHttpHeaderSent();
3889
		$this->ensureContentTypeHeaderSent();
3890
	}
3891
	public function flushContent($continueBuffering = true)
3892
	{
3893
		$this->ensureHeadersSent();
3894
		if($this->_bufferOutput)
3895
		{
3896
						if (ob_get_length()>0)
3897
			{
3898
				if (!$continueBuffering)
3899
				{
3900
					$this->_bufferOutput = false;
3901
					ob_end_flush();
3902
				}
3903
				else
3904
					ob_flush();
3905
				flush();
3906
			}
3907
		}
3908
		else
3909
			flush();
3910
	}
3911
	protected function ensureHttpHeaderSent()
3912
	{
3913
		if (!$this->_httpHeaderSent)
3914
			$this->sendHttpHeader();
3915
	}
3916
	protected function sendHttpHeader()
3917
	{
3918
		$protocol=$this->getRequest()->getHttpProtocolVersion();
3919
		if($this->getRequest()->getHttpProtocolVersion() === null)
3920
			$protocol='HTTP/1.1';
3921
		$phpSapiName = substr(php_sapi_name(), 0, 3);
3922
		$cgi = $phpSapiName == 'cgi' || $phpSapiName == 'fpm';
3923
		header(($cgi ? 'Status:' : $protocol).' '.$this->_status.' '.$this->_reason, true, TPropertyValue::ensureInteger($this->_status));
3924
		$this->_httpHeaderSent = true;
3925
	}
3926
	protected function ensureContentTypeHeaderSent()
3927
	{
3928
		if (!$this->_contentTypeHeaderSent)
3929
			$this->sendContentTypeHeader();
3930
	}
3931
	protected function sendContentTypeHeader()
3932
	{
3933
		$contentType=$this->_contentType===null?self::DEFAULT_CONTENTTYPE:$this->_contentType;
3934
		$charset=$this->getCharset();
3935
		if($charset === false) {
3936
			$this->appendHeader('Content-Type: '.$contentType);
3937
			return;
3938
		}
3939
		if($charset==='' && ($globalization=$this->getApplication()->getGlobalization(false))!==null)
3940
			$charset=$globalization->getCharset();
3941
		if($charset==='') $charset = self::DEFAULT_CHARSET;
3942
		$this->appendHeader('Content-Type: '.$contentType.';charset='.$charset);
3943
		$this->_contentTypeHeaderSent = true;
3944
	}
3945
	public function getContents()
3946
	{
3947
		return $this->_bufferOutput?ob_get_contents():'';
3948
	}
3949
	public function clear()
3950
	{
3951
		if($this->_bufferOutput)
3952
			ob_clean();
3953
	}
3954
	public function getHeaders($case=null)
3955
	{
3956
		$result = array();
3957
		$headers = headers_list();
3958
		foreach($headers as $header) {
3959
			$tmp = explode(':', $header);
3960
			$key = trim(array_shift($tmp));
3961
			$value = trim(implode(':', $tmp));
3962
			if(isset($result[$key]))
3963
				$result[$key] .= ', ' . $value;
3964
			else
3965
				$result[$key] = $value;
3966
		}
3967
		if($case !== null)
3968
			return array_change_key_case($result, $case);
3969
		return $result;
3970
	}
3971
	public function appendHeader($value, $replace=true)
3972
	{
3973
		header($value, $replace);
3974
	}
3975
	public function appendLog($message,$messageType=0,$destination='',$extraHeaders='')
3976
	{
3977
		error_log($message,$messageType,$destination,$extraHeaders);
3978
	}
3979
	public function addCookie($cookie)
3980
	{
3981
		$request=$this->getRequest();
3982
		if($request->getEnableCookieValidation())
3983
		{
3984
			$value=$this->getApplication()->getSecurityManager()->hashData($cookie->getValue());
3985
			setcookie(
3986
				$cookie->getName(),
3987
				$value,
3988
				$cookie->getExpire(),
3989
				$cookie->getPath(),
3990
				$cookie->getDomain(),
3991
				$cookie->getSecure(),
3992
				$cookie->getHttpOnly()
3993
			);
3994
		}
3995
		else {
3996
			setcookie(
3997
				$cookie->getName(),
3998
				$cookie->getValue(),
3999
				$cookie->getExpire(),
4000
				$cookie->getPath(),
4001
				$cookie->getDomain(),
4002
				$cookie->getSecure(),
4003
				$cookie->getHttpOnly()
4004
			);
4005
		}
4006
	}
4007
	public function removeCookie($cookie)
4008
	{
4009
		setcookie(
4010
			$cookie->getName(),
4011
			null,
4012
			0,
4013
			$cookie->getPath(),
4014
			$cookie->getDomain(),
4015
			$cookie->getSecure(),
4016
			$cookie->getHttpOnly()
4017
		);
4018
	}
4019
	public function getHtmlWriterType()
4020
	{
4021
		return $this->_htmlWriterType;
4022
	}
4023
	public function setHtmlWriterType($value)
4024
	{
4025
		$this->_htmlWriterType=$value;
4026
	}
4027
	public function createHtmlWriter($type=null)
4028
	{
4029
		if($type===null)
4030
			$type=$this->getHtmlWriterType();
4031
		if($this->getHasAdapter())
4032
			return $this->_adapter->createNewHtmlWriter($type, $this);
4033
		else
4034
			return $this->createNewHtmlWriter($type, $this);
4035
	}
4036
	public function createNewHtmlWriter($type, $writer)
4037
	{
4038
		return Prado::createComponent($type, $writer);
4039
	}
4040
}
4041
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...
4042
{
4043
	private $_initialized=false;
4044
	private $_started=false;
4045
	private $_autoStart=false;
4046
	private $_cookie=null;
4047
	private $_id;
4048
	private $_customStorage=false;
4049
	public function getID()
4050
	{
4051
		return $this->_id;
4052
	}
4053
	public function setID($value)
4054
	{
4055
		$this->_id=$value;
4056
	}
4057
	public function init($config)
4058
	{
4059
		if($this->_autoStart)
4060
			$this->open();
4061
		$this->_initialized=true;
4062
		$this->getApplication()->setSession($this);
4063
		register_shutdown_function(array($this, "close"));
4064
	}
4065
	public function open()
4066
	{
4067
		if(!$this->_started)
4068
		{
4069
			if($this->_customStorage)
4070
				session_set_save_handler(array($this,'_open'),array($this,'_close'),array($this,'_read'),array($this,'_write'),array($this,'_destroy'),array($this,'_gc'));
4071
			if($this->_cookie!==null)
4072
				session_set_cookie_params($this->_cookie->getExpire(),$this->_cookie->getPath(),$this->_cookie->getDomain(),$this->_cookie->getSecure(),$this->_cookie->getHttpOnly());
4073
			if(ini_get('session.auto_start')!=='1')
4074
				session_start();
4075
			$this->_started=true;
4076
		}
4077
	}
4078
	public function close()
4079
	{
4080
		if($this->_started)
4081
		{
4082
			session_write_close();
4083
			$this->_started=false;
4084
		}
4085
	}
4086
	public function destroy()
4087
	{
4088
		if($this->_started)
4089
		{
4090
			session_destroy();
4091
			$this->_started=false;
4092
		}
4093
	}
4094
	public function regenerate($deleteOld=false)
4095
	{
4096
		$old = $this->getSessionID();
4097
		session_regenerate_id($deleteOld);
4098
		return $old;
4099
	}
4100
	public function getIsStarted()
4101
	{
4102
		return $this->_started;
4103
	}
4104
	public function getSessionID()
4105
	{
4106
		return session_id();
4107
	}
4108
	public function setSessionID($value)
4109
	{
4110
		if($this->_started)
4111
			throw new TInvalidOperationException('httpsession_sessionid_unchangeable');
4112
		else
4113
			session_id($value);
4114
	}
4115
	public function getSessionName()
4116
	{
4117
		return session_name();
4118
	}
4119
	public function setSessionName($value)
4120
	{
4121
		if($this->_started)
4122
			throw new TInvalidOperationException('httpsession_sessionname_unchangeable');
4123
		else if(ctype_alnum($value))
4124
			session_name($value);
4125
		else
4126
			throw new TInvalidDataValueException('httpsession_sessionname_invalid',$value);
4127
	}
4128
	public function getSavePath()
4129
	{
4130
		return session_save_path();
4131
	}
4132
	public function setSavePath($value)
4133
	{
4134
		if($this->_started)
4135
			throw new TInvalidOperationException('httpsession_savepath_unchangeable');
4136
		else if(is_dir($value))
4137
			session_save_path($value);
4138
		else
4139
			throw new TInvalidDataValueException('httpsession_savepath_invalid',$value);
4140
	}
4141
	public function getUseCustomStorage()
4142
	{
4143
		return $this->_customStorage;
4144
	}
4145
	public function setUseCustomStorage($value)
4146
	{
4147
		$this->_customStorage=TPropertyValue::ensureBoolean($value);
4148
	}
4149
	public function getCookie()
4150
	{
4151
		if($this->_cookie===null)
4152
			$this->_cookie=new THttpCookie($this->getSessionName(),$this->getSessionID());
4153
		return $this->_cookie;
4154
	}
4155
	public function getCookieMode()
4156
	{
4157
		if(ini_get('session.use_cookies')==='0')
4158
			return THttpSessionCookieMode::None;
4159
		else if(ini_get('session.use_only_cookies')==='0')
4160
			return THttpSessionCookieMode::Allow;
4161
		else
4162
			return THttpSessionCookieMode::Only;
4163
	}
4164
	public function setCookieMode($value)
4165
	{
4166
		if($this->_started)
4167
			throw new TInvalidOperationException('httpsession_cookiemode_unchangeable');
4168
		else
4169
		{
4170
			$value=TPropertyValue::ensureEnum($value,'THttpSessionCookieMode');
4171
			if($value===THttpSessionCookieMode::None) 
4172
      {
4173
				ini_set('session.use_cookies','0');
4174
			  ini_set('session.use_only_cookies','0');
4175
      }
4176
			else if($value===THttpSessionCookieMode::Allow)
4177
			{
4178
				ini_set('session.use_cookies','1');
4179
				ini_set('session.use_only_cookies','0');
4180
			}
4181
			else
4182
			{
4183
				ini_set('session.use_cookies','1');
4184
				ini_set('session.use_only_cookies','1');
4185
				ini_set('session.use_trans_sid', 0);
4186
			}
4187
		}
4188
	}
4189
	public function getAutoStart()
4190
	{
4191
		return $this->_autoStart;
4192
	}
4193
	public function setAutoStart($value)
4194
	{
4195
		if($this->_initialized)
4196
			throw new TInvalidOperationException('httpsession_autostart_unchangeable');
4197
		else
4198
			$this->_autoStart=TPropertyValue::ensureBoolean($value);
4199
	}
4200
	public function getGCProbability()
4201
	{
4202
		return TPropertyValue::ensureInteger(ini_get('session.gc_probability'));
4203
	}
4204
	public function setGCProbability($value)
4205
	{
4206
		if($this->_started)
4207
			throw new TInvalidOperationException('httpsession_gcprobability_unchangeable');
4208
		else
4209
		{
4210
			$value=TPropertyValue::ensureInteger($value);
4211
			if($value>=0 && $value<=100)
4212
			{
4213
				ini_set('session.gc_probability',$value);
4214
				ini_set('session.gc_divisor','100');
4215
			}
4216
			else
4217
				throw new TInvalidDataValueException('httpsession_gcprobability_invalid',$value);
4218
		}
4219
	}
4220
	public function getUseTransparentSessionID()
4221
	{
4222
		return ini_get('session.use_trans_sid')==='1';
4223
	}
4224
	public function setUseTransparentSessionID($value)
4225
	{
4226
		if($this->_started)
4227
			throw new TInvalidOperationException('httpsession_transid_unchangeable');
4228
		else
4229
		{
4230
			$value=TPropertyValue::ensureBoolean($value);
4231
			if ($value && $this->getCookieMode()==THttpSessionCookieMode::Only)
4232
					throw new TInvalidOperationException('httpsession_transid_cookieonly');
4233
			ini_set('session.use_trans_sid',$value?'1':'0');
4234
		}
4235
	}
4236
	public function getTimeout()
4237
	{
4238
		return TPropertyValue::ensureInteger(ini_get('session.gc_maxlifetime'));
4239
	}
4240
	public function setTimeout($value)
4241
	{
4242
		if($this->_started)
4243
			throw new TInvalidOperationException('httpsession_maxlifetime_unchangeable');
4244
		else
4245
			ini_set('session.gc_maxlifetime',$value);
4246
	}
4247
	public function _open($savePath,$sessionName)
4248
	{
4249
		return true;
4250
	}
4251
	public function _close()
4252
	{
4253
		return true;
4254
	}
4255
	public function _read($id)
4256
	{
4257
		return '';
4258
	}
4259
	public function _write($id,$data)
4260
	{
4261
		return true;
4262
	}
4263
	public function _destroy($id)
4264
	{
4265
		return true;
4266
	}
4267
	public function _gc($maxLifetime)
4268
	{
4269
		return true;
4270
	}
4271
	public function getIterator()
4272
	{
4273
		return new TSessionIterator;
4274
	}
4275
	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...
4276
	{
4277
		return count($_SESSION);
4278
	}
4279
	public function count()
4280
	{
4281
		return $this->getCount();
4282
	}
4283
	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...
4284
	{
4285
		return array_keys($_SESSION);
4286
	}
4287
	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...
4288
	{
4289
		return isset($_SESSION[$key]) ? $_SESSION[$key] : null;
4290
	}
4291
	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...
4292
	{
4293
		$_SESSION[$key]=$value;
4294
	}
4295
	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...
4296
	{
4297
		if(isset($_SESSION[$key]))
4298
		{
4299
			$value=$_SESSION[$key];
4300
			unset($_SESSION[$key]);
4301
			return $value;
4302
		}
4303
		else
4304
			return null;
4305
	}
4306
	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...
4307
	{
4308
		foreach(array_keys($_SESSION) as $key)
4309
			unset($_SESSION[$key]);
4310
	}
4311
	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...
4312
	{
4313
		return isset($_SESSION[$key]);
4314
	}
4315
	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...
4316
	{
4317
		return $_SESSION;
4318
	}
4319
	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...
4320
	{
4321
		return isset($_SESSION[$offset]);
4322
	}
4323
	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...
4324
	{
4325
		return isset($_SESSION[$offset]) ? $_SESSION[$offset] : null;
4326
	}
4327
	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...
4328
	{
4329
		$_SESSION[$offset]=$item;
4330
	}
4331
	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...
4332
	{
4333
		unset($_SESSION[$offset]);
4334
	}
4335
}
4336
class TSessionIterator implements Iterator
4337
{
4338
	private $_keys;
4339
	private $_key;
4340
	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...
4341
	{
4342
		$this->_keys=array_keys($_SESSION);
4343
	}
4344
	public function rewind()
4345
	{
4346
		$this->_key=reset($this->_keys);
4347
	}
4348
	public function key()
4349
	{
4350
		return $this->_key;
4351
	}
4352
	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...
4353
	{
4354
		return isset($_SESSION[$this->_key])?$_SESSION[$this->_key]:null;
4355
	}
4356
	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...
4357
	{
4358
		do
4359
		{
4360
			$this->_key=next($this->_keys);
4361
		}
4362
		while(!isset($_SESSION[$this->_key]) && $this->_key!==false);
4363
	}
4364
	public function valid()
4365
	{
4366
		return $this->_key!==false;
4367
	}
4368
}
4369
class THttpSessionCookieMode extends TEnumerable
4370
{
4371
	const None='None';
4372
	const Allow='Allow';
4373
	const Only='Only';
4374
}
4375
Prado::using('System.Web.UI.WebControls.*');
4376
class TAttributeCollection extends TMap
4377
{
4378
	private $_caseSensitive=false;
4379
	protected function _getZappableSleepProps(&$exprops)
4380
	{
4381
		parent::_getZappableSleepProps($exprops);
4382
		if ($this->_caseSensitive===false)
4383
			$exprops[] = "\0TAttributeCollection\0_caseSensitive";
4384
	}
4385
	public function __get($name)
4386
	{
4387
		return $this->contains($name)?$this->itemAt($name):parent::__get($name);
4388
	}
4389
	public function __set($name,$value)
4390
	{
4391
		$this->add($name,$value);
4392
	}
4393
	public function getCaseSensitive()
4394
	{
4395
		return $this->_caseSensitive;
4396
	}
4397
	public function setCaseSensitive($value)
4398
	{
4399
		$this->_caseSensitive=TPropertyValue::ensureBoolean($value);
4400
	}
4401
	public function itemAt($key)
4402
	{
4403
		return parent::itemAt($this->_caseSensitive?$key:strtolower($key));
4404
	}
4405
	public function add($key,$value)
4406
	{
4407
		parent::add($this->_caseSensitive?$key:strtolower($key),$value);
4408
	}
4409
	public function remove($key)
4410
	{
4411
		return parent::remove($this->_caseSensitive?$key:strtolower($key));
4412
	}
4413
	public function contains($key)
4414
	{
4415
		return parent::contains($this->_caseSensitive?$key:strtolower($key));
4416
	}
4417
	public function hasProperty($name)
4418
	{
4419
		return $this->contains($name) || parent::canGetProperty($name) || parent::canSetProperty($name);
4420
	}
4421
	public function canGetProperty($name)
4422
	{
4423
		return $this->contains($name) || parent::canGetProperty($name);
4424
	}
4425
	public function canSetProperty($name)
4426
	{
4427
		return true;
4428
	}
4429
}
4430
class TControlAdapter extends TApplicationComponent
4431
{
4432
	protected $_control;
4433
	public function __construct($control)
4434
	{
4435
		$this->_control=$control;
4436
	}
4437
	public function getControl()
4438
	{
4439
		return $this->_control;
4440
	}
4441
	public function getPage()
4442
	{
4443
		return $this->_control?$this->_control->getPage():null;
4444
	}
4445
	public function createChildControls()
4446
	{
4447
		$this->_control->createChildControls();
4448
	}
4449
	public function loadState()
4450
	{
4451
		$this->_control->loadState();
4452
	}
4453
	public function saveState()
4454
	{
4455
		$this->_control->saveState();
4456
	}
4457
	public function onInit($param)
4458
	{
4459
		$this->_control->onInit($param);
4460
	}
4461
	public function onLoad($param)
4462
	{
4463
		$this->_control->onLoad($param);
4464
	}
4465
	public function onPreRender($param)
4466
	{
4467
		$this->_control->onPreRender($param);
4468
	}
4469
	public function onUnload($param)
4470
	{
4471
		$this->_control->onUnload($param);
4472
	}
4473
	public function render($writer)
4474
	{
4475
		$this->_control->render($writer);
4476
	}
4477
	public function renderChildren($writer)
4478
	{
4479
		$this->_control->renderChildren($writer);
4480
	}
4481
}
4482
class TControl extends TApplicationComponent implements IRenderable, IBindable
4483
{
4484
	const ID_FORMAT='/^[a-zA-Z_]\\w*$/';
4485
	const ID_SEPARATOR='$';
4486
	const CLIENT_ID_SEPARATOR='_';
4487
	const AUTOMATIC_ID_PREFIX='ctl';
4488
	const CS_CONSTRUCTED=0;
4489
	const CS_CHILD_INITIALIZED=1;
4490
	const CS_INITIALIZED=2;
4491
	const CS_STATE_LOADED=3;
4492
	const CS_LOADED=4;
4493
	const CS_PRERENDERED=5;
4494
	const IS_ID_SET=0x01;
4495
	const IS_DISABLE_VIEWSTATE=0x02;
4496
	const IS_SKIN_APPLIED=0x04;
4497
	const IS_STYLESHEET_APPLIED=0x08;
4498
	const IS_DISABLE_THEMING=0x10;
4499
	const IS_CHILD_CREATED=0x20;
4500
	const IS_CREATING_CHILD=0x40;
4501
	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...
4502
	private $_id='';
4503
	private $_uid;
4504
	private $_parent;
4505
	private $_page;
4506
	private $_namingContainer;
4507
	private $_tplControl;
4508
	private $_viewState=array();
4509
	private $_tempState=array();
4510
	private $_trackViewState=true;
4511
	private $_stage=0;
4512
	private $_flags=0;
4513
	private $_rf=array();
4514
	public function __get($name)
4515
	{
4516
		if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
4517
			return $this->_rf[self::RF_NAMED_OBJECTS][$name];
4518
		else
4519
			return parent::__get($name);
4520
	}
4521
	public function __isset($name) {
4522
		if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name])) {
4523
			return true;
4524
		} else {
4525
			return parent::__isset($name);
4526
		}
4527
	}
4528
	public function getHasAdapter()
4529
	{
4530
		return isset($this->_rf[self::RF_ADAPTER]);
4531
	}
4532
	public function getAdapter()
4533
	{
4534
		return isset($this->_rf[self::RF_ADAPTER])?$this->_rf[self::RF_ADAPTER]:null;
4535
	}
4536
	public function setAdapter(TControlAdapter $adapter)
4537
	{
4538
		$this->_rf[self::RF_ADAPTER]=$adapter;
4539
	}
4540
	public function getParent()
4541
	{
4542
		return $this->_parent;
4543
	}
4544
	public function getNamingContainer()
4545
	{
4546
		if(!$this->_namingContainer && $this->_parent)
4547
		{
4548
			if($this->_parent instanceof INamingContainer)
4549
				$this->_namingContainer=$this->_parent;
4550
			else
4551
				$this->_namingContainer=$this->_parent->getNamingContainer();
4552
		}
4553
		return $this->_namingContainer;
4554
	}
4555
	public function getPage()
4556
	{
4557
		if(!$this->_page)
4558
		{
4559
			if($this->_parent)
4560
				$this->_page=$this->_parent->getPage();
4561
			else if($this->_tplControl)
4562
				$this->_page=$this->_tplControl->getPage();
4563
		}
4564
		return $this->_page;
4565
	}
4566
	public function setPage($page)
4567
	{
4568
		$this->_page=$page;
4569
	}
4570
	public function setTemplateControl($control)
4571
	{
4572
		$this->_tplControl=$control;
4573
	}
4574
	public function getTemplateControl()
4575
	{
4576
		if(!$this->_tplControl && $this->_parent)
4577
			$this->_tplControl=$this->_parent->getTemplateControl();
4578
		return $this->_tplControl;
4579
	}
4580
	public function getSourceTemplateControl()
4581
	{
4582
		$control=$this;
4583
		while(($control instanceof TControl) && ($control=$control->getTemplateControl())!==null)
4584
		{
4585
			if(($control instanceof TTemplateControl) && $control->getIsSourceTemplateControl())
4586
				return $control;
4587
		}
4588
		return $this->getPage();
4589
	}
4590
	protected function getControlStage()
4591
	{
4592
		return $this->_stage;
4593
	}
4594
	protected function setControlStage($value)
4595
	{
4596
		$this->_stage=$value;
4597
	}
4598
	public function getID($hideAutoID=true)
4599
	{
4600
		if($hideAutoID)
4601
			return ($this->_flags & self::IS_ID_SET) ? $this->_id : '';
4602
		else
4603
			return $this->_id;
4604
	}
4605
	public function setID($id)
4606
	{
4607
		if(!preg_match(self::ID_FORMAT,$id))
4608
			throw new TInvalidDataValueException('control_id_invalid',get_class($this),$id);
4609
		$this->_id=$id;
4610
		$this->_flags |= self::IS_ID_SET;
4611
		$this->clearCachedUniqueID($this instanceof INamingContainer);
4612
		if($this->_namingContainer)
4613
			$this->_namingContainer->clearNameTable();
4614
	}
4615
	public function getUniqueID()
4616
	{
4617
		if($this->_uid==='' || $this->_uid===null)			{
4618
			$this->_uid='';  			if($namingContainer=$this->getNamingContainer())
4619
			{
4620
				if($this->getPage()===$namingContainer)
4621
					return ($this->_uid=$this->_id);
4622
				else if(($prefix=$namingContainer->getUniqueID())==='')
4623
					return $this->_id;
4624
				else
4625
					return ($this->_uid=$prefix.self::ID_SEPARATOR.$this->_id);
4626
			}
4627
			else					return $this->_id;
4628
		}
4629
		else
4630
			return $this->_uid;
4631
	}
4632
	public function focus()
4633
	{
4634
		$this->getPage()->setFocus($this);
4635
	}
4636
	public function getClientID()
4637
	{
4638
		return strtr($this->getUniqueID(),self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
4639
	}
4640
	public static function convertUniqueIdToClientId($uniqueID)
4641
	{
4642
		return strtr($uniqueID,self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
4643
	}
4644
	public function getSkinID()
4645
	{
4646
		return isset($this->_rf[self::RF_SKIN_ID])?$this->_rf[self::RF_SKIN_ID]:'';
4647
	}
4648
	public function setSkinID($value)
4649
	{
4650
		if(($this->_flags & self::IS_SKIN_APPLIED) || $this->_stage>=self::CS_CHILD_INITIALIZED)
4651
			throw new TInvalidOperationException('control_skinid_unchangeable',get_class($this));
4652
		else
4653
			$this->_rf[self::RF_SKIN_ID]=$value;
4654
	}
4655
	public function getIsSkinApplied()
4656
	{
4657
		return ($this->_flags & self::IS_SKIN_APPLIED);
4658
	}
4659
	public function getEnableTheming()
4660
	{
4661
		if($this->_flags & self::IS_DISABLE_THEMING)
4662
			return false;
4663
		else
4664
			return $this->_parent?$this->_parent->getEnableTheming():true;
4665
	}
4666
	public function setEnableTheming($value)
4667
	{
4668
		if($this->_stage>=self::CS_CHILD_INITIALIZED)
4669
			throw new TInvalidOperationException('control_enabletheming_unchangeable',get_class($this),$this->getUniqueID());
4670
		else if(TPropertyValue::ensureBoolean($value))
4671
			$this->_flags &= ~self::IS_DISABLE_THEMING;
4672
		else
4673
			$this->_flags |= self::IS_DISABLE_THEMING;
4674
	}
4675
	public function getCustomData()
4676
	{
4677
		return $this->getViewState('CustomData',null);
4678
	}
4679
	public function setCustomData($value)
4680
	{
4681
		$this->setViewState('CustomData',$value,null);
4682
	}
4683
	public function getHasControls()
4684
	{
4685
		return isset($this->_rf[self::RF_CONTROLS]) && $this->_rf[self::RF_CONTROLS]->getCount()>0;
4686
	}
4687
	public function getControls()
4688
	{
4689
		if(!isset($this->_rf[self::RF_CONTROLS]))
4690
			$this->_rf[self::RF_CONTROLS]=$this->createControlCollection();
4691
		return $this->_rf[self::RF_CONTROLS];
4692
	}
4693
	protected function createControlCollection()
4694
	{
4695
		return $this->getAllowChildControls()?new TControlCollection($this):new TEmptyControlCollection($this);
4696
	}
4697
	public function getVisible($checkParents=true)
4698
	{
4699
		if($checkParents)
4700
		{
4701
			for($control=$this;$control;$control=$control->_parent)
4702
				if(!$control->getVisible(false))
4703
					return false;
4704
			return true;
4705
		}
4706
		else
4707
			return $this->getViewState('Visible',true);
4708
	}
4709
	public function setVisible($value)
4710
	{
4711
		$this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true);
4712
	}
4713
	public function getEnabled($checkParents=false)
4714
	{
4715
		if($checkParents)
4716
		{
4717
			for($control=$this;$control;$control=$control->_parent)
4718
				if(!$control->getViewState('Enabled',true))
4719
					return false;
4720
			return true;
4721
		}
4722
		else
4723
			return $this->getViewState('Enabled',true);
4724
	}
4725
	public function setEnabled($value)
4726
	{
4727
		$this->setViewState('Enabled',TPropertyValue::ensureBoolean($value),true);
4728
	}
4729
	public function getHasAttributes()
4730
	{
4731
		if($attributes=$this->getViewState('Attributes',null))
4732
			return $attributes->getCount()>0;
4733
		else
4734
			return false;
4735
	}
4736
	public function getAttributes()
4737
	{
4738
		if($attributes=$this->getViewState('Attributes',null))
4739
			return $attributes;
4740
		else
4741
		{
4742
			$attributes=new TAttributeCollection;
4743
			$this->setViewState('Attributes',$attributes,null);
4744
			return $attributes;
4745
		}
4746
	}
4747
	public function hasAttribute($name)
4748
	{
4749
		if($attributes=$this->getViewState('Attributes',null))
4750
			return $attributes->contains($name);
4751
		else
4752
			return false;
4753
	}
4754
	public function getAttribute($name)
4755
	{
4756
		if($attributes=$this->getViewState('Attributes',null))
4757
			return $attributes->itemAt($name);
4758
		else
4759
			return null;
4760
	}
4761
	public function setAttribute($name,$value)
4762
	{
4763
		$this->getAttributes()->add($name,$value);
4764
	}
4765
	public function removeAttribute($name)
4766
	{
4767
		if($attributes=$this->getViewState('Attributes',null))
4768
			return $attributes->remove($name);
4769
		else
4770
			return null;
4771
	}
4772
	public function getEnableViewState($checkParents=false)
4773
	{
4774
		if($checkParents)
4775
		{
4776
			for($control=$this;$control!==null;$control=$control->getParent())
4777
				if($control->_flags & self::IS_DISABLE_VIEWSTATE)
4778
					return false;
4779
			return true;
4780
		}
4781
		else
4782
			return !($this->_flags & self::IS_DISABLE_VIEWSTATE);
4783
	}
4784
	public function setEnableViewState($value)
4785
	{
4786
		if(TPropertyValue::ensureBoolean($value))
4787
			$this->_flags &= ~self::IS_DISABLE_VIEWSTATE;
4788
		else
4789
			$this->_flags |= self::IS_DISABLE_VIEWSTATE;
4790
	}
4791
	protected function getControlState($key,$defaultValue=null)
4792
	{
4793
		return isset($this->_rf[self::RF_CONTROLSTATE][$key])?$this->_rf[self::RF_CONTROLSTATE][$key]:$defaultValue;
4794
	}
4795
	protected function setControlState($key,$value,$defaultValue=null)
4796
	{
4797
		if($value===$defaultValue)
4798
			unset($this->_rf[self::RF_CONTROLSTATE][$key]);
4799
		else
4800
			$this->_rf[self::RF_CONTROLSTATE][$key]=$value;
4801
	}
4802
	protected function clearControlState($key)
4803
	{
4804
		unset($this->_rf[self::RF_CONTROLSTATE][$key]);
4805
	}
4806
	public function trackViewState($enabled)
4807
	{
4808
		$this->_trackViewState=TPropertyValue::ensureBoolean($enabled);
4809
	}
4810
	public function getViewState($key,$defaultValue=null)
4811
	{
4812
		if(isset($this->_viewState[$key]))
4813
			return $this->_viewState[$key]!==null?$this->_viewState[$key]:$defaultValue;
4814
		else if(isset($this->_tempState[$key]))
4815
		{
4816
			if(is_object($this->_tempState[$key]) && $this->_trackViewState)
4817
				$this->_viewState[$key]=$this->_tempState[$key];
4818
			return $this->_tempState[$key];
4819
		}
4820
		else
4821
			return $defaultValue;
4822
	}
4823
	public function setViewState($key,$value,$defaultValue=null)
4824
	{
4825
		if($this->_trackViewState)
4826
		{
4827
			unset($this->_tempState[$key]);
4828
			if($value===$defaultValue)
4829
				unset($this->_viewState[$key]);
4830
			else
4831
				$this->_viewState[$key]=$value;
4832
		}
4833
		else
4834
		{
4835
			unset($this->_viewState[$key]);
4836
			if($value===$defaultValue)
4837
				unset($this->_tempState[$key]);
4838
			else
4839
				$this->_tempState[$key]=$value;
4840
		}
4841
	}
4842
	public function clearViewState($key)
4843
	{
4844
		unset($this->_viewState[$key]);
4845
		unset($this->_tempState[$key]);
4846
	}
4847
	public function bindProperty($name,$expression)
4848
	{
4849
		$this->_rf[self::RF_DATA_BINDINGS][$name]=$expression;
4850
	}
4851
	public function unbindProperty($name)
4852
	{
4853
		unset($this->_rf[self::RF_DATA_BINDINGS][$name]);
4854
	}
4855
	public function autoBindProperty($name,$expression)
4856
	{
4857
		$this->_rf[self::RF_AUTO_BINDINGS][$name]=$expression;
4858
	}
4859
	public function dataBind()
4860
	{
4861
		$this->dataBindProperties();
4862
		$this->onDataBinding(null);
4863
		$this->dataBindChildren();
4864
	}
4865
	protected function dataBindProperties()
4866
	{
4867
		if(isset($this->_rf[self::RF_DATA_BINDINGS]))
4868
		{
4869
			if(($context=$this->getTemplateControl())===null)
4870
				$context=$this;
4871
			foreach($this->_rf[self::RF_DATA_BINDINGS] as $property=>$expression)
4872
				$this->setSubProperty($property,$context->evaluateExpression($expression));
4873
		}
4874
	}
4875
	protected function autoDataBindProperties()
4876
	{
4877
		if(isset($this->_rf[self::RF_AUTO_BINDINGS]))
4878
		{
4879
			if(($context=$this->getTemplateControl())===null)
4880
				$context=$this;
4881
			foreach($this->_rf[self::RF_AUTO_BINDINGS] as $property=>$expression)
4882
				$this->setSubProperty($property,$context->evaluateExpression($expression));
4883
		}
4884
	}
4885
	protected function dataBindChildren()
4886
	{
4887
		if(isset($this->_rf[self::RF_CONTROLS]))
4888
		{
4889
			foreach($this->_rf[self::RF_CONTROLS] as $control)
4890
				if($control instanceof IBindable)
4891
					$control->dataBind();
4892
		}
4893
	}
4894
	final protected function getChildControlsCreated()
4895
	{
4896
		return ($this->_flags & self::IS_CHILD_CREATED)!==0;
4897
	}
4898
	final protected function setChildControlsCreated($value)
4899
	{
4900
		if($value)
4901
			$this->_flags |= self::IS_CHILD_CREATED;
4902
		else
4903
		{
4904
			if($this->getHasControls() && ($this->_flags & self::IS_CHILD_CREATED))
4905
				$this->getControls()->clear();
4906
			$this->_flags &= ~self::IS_CHILD_CREATED;
4907
		}
4908
	}
4909
	public function ensureChildControls()
4910
	{
4911
		if(!($this->_flags & self::IS_CHILD_CREATED) && !($this->_flags & self::IS_CREATING_CHILD))
4912
		{
4913
			try
4914
			{
4915
				$this->_flags |= self::IS_CREATING_CHILD;
4916
				if(isset($this->_rf[self::RF_ADAPTER]))
4917
					$this->_rf[self::RF_ADAPTER]->createChildControls();
4918
				else
4919
					$this->createChildControls();
4920
				$this->_flags &= ~self::IS_CREATING_CHILD;
4921
				$this->_flags |= self::IS_CHILD_CREATED;
4922
			}
4923
			catch(Exception $e)
4924
			{
4925
				$this->_flags &= ~self::IS_CREATING_CHILD;
4926
				$this->_flags |= self::IS_CHILD_CREATED;
4927
				throw $e;
4928
			}
4929
		}
4930
	}
4931
	public function createChildControls()
4932
	{
4933
	}
4934
	public function findControl($id)
4935
	{
4936
		$id=strtr($id,'.',self::ID_SEPARATOR);
4937
		$container=($this instanceof INamingContainer)?$this:$this->getNamingContainer();
4938
		if(!$container || !$container->getHasControls())
4939
			return null;
4940
		if(!isset($container->_rf[self::RF_NAMED_CONTROLS]))
4941
		{
4942
			$container->_rf[self::RF_NAMED_CONTROLS]=array();
4943
			$container->fillNameTable($container,$container->_rf[self::RF_CONTROLS]);
4944
		}
4945
		if(($pos=strpos($id,self::ID_SEPARATOR))===false)
4946
			return isset($container->_rf[self::RF_NAMED_CONTROLS][$id])?$container->_rf[self::RF_NAMED_CONTROLS][$id]:null;
4947
		else
4948
		{
4949
			$cid=substr($id,0,$pos);
4950
			$sid=substr($id,$pos+1);
4951
			if(isset($container->_rf[self::RF_NAMED_CONTROLS][$cid]))
4952
				return $container->_rf[self::RF_NAMED_CONTROLS][$cid]->findControl($sid);
4953
			else
4954
				return null;
4955
		}
4956
	}
4957
	public function findControlsByType($type,$strict=true)
4958
	{
4959
		$controls=array();
4960
		if($this->getHasControls())
4961
		{
4962
			foreach($this->_rf[self::RF_CONTROLS] as $control)
4963
			{
4964
				if(is_object($control) && (get_class($control)===$type || (!$strict && ($control instanceof $type))))
4965
					$controls[]=$control;
4966
				if(($control instanceof TControl) && $control->getHasControls())
4967
					$controls=array_merge($controls,$control->findControlsByType($type,$strict));
4968
			}
4969
		}
4970
		return $controls;
4971
	}
4972
	public function findControlsByID($id)
4973
	{
4974
		$controls=array();
4975
		if($this->getHasControls())
4976
		{
4977
			foreach($this->_rf[self::RF_CONTROLS] as $control)
4978
			{
4979
				if($control instanceof TControl)
4980
				{
4981
					if($control->_id===$id)
4982
						$controls[]=$control;
4983
					$controls=array_merge($controls,$control->findControlsByID($id));
4984
				}
4985
			}
4986
		}
4987
		return $controls;
4988
	}
4989
	public function clearNamingContainer()
4990
	{
4991
		unset($this->_rf[self::RF_NAMED_CONTROLS_ID]);
4992
		$this->clearNameTable();
4993
	}
4994
	public function registerObject($name,$object)
4995
	{
4996
		if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
4997
			throw new TInvalidOperationException('control_object_reregistered',$name);
4998
		$this->_rf[self::RF_NAMED_OBJECTS][$name]=$object;
4999
	}
5000
	public function unregisterObject($name)
5001
	{
5002
		unset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
5003
	}
5004
	public function isObjectRegistered($name)
5005
	{
5006
		return isset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
5007
	}
5008
	public function getHasChildInitialized()
5009
	{
5010
		return $this->getControlStage() >= self::CS_CHILD_INITIALIZED;
5011
	}
5012
	public function getHasInitialized()
5013
	{
5014
		return $this->getControlStage() >= self::CS_INITIALIZED;
5015
	}
5016
	public function getHasLoadedPostData()
5017
	{
5018
		return $this->getControlStage() >= self::CS_STATE_LOADED;
5019
	}
5020
	public function getHasLoaded()
5021
	{
5022
		return $this->getControlStage() >= self::CS_LOADED;
5023
	}
5024
	public function getHasPreRendered()
5025
	{
5026
		return $this->getControlStage() >= self::CS_PRERENDERED;
5027
	}
5028
	public function getRegisteredObject($name)
5029
	{
5030
		return isset($this->_rf[self::RF_NAMED_OBJECTS][$name])?$this->_rf[self::RF_NAMED_OBJECTS][$name]:null;
5031
	}
5032
	public function getAllowChildControls()
5033
	{
5034
		return true;
5035
	}
5036
	public function addParsedObject($object)
5037
	{
5038
		$this->getControls()->add($object);
5039
	}
5040
	final protected function clearChildState()
5041
	{
5042
		unset($this->_rf[self::RF_CHILD_STATE]);
5043
	}
5044
	final protected function isDescendentOf($ancestor)
5045
	{
5046
		$control=$this;
5047
		while($control!==$ancestor && $control->_parent)
5048
			$control=$control->_parent;
5049
		return $control===$ancestor;
5050
	}
5051
	public function addedControl($control)
5052
	{
5053
		if($control->_parent)
5054
			$control->_parent->getControls()->remove($control);
5055
		$control->_parent=$this;
5056
		$control->_page=$this->getPage();
5057
		$namingContainer=($this instanceof INamingContainer)?$this:$this->_namingContainer;
5058
		if($namingContainer)
5059
		{
5060
			$control->_namingContainer=$namingContainer;
5061
			if($control->_id==='')
5062
				$control->generateAutomaticID();
5063
			else
5064
				$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...
5065
			$control->clearCachedUniqueID($control instanceof INamingContainer);
5066
		}
5067
		if($this->_stage>=self::CS_CHILD_INITIALIZED)
5068
		{
5069
			$control->initRecursive($namingContainer);
5070
			if($this->_stage>=self::CS_STATE_LOADED)
5071
			{
5072
				if(isset($this->_rf[self::RF_CHILD_STATE][$control->_id]))
5073
				{
5074
					$state=$this->_rf[self::RF_CHILD_STATE][$control->_id];
5075
					unset($this->_rf[self::RF_CHILD_STATE][$control->_id]);
5076
				}
5077
				else
5078
					$state=null;
5079
				$control->loadStateRecursive($state,!($this->_flags & self::IS_DISABLE_VIEWSTATE));
5080
				if($this->_stage>=self::CS_LOADED)
5081
				{
5082
					$control->loadRecursive();
5083
					if($this->_stage>=self::CS_PRERENDERED)
5084
						$control->preRenderRecursive();
5085
				}
5086
			}
5087
		}
5088
	}
5089
	public function removedControl($control)
5090
	{
5091
		if($this->_namingContainer)
5092
			$this->_namingContainer->clearNameTable();
5093
		$control->unloadRecursive();
5094
		$control->_parent=null;
5095
		$control->_page=null;
5096
		$control->_namingContainer=null;
5097
		$control->_tplControl=null;
5098
				if(!($control->_flags & self::IS_ID_SET))
5099
			$control->_id='';
5100
		else
5101
			unset($this->_rf[self::RF_NAMED_OBJECTS][$control->_id]);
5102
		$control->clearCachedUniqueID(true);
5103
	}
5104
	protected function initRecursive($namingContainer=null)
5105
	{
5106
		$this->ensureChildControls();
5107
		if($this->getHasControls())
5108
		{
5109
			if($this instanceof INamingContainer)
5110
				$namingContainer=$this;
5111
			$page=$this->getPage();
5112
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5113
			{
5114
				if($control instanceof TControl)
5115
				{
5116
					$control->_namingContainer=$namingContainer;
5117
					$control->_page=$page;
5118
					if($control->_id==='' && $namingContainer)
5119
						$control->generateAutomaticID();
5120
					$control->initRecursive($namingContainer);
5121
				}
5122
			}
5123
		}
5124
		if($this->_stage<self::CS_INITIALIZED)
5125
		{
5126
			$this->_stage=self::CS_CHILD_INITIALIZED;
5127
			if(($page=$this->getPage()) && $this->getEnableTheming() && !($this->_flags & self::IS_SKIN_APPLIED))
5128
			{
5129
				$page->applyControlSkin($this);
5130
				$this->_flags |= self::IS_SKIN_APPLIED;
5131
			}
5132
			if(isset($this->_rf[self::RF_ADAPTER]))
5133
				$this->_rf[self::RF_ADAPTER]->onInit(null);
5134
			else
5135
				$this->onInit(null);
5136
			$this->_stage=self::CS_INITIALIZED;
5137
		}
5138
	}
5139
	protected function loadRecursive()
5140
	{
5141
		if($this->_stage<self::CS_LOADED)
5142
		{
5143
			if(isset($this->_rf[self::RF_ADAPTER]))
5144
				$this->_rf[self::RF_ADAPTER]->onLoad(null);
5145
			else
5146
				$this->onLoad(null);
5147
		}
5148
		if($this->getHasControls())
5149
		{
5150
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5151
			{
5152
				if($control instanceof TControl)
5153
					$control->loadRecursive();
5154
			}
5155
		}
5156
		if($this->_stage<self::CS_LOADED)
5157
			$this->_stage=self::CS_LOADED;
5158
	}
5159
	protected function preRenderRecursive()
5160
	{
5161
		$this->autoDataBindProperties();
5162
		if($this->getVisible(false))
5163
		{
5164
			if(isset($this->_rf[self::RF_ADAPTER]))
5165
				$this->_rf[self::RF_ADAPTER]->onPreRender(null);
5166
			else
5167
				$this->onPreRender(null);
5168
			if($this->getHasControls())
5169
			{
5170
				foreach($this->_rf[self::RF_CONTROLS] as $control)
5171
				{
5172
					if($control instanceof TControl)
5173
						$control->preRenderRecursive();
5174
					else if($control instanceof TCompositeLiteral)
5175
						$control->evaluateDynamicContent();
5176
				}
5177
			}
5178
		}
5179
		$this->_stage=self::CS_PRERENDERED;
5180
	}
5181
	protected function unloadRecursive()
5182
	{
5183
		if(!($this->_flags & self::IS_ID_SET))
5184
			$this->_id='';
5185
		if($this->getHasControls())
5186
		{
5187
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5188
				if($control instanceof TControl)
5189
					$control->unloadRecursive();
5190
		}
5191
		if(isset($this->_rf[self::RF_ADAPTER]))
5192
			$this->_rf[self::RF_ADAPTER]->onUnload(null);
5193
		else
5194
			$this->onUnload(null);
5195
	}
5196
	public function onInit($param)
5197
	{
5198
		$this->raiseEvent('OnInit',$this,$param);
5199
	}
5200
	public function onLoad($param)
5201
	{
5202
		$this->raiseEvent('OnLoad',$this,$param);
5203
	}
5204
	public function onDataBinding($param)
5205
	{
5206
		$this->raiseEvent('OnDataBinding',$this,$param);
5207
	}
5208
	public function onUnload($param)
5209
	{
5210
		$this->raiseEvent('OnUnload',$this,$param);
5211
	}
5212
	public function onPreRender($param)
5213
	{
5214
		$this->raiseEvent('OnPreRender',$this,$param);
5215
	}
5216
	protected function raiseBubbleEvent($sender,$param)
5217
	{
5218
		$control=$this;
5219
		while($control=$control->_parent)
5220
		{
5221
			if($control->bubbleEvent($sender,$param))
5222
				break;
5223
		}
5224
	}
5225
	public function bubbleEvent($sender,$param)
5226
	{
5227
		return false;
5228
	}
5229
	public function broadcastEvent($name,$sender,$param)
5230
	{
5231
		$rootControl=(($page=$this->getPage())===null)?$this:$page;
5232
		$rootControl->broadcastEventInternal($name,$sender,new TBroadcastEventParameter($name,$param));
5233
	}
5234
	private function broadcastEventInternal($name,$sender,$param)
5235
	{
5236
		if($this->hasEvent($name))
5237
			$this->raiseEvent($name,$sender,$param->getParameter());
5238
		if($this instanceof IBroadcastEventReceiver)
5239
			$this->broadcastEventReceived($sender,$param);
5240
		if($this->getHasControls())
5241
		{
5242
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5243
			{
5244
				if($control instanceof TControl)
5245
					$control->broadcastEventInternal($name,$sender,$param);
5246
			}
5247
		}
5248
	}
5249
	protected function traverseChildControls($param,$preCallback=null,$postCallback=null)
5250
	{
5251
		if($preCallback!==null)
5252
			call_user_func($preCallback,$this,$param);
5253
		if($this->getHasControls())
5254
		{
5255
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5256
			{
5257
				if($control instanceof TControl)
5258
				{
5259
					$control->traverseChildControls($param,$preCallback,$postCallback);
5260
				}
5261
			}
5262
		}
5263
		if($postCallback!==null)
5264
			call_user_func($postCallback,$this,$param);
5265
	}
5266
	public function renderControl($writer)
5267
	{
5268
		if($this instanceof IActiveControl || $this->getVisible(false))
5269
		{
5270
			if(isset($this->_rf[self::RF_ADAPTER]))
5271
				$this->_rf[self::RF_ADAPTER]->render($writer);
5272
			else
5273
				$this->render($writer);
5274
		}
5275
	}
5276
	public function render($writer)
5277
	{
5278
		$this->renderChildren($writer);
5279
	}
5280
	public function renderChildren($writer)
5281
	{
5282
		if($this->getHasControls())
5283
		{
5284
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5285
			{
5286
				if(is_string($control))
5287
					$writer->write($control);
5288
				else if($control instanceof TControl)
5289
					$control->renderControl($writer);
5290
				else if($control instanceof IRenderable)
5291
					$control->render($writer);
5292
			}
5293
		}
5294
	}
5295
	public function saveState()
5296
	{
5297
	}
5298
	public function loadState()
5299
	{
5300
	}
5301
	protected function loadStateRecursive(&$state,$needViewState=true)
5302
	{
5303
		if(is_array($state))
5304
		{
5305
									$needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
5306
			if(isset($state[1]))
5307
			{
5308
				$this->_rf[self::RF_CONTROLSTATE]=&$state[1];
5309
				unset($state[1]);
5310
			}
5311
			else
5312
				unset($this->_rf[self::RF_CONTROLSTATE]);
5313
			if($needViewState)
5314
			{
5315
				if(isset($state[0]))
5316
					$this->_viewState=&$state[0];
5317
				else
5318
					$this->_viewState=array();
5319
			}
5320
			unset($state[0]);
5321
			if($this->getHasControls())
5322
			{
5323
				foreach($this->_rf[self::RF_CONTROLS] as $control)
5324
				{
5325
					if($control instanceof TControl)
5326
					{
5327
						if(isset($state[$control->_id]))
5328
						{
5329
							$control->loadStateRecursive($state[$control->_id],$needViewState);
5330
							unset($state[$control->_id]);
5331
						}
5332
					}
5333
				}
5334
			}
5335
			if(!empty($state))
5336
				$this->_rf[self::RF_CHILD_STATE]=&$state;
5337
		}
5338
		$this->_stage=self::CS_STATE_LOADED;
5339
		if(isset($this->_rf[self::RF_ADAPTER]))
5340
			$this->_rf[self::RF_ADAPTER]->loadState();
5341
		else
5342
			$this->loadState();
5343
	}
5344
	protected function &saveStateRecursive($needViewState=true)
5345
	{
5346
		if(isset($this->_rf[self::RF_ADAPTER]))
5347
			$this->_rf[self::RF_ADAPTER]->saveState();
5348
		else
5349
			$this->saveState();
5350
		$needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
5351
		$state=array();
5352
		if($this->getHasControls())
5353
		{
5354
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5355
			{
5356
				if($control instanceof TControl)
5357
				{
5358
					if(count($tmp = &$control->saveStateRecursive($needViewState)))
5359
						$state[$control->_id]=$tmp;
5360
				}
5361
			}
5362
		}
5363
		if($needViewState && !empty($this->_viewState))
5364
			$state[0]=&$this->_viewState;
5365
		if(isset($this->_rf[self::RF_CONTROLSTATE]))
5366
			$state[1]=&$this->_rf[self::RF_CONTROLSTATE];
5367
		return $state;
5368
	}
5369
	public function applyStyleSheetSkin($page)
5370
	{
5371
		if($page && !($this->_flags & self::IS_STYLESHEET_APPLIED))
5372
		{
5373
			$page->applyControlStyleSheet($this);
5374
			$this->_flags |= self::IS_STYLESHEET_APPLIED;
5375
		}
5376
		else if($this->_flags & self::IS_STYLESHEET_APPLIED)
5377
			throw new TInvalidOperationException('control_stylesheet_applied',get_class($this));
5378
	}
5379
	private function clearCachedUniqueID($recursive)
5380
	{
5381
		if($recursive && $this->_uid!==null && isset($this->_rf[self::RF_CONTROLS]))
5382
		{
5383
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5384
				if($control instanceof TControl)
5385
					$control->clearCachedUniqueID($recursive);
5386
		}
5387
		$this->_uid=null;
5388
	}
5389
	private function generateAutomaticID()
5390
	{
5391
		$this->_flags &= ~self::IS_ID_SET;
5392
		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...
5393
			$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...
5394
		$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...
5395
		$this->_id=self::AUTOMATIC_ID_PREFIX . $id;
5396
		$this->_namingContainer->clearNameTable();
5397
	}
5398
	private function clearNameTable()
5399
	{
5400
		unset($this->_rf[self::RF_NAMED_CONTROLS]);
5401
	}
5402
	private function fillNameTable($container,$controls)
5403
	{
5404
		foreach($controls as $control)
5405
		{
5406
			if($control instanceof TControl)
5407
			{
5408
				if($control->_id!=='')
5409
				{
5410
					if(isset($container->_rf[self::RF_NAMED_CONTROLS][$control->_id]))
5411
						throw new TInvalidDataValueException('control_id_nonunique',get_class($control),$control->_id);
5412
					else
5413
						$container->_rf[self::RF_NAMED_CONTROLS][$control->_id]=$control;
5414
				}
5415
				if(!($control instanceof INamingContainer) && $control->getHasControls())
5416
					$this->fillNameTable($container,$control->_rf[self::RF_CONTROLS]);
5417
			}
5418
		}
5419
	}
5420
}
5421
class TControlCollection extends TList
5422
{
5423
	private $_o;
5424
	public function __construct(TControl $owner,$readOnly=false)
5425
	{
5426
		$this->_o=$owner;
5427
		parent::__construct(null,$readOnly);
5428
	}
5429
	protected function getOwner()
5430
	{
5431
		return $this->_o;
5432
	}
5433
	public function insertAt($index,$item)
5434
	{
5435
		if($item instanceof TControl)
5436
		{
5437
			parent::insertAt($index,$item);
5438
			$this->_o->addedControl($item);
5439
		}
5440
		else if(is_string($item) || ($item instanceof IRenderable))
5441
			parent::insertAt($index,$item);
5442
		else
5443
			throw new TInvalidDataTypeException('controlcollection_control_required');
5444
	}
5445
	public function removeAt($index)
5446
	{
5447
		$item=parent::removeAt($index);
5448
		if($item instanceof TControl)
5449
			$this->_o->removedControl($item);
5450
		return $item;
5451
	}
5452
	public function clear()
5453
	{
5454
		parent::clear();
5455
		if($this->_o instanceof INamingContainer)
5456
			$this->_o->clearNamingContainer();
5457
	}
5458
}
5459
class TEmptyControlCollection extends TControlCollection
5460
{
5461
	public function __construct(TControl $owner)
5462
	{
5463
		parent::__construct($owner,true);
5464
	}
5465
	public function insertAt($index,$item)
5466
	{
5467
		if(!is_string($item))  			parent::insertAt($index,$item);  	}
5468
}
5469
interface INamingContainer
5470
{
5471
}
5472
interface IPostBackEventHandler
5473
{
5474
	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...
5475
}
5476
interface IPostBackDataHandler
5477
{
5478
	public function loadPostData($key,$values);
5479
	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...
5480
	public function getDataChanged();
5481
}
5482
interface IValidator
5483
{
5484
	public function validate();
5485
	public function getIsValid();
5486
	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...
5487
	public function getErrorMessage();
5488
	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...
5489
}
5490
interface IValidatable
5491
{
5492
	public function getValidationPropertyValue();
5493
	public function getIsValid();
5494
	public function setIsValid($value);
5495
}
5496
interface IBroadcastEventReceiver
5497
{
5498
	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...
5499
}
5500
interface ITheme
5501
{
5502
	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...
5503
}
5504
interface ITemplate
5505
{
5506
	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...
5507
}
5508
interface IButtonControl
5509
{
5510
	public function getText();
5511
	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...
5512
	public function getCausesValidation();
5513
	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...
5514
	public function getCommandName();
5515
	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...
5516
	public function getCommandParameter();
5517
	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...
5518
	public function getValidationGroup();
5519
	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...
5520
	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...
5521
	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...
5522
	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...
5523
	public function getIsDefaultButton();
5524
}
5525
interface ISurroundable
5526
{
5527
	public function getSurroundingTag();
5528
	public function getSurroundingTagID();
5529
}
5530
class TBroadcastEventParameter extends TEventParameter
5531
{
5532
	private $_name;
5533
	private $_param;
5534
	public function __construct($name='',$parameter=null)
5535
	{
5536
		$this->_name=$name;
5537
		$this->_param=$parameter;
5538
	}
5539
	public function getName()
5540
	{
5541
		return $this->_name;
5542
	}
5543
	public function setName($value)
5544
	{
5545
		$this->_name=$value;
5546
	}
5547
	public function getParameter()
5548
	{
5549
		return $this->_param;
5550
	}
5551
	public function setParameter($value)
5552
	{
5553
		$this->_param=$value;
5554
	}
5555
}
5556
class TCommandEventParameter extends TEventParameter
5557
{
5558
	private $_name;
5559
	private $_param;
5560
	public function __construct($name='',$parameter='')
5561
	{
5562
		$this->_name=$name;
5563
		$this->_param=$parameter;
5564
	}
5565
	public function getCommandName()
5566
	{
5567
		return $this->_name;
5568
	}
5569
	public function getCommandParameter()
5570
	{
5571
		return $this->_param;
5572
	}
5573
}
5574
class TCompositeLiteral extends TComponent implements IRenderable, IBindable
5575
{
5576
	const TYPE_EXPRESSION=0;
5577
	const TYPE_STATEMENTS=1;
5578
	const TYPE_DATABINDING=2;
5579
	private $_container=null;
5580
	private $_items=array();
5581
	private $_expressions=array();
5582
	private $_statements=array();
5583
	private $_bindings=array();
5584
	public function __construct($items)
5585
	{
5586
		$this->_items=array();
5587
		$this->_expressions=array();
5588
		$this->_statements=array();
5589
		foreach($items as $id=>$item)
5590
		{
5591
			if(is_array($item))
5592
			{
5593
				if($item[0]===self::TYPE_EXPRESSION)
5594
					$this->_expressions[$id]=$item[1];
5595
				else if($item[0]===self::TYPE_STATEMENTS)
5596
					$this->_statements[$id]=$item[1];
5597
				else if($item[0]===self::TYPE_DATABINDING)
5598
					$this->_bindings[$id]=$item[1];
5599
				$this->_items[$id]='';
5600
			}
5601
			else
5602
				$this->_items[$id]=$item;
5603
		}
5604
	}
5605
	public function getContainer()
5606
	{
5607
		return $this->_container;
5608
	}
5609
	public function setContainer(TComponent $value)
5610
	{
5611
		$this->_container=$value;
5612
	}
5613
	public function evaluateDynamicContent()
5614
	{
5615
		$context=$this->_container===null?$this:$this->_container;
5616
		foreach($this->_expressions as $id=>$expression)
5617
			$this->_items[$id]=$context->evaluateExpression($expression);
5618
		foreach($this->_statements as $id=>$statement)
5619
			$this->_items[$id]=$context->evaluateStatements($statement);
5620
	}
5621
	public function dataBind()
5622
	{
5623
		$context=$this->_container===null?$this:$this->_container;
5624
		foreach($this->_bindings as $id=>$binding)
5625
			$this->_items[$id]=$context->evaluateExpression($binding);
5626
	}
5627
	public function render($writer)
5628
	{
5629
		$writer->write(implode('',$this->_items));
5630
	}
5631
}
5632
class TFont extends TComponent
5633
{
5634
	const IS_BOLD=0x01;
5635
	const IS_ITALIC=0x02;
5636
	const IS_OVERLINE=0x04;
5637
	const IS_STRIKEOUT=0x08;
5638
	const IS_UNDERLINE=0x10;
5639
	const IS_SET_BOLD=0x01000;
5640
	const IS_SET_ITALIC=0x02000;
5641
	const IS_SET_OVERLINE=0x04000;
5642
	const IS_SET_STRIKEOUT=0x08000;
5643
	const IS_SET_UNDERLINE=0x10000;
5644
	const IS_SET_SIZE=0x20000;
5645
	const IS_SET_NAME=0x40000;
5646
	private $_flags=0;
5647
	private $_name='';
5648
	private $_size='';
5649
	protected function _getZappableSleepProps(&$exprops)
5650
	{
5651
		parent::_getZappableSleepProps($exprops);
5652
		if ($this->_flags===0)
5653
			$exprops[] = "\0TFont\0_flags";
5654
		if ($this->_name==='')
5655
			$exprops[] = "\0TFont\0_name";
5656
		if ($this->_size==='')
5657
			$exprops[] = "\0TFont\0_size";
5658
	}
5659
	public function getBold()
5660
	{
5661
		return ($this->_flags & self::IS_BOLD)!==0;
5662
	}
5663
	public function setBold($value)
5664
	{
5665
		$this->_flags |= self::IS_SET_BOLD;
5666
		if(TPropertyValue::ensureBoolean($value))
5667
			$this->_flags |= self::IS_BOLD;
5668
		else
5669
			$this->_flags &= ~self::IS_BOLD;
5670
	}
5671
	public function getItalic()
5672
	{
5673
		return ($this->_flags & self::IS_ITALIC)!==0;
5674
	}
5675
	public function setItalic($value)
5676
	{
5677
		$this->_flags |= self::IS_SET_ITALIC;
5678
		if(TPropertyValue::ensureBoolean($value))
5679
			$this->_flags |= self::IS_ITALIC;
5680
		else
5681
			$this->_flags &= ~self::IS_ITALIC;
5682
	}
5683
	public function getOverline()
5684
	{
5685
		return ($this->_flags & self::IS_OVERLINE)!==0;
5686
	}
5687
	public function setOverline($value)
5688
	{
5689
		$this->_flags |= self::IS_SET_OVERLINE;
5690
		if(TPropertyValue::ensureBoolean($value))
5691
			$this->_flags |= self::IS_OVERLINE;
5692
		else
5693
			$this->_flags &= ~self::IS_OVERLINE;
5694
	}
5695
	public function getSize()
5696
	{
5697
		return $this->_size;
5698
	}
5699
	public function setSize($value)
5700
	{
5701
		$this->_flags |= self::IS_SET_SIZE;
5702
		$this->_size=$value;
5703
	}
5704
	public function getStrikeout()
5705
	{
5706
		return ($this->_flags & self::IS_STRIKEOUT)!==0;
5707
	}
5708
	public function setStrikeout($value)
5709
	{
5710
		$this->_flags |= self::IS_SET_STRIKEOUT;
5711
		if(TPropertyValue::ensureBoolean($value))
5712
			$this->_flags |= self::IS_STRIKEOUT;
5713
		else
5714
			$this->_flags &= ~self::IS_STRIKEOUT;
5715
	}
5716
	public function getUnderline()
5717
	{
5718
		return ($this->_flags & self::IS_UNDERLINE)!==0;
5719
	}
5720
	public function setUnderline($value)
5721
	{
5722
		$this->_flags |= self::IS_SET_UNDERLINE;
5723
		if(TPropertyValue::ensureBoolean($value))
5724
			$this->_flags |= self::IS_UNDERLINE;
5725
		else
5726
			$this->_flags &= ~self::IS_UNDERLINE;
5727
	}
5728
	public function getName()
5729
	{
5730
		return $this->_name;
5731
	}
5732
	public function setName($value)
5733
	{
5734
		$this->_flags |= self::IS_SET_NAME;
5735
		$this->_name=$value;
5736
	}
5737
	public function getIsEmpty()
5738
	{
5739
		return !$this->_flags;
5740
	}
5741
	public function reset()
5742
	{
5743
		$this->_flags=0;
5744
		$this->_name='';
5745
		$this->_size='';
5746
	}
5747
	public function mergeWith($font)
5748
	{
5749
		if($font===null || $font->_flags===0)
5750
			return;
5751
		if(!($this->_flags & self::IS_SET_BOLD) && ($font->_flags & self::IS_SET_BOLD))
5752
			$this->setBold($font->getBold());
5753
		if(!($this->_flags & self::IS_SET_ITALIC) && ($font->_flags & self::IS_SET_ITALIC))
5754
			$this->setItalic($font->getItalic());
5755
		if(!($this->_flags & self::IS_SET_OVERLINE) && ($font->_flags & self::IS_SET_OVERLINE))
5756
			$this->setOverline($font->getOverline());
5757
		if(!($this->_flags & self::IS_SET_STRIKEOUT) && ($font->_flags & self::IS_SET_STRIKEOUT))
5758
			$this->setStrikeout($font->getStrikeout());
5759
		if(!($this->_flags & self::IS_SET_UNDERLINE) && ($font->_flags & self::IS_SET_UNDERLINE))
5760
			$this->setUnderline($font->getUnderline());
5761
		if(!($this->_flags & self::IS_SET_SIZE) && ($font->_flags & self::IS_SET_SIZE))
5762
			$this->setSize($font->getSize());
5763
		if(!($this->_flags & self::IS_SET_NAME) && ($font->_flags & self::IS_SET_NAME))
5764
			$this->setName($font->getName());
5765
	}
5766
	public function copyFrom($font)
5767
	{
5768
		if($font===null || $font->_flags===0)
5769
			return;
5770
		if($font->_flags & self::IS_SET_BOLD)
5771
			$this->setBold($font->getBold());
5772
		if($font->_flags & self::IS_SET_ITALIC)
5773
			$this->setItalic($font->getItalic());
5774
		if($font->_flags & self::IS_SET_OVERLINE)
5775
			$this->setOverline($font->getOverline());
5776
		if($font->_flags & self::IS_SET_STRIKEOUT)
5777
			$this->setStrikeout($font->getStrikeout());
5778
		if($font->_flags & self::IS_SET_UNDERLINE)
5779
			$this->setUnderline($font->getUnderline());
5780
		if($font->_flags & self::IS_SET_SIZE)
5781
			$this->setSize($font->getSize());
5782
		if($font->_flags & self::IS_SET_NAME)
5783
			$this->setName($font->getName());
5784
	}
5785
	public function toString()
5786
	{
5787
		if($this->_flags===0)
5788
			return '';
5789
		$str='';
5790
		if($this->_flags & self::IS_SET_BOLD)
5791
			$str.='font-weight:'.(($this->_flags & self::IS_BOLD)?'bold;':'normal;');
5792
		if($this->_flags & self::IS_SET_ITALIC)
5793
			$str.='font-style:'.(($this->_flags & self::IS_ITALIC)?'italic;':'normal;');
5794
		$textDec='';
5795
		if($this->_flags & self::IS_UNDERLINE)
5796
			$textDec.='underline';
5797
		if($this->_flags & self::IS_OVERLINE)
5798
			$textDec.=' overline';
5799
		if($this->_flags & self::IS_STRIKEOUT)
5800
			$textDec.=' line-through';
5801
		$textDec=ltrim($textDec);
5802
		if($textDec!=='')
5803
			$str.='text-decoration:'.$textDec.';';
5804
		if($this->_size!=='')
5805
			$str.='font-size:'.$this->_size.';';
5806
		if($this->_name!=='')
5807
			$str.='font-family:'.$this->_name.';';
5808
		return $str;
5809
	}
5810
	public function addAttributesToRender($writer)
5811
	{
5812
		if($this->_flags===0)
5813
			return;
5814
		if($this->_flags & self::IS_SET_BOLD)
5815
			$writer->addStyleAttribute('font-weight',(($this->_flags & self::IS_BOLD)?'bold':'normal'));
5816
		if($this->_flags & self::IS_SET_ITALIC)
5817
			$writer->addStyleAttribute('font-style',(($this->_flags & self::IS_ITALIC)?'italic':'normal'));
5818
		$textDec='';
5819
		if($this->_flags & self::IS_UNDERLINE)
5820
			$textDec.='underline';
5821
		if($this->_flags & self::IS_OVERLINE)
5822
			$textDec.=' overline';
5823
		if($this->_flags & self::IS_STRIKEOUT)
5824
			$textDec.=' line-through';
5825
		$textDec=ltrim($textDec);
5826
		if($textDec!=='')
5827
			$writer->addStyleAttribute('text-decoration',$textDec);
5828
		if($this->_size!=='')
5829
			$writer->addStyleAttribute('font-size',$this->_size);
5830
		if($this->_name!=='')
5831
			$writer->addStyleAttribute('font-family',$this->_name);
5832
	}
5833
}
5834
class TStyle extends TComponent
5835
{
5836
	private $_fields=array();
5837
	private $_font=null;
5838
	private $_class=null;
5839
	private $_customStyle=null;
5840
	private $_displayStyle='Fixed';
5841
	protected function _getZappableSleepProps(&$exprops)
5842
	{
5843
		parent::_getZappableSleepProps($exprops);
5844
		if ($this->_fields===array())
5845
			$exprops[] = "\0TStyle\0_fields";
5846
		if($this->_font===null)
5847
			$exprops[] = "\0TStyle\0_font";
5848
		if($this->_class===null)
5849
			$exprops[] = "\0TStyle\0_class";
5850
		if ($this->_customStyle===null)
5851
			$exprops[] = "\0TStyle\0_customStyle";
5852
		if ($this->_displayStyle==='Fixed')
5853
			$exprops[] = "\0TStyle\0_displayStyle";
5854
	}
5855
	public function __construct($style=null)
5856
	{
5857
    parent::__construct();
5858
		if($style!==null)
5859
			$this->copyFrom($style);
5860
	}
5861
	public function __clone()
5862
	{
5863
		if($this->_font!==null)
5864
			$this->_font = clone($this->_font);
5865
	}
5866
	public function getBackColor()
5867
	{
5868
		return isset($this->_fields['background-color'])?$this->_fields['background-color']:'';
5869
	}
5870
	public function setBackColor($value)
5871
	{
5872
		if(trim($value)==='')
5873
			unset($this->_fields['background-color']);
5874
		else
5875
			$this->_fields['background-color']=$value;
5876
	}
5877
	public function getBorderColor()
5878
	{
5879
		return isset($this->_fields['border-color'])?$this->_fields['border-color']:'';
5880
	}
5881
	public function setBorderColor($value)
5882
	{
5883
		if(trim($value)==='')
5884
			unset($this->_fields['border-color']);
5885
		else
5886
			$this->_fields['border-color']=$value;
5887
	}
5888
	public function getBorderStyle()
5889
	{
5890
		return isset($this->_fields['border-style'])?$this->_fields['border-style']:'';
5891
	}
5892
	public function setBorderStyle($value)
5893
	{
5894
		if(trim($value)==='')
5895
			unset($this->_fields['border-style']);
5896
		else
5897
			$this->_fields['border-style']=$value;
5898
	}
5899
	public function getBorderWidth()
5900
	{
5901
		return isset($this->_fields['border-width'])?$this->_fields['border-width']:'';
5902
	}
5903
	public function setBorderWidth($value)
5904
	{
5905
		if(trim($value)==='')
5906
			unset($this->_fields['border-width']);
5907
		else
5908
			$this->_fields['border-width']=$value;
5909
	}
5910
	public function getCssClass()
5911
	{
5912
		return $this->_class===null?'':$this->_class;
5913
	}
5914
	public function hasCssClass()
5915
	{
5916
		return ($this->_class!==null);
5917
	}
5918
	public function setCssClass($value)
5919
	{
5920
		$this->_class=$value;
5921
	}
5922
	public function getFont()
5923
	{
5924
		if($this->_font===null)
5925
			$this->_font=new TFont;
5926
		return $this->_font;
5927
	}
5928
	public function hasFont()
5929
	{
5930
		return $this->_font !== null;
5931
	}
5932
	public function setDisplayStyle($value)
5933
	{
5934
		$this->_displayStyle = TPropertyValue::ensureEnum($value, 'TDisplayStyle');
5935
		switch($this->_displayStyle)
5936
		{
5937
			case TDisplayStyle::None:
5938
				$this->_fields['display'] = 'none';
5939
				break;
5940
			case TDisplayStyle::Dynamic:
5941
				$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...
5942
			case TDisplayStyle::Fixed:
5943
				$this->_fields['visibility'] = 'visible';
5944
				break;
5945
			case TDisplayStyle::Hidden:
5946
				$this->_fields['visibility'] = 'hidden';
5947
				break;
5948
		}
5949
	}
5950
	public function getDisplayStyle()
5951
	{
5952
		return $this->_displayStyle;
5953
	}
5954
	public function getForeColor()
5955
	{
5956
		return isset($this->_fields['color'])?$this->_fields['color']:'';
5957
	}
5958
	public function setForeColor($value)
5959
	{
5960
		if(trim($value)==='')
5961
			unset($this->_fields['color']);
5962
		else
5963
			$this->_fields['color']=$value;
5964
	}
5965
	public function getHeight()
5966
	{
5967
		return isset($this->_fields['height'])?$this->_fields['height']:'';
5968
	}
5969
	public function setHeight($value)
5970
	{
5971
		if(trim($value)==='')
5972
			unset($this->_fields['height']);
5973
		else
5974
			$this->_fields['height']=$value;
5975
	}
5976
	public function getCustomStyle()
5977
	{
5978
		return $this->_customStyle===null?'':$this->_customStyle;
5979
	}
5980
	public function setCustomStyle($value)
5981
	{
5982
		$this->_customStyle=$value;
5983
	}
5984
	public function getStyleField($name)
5985
	{
5986
		return isset($this->_fields[$name])?$this->_fields[$name]:'';
5987
	}
5988
	public function setStyleField($name,$value)
5989
	{
5990
		$this->_fields[$name]=$value;
5991
	}
5992
	public function clearStyleField($name)
5993
	{
5994
		unset($this->_fields[$name]);
5995
	}
5996
	public function hasStyleField($name)
5997
	{
5998
		return isset($this->_fields[$name]);
5999
	}
6000
	public function getWidth()
6001
	{
6002
		return isset($this->_fields['width'])?$this->_fields['width']:'';
6003
	}
6004
	public function setWidth($value)
6005
	{
6006
		$this->_fields['width']=$value;
6007
	}
6008
	public function reset()
6009
	{
6010
		$this->_fields=array();
6011
		$this->_font=null;
6012
		$this->_class=null;
6013
		$this->_customStyle=null;
6014
	}
6015
	public function copyFrom($style)
6016
	{
6017
		if($style instanceof TStyle)
6018
		{
6019
			$this->_fields=array_merge($this->_fields,$style->_fields);
6020
			if($style->_class!==null)
6021
				$this->_class=$style->_class;
6022
			if($style->_customStyle!==null)
6023
				$this->_customStyle=$style->_customStyle;
6024
			if($style->_font!==null)
6025
				$this->getFont()->copyFrom($style->_font);
6026
		}
6027
	}
6028
	public function mergeWith($style)
6029
	{
6030
		if($style instanceof TStyle)
6031
		{
6032
			$this->_fields=array_merge($style->_fields,$this->_fields);
6033
			if($this->_class===null)
6034
				$this->_class=$style->_class;
6035
			if($this->_customStyle===null)
6036
				$this->_customStyle=$style->_customStyle;
6037
			if($style->_font!==null)
6038
				$this->getFont()->mergeWith($style->_font);
6039
		}
6040
	}
6041
	public function addAttributesToRender($writer)
6042
	{
6043
		if($this->_customStyle!==null)
6044
		{
6045
			foreach(explode(';',$this->_customStyle) as $style)
6046
			{
6047
				$arr=explode(':',$style,2);
6048
				if(isset($arr[1]) && trim($arr[0])!=='')
6049
					$writer->addStyleAttribute(trim($arr[0]),trim($arr[1]));
6050
			}
6051
		}
6052
		$writer->addStyleAttributes($this->_fields);
6053
		if($this->_font!==null)
6054
			$this->_font->addAttributesToRender($writer);
6055
		if($this->_class!==null)
6056
			$writer->addAttribute('class',$this->_class);
6057
	}
6058
	public function getStyleFields()
6059
	{
6060
		return $this->_fields;
6061
	}
6062
}
6063
class TDisplayStyle extends TEnumerable
6064
{
6065
	const None='None';
6066
	const Dynamic='Dynamic';
6067
	const Fixed='Fixed';
6068
	const Hidden='Hidden';
6069
}
6070
class TTableStyle extends TStyle
6071
{
6072
	private $_backImageUrl=null;
6073
	private $_horizontalAlign=null;
6074
	private $_cellPadding=null;
6075
	private $_cellSpacing=null;
6076
	private $_gridLines=null;
6077
	private $_borderCollapse=null;
6078
	protected function _getZappableSleepProps(&$exprops)
6079
	{
6080
		parent::_getZappableSleepProps($exprops);
6081
		if ($this->_backImageUrl===null)
6082
			$exprops[] = "\0TTableStyle\0_backImageUrl";
6083
		if ($this->_horizontalAlign===null)
6084
			$exprops[] = "\0TTableStyle\0_horizontalAlign";
6085
		if ($this->_cellPadding===null)
6086
			$exprops[] = "\0TTableStyle\0_cellPadding";
6087
		if ($this->_cellSpacing===null)
6088
			$exprops[] = "\0TTableStyle\0_cellSpacing";
6089
		if ($this->_gridLines===null)
6090
			$exprops[] = "\0TTableStyle\0_gridLines";
6091
		if ($this->_borderCollapse===null)
6092
			$exprops[] = "\0TTableStyle\0_borderCollapse";
6093
	}
6094
	public function reset()
6095
	{
6096
		$this->_backImageUrl=null;
6097
		$this->_horizontalAlign=null;
6098
		$this->_cellPadding=null;
6099
		$this->_cellSpacing=null;
6100
		$this->_gridLines=null;
6101
		$this->_borderCollapse=null;
6102
	}
6103
	public function copyFrom($style)
6104
	{
6105
		parent::copyFrom($style);
6106
		if($style instanceof TTableStyle)
6107
		{
6108
			if($style->_backImageUrl!==null)
6109
				$this->_backImageUrl=$style->_backImageUrl;
6110
			if($style->_horizontalAlign!==null)
6111
				$this->_horizontalAlign=$style->_horizontalAlign;
6112
			if($style->_cellPadding!==null)
6113
				$this->_cellPadding=$style->_cellPadding;
6114
			if($style->_cellSpacing!==null)
6115
				$this->_cellSpacing=$style->_cellSpacing;
6116
			if($style->_gridLines!==null)
6117
				$this->_gridLines=$style->_gridLines;
6118
			if($style->_borderCollapse!==null)
6119
				$this->_borderCollapse=$style->_borderCollapse;
6120
		}
6121
	}
6122
	public function mergeWith($style)
6123
	{
6124
		parent::mergeWith($style);
6125
		if($style instanceof TTableStyle)
6126
		{
6127
			if($this->_backImageUrl===null && $style->_backImageUrl!==null)
6128
				$this->_backImageUrl=$style->_backImageUrl;
6129
			if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
6130
				$this->_horizontalAlign=$style->_horizontalAlign;
6131
			if($this->_cellPadding===null && $style->_cellPadding!==null)
6132
				$this->_cellPadding=$style->_cellPadding;
6133
			if($this->_cellSpacing===null && $style->_cellSpacing!==null)
6134
				$this->_cellSpacing=$style->_cellSpacing;
6135
			if($this->_gridLines===null && $style->_gridLines!==null)
6136
				$this->_gridLines=$style->_gridLines;
6137
			if($this->_borderCollapse===null && $style->_borderCollapse!==null)
6138
				$this->_borderCollapse=$style->_borderCollapse;
6139
		}
6140
	}
6141
	public function addAttributesToRender($writer)
6142
	{
6143
		if(($url=trim($this->getBackImageUrl()))!=='')
6144
			$writer->addStyleAttribute('background-image','url('.$url.')');
6145
		if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
6146
			$writer->addStyleAttribute('text-align',strtolower($horizontalAlign));
6147
		if(($cellPadding=$this->getCellPadding())>=0)
6148
			$writer->addAttribute('cellpadding',"$cellPadding");
6149
		if(($cellSpacing=$this->getCellSpacing())>=0)
6150
			$writer->addAttribute('cellspacing',"$cellSpacing");
6151
		if($this->getBorderCollapse())
6152
			$writer->addStyleAttribute('border-collapse','collapse');
6153
		switch($this->getGridLines())
6154
		{
6155
			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...
6156
			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...
6157
			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...
6158
		}
6159
		parent::addAttributesToRender($writer);
6160
	}
6161
	public function getBackImageUrl()
6162
	{
6163
		return $this->_backImageUrl===null?'':$this->_backImageUrl;
6164
	}
6165
	public function setBackImageUrl($value)
6166
	{
6167
		$this->_backImageUrl=$value;
6168
	}
6169
	public function getHorizontalAlign()
6170
	{
6171
		return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
6172
	}
6173
	public function setHorizontalAlign($value)
6174
	{
6175
		$this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
6176
	}
6177
	public function getCellPadding()
6178
	{
6179
		return $this->_cellPadding===null?-1:$this->_cellPadding;
6180
	}
6181
	public function setCellPadding($value)
6182
	{
6183
		if(($this->_cellPadding=TPropertyValue::ensureInteger($value))<-1)
6184
			throw new TInvalidDataValueException('tablestyle_cellpadding_invalid');
6185
	}
6186
	public function getCellSpacing()
6187
	{
6188
		return $this->_cellSpacing===null?-1:$this->_cellSpacing;
6189
	}
6190
	public function setCellSpacing($value)
6191
	{
6192
		if(($this->_cellSpacing=TPropertyValue::ensureInteger($value))<-1)
6193
			throw new TInvalidDataValueException('tablestyle_cellspacing_invalid');
6194
	}
6195
	public function getGridLines()
6196
	{
6197
		return $this->_gridLines===null?TTableGridLines::None:$this->_gridLines;
6198
	}
6199
	public function setGridLines($value)
6200
	{
6201
		$this->_gridLines=TPropertyValue::ensureEnum($value,'TTableGridLines');
6202
	}
6203
	public function getBorderCollapse()
6204
	{
6205
		return $this->_borderCollapse===null?false:$this->_borderCollapse;
6206
	}
6207
	public function setBorderCollapse($value)
6208
	{
6209
		$this->_borderCollapse=TPropertyValue::ensureBoolean($value);
6210
	}
6211
}
6212
class TTableItemStyle extends TStyle
6213
{
6214
	private $_horizontalAlign=null;
6215
	private $_verticalAlign=null;
6216
	private $_wrap=null;
6217
	protected function _getZappableSleepProps(&$exprops)
6218
	{
6219
		parent::_getZappableSleepProps($exprops);
6220
		if ($this->_horizontalAlign===null)
6221
			$exprops[] = "\0TTableItemStyle\0_horizontalAlign";
6222
		if ($this->_verticalAlign===null)
6223
			$exprops[] = "\0TTableItemStyle\0_verticalAlign";
6224
		if ($this->_wrap===null)
6225
			$exprops[] = "\0TTableItemStyle\0_wrap";
6226
	}
6227
	public function reset()
6228
	{
6229
		parent::reset();
6230
		$this->_verticalAlign=null;
6231
		$this->_horizontalAlign=null;
6232
		$this->_wrap=null;
6233
	}
6234
	public function copyFrom($style)
6235
	{
6236
		parent::copyFrom($style);
6237
		if($style instanceof TTableItemStyle)
6238
		{
6239
			if($this->_verticalAlign===null && $style->_verticalAlign!==null)
6240
				$this->_verticalAlign=$style->_verticalAlign;
6241
			if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
6242
				$this->_horizontalAlign=$style->_horizontalAlign;
6243
			if($this->_wrap===null && $style->_wrap!==null)
6244
				$this->_wrap=$style->_wrap;
6245
		}
6246
	}
6247
	public function mergeWith($style)
6248
	{
6249
		parent::mergeWith($style);
6250
		if($style instanceof TTableItemStyle)
6251
		{
6252
			if($style->_verticalAlign!==null)
6253
				$this->_verticalAlign=$style->_verticalAlign;
6254
			if($style->_horizontalAlign!==null)
6255
				$this->_horizontalAlign=$style->_horizontalAlign;
6256
			if($style->_wrap!==null)
6257
				$this->_wrap=$style->_wrap;
6258
		}
6259
	}
6260
	public function addAttributesToRender($writer)
6261
	{
6262
		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...
6263
			$writer->addStyleAttribute('white-space','nowrap');
6264
		if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
6265
			$writer->addAttribute('align',strtolower($horizontalAlign));
6266
		if(($verticalAlign=$this->getVerticalAlign())!==TVerticalAlign::NotSet)
6267
			$writer->addAttribute('valign',strtolower($verticalAlign));
6268
		parent::addAttributesToRender($writer);
6269
	}
6270
	public function getHorizontalAlign()
6271
	{
6272
		return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
6273
	}
6274
	public function setHorizontalAlign($value)
6275
	{
6276
		$this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
6277
	}
6278
	public function getVerticalAlign()
6279
	{
6280
		return $this->_verticalAlign===null?TVerticalAlign::NotSet:$this->_verticalAlign;
6281
	}
6282
	public function setVerticalAlign($value)
6283
	{
6284
		$this->_verticalAlign=TPropertyValue::ensureEnum($value,'TVerticalAlign');
6285
	}
6286
	public function getWrap()
6287
	{
6288
		return $this->_wrap===null?true:$this->_wrap;
6289
	}
6290
	public function setWrap($value)
6291
	{
6292
		$this->_wrap=TPropertyValue::ensureBoolean($value);
6293
	}
6294
}
6295
class THorizontalAlign extends TEnumerable
6296
{
6297
	const NotSet='NotSet';
6298
	const Left='Left';
6299
	const Right='Right';
6300
	const Center='Center';
6301
	const Justify='Justify';
6302
}
6303
class TVerticalAlign extends TEnumerable
6304
{
6305
	const NotSet='NotSet';
6306
	const Top='Top';
6307
	const Bottom='Bottom';
6308
	const Middle='Middle';
6309
}
6310
class TTableGridLines extends TEnumerable
6311
{
6312
	const None='None';
6313
	const Horizontal='Horizontal';
6314
	const Vertical='Vertical';
6315
	const Both='Both';
6316
}
6317
class TWebControlAdapter extends TControlAdapter
6318
{
6319
	public function render($writer)
6320
	{
6321
		$this->renderBeginTag($writer);
6322
		$this->renderContents($writer);
6323
		$this->renderEndTag($writer);
6324
	}
6325
	public function renderBeginTag($writer)
6326
	{
6327
		$this->getControl()->renderBeginTag($writer);
6328
	}
6329
	public function renderContents($writer)
6330
	{
6331
		$this->getControl()->renderContents($writer);
6332
	}
6333
	public function renderEndTag($writer)
6334
	{
6335
		$this->getControl()->renderEndTag($writer);
6336
	}
6337
}
6338
class TWebControlDecorator extends TComponent {
6339
	private $_internalonly;
6340
	private $_usestate = false;
6341
	private $_control;
6342
	private $_outercontrol;
6343
	private $_addedTemplateDecoration=false;
6344
	private $_pretagtext = '';
6345
	private $_precontentstext = '';
6346
	private $_postcontentstext = '';
6347
	private $_posttagtext = '';
6348
	private $_pretagtemplate;
6349
	private $_precontentstemplate;
6350
	private $_postcontentstemplate;
6351
	private $_posttagtemplate;
6352
	public function __construct($control, $onlyinternal = false) {
6353
		$this->_control = $control;
6354
		$this->_internalonly = $onlyinternal;
6355
	}
6356
	public function getUseState()
6357
	{
6358
		return $this->_usestate;
6359
	}
6360
	public function setUseState($value)
6361
	{
6362
		$this->_usestate = TPropertyValue::ensureBoolean($value);
6363
	}
6364
	public function getPreTagText() {
6365
		return $this->_pretagtext;
6366
	}
6367
	public function setPreTagText($value) {
6368
		if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
6369
			$this->_pretagtext = TPropertyValue::ensureString($value);
6370
	}
6371
	public function getPreContentsText() {
6372
		return $this->_precontentstext;
6373
	}
6374
	public function setPreContentsText($value) {
6375
		if(!$this->_control->getIsSkinApplied())
6376
			$this->_precontentstext = TPropertyValue::ensureString($value);
6377
	}
6378
	public function getPostContentsText() {
6379
		return $this->_postcontentstext;
6380
	}
6381
	public function setPostContentsText($value) {
6382
		if(!$this->_control->getIsSkinApplied())
6383
			$this->_postcontentstext = TPropertyValue::ensureString($value);
6384
	}
6385
	public function getPostTagText() {
6386
		return $this->_posttagtext;
6387
	}
6388
	public function setPostTagText($value) {
6389
		if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
6390
			$this->_posttagtext = TPropertyValue::ensureString($value);
6391
	}
6392
	public function getPreTagTemplate() {
6393
		return $this->_pretagtemplate;
6394
	}
6395
	public function setPreTagTemplate($value) {
6396
		if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
6397
			$this->_pretagtemplate = $value;
6398
	}
6399
	public function getPreContentsTemplate() {
6400
		return $this->_precontentstemplate;
6401
	}
6402
	public function setPreContentsTemplate($value) {
6403
		if(!$this->_control->getIsSkinApplied())
6404
			$this->_precontentstemplate = $value;
6405
	}
6406
	public function getPostContentsTemplate() {
6407
		return $this->_postcontentstemplate;
6408
	}
6409
	public function setPostContentsTemplate($value) {
6410
		if(!$this->_control->getIsSkinApplied())
6411
			$this->_postcontentstemplate = $value;
6412
	}
6413
	public function getPostTagTemplate() {
6414
		return $this->_posttagtemplate;
6415
	}
6416
	public function setPostTagTemplate($value) {
6417
		if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
6418
			$this->_posttagtemplate = $value;
6419
	}
6420
	public function instantiate($outercontrol = null) {
6421
		if($this->getPreTagTemplate() || $this->getPreContentsTemplate() ||
6422
			$this->getPostContentsTemplate() || $this->getPostTagTemplate()) {
6423
			$this->_outercontrol = $outercontrol;
6424
			if($this->getUseState())
6425
				$this->ensureTemplateDecoration();
6426
			else
6427
				$this->_control->getPage()->onSaveStateComplete[] = array($this, 'ensureTemplateDecoration');
6428
		}
6429
	}
6430
	public function ensureTemplateDecoration($sender=null, $param=null) {
6431
		$control = $this->_control;
6432
		$outercontrol = $this->_outercontrol;
6433
		if($outercontrol === null)
6434
			$outercontrol = $control;
6435
		if($this->_addedTemplateDecoration)
6436
			return $this->_addedTemplateDecoration;
6437
		$this->_addedTemplateDecoration = true;
6438
		if($this->getPreContentsTemplate())
6439
		{
6440
			$precontents = Prado::createComponent('TCompositeControl');
6441
			$this->getPreContentsTemplate()->instantiateIn($precontents);
6442
			$control->getControls()->insertAt(0, $precontents);
6443
		}
6444
		if($this->getPostContentsTemplate())
6445
		{
6446
			$postcontents = Prado::createComponent('TCompositeControl');
6447
			$this->getPostContentsTemplate()->instantiateIn($postcontents);
6448
			$control->getControls()->add($postcontents);
6449
		}
6450
		if(!$outercontrol->getParent())
6451
			return $this->_addedTemplateDecoration;
6452
		if($this->getPreTagTemplate())
6453
		{
6454
			$pretag = Prado::createComponent('TCompositeControl');
6455
			$this->getPreTagTemplate()->instantiateIn($pretag);
6456
			$outercontrol->getParent()->getControls()->insertBefore($outercontrol, $pretag);
6457
		}
6458
		if($this->getPostTagTemplate())
6459
		{
6460
			$posttag = Prado::createComponent('TCompositeControl');
6461
			$this->getPostTagTemplate()->instantiateIn($posttag);
6462
			$outercontrol->getParent()->getControls()->insertAfter($outercontrol, $posttag);
6463
		}
6464
		return true;
6465
	}
6466
	public function renderPreTagText($writer) {
6467
		$writer->write($this->getPreTagText());
6468
	}
6469
	public function renderPreContentsText($writer) {
6470
		$writer->write($this->getPreContentsText());
6471
	}
6472
	public function renderPostContentsText($writer) {
6473
		$writer->write($this->getPostContentsText());
6474
	}
6475
	public function renderPostTagText($writer) {
6476
		$writer->write($this->getPostTagText());
6477
	}
6478
}
6479
class TWebControl extends TControl implements IStyleable
6480
{
6481
	private $_ensureid=false;
6482
	protected $_decorator;
6483
	public function setEnsureId($value)
6484
	{
6485
		$this->_ensureid |= TPropertyValue::ensureBoolean($value);
6486
	}
6487
	public function getEnsureId()
6488
	{
6489
		return $this->_ensureid;
6490
	}
6491
	public function getDecorator($create=true)
6492
	{
6493
		if($create && !$this->_decorator)
6494
			$this->_decorator = Prado::createComponent('TWebControlDecorator', $this);
6495
		return $this->_decorator;
6496
	}
6497
	public function copyBaseAttributes(TWebControl $control)
6498
	{
6499
		$this->setAccessKey($control->getAccessKey());
6500
		$this->setToolTip($control->getToolTip());
6501
		$this->setTabIndex($control->getTabIndex());
6502
		if(!$control->getEnabled())
6503
			$this->setEnabled(false);
6504
		if($control->getHasAttributes())
6505
			$this->getAttributes()->copyFrom($control->getAttributes());
6506
	}
6507
	public function getAccessKey()
6508
	{
6509
		return $this->getViewState('AccessKey','');
6510
	}
6511
	public function setAccessKey($value)
6512
	{
6513
		if(strlen($value)>1)
6514
			throw new TInvalidDataValueException('webcontrol_accesskey_invalid',get_class($this),$value);
6515
		$this->setViewState('AccessKey',$value,'');
6516
	}
6517
	public function getBackColor()
6518
	{
6519
		if($style=$this->getViewState('Style',null))
6520
			return $style->getBackColor();
6521
		else
6522
			return '';
6523
	}
6524
	public function setBackColor($value)
6525
	{
6526
		$this->getStyle()->setBackColor($value);
6527
	}
6528
	public function getBorderColor()
6529
	{
6530
		if($style=$this->getViewState('Style',null))
6531
			return $style->getBorderColor();
6532
		else
6533
			return '';
6534
	}
6535
	public function setBorderColor($value)
6536
	{
6537
		$this->getStyle()->setBorderColor($value);
6538
	}
6539
	public function getBorderStyle()
6540
	{
6541
		if($style=$this->getViewState('Style',null))
6542
			return $style->getBorderStyle();
6543
		else
6544
			return '';
6545
	}
6546
	public function setBorderStyle($value)
6547
	{
6548
		$this->getStyle()->setBorderStyle($value);
6549
	}
6550
	public function getBorderWidth()
6551
	{
6552
		if($style=$this->getViewState('Style',null))
6553
			return $style->getBorderWidth();
6554
		else
6555
			return '';
6556
	}
6557
	public function setBorderWidth($value)
6558
	{
6559
		$this->getStyle()->setBorderWidth($value);
6560
	}
6561
	public function getFont()
6562
	{
6563
		return $this->getStyle()->getFont();
6564
	}
6565
	public function getForeColor()
6566
	{
6567
		if($style=$this->getViewState('Style',null))
6568
			return $style->getForeColor();
6569
		else
6570
			return '';
6571
	}
6572
	public function setForeColor($value)
6573
	{
6574
		$this->getStyle()->setForeColor($value);
6575
	}
6576
	public function getHeight()
6577
	{
6578
		if($style=$this->getViewState('Style',null))
6579
			return $style->getHeight();
6580
		else
6581
			return '';
6582
	}
6583
	public function setDisplay($value)
6584
	{
6585
		$this->getStyle()->setDisplayStyle($value);
6586
	}
6587
	public function getDisplay()
6588
	{
6589
		return $this->getStyle()->getDisplayStyle();
6590
	}
6591
	public function setCssClass($value)
6592
	{
6593
		$this->getStyle()->setCssClass($value);
6594
	}
6595
	public function getCssClass()
6596
	{
6597
		if($style=$this->getViewState('Style',null))
6598
			return $style->getCssClass();
6599
		else
6600
			return '';
6601
	}
6602
	public function setHeight($value)
6603
	{
6604
		$this->getStyle()->setHeight($value);
6605
	}
6606
	public function getHasStyle()
6607
	{
6608
		return $this->getViewState('Style',null)!==null;
6609
	}
6610
	protected function createStyle()
6611
	{
6612
		return new TStyle;
6613
	}
6614
	public function getStyle()
6615
	{
6616
		if($style=$this->getViewState('Style',null))
6617
			return $style;
6618
		else
6619
		{
6620
			$style=$this->createStyle();
6621
			$this->setViewState('Style',$style,null);
6622
			return $style;
6623
		}
6624
	}
6625
	public function setStyle($value)
6626
	{
6627
		if(is_string($value))
6628
			$this->getStyle()->setCustomStyle($value);
6629
		else
6630
			throw new TInvalidDataValueException('webcontrol_style_invalid',get_class($this));
6631
	}
6632
	public function clearStyle()
6633
	{
6634
		$this->clearViewState('Style');
6635
	}
6636
	public function getTabIndex()
6637
	{
6638
		return $this->getViewState('TabIndex',0);
6639
	}
6640
	public function setTabIndex($value)
6641
	{
6642
		$this->setViewState('TabIndex',TPropertyValue::ensureInteger($value),0);
6643
	}
6644
	protected function getTagName()
6645
	{
6646
		return 'span';
6647
	}
6648
	public function getToolTip()
6649
	{
6650
		return $this->getViewState('ToolTip','');
6651
	}
6652
	public function setToolTip($value)
6653
	{
6654
		$this->setViewState('ToolTip',$value,'');
6655
	}
6656
	public function getWidth()
6657
	{
6658
		if($style=$this->getViewState('Style',null))
6659
			return $style->getWidth();
6660
		else
6661
			return '';
6662
	}
6663
	public function setWidth($value)
6664
	{
6665
		$this->getStyle()->setWidth($value);
6666
	}
6667
	public function onPreRender($param) {
6668
		if($decorator = $this->getDecorator(false))
6669
			$decorator->instantiate();
6670
		parent::onPreRender($param);
6671
	}
6672
	protected function addAttributesToRender($writer)
6673
	{
6674
		if($this->getID()!=='' || $this->getEnsureId())
6675
			$writer->addAttribute('id',$this->getClientID());
6676
		if(($accessKey=$this->getAccessKey())!=='')
6677
			$writer->addAttribute('accesskey',$accessKey);
6678
		if(!$this->getEnabled())
6679
			$writer->addAttribute('disabled','disabled');
6680
		if(($tabIndex=$this->getTabIndex())>0)
6681
			$writer->addAttribute('tabindex',"$tabIndex");
6682
		if(($toolTip=$this->getToolTip())!=='')
6683
			$writer->addAttribute('title',$toolTip);
6684
		if($style=$this->getViewState('Style',null))
6685
			$style->addAttributesToRender($writer);
6686
		if($this->getHasAttributes())
6687
		{
6688
			foreach($this->getAttributes() as $name=>$value)
6689
				$writer->addAttribute($name,$value);
6690
		}
6691
	}
6692
	public function render($writer)
6693
	{
6694
		$this->renderBeginTag($writer);
6695
		$this->renderContents($writer);
6696
		$this->renderEndTag($writer);
6697
	}
6698
	public function renderBeginTag($writer)
6699
	{
6700
		if($decorator = $this->getDecorator(false)) {
6701
			$decorator->renderPreTagText($writer);
6702
			$this->addAttributesToRender($writer);
6703
			$writer->renderBeginTag($this->getTagName());
6704
			$decorator->renderPreContentsText($writer);
6705
		} else {
6706
			$this->addAttributesToRender($writer);
6707
			$writer->renderBeginTag($this->getTagName());
6708
		}
6709
	}
6710
	public function renderContents($writer)
6711
	{
6712
		parent::renderChildren($writer);
6713
	}
6714
	public function renderEndTag($writer)
6715
	{
6716
		if($decorator = $this->getDecorator(false)) {
6717
			$decorator->renderPostContentsText($writer);
6718
			$writer->renderEndTag();
6719
			$decorator->renderPostTagText($writer);
6720
		} else
6721
			$writer->renderEndTag($writer);
6722
	}
6723
}
6724
class TCompositeControl extends TControl implements INamingContainer
6725
{
6726
	protected function initRecursive($namingContainer=null)
6727
	{
6728
		$this->ensureChildControls();
6729
		parent::initRecursive($namingContainer);
6730
	}
6731
}
6732
class TTemplateControl extends TCompositeControl
6733
{
6734
	const EXT_TEMPLATE='.tpl';
6735
	private static $_template=array();
6736
	private $_localTemplate=null;
6737
	private $_master=null;
6738
	private $_masterClass='';
6739
	private $_contents=array();
6740
	private $_placeholders=array();
6741
	public function getTemplate()
6742
	{
6743
		if($this->_localTemplate===null)
6744
		{
6745
			$class=get_class($this);
6746
			if(!isset(self::$_template[$class]))
6747
				self::$_template[$class]=$this->loadTemplate();
6748
			return self::$_template[$class];
6749
		}
6750
		else
6751
			return $this->_localTemplate;
6752
	}
6753
	public function setTemplate($value)
6754
	{
6755
		$this->_localTemplate=$value;
6756
	}
6757
	public function getIsSourceTemplateControl()
6758
	{
6759
		if(($template=$this->getTemplate())!==null)
6760
			return $template->getIsSourceTemplate();
6761
		else
6762
			return false;
6763
	}
6764
	public function getTemplateDirectory()
6765
	{
6766
		if(($template=$this->getTemplate())!==null)
6767
			return $template->getContextPath();
6768
		else
6769
			return '';
6770
	}
6771
	protected function loadTemplate()
6772
	{
6773
		$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...
6774
		return $template;
6775
	}
6776
	public function createChildControls()
6777
	{
6778
		if($tpl=$this->getTemplate())
6779
		{
6780
			foreach($tpl->getDirective() as $name=>$value)
6781
			{
6782
				if(is_string($value))
6783
					$this->setSubProperty($name,$value);
6784
				else
6785
					throw new TConfigurationException('templatecontrol_directive_invalid',get_class($this),$name);
6786
			}
6787
			$tpl->instantiateIn($this);
6788
		}
6789
	}
6790
	public function registerContent($id,TContent $object)
6791
	{
6792
		if(isset($this->_contents[$id]))
6793
			throw new TConfigurationException('templatecontrol_contentid_duplicated',$id);
6794
		else
6795
			$this->_contents[$id]=$object;
6796
	}
6797
	public function registerContentPlaceHolder($id,TContentPlaceHolder $object)
6798
	{
6799
		if(isset($this->_placeholders[$id]))
6800
			throw new TConfigurationException('templatecontrol_placeholderid_duplicated',$id);
6801
		else
6802
			$this->_placeholders[$id]=$object;
6803
	}
6804
	public function getMasterClass()
6805
	{
6806
		return $this->_masterClass;
6807
	}
6808
	public function setMasterClass($value)
6809
	{
6810
		$this->_masterClass=$value;
6811
	}
6812
	public function getMaster()
6813
	{
6814
		return $this->_master;
6815
	}
6816
	public function injectContent($id,$content)
6817
	{
6818
		if(isset($this->_placeholders[$id]))
6819
		{
6820
			$placeholder=$this->_placeholders[$id];
6821
			$controls=$placeholder->getParent()->getControls();
6822
			$loc=$controls->remove($placeholder);
6823
			$controls->insertAt($loc,$content);
6824
		}
6825
		else
6826
			throw new TConfigurationException('templatecontrol_placeholder_inexistent',$id);
6827
	}
6828
	protected function initRecursive($namingContainer=null)
6829
	{
6830
		$this->ensureChildControls();
6831
		if($this->_masterClass!=='')
6832
		{
6833
			$master=Prado::createComponent($this->_masterClass);
6834
			if(!($master instanceof TTemplateControl))
6835
				throw new TInvalidDataValueException('templatecontrol_mastercontrol_invalid');
6836
			$this->_master=$master;
6837
			$this->getControls()->clear();
6838
			$this->getControls()->add($master);
6839
			$master->ensureChildControls();
6840
			foreach($this->_contents as $id=>$content)
6841
				$master->injectContent($id,$content);
6842
		}
6843
		else if(!empty($this->_contents))
6844
			throw new TConfigurationException('templatecontrol_mastercontrol_required',get_class($this));
6845
		parent::initRecursive($namingContainer);
6846
	}
6847
        public function tryToUpdateView($arObj, $throwExceptions = false)
6848
        {
6849
                $objAttrs = get_class_vars(get_class($arObj));
6850
                foreach (array_keys($objAttrs) as $key)
6851
                {
6852
                        try
6853
                        {
6854
                                if ($key != "RELATIONS")
6855
                                {
6856
                                        $control = $this->{$key};
6857
                                        if ($control instanceof TTextBox)
6858
                                                $control->Text = $arObj->{$key};
6859
                                        elseif ($control instanceof TCheckBox)
6860
                                                $control->Checked = (boolean) $arObj->{$key};
6861
                                        elseif ($control instanceof TDatePicker)
6862
                                                $control->Date = $arObj->{$key};
6863
                                }
6864
                                else
6865
                                {
6866
                                        foreach ($objAttrs["RELATIONS"] as $relKey => $relValues)
6867
                                        {
6868
                                                $relControl = $this->{$relKey};
6869
                                                switch ($relValues[0])
6870
                                                {
6871
                                                        case TActiveRecord::BELONGS_TO:
6872
                                                        case TActiveRecord::HAS_ONE:
6873
                                                                $relControl->Text = $arObj->{$relKey};
6874
                                                                break;
6875
                                                        case TActiveRecord::HAS_MANY:
6876
                                                                if ($relControl instanceof TListControl)
6877
                                                                {
6878
                                                                        $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...
6879
                                                                        $relControl->dataBind();
6880
                                                                }
6881
                                                                break;
6882
                                                }
6883
                                        }
6884
                                        break;
6885
                                }
6886
                        } 
6887
                        catch (Exception $ex)
6888
                        {
6889
                                if ($throwExceptions)
6890
                                        throw $ex;
6891
                        }
6892
                }
6893
        }
6894
        public function tryToUpdateAR($arObj, $throwExceptions = false)
6895
        {
6896
                $objAttrs = get_class_vars(get_class($arObj));
6897
                foreach (array_keys($objAttrs) as $key)
6898
                {
6899
                        try
6900
                        {
6901
                                if ($key == "RELATIONS")
6902
                                        break;
6903
                                $control = $this->{$key};
6904
                                if ($control instanceof TTextBox)
6905
                                        $arObj->{$key} = $control->Text;
6906
                                elseif ($control instanceof TCheckBox)
6907
                                        $arObj->{$key} = $control->Checked;
6908
                                elseif ($control instanceof TDatePicker)
6909
                                        $arObj->{$key} = $control->Date;
6910
                        } 
6911
                        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...
6912
                        {
6913
                                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...
6914
                                        throw $ex;
6915
                        }
6916
                }
6917
        }
6918
}
6919
class TForm extends TControl
6920
{
6921
	public function onInit($param)
6922
	{
6923
		parent::onInit($param);
6924
		$this->getPage()->setForm($this);
6925
	}
6926
	protected function addAttributesToRender($writer)
6927
	{
6928
		$writer->addAttribute('id',$this->getClientID());
6929
		$writer->addAttribute('method',$this->getMethod());
6930
		$uri=$this->getRequest()->getRequestURI();
6931
		$writer->addAttribute('action',str_replace('&','&amp;',str_replace('&amp;','&',$uri)));
6932
		if(($enctype=$this->getEnctype())!=='')
6933
			$writer->addAttribute('enctype',$enctype);
6934
		$attributes=$this->getAttributes();
6935
		$attributes->remove('action');
6936
		$writer->addAttributes($attributes);
6937
		if(($butt=$this->getDefaultButton())!=='')
6938
		{
6939
			if(($button=$this->findControl($butt))!==null)
6940
				$this->getPage()->getClientScript()->registerDefaultButton($this, $button);
6941
			else
6942
				throw new TInvalidDataValueException('form_defaultbutton_invalid',$butt);
6943
		}
6944
	}
6945
	public function render($writer)
6946
	{
6947
		$page=$this->getPage();
6948
		$this->addAttributesToRender($writer);
6949
		$writer->renderBeginTag('form');
6950
		$cs=$page->getClientScript();
6951
		if($page->getClientSupportsJavaScript())
6952
		{
6953
			$cs->renderHiddenFieldsBegin($writer);
6954
			$cs->renderScriptFilesBegin($writer);
6955
			$cs->renderBeginScripts($writer);
6956
 			$page->beginFormRender($writer);
6957
 			$this->renderChildren($writer);
6958
			$cs->renderHiddenFieldsEnd($writer);
6959
 			$page->endFormRender($writer);
6960
			$cs->renderScriptFilesEnd($writer);
6961
			$cs->renderEndScripts($writer);
6962
		}
6963
		else
6964
		{
6965
			$cs->renderHiddenFieldsBegin($writer);
6966
			$page->beginFormRender($writer);
6967
			$this->renderChildren($writer);
6968
			$page->endFormRender($writer);
6969
			$cs->renderHiddenFieldsEnd($writer);
6970
		}
6971
		$writer->renderEndTag();
6972
	}
6973
	public function getDefaultButton()
6974
	{
6975
		return $this->getViewState('DefaultButton','');
6976
	}
6977
	public function setDefaultButton($value)
6978
	{
6979
		$this->setViewState('DefaultButton',$value,'');
6980
	}
6981
	public function getMethod()
6982
	{
6983
		return $this->getViewState('Method','post');
6984
	}
6985
	public function setMethod($value)
6986
	{
6987
		$this->setViewState('Method',TPropertyValue::ensureEnum($value,'post','get'),'post');
6988
	}
6989
	public function getEnctype()
6990
	{
6991
		return $this->getViewState('Enctype','');
6992
	}
6993
	public function setEnctype($value)
6994
	{
6995
		$this->setViewState('Enctype',$value,'');
6996
	}
6997
	public function getName()
6998
	{
6999
		return $this->getUniqueID();
7000
	}
7001
}
7002
class TClientScriptManager extends TApplicationComponent
7003
{
7004
	const SCRIPT_PATH='Web/Javascripts/source';
7005
	const PACKAGES_FILE='Web/Javascripts/packages.php';
7006
	const CSS_PACKAGES_FILE='Web/Javascripts/css-packages.php';
7007
	private $_page;
7008
	private $_hiddenFields=array();
7009
	private $_beginScripts=array();
7010
	private $_endScripts=array();
7011
	private $_scriptFiles=array();
7012
	private $_headScriptFiles=array();
7013
	private $_headScripts=array();
7014
	private $_styleSheetFiles=array();
7015
	private $_styleSheets=array();
7016
	private $_registeredPradoScripts=array();
7017
	private static $_pradoScripts;
7018
	private static $_pradoPackages;
7019
	private $_registeredPradoStyles=array();
7020
	private static $_pradoStyles;
7021
	private static $_pradoStylePackages;
7022
	private $_renderedHiddenFields;
7023
	private $_renderedScriptFiles=array();
7024
	private $_expandedPradoScripts;
7025
	private $_expandedPradoStyles;
7026
	public function __construct(TPage $owner)
7027
	{
7028
		$this->_page=$owner;
7029
	}
7030
	public function getRequiresHead()
7031
	{
7032
		return count($this->_styleSheetFiles) || count($this->_styleSheets)
7033
			|| count($this->_headScriptFiles) || count($this->_headScripts);
7034
	}
7035
	public static function getPradoPackages()
7036
	{
7037
		return self::$_pradoPackages;
7038
	}
7039
	public static function getPradoScripts()
7040
	{
7041
		return self::$_pradoScripts;
7042
	}
7043
	public function registerPradoScript($name)
7044
	{
7045
		$this->registerPradoScriptInternal($name);
7046
		$params=func_get_args();
7047
		$this->_page->registerCachingAction('Page.ClientScript','registerPradoScript',$params);
7048
	}
7049
	protected function registerPradoScriptInternal($name)
7050
	{
7051
				if(!isset($this->_registeredPradoScripts[$name]))
7052
		{
7053
			if(self::$_pradoScripts === null)
7054
			{
7055
				$packageFile = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::PACKAGES_FILE;
7056
				list($packages,$deps)= include($packageFile);
7057
				self::$_pradoScripts = $deps;
7058
				self::$_pradoPackages = $packages;
7059
			}
7060
			if (isset(self::$_pradoScripts[$name]))
7061
				$this->_registeredPradoScripts[$name]=true;
7062
			else
7063
				throw new TInvalidOperationException('csmanager_pradoscript_invalid',$name);
7064
			if(($packages=array_keys($this->_registeredPradoScripts))!==array())
7065
			{
7066
				$base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
7067
				list($path,$baseUrl)=$this->getPackagePathUrl($base);
7068
				$packagesUrl=array();
7069
				$isDebug=$this->getApplication()->getMode()===TApplicationMode::Debug;
7070
				foreach ($packages as $p)
7071
				{
7072
					foreach (self::$_pradoScripts[$p] as $dep)
7073
					{
7074
						foreach (self::$_pradoPackages[$dep] as $script)
7075
						if (!isset($this->_expandedPradoScripts[$script]))
7076
						{
7077
							$this->_expandedPradoScripts[$script] = true;
7078
							if($isDebug)
7079
							{
7080
								if (!in_array($url=$baseUrl.'/'.$script,$packagesUrl))
7081
									$packagesUrl[]=$url;
7082
							} else {
7083
								if (!in_array($url=$baseUrl.'/min/'.$script,$packagesUrl))
7084
								{
7085
									if(!is_file($filePath=$path.'/min/'.$script))
7086
									{
7087
										$dirPath=dirname($filePath);
7088
										if(!is_dir($dirPath))
7089
											mkdir($dirPath, PRADO_CHMOD, true);
7090
										file_put_contents($filePath, TJavaScript::JSMin(file_get_contents($base.'/'.$script)));
7091
										chmod($filePath, PRADO_CHMOD);
7092
									}
7093
									$packagesUrl[]=$url;
7094
								}
7095
							}
7096
						}
7097
					}
7098
				}
7099
				foreach($packagesUrl as $url)
7100
					$this->registerScriptFile($url,$url);
7101
			}
7102
		}
7103
	}
7104
	public function getPradoScriptAssetUrl()
7105
	{
7106
		$base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
7107
		$assets = Prado::getApplication()->getAssetManager();
7108
		return $assets->getPublishedUrl($base);
7109
	}
7110
	public function getScriptUrls()
7111
	{
7112
		$scripts = array_values($this->_headScriptFiles);
7113
		$scripts = array_merge($scripts, array_values($this->_scriptFiles));
7114
		$scripts = array_unique($scripts);
7115
		return $scripts;
7116
	}
7117
	protected function getPackagePathUrl($base)
7118
	{
7119
		$assets = Prado::getApplication()->getAssetManager();
7120
		if(strpos($base, $assets->getBaseUrl())===false)
7121
		{
7122
			if(($dir = Prado::getPathOfNameSpace($base)) !== null) {
7123
				$base = $dir;
7124
			}
7125
			return array($assets->getPublishedPath($base), $assets->publishFilePath($base));
7126
		}
7127
		else
7128
		{
7129
			return array($assets->getBasePath().str_replace($assets->getBaseUrl(),'',$base), $base);
7130
		}
7131
	}
7132
	public function getCallbackReference(ICallbackEventHandler $callbackHandler, $options=null)
7133
	{
7134
		$options = !is_array($options) ? array() : $options;
7135
		$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...
7136
		$clientSide = $callbackHandler->getActiveControl()->getClientSide();
7137
		$options = array_merge($options, $clientSide->getOptions()->toArray());
7138
		$optionString = TJavaScript::encode($options);
7139
		$this->registerPradoScriptInternal('ajax');
7140
		$id = $callbackHandler->getUniqueID();
7141
		return "new Prado.CallbackRequest('{$id}',{$optionString})";
7142
	}
7143
	public function registerCallbackControl($class, $options)
7144
	{
7145
		$optionString=TJavaScript::encode($options);
7146
		$code="new {$class}({$optionString});";
7147
		$this->_endScripts[sprintf('%08X', crc32($code))]=$code;
7148
		$this->registerPradoScriptInternal('ajax');
7149
		$params=func_get_args();
7150
		$this->_page->registerCachingAction('Page.ClientScript','registerCallbackControl',$params);
7151
	}
7152
	public function registerPostBackControl($class,$options)
7153
	{
7154
		if($class === null) {
7155
			return;
7156
		}
7157
		if(!isset($options['FormID']) && ($form=$this->_page->getForm())!==null)
7158
			$options['FormID']=$form->getClientID();
7159
		$optionString=TJavaScript::encode($options);
7160
		$code="new {$class}({$optionString});";
7161
		$this->_endScripts[sprintf('%08X', crc32($code))]=$code;
7162
		$this->registerPradoScriptInternal('prado');
7163
		$params=func_get_args();
7164
		$this->_page->registerCachingAction('Page.ClientScript','registerPostBackControl',$params);
7165
	}
7166
	public function registerDefaultButton($panel, $button)
7167
	{
7168
		$panelID=is_string($panel)?$panel:$panel->getUniqueID();
7169
		if(is_string($button))
7170
			$buttonID=$button;
7171
		else
7172
		{
7173
			$button->setIsDefaultButton(true);
7174
			$buttonID=$button->getUniqueID();
7175
		}
7176
		$options = TJavaScript::encode($this->getDefaultButtonOptions($panelID, $buttonID));
7177
		$code = "new Prado.WebUI.DefaultButton($options);";
7178
		$this->_endScripts['prado:'.$panelID]=$code;
7179
		$this->registerPradoScriptInternal('prado');
7180
		$params=array($panelID,$buttonID);
7181
		$this->_page->registerCachingAction('Page.ClientScript','registerDefaultButton',$params);
7182
	}
7183
	protected function getDefaultButtonOptions($panelID, $buttonID)
7184
	{
7185
		$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...
7186
		$options['Panel'] = TControl::convertUniqueIdToClientId($panelID);
7187
		$options['Target'] = TControl::convertUniqueIdToClientId($buttonID);
7188
		$options['EventTarget'] = $buttonID;
7189
		$options['Event'] = 'click';
7190
		return $options;
7191
	}
7192
	public function registerFocusControl($target)
7193
	{
7194
		$this->registerPradoScriptInternal('jquery');
7195
		if($target instanceof TControl)
7196
			$target=$target->getClientID();
7197
		$this->_endScripts['prado:focus'] = 'jQuery(\'#'.$target.'\').focus();';
7198
		$params=func_get_args();
7199
		$this->_page->registerCachingAction('Page.ClientScript','registerFocusControl',$params);
7200
	}
7201
	public function registerPradoStyle($name)
7202
	{
7203
		$this->registerPradoStyleInternal($name);
7204
		$params=func_get_args();
7205
		$this->_page->registerCachingAction('Page.ClientScript','registerPradoStyle',$params);
7206
	}
7207
	protected function registerPradoStyleInternal($name)
7208
	{
7209
				if(!isset($this->_registeredPradoStyles[$name]))
7210
		{
7211
			$base = $this->getPradoScriptAssetUrl();
7212
			if(self::$_pradoStyles === null)
7213
			{
7214
				$packageFile = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::CSS_PACKAGES_FILE;
7215
				list($packages,$deps)= include($packageFile);
7216
				self::$_pradoStyles = $deps;
7217
				self::$_pradoStylePackages = $packages;
7218
			}
7219
			if (isset(self::$_pradoStyles[$name]))
7220
				$this->_registeredPradoStyles[$name]=true;
7221
			else
7222
				throw new TInvalidOperationException('csmanager_pradostyle_invalid',$name);
7223
			if(($packages=array_keys($this->_registeredPradoStyles))!==array())
7224
			{
7225
				$base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
7226
				list($path,$baseUrl)=$this->getPackagePathUrl($base);
0 ignored issues
show
Unused Code introduced by
The assignment to $path is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
7227
				$packagesUrl=array();
7228
				$isDebug=$this->getApplication()->getMode()===TApplicationMode::Debug;
0 ignored issues
show
Unused Code introduced by
$isDebug 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...
7229
				foreach ($packages as $p)
7230
				{
7231
					foreach (self::$_pradoStyles[$p] as $dep)
7232
					{
7233
						foreach (self::$_pradoStylePackages[$dep] as $style)
7234
						if (!isset($this->_expandedPradoStyles[$style]))
7235
						{
7236
							$this->_expandedPradoStyles[$style] = true;
7237
														if (!in_array($url=$baseUrl.'/'.$style,$packagesUrl))
7238
								$packagesUrl[]=$url;
7239
						}
7240
					}
7241
				}
7242
				foreach($packagesUrl as $url)
7243
					$this->registerStyleSheetFile($url,$url);
7244
			}
7245
		}
7246
	}
7247
	public function registerStyleSheetFile($key,$url,$media='')
7248
	{
7249
		if($media==='')
7250
			$this->_styleSheetFiles[$key]=$url;
7251
		else
7252
			$this->_styleSheetFiles[$key]=array($url,$media);
7253
		$params=func_get_args();
7254
		$this->_page->registerCachingAction('Page.ClientScript','registerStyleSheetFile',$params);
7255
	}
7256
	public function registerStyleSheet($key,$css,$media='')
7257
	{
7258
		$this->_styleSheets[$key]=$css;
7259
		$params=func_get_args();
7260
		$this->_page->registerCachingAction('Page.ClientScript','registerStyleSheet',$params);
7261
	}
7262
	public function getStyleSheetUrls()
7263
	{
7264
		$stylesheets = array_values(
7265
			array_map(function($e) {
7266
				return is_array($e) ? $e[0] : $e;
7267
			}, $this->_styleSheetFiles)
7268
		);
7269
		foreach(Prado::getApplication()->getAssetManager()->getPublished() as $path=>$url)
7270
			if (substr($url,strlen($url)-4)=='.css')
7271
				$stylesheets[] = $url;
7272
		$stylesheets = array_unique($stylesheets);
7273
		return $stylesheets;
7274
	}
7275
	public function getStyleSheetCodes()
7276
	{
7277
		return array_unique(array_values($this->_styleSheets));
7278
	}
7279
	public function registerHeadScriptFile($key,$url)
7280
	{
7281
		$this->checkIfNotInRender();
7282
		$this->_headScriptFiles[$key]=$url;
7283
		$params=func_get_args();
7284
		$this->_page->registerCachingAction('Page.ClientScript','registerHeadScriptFile',$params);
7285
	}
7286
	public function registerHeadScript($key,$script)
7287
	{
7288
		$this->checkIfNotInRender();
7289
		$this->_headScripts[$key]=$script;
7290
		$params=func_get_args();
7291
		$this->_page->registerCachingAction('Page.ClientScript','registerHeadScript',$params);
7292
	}
7293
	public function registerScriptFile($key, $url)
7294
	{
7295
		$this->_scriptFiles[$key]=$url;
7296
		$params=func_get_args();
7297
		$this->_page->registerCachingAction('Page.ClientScript','registerScriptFile',$params);
7298
	}
7299
	public function registerBeginScript($key,$script)
7300
	{
7301
		$this->checkIfNotInRender();
7302
		$this->_beginScripts[$key]=$script;
7303
		$params=func_get_args();
7304
		$this->_page->registerCachingAction('Page.ClientScript','registerBeginScript',$params);
7305
	}
7306
	public function registerEndScript($key,$script)
7307
	{
7308
		$this->_endScripts[$key]=$script;
7309
		$params=func_get_args();
7310
		$this->_page->registerCachingAction('Page.ClientScript','registerEndScript',$params);
7311
	}
7312
	public function registerHiddenField($name,$value)
7313
	{
7314
		$this->_hiddenFields[$name]=$value;
7315
		$params=func_get_args();
7316
		$this->_page->registerCachingAction('Page.ClientScript','registerHiddenField',$params);
7317
	}
7318
	public function isStyleSheetFileRegistered($key)
7319
	{
7320
		return isset($this->_styleSheetFiles[$key]);
7321
	}
7322
	public function isStyleSheetRegistered($key)
7323
	{
7324
		return isset($this->_styleSheets[$key]);
7325
	}
7326
	public function isHeadScriptFileRegistered($key)
7327
	{
7328
		return isset($this->_headScriptFiles[$key]);
7329
	}
7330
	public function isHeadScriptRegistered($key)
7331
	{
7332
		return isset($this->_headScripts[$key]);
7333
	}
7334
	public function isScriptFileRegistered($key)
7335
	{
7336
		return isset($this->_scriptFiles[$key]);
7337
	}
7338
	public function isBeginScriptRegistered($key)
7339
	{
7340
		return isset($this->_beginScripts[$key]);
7341
	}
7342
	public function isEndScriptRegistered($key)
7343
	{
7344
		return isset($this->_endScripts[$key]);
7345
	}
7346
	public function hasEndScripts()
7347
	{
7348
		return count($this->_endScripts) > 0;
7349
	}
7350
	public function hasBeginScripts()
7351
	{
7352
		return count($this->_beginScripts) > 0;
7353
	}
7354
	public function isHiddenFieldRegistered($key)
7355
	{
7356
		return isset($this->_hiddenFields[$key]);
7357
	}
7358
	public function renderStyleSheetFiles($writer)
7359
	{
7360
		$str='';
7361
		foreach($this->_styleSheetFiles as $url)
7362
		{
7363
			if(is_array($url))
7364
				$str.="<link rel=\"stylesheet\" type=\"text/css\" media=\"{$url[1]}\" href=\"".THttpUtility::htmlEncode($url[0])."\" />\n";
7365
			else
7366
				$str.="<link rel=\"stylesheet\" type=\"text/css\" href=\"".THttpUtility::htmlEncode($url)."\" />\n";
7367
		}
7368
		$writer->write($str);
7369
	}
7370
	public function renderStyleSheets($writer)
7371
	{
7372
		if(count($this->_styleSheets))
7373
			$writer->write("<style type=\"text/css\">\n/*<![CDATA[*/\n".implode("\n",$this->_styleSheets)."\n/*]]>*/\n</style>\n");
7374
	}
7375
	public function renderHeadScriptFiles($writer)
7376
	{
7377
		$this->renderScriptFiles($writer,$this->_headScriptFiles);
7378
	}
7379
	public function renderHeadScripts($writer)
7380
	{
7381
		$writer->write(TJavaScript::renderScriptBlocks($this->_headScripts));
7382
	}
7383
	public function renderScriptFilesBegin($writer)
7384
	{
7385
		$this->renderAllPendingScriptFiles($writer);
7386
	}
7387
	public function renderScriptFilesEnd($writer)
7388
	{
7389
		$this->renderAllPendingScriptFiles($writer);
7390
	}
7391
	public function markScriptFileAsRendered($url)
7392
	{
7393
		$this->_renderedScriptFiles[$url] = $url;
7394
		$params=func_get_args();
7395
		$this->_page->registerCachingAction('Page.ClientScript','markScriptFileAsRendered',$params);
7396
	}
7397
	protected function renderScriptFiles($writer, Array $scripts)
7398
	{
7399
		foreach($scripts as $script)
7400
		{
7401
			$writer->write(TJavaScript::renderScriptFile($script));
7402
			$this->markScriptFileAsRendered($script);
7403
		}
7404
	}
7405
	protected function getRenderedScriptFiles()
7406
	{
7407
		return $this->_renderedScriptFiles;
7408
	}
7409
	public function renderAllPendingScriptFiles($writer)
7410
	{
7411
		if(!empty($this->_scriptFiles))
7412
		{
7413
			$addedScripts = array_diff($this->_scriptFiles,$this->getRenderedScriptFiles());
7414
			$this->renderScriptFiles($writer,$addedScripts);
7415
		}
7416
	}
7417
	public function renderBeginScripts($writer)
7418
	{
7419
		$writer->write(TJavaScript::renderScriptBlocks($this->_beginScripts));
7420
	}
7421
	public function renderEndScripts($writer)
7422
	{
7423
		$writer->write(TJavaScript::renderScriptBlocks($this->_endScripts));
7424
	}
7425
	public function renderBeginScriptsCallback($writer)
7426
	{
7427
		$writer->write(TJavaScript::renderScriptBlocksCallback($this->_beginScripts));
7428
	}
7429
	public function renderEndScriptsCallback($writer)
7430
	{
7431
		$writer->write(TJavaScript::renderScriptBlocksCallback($this->_endScripts));
7432
	}
7433
	public function renderHiddenFieldsBegin($writer)
7434
	{
7435
		$this->renderHiddenFieldsInt($writer,true);
7436
	}
7437
	public function renderHiddenFieldsEnd($writer)
7438
	{
7439
		$this->renderHiddenFieldsInt($writer,false);
7440
	}
7441
	public function flushScriptFiles($writer, $control=null)
7442
	{
7443
		if(!$this->_page->getIsCallback())
7444
		{
7445
			$this->_page->ensureRenderInForm($control);
7446
			$this->renderAllPendingScriptFiles($writer);
7447
		}
7448
	}
7449
	protected function renderHiddenFieldsInt($writer, $initial)
7450
 	{
7451
		if ($initial) $this->_renderedHiddenFields = array();
7452
		$str='';
7453
		foreach($this->_hiddenFields as $name=>$value)
7454
		{
7455
			if (in_array($name,$this->_renderedHiddenFields)) continue;
7456
			$id=strtr($name,':','_');
7457
			if(is_array($value))
7458
			{
7459
				foreach($value as $v)
7460
					$str.='<input type="hidden" name="'.$name.'[]" id="'.$id.'" value="'.THttpUtility::htmlEncode($value)."\" />\n";
7461
			}
7462
			else
7463
			{
7464
				$str.='<input type="hidden" name="'.$name.'" id="'.$id.'" value="'.THttpUtility::htmlEncode($value)."\" />\n";
7465
			}
7466
			$this->_renderedHiddenFields[] = $name;
7467
		}
7468
		if($str!=='')
7469
			$writer->write("<div style=\"visibility:hidden;\">\n".$str."</div>\n");
7470
	}
7471
	public function getHiddenFields()
7472
	{
7473
		return $this->_hiddenFields;
7474
	}
7475
	protected function checkIfNotInRender()
7476
	{
7477
		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...
7478
			throw new Exception('Operation invalid when page is already rendering');
7479
	}
7480
}
7481
abstract class TClientSideOptions extends TComponent
7482
{
7483
	private $_options;
7484
	protected function setFunction($name, $code)
7485
	{
7486
		if(!TJavaScript::isJsLiteral($code))
7487
			$code = TJavaScript::quoteJsLiteral($this->ensureFunction($code));
7488
		$this->setOption($name, $code);
7489
	}
7490
	protected function getOption($name)
7491
	{
7492
		if ($this->_options)
7493
			return $this->_options->itemAt($name);
7494
		else
7495
			return null;
7496
	}
7497
	protected function setOption($name, $value)
7498
	{
7499
		$this->getOptions()->add($name, $value);
7500
	}
7501
	public function getOptions()
7502
	{
7503
		if (!$this->_options)
7504
			$this->_options = Prado::createComponent('System.Collections.TMap');
7505
		return $this->_options;
7506
	}
7507
	protected function ensureFunction($javascript)
7508
	{
7509
		return "function(sender, parameter){ {$javascript} }";
7510
	}
7511
}
7512
class TPage extends TTemplateControl
7513
{
7514
	const FIELD_POSTBACK_TARGET='PRADO_POSTBACK_TARGET';
7515
	const FIELD_POSTBACK_PARAMETER='PRADO_POSTBACK_PARAMETER';
7516
	const FIELD_LASTFOCUS='PRADO_LASTFOCUS';
7517
	const FIELD_PAGESTATE='PRADO_PAGESTATE';
7518
	const FIELD_CALLBACK_TARGET='PRADO_CALLBACK_TARGET';
7519
	const FIELD_CALLBACK_PARAMETER='PRADO_CALLBACK_PARAMETER';
7520
	private static $_systemPostFields=array(
7521
		'PRADO_POSTBACK_TARGET'=>true,
7522
		'PRADO_POSTBACK_PARAMETER'=>true,
7523
		'PRADO_LASTFOCUS'=>true,
7524
		'PRADO_PAGESTATE'=>true,
7525
		'PRADO_CALLBACK_TARGET'=>true,
7526
		'PRADO_CALLBACK_PARAMETER'=>true
7527
	);
7528
	private $_form;
7529
	private $_head;
7530
	private $_validators=array();
7531
	private $_validated=false;
7532
	private $_theme;
7533
	private $_title;
7534
	private $_styleSheet;
7535
	private $_clientScript;
7536
	protected $_postData;
7537
	protected $_restPostData;
7538
	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...
7539
	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...
7540
	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...
7541
	private $_postBackEventTarget;
7542
	private $_postBackEventParameter;
7543
	protected $_formRendered=false;
7544
	protected $_inFormRender=false;
7545
	private $_focus;
7546
	private $_pagePath='';
7547
	private $_enableStateValidation=true;
7548
	private $_enableStateEncryption=false;
7549
	private $_enableStateCompression=true;
7550
	private $_statePersisterClass='System.Web.UI.TPageStatePersister';
7551
	private $_statePersister;
7552
	private $_cachingStack;
7553
	private $_clientState='';
7554
	protected $_isLoadingPostData=false;
7555
	private $_enableJavaScript=true;
7556
	private $_writer;
7557
	public function __construct()
7558
	{
7559
		$this->setPage($this);
7560
	}
7561
	public function run($writer)
7562
	{
7563
		$this->_writer = $writer;
7564
		$this->determinePostBackMode();
7565
		if($this->getIsPostBack())
7566
		{
7567
			if($this->getIsCallback())
7568
				$this->processCallbackRequest($writer);
7569
			else
7570
				$this->processPostBackRequest($writer);
7571
		}
7572
		else
7573
			$this->processNormalRequest($writer);
7574
		$this->_writer = null;
7575
	}
7576
	protected function processNormalRequest($writer)
7577
	{
7578
		$this->onPreInit(null);
7579
		$this->initRecursive();
7580
		$this->onInitComplete(null);
7581
		$this->onPreLoad(null);
7582
		$this->loadRecursive();
7583
		$this->onLoadComplete(null);
7584
		$this->preRenderRecursive();
7585
		$this->onPreRenderComplete(null);
7586
		$this->savePageState();
7587
		$this->onSaveStateComplete(null);
7588
		$this->renderControl($writer);
7589
		$this->unloadRecursive();
7590
	}
7591
	protected function processPostBackRequest($writer)
7592
	{
7593
		$this->onPreInit(null);
7594
		$this->initRecursive();
7595
		$this->onInitComplete(null);
7596
		$this->_restPostData=new TMap;
7597
		$this->loadPageState();
7598
		$this->processPostData($this->_postData,true);
7599
		$this->onPreLoad(null);
7600
		$this->loadRecursive();
7601
		$this->processPostData($this->_restPostData,false);
7602
		$this->raiseChangedEvents();
7603
		$this->raisePostBackEvent();
7604
		$this->onLoadComplete(null);
7605
		$this->preRenderRecursive();
7606
		$this->onPreRenderComplete(null);
7607
		$this->savePageState();
7608
		$this->onSaveStateComplete(null);
7609
		$this->renderControl($writer);
7610
		$this->unloadRecursive();
7611
	}
7612
	protected static function decodeUTF8($data, $enc)
7613
	{
7614
		if(is_array($data))
7615
		{
7616
			foreach($data as $k=>$v)
7617
				$data[$k]=self::decodeUTF8($v, $enc);
7618
			return $data;
7619
		} elseif(is_string($data)) {
7620
			return iconv('UTF-8',$enc.'//IGNORE',$data);
7621
		} else {
7622
			return $data;
7623
		}
7624
	}
7625
	protected function processCallbackRequest($writer)
7626
	{
7627
		Prado::using('System.Web.UI.ActiveControls.TActivePageAdapter');
7628
		Prado::using('System.Web.UI.JuiControls.TJuiControlOptions');
7629
		$this->setAdapter(new TActivePageAdapter($this));
7630
        $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...
7631
        if(strlen($callbackEventParameter) > 0)
7632
            $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...
7633
                if (($g=$this->getApplication()->getGlobalization(false))!==null &&
7634
            strtoupper($enc=$g->getCharset())!='UTF-8')
7635
                foreach ($this->_postData as $k=>$v)
7636
                	$this->_postData[$k]=self::decodeUTF8($v, $enc);
7637
		$this->onPreInit(null);
7638
		$this->initRecursive();
7639
		$this->onInitComplete(null);
7640
		$this->_restPostData=new TMap;
7641
		$this->loadPageState();
7642
		$this->processPostData($this->_postData,true);
7643
		$this->onPreLoad(null);
7644
		$this->loadRecursive();
7645
		$this->processPostData($this->_restPostData,false);
7646
		$this->raiseChangedEvents();
7647
		$this->getAdapter()->processCallbackEvent($writer);
7648
		$this->onLoadComplete(null);
7649
		$this->preRenderRecursive();
7650
		$this->onPreRenderComplete(null);
7651
		$this->savePageState();
7652
		$this->onSaveStateComplete(null);
7653
		$this->getAdapter()->renderCallbackResponse($writer);
7654
		$this->unloadRecursive();
7655
	}
7656
	public function getCallbackClient()
7657
	{
7658
		if($this->getAdapter() !== null)
7659
			return $this->getAdapter()->getCallbackClientHandler();
7660
		else
7661
			return new TCallbackClientScript();
7662
	}
7663
	public function setCallbackClient($client)
7664
	{
7665
		$this->getAdapter()->setCallbackClientHandler($client);
7666
	}
7667
	public function getCallbackEventTarget()
7668
	{
7669
		return $this->getAdapter()->getCallbackEventTarget();
7670
	}
7671
	public function setCallbackEventTarget(TControl $control)
7672
	{
7673
		$this->getAdapter()->setCallbackEventTarget($control);
7674
	}
7675
	public function getCallbackEventParameter()
7676
	{
7677
		return $this->getAdapter()->getCallbackEventParameter();
7678
	}
7679
	public function setCallbackEventParameter($value)
7680
	{
7681
		$this->getAdapter()->setCallbackEventParameter($value);
7682
	}
7683
	public function getForm()
7684
	{
7685
		return $this->_form;
7686
	}
7687
	public function setForm(TForm $form)
7688
	{
7689
		if($this->_form===null)
7690
			$this->_form=$form;
7691
		else
7692
			throw new TInvalidOperationException('page_form_duplicated');
7693
	}
7694
	public function getValidators($validationGroup=null)
7695
	{
7696
		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...
7697
			$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...
7698
		if(empty($validationGroup) === true)
7699
			return $this->_validators;
7700
		else
7701
		{
7702
			$list=new TList;
7703
			foreach($this->_validators as $validator)
7704
				if($validator->getValidationGroup()===$validationGroup)
7705
					$list->add($validator);
7706
			return $list;
7707
		}
7708
	}
7709
	public function validate($validationGroup=null)
7710
	{
7711
		$this->_validated=true;
7712
		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...
7713
		{
7714
			if($validationGroup===null)
7715
			{
7716
				foreach($this->_validators as $validator)
7717
					$validator->validate();
7718
			}
7719
			else
7720
			{
7721
				foreach($this->_validators as $validator)
7722
				{
7723
					if($validator->getValidationGroup()===$validationGroup)
7724
						$validator->validate();
7725
				}
7726
			}
7727
		}
7728
	}
7729
	public function getIsValid()
7730
	{
7731
		if($this->_validated)
7732
		{
7733
			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...
7734
			{
7735
				foreach($this->_validators as $validator)
7736
					if(!$validator->getIsValid())
7737
						return false;
7738
			}
7739
			return true;
7740
		}
7741
		else
7742
			throw new TInvalidOperationException('page_isvalid_unknown');
7743
	}
7744
	public function getTheme()
7745
	{
7746
		if(is_string($this->_theme))
7747
			$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...
7748
		return $this->_theme;
7749
	}
7750
	public function setTheme($value)
7751
	{
7752
		$this->_theme=empty($value)?null:$value;
7753
	}
7754
	public function getStyleSheetTheme()
7755
	{
7756
		if(is_string($this->_styleSheet))
7757
			$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...
7758
		return $this->_styleSheet;
7759
	}
7760
	public function setStyleSheetTheme($value)
7761
	{
7762
		$this->_styleSheet=empty($value)?null:$value;
7763
	}
7764
	public function applyControlSkin($control)
7765
	{
7766
		if(($theme=$this->getTheme())!==null)
7767
			$theme->applySkin($control);
7768
	}
7769
	public function applyControlStyleSheet($control)
7770
	{
7771
		if(($theme=$this->getStyleSheetTheme())!==null)
7772
			$theme->applySkin($control);
7773
	}
7774
	public function getClientScript()
7775
	{
7776
		if(!$this->_clientScript) {
7777
			$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...
7778
			Prado::using($className);
7779
			if(($pos=strrpos($className,'.'))!==false)
7780
				$className=substr($className,$pos+1);
7781
 			if(!class_exists($className,false) || ($className!=='TClientScriptManager' && !is_subclass_of($className,'TClientScriptManager')))
7782
				throw new THttpException(404,'page_csmanagerclass_invalid',$classPath);
7783
			$this->_clientScript=new $className($this);
7784
		}
7785
		return $this->_clientScript;
7786
	}
7787
	public function onPreInit($param)
7788
	{
7789
		$this->raiseEvent('OnPreInit',$this,$param);
7790
	}
7791
	public function onInitComplete($param)
7792
	{
7793
		$this->raiseEvent('OnInitComplete',$this,$param);
7794
	}
7795
	public function onPreLoad($param)
7796
	{
7797
		$this->raiseEvent('OnPreLoad',$this,$param);
7798
	}
7799
	public function onLoadComplete($param)
7800
	{
7801
		$this->raiseEvent('OnLoadComplete',$this,$param);
7802
	}
7803
	public function onPreRenderComplete($param)
7804
	{
7805
		$this->raiseEvent('OnPreRenderComplete',$this,$param);
7806
		$cs=$this->getClientScript();
7807
		$theme=$this->getTheme();
7808
		if($theme instanceof ITheme)
7809
		{
7810
			foreach($theme->getStyleSheetFiles() as $url)
7811
				$cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
7812
			foreach($theme->getJavaScriptFiles() as $url)
7813
				$cs->registerHeadScriptFile($url,$url);
7814
		}
7815
		$styleSheet=$this->getStyleSheetTheme();
7816
		if($styleSheet instanceof ITheme)
7817
		{
7818
			foreach($styleSheet->getStyleSheetFiles() as $url)
7819
				$cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
7820
			foreach($styleSheet->getJavaScriptFiles() as $url)
7821
				$cs->registerHeadScriptFile($url,$url);
7822
		}
7823
		if($cs->getRequiresHead() && $this->getHead()===null)
7824
			throw new TConfigurationException('page_head_required');
7825
	}
7826
	private function getCssMediaType($url)
7827
	{
7828
		$segs=explode('.',basename($url));
7829
		if(isset($segs[2]))
7830
			return $segs[count($segs)-2];
7831
		else
7832
			return '';
7833
	}
7834
	public function onSaveStateComplete($param)
7835
	{
7836
		$this->raiseEvent('OnSaveStateComplete',$this,$param);
7837
	}
7838
	private function determinePostBackMode()
7839
	{
7840
		$postData=$this->getRequest();
7841
		if($postData->contains(self::FIELD_PAGESTATE) || $postData->contains(self::FIELD_POSTBACK_TARGET))
7842
			$this->_postData=$postData;
7843
	}
7844
	public function getIsPostBack()
7845
	{
7846
		return $this->_postData!==null;
7847
	}
7848
	public function getIsCallback()
7849
	{
7850
		return $this->getIsPostBack() && $this->getRequest()->contains(self::FIELD_CALLBACK_TARGET);
7851
	}
7852
	public function saveState()
7853
	{
7854
		parent::saveState();
7855
		$this->setViewState('ControlsRequiringPostBack',$this->_controlsRegisteredForPostData,array());
7856
	}
7857
	public function loadState()
7858
	{
7859
		parent::loadState();
7860
		$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...
7861
	}
7862
	protected function loadPageState()
7863
	{
7864
		$state=$this->getStatePersister()->load();
7865
		$this->loadStateRecursive($state,$this->getEnableViewState());
7866
	}
7867
	protected function savePageState()
7868
	{
7869
		$state=&$this->saveStateRecursive($this->getEnableViewState());
7870
		$this->getStatePersister()->save($state);
7871
	}
7872
	protected function isSystemPostField($field)
7873
	{
7874
		return isset(self::$_systemPostFields[$field]);
7875
	}
7876
	public function registerRequiresPostData($control)
7877
	{
7878
		$id=is_string($control)?$control:$control->getUniqueID();
7879
		$this->_controlsRegisteredForPostData[$id]=true;
7880
		$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...
7881
		foreach($this->getCachingStack() as $item)
7882
			$item->registerAction('Page','registerRequiresPostData',array($id));
7883
	}
7884
	public function getPostBackEventTarget()
7885
	{
7886
		if($this->_postBackEventTarget===null && $this->_postData!==null)
7887
		{
7888
			$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...
7889
			if(!empty($eventTarget))
7890
				$this->_postBackEventTarget=$this->findControl($eventTarget);
7891
		}
7892
		return $this->_postBackEventTarget;
7893
	}
7894
	public function setPostBackEventTarget(TControl $control)
7895
	{
7896
		$this->_postBackEventTarget=$control;
7897
	}
7898
	public function getPostBackEventParameter()
7899
	{
7900
		if($this->_postBackEventParameter===null && $this->_postData!==null)
7901
		{
7902
			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...
7903
				$this->_postBackEventParameter='';
7904
		}
7905
		return $this->_postBackEventParameter;
7906
	}
7907
	public function setPostBackEventParameter($value)
7908
	{
7909
		$this->_postBackEventParameter=$value;
7910
	}
7911
	protected function processPostData($postData,$beforeLoad)
7912
	{
7913
		$this->_isLoadingPostData=true;
7914
		if($beforeLoad)
7915
			$this->_restPostData=new TMap;
7916
		foreach($postData as $key=>$value)
7917
		{
7918
			if($this->isSystemPostField($key))
7919
				continue;
7920
			else if($control=$this->findControl($key))
7921
			{
7922
				if($control instanceof IPostBackDataHandler)
7923
				{
7924
					if($control->loadPostData($key,$postData))
7925
						$this->_controlsPostDataChanged[]=$control;
7926
				}
7927
				else if($control instanceof IPostBackEventHandler &&
7928
					empty($this->_postData[self::FIELD_POSTBACK_TARGET]))
7929
				{
7930
					$this->_postData->add(self::FIELD_POSTBACK_TARGET,$key);  				}
7931
				unset($this->_controlsRequiringPostData[$key]);
7932
			}
7933
			else if($beforeLoad)
7934
				$this->_restPostData->add($key,$value);
7935
		}
7936
		foreach($this->_controlsRequiringPostData as $key=>$value)
7937
		{
7938
			if($control=$this->findControl($key))
7939
			{
7940
				if($control instanceof IPostBackDataHandler)
7941
				{
7942
					if($control->loadPostData($key,$this->_postData))
7943
						$this->_controlsPostDataChanged[]=$control;
7944
				}
7945
				else
7946
					throw new TInvalidDataValueException('page_postbackcontrol_invalid',$key);
7947
				unset($this->_controlsRequiringPostData[$key]);
7948
			}
7949
		}
7950
		$this->_isLoadingPostData=false;
7951
	}
7952
	public function getIsLoadingPostData()
7953
	{
7954
		return $this->_isLoadingPostData;
7955
	}
7956
	protected function raiseChangedEvents()
7957
	{
7958
		foreach($this->_controlsPostDataChanged as $control)
7959
			$control->raisePostDataChangedEvent();
7960
	}
7961
	protected function raisePostBackEvent()
7962
	{
7963
		if(($postBackHandler=$this->getPostBackEventTarget())===null)
7964
			$this->validate();
7965
		else if($postBackHandler instanceof IPostBackEventHandler)
7966
			$postBackHandler->raisePostBackEvent($this->getPostBackEventParameter());
7967
	}
7968
	public function getInFormRender()
7969
	{
7970
		return $this->_inFormRender;
7971
	}
7972
	public function ensureRenderInForm($control)
7973
	{
7974
		if(!$this->getIsCallback() && !$this->_inFormRender)
7975
			throw new TConfigurationException('page_control_outofform',get_class($control), $control ? $control->getUniqueID() : null);
7976
	}
7977
	public function beginFormRender($writer)
7978
	{
7979
		if($this->_formRendered)
7980
			throw new TConfigurationException('page_form_duplicated');
7981
		$this->_formRendered=true;
7982
		$this->getClientScript()->registerHiddenField(self::FIELD_PAGESTATE,$this->getClientState());
7983
		$this->_inFormRender=true;
7984
	}
7985
	public function endFormRender($writer)
7986
	{
7987
		if($this->_focus)
7988
		{
7989
			if(($this->_focus instanceof TControl) && $this->_focus->getVisible(true))
7990
				$focus=$this->_focus->getClientID();
7991
			else
7992
				$focus=$this->_focus;
7993
			$this->getClientScript()->registerFocusControl($focus);
7994
		}
7995
		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...
7996
			$this->getClientScript()->registerFocusControl($lastFocus);
7997
		$this->_inFormRender=false;
7998
	}
7999
	public function setFocus($value)
8000
	{
8001
		$this->_focus=$value;
8002
	}
8003
	public function getClientSupportsJavaScript()
8004
	{
8005
		return $this->_enableJavaScript;
8006
	}
8007
	public function setClientSupportsJavaScript($value)
8008
	{
8009
		$this->_enableJavaScript=TPropertyValue::ensureBoolean($value);
8010
	}
8011
	public function getHead()
8012
	{
8013
		return $this->_head;
8014
	}
8015
	public function setHead(THead $value)
8016
	{
8017
		if($this->_head)
8018
			throw new TInvalidOperationException('page_head_duplicated');
8019
		$this->_head=$value;
8020
		if($this->_title!==null)
8021
		{
8022
			$this->_head->setTitle($this->_title);
8023
			$this->_title=null;
8024
		}
8025
	}
8026
	public function getTitle()
8027
	{
8028
		if($this->_head)
8029
			return $this->_head->getTitle();
8030
		else
8031
			return $this->_title===null ? '' : $this->_title;
8032
	}
8033
	public function setTitle($value)
8034
	{
8035
		if($this->_head)
8036
			$this->_head->setTitle($value);
8037
		else
8038
			$this->_title=$value;
8039
	}
8040
	public function getClientState()
8041
	{
8042
		return $this->_clientState;
8043
	}
8044
	public function setClientState($state)
8045
	{
8046
		$this->_clientState=$state;
8047
	}
8048
	public function getRequestClientState()
8049
	{
8050
		return $this->getRequest()->itemAt(self::FIELD_PAGESTATE);
8051
	}
8052
	public function getStatePersisterClass()
8053
	{
8054
		return $this->_statePersisterClass;
8055
	}
8056
	public function setStatePersisterClass($value)
8057
	{
8058
		$this->_statePersisterClass=$value;
8059
	}
8060
	public function getStatePersister()
8061
	{
8062
		if($this->_statePersister===null)
8063
		{
8064
			$this->_statePersister=Prado::createComponent($this->_statePersisterClass);
8065
			if(!($this->_statePersister instanceof IPageStatePersister))
8066
				throw new TInvalidDataTypeException('page_statepersister_invalid');
8067
			$this->_statePersister->setPage($this);
8068
		}
8069
		return $this->_statePersister;
8070
	}
8071
	public function getEnableStateValidation()
8072
	{
8073
		return $this->_enableStateValidation;
8074
	}
8075
	public function setEnableStateValidation($value)
8076
	{
8077
		$this->_enableStateValidation=TPropertyValue::ensureBoolean($value);
8078
	}
8079
	public function getEnableStateEncryption()
8080
	{
8081
		return $this->_enableStateEncryption;
8082
	}
8083
	public function setEnableStateEncryption($value)
8084
	{
8085
		$this->_enableStateEncryption=TPropertyValue::ensureBoolean($value);
8086
	}
8087
	public function getEnableStateCompression()
8088
	{
8089
		return $this->_enableStateCompression;
8090
	}
8091
	public function setEnableStateCompression($value)
8092
	{
8093
		$this->_enableStateCompression=TPropertyValue::ensureBoolean($value);
8094
	}
8095
	public function getPagePath()
8096
	{
8097
		return $this->_pagePath;
8098
	}
8099
	public function setPagePath($value)
8100
	{
8101
		$this->_pagePath=$value;
8102
	}
8103
	public function registerCachingAction($context,$funcName,$funcParams)
8104
	{
8105
		if($this->_cachingStack)
8106
		{
8107
			foreach($this->_cachingStack as $cache)
8108
				$cache->registerAction($context,$funcName,$funcParams);
8109
		}
8110
	}
8111
	public function getCachingStack()
8112
	{
8113
		if(!$this->_cachingStack)
8114
			$this->_cachingStack=new TStack;
8115
		return $this->_cachingStack;
8116
	}
8117
	public function flushWriter()
8118
	{
8119
		if ($this->_writer)
8120
			$this->Response->write($this->_writer->flush());
8121
	}
8122
}
8123
interface IPageStatePersister
8124
{
8125
	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...
8126
	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...
8127
	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...
8128
	public function load();
8129
}
8130
class TPageStateFormatter
8131
{
8132
	public static function serialize($page,$data)
8133
	{
8134
		$sm=$page->getApplication()->getSecurityManager();
8135
		if($page->getEnableStateValidation())
8136
			$str=$sm->hashData(serialize($data));
8137
		else
8138
			$str=serialize($data);
8139
		if($page->getEnableStateCompression() && extension_loaded('zlib'))
8140
			$str=gzcompress($str);
8141
		if($page->getEnableStateEncryption())
8142
			$str=$sm->encrypt($str);
8143
		return base64_encode($str);
8144
	}
8145
	public static function unserialize($page,$data)
8146
	{
8147
		$str=base64_decode($data);
8148
		if($str==='')
8149
			return null;
8150
		if($str!==false)
8151
		{
8152
			$sm=$page->getApplication()->getSecurityManager();
8153
			if($page->getEnableStateEncryption())
8154
				$str=$sm->decrypt($str);
8155
			if($page->getEnableStateCompression() && extension_loaded('zlib'))
8156
				$str=@gzuncompress($str);
8157
			if($page->getEnableStateValidation())
8158
			{
8159
				if(($str=$sm->validateData($str))!==false)
8160
					return unserialize($str);
8161
			}
8162
			else
8163
				return unserialize($str);
8164
		}
8165
		return null;
8166
	}
8167
}
8168
class TOutputCache extends TControl implements INamingContainer
8169
{
8170
	const CACHE_ID_PREFIX='prado:outputcache';
8171
	private $_cacheModuleID='';
8172
	private $_dataCached=false;
8173
	private $_cacheAvailable=false;
8174
	private $_cacheChecked=false;
8175
	private $_cacheKey=null;
8176
	private $_duration=60;
8177
	private $_cache=null;
8178
	private $_contents;
8179
	private $_state;
8180
	private $_actions=array();
8181
	private $_varyByParam='';
8182
	private $_keyPrefix='';
8183
	private $_varyBySession=false;
8184
	private $_cachePostBack=false;
8185
	private $_cacheTime=0;
8186
	public function getAllowChildControls()
8187
	{
8188
		$this->determineCacheability();
8189
		return !$this->_dataCached;
8190
	}
8191
	private function determineCacheability()
8192
	{
8193
		if(!$this->_cacheChecked)
8194
		{
8195
			$this->_cacheChecked=true;
8196
			if($this->_duration>0 && ($this->_cachePostBack || !$this->getPage()->getIsPostBack()))
8197
			{
8198
				if($this->_cacheModuleID!=='')
8199
				{
8200
					$this->_cache=$this->getApplication()->getModule($this->_cacheModuleID);
8201
					if(!($this->_cache instanceof ICache))
8202
						throw new TConfigurationException('outputcache_cachemoduleid_invalid',$this->_cacheModuleID);
8203
				}
8204
				else
8205
					$this->_cache=$this->getApplication()->getCache();
8206
				if($this->_cache!==null)
8207
				{
8208
					$this->_cacheAvailable=true;
8209
					$data=$this->_cache->get($this->getCacheKey());
8210
					if(is_array($data))
8211
					{
8212
						$param=new TOutputCacheCheckDependencyEventParameter;
8213
						$param->setCacheTime(isset($data[3])?$data[3]:0);
8214
						$this->onCheckDependency($param);
8215
						$this->_dataCached=$param->getIsValid();
8216
					}
8217
					else
8218
						$this->_dataCached=false;
8219
					if($this->_dataCached)
8220
						list($this->_contents,$this->_state,$this->_actions,$this->_cacheTime)=$data;
8221
				}
8222
			}
8223
		}
8224
	}
8225
	protected function initRecursive($namingContainer=null)
8226
	{
8227
		if($this->_cacheAvailable && !$this->_dataCached)
8228
		{
8229
			$stack=$this->getPage()->getCachingStack();
8230
			$stack->push($this);
8231
			parent::initRecursive($namingContainer);
8232
			$stack->pop();
8233
		}
8234
		else
8235
			parent::initRecursive($namingContainer);
8236
	}
8237
	protected function loadRecursive()
8238
	{
8239
		if($this->_cacheAvailable && !$this->_dataCached)
8240
		{
8241
			$stack=$this->getPage()->getCachingStack();
8242
			$stack->push($this);
8243
			parent::loadRecursive();
8244
			$stack->pop();
8245
		}
8246
		else
8247
		{
8248
			if($this->_dataCached)
8249
				$this->performActions();
8250
			parent::loadRecursive();
8251
		}
8252
	}
8253
	private function performActions()
8254
	{
8255
		$page=$this->getPage();
8256
		$cs=$page->getClientScript();
8257
		foreach($this->_actions as $action)
8258
		{
8259
			if($action[0]==='Page.ClientScript')
8260
				call_user_func_array(array($cs,$action[1]),$action[2]);
8261
			else if($action[0]==='Page')
8262
				call_user_func_array(array($page,$action[1]),$action[2]);
8263
			else
8264
				call_user_func_array(array($this->getSubProperty($action[0]),$action[1]),$action[2]);
8265
		}
8266
	}
8267
	protected function preRenderRecursive()
8268
	{
8269
		if($this->_cacheAvailable && !$this->_dataCached)
8270
		{
8271
			$stack=$this->getPage()->getCachingStack();
8272
			$stack->push($this);
8273
			parent::preRenderRecursive();
8274
			$stack->pop();
8275
		}
8276
		else
8277
			parent::preRenderRecursive();
8278
	}
8279
	protected function loadStateRecursive(&$state,$needViewState=true)
8280
	{
8281
		$st=unserialize($state);
8282
		parent::loadStateRecursive($st,$needViewState);
8283
	}
8284
	protected function &saveStateRecursive($needViewState=true)
8285
	{
8286
		if($this->_dataCached)
8287
			return $this->_state;
8288
		else
8289
		{
8290
			$st=parent::saveStateRecursive($needViewState);
8291
						$this->_state=serialize($st);
8292
			return $this->_state;
8293
		}
8294
	}
8295
	public function registerAction($context,$funcName,$funcParams)
8296
	{
8297
		$this->_actions[]=array($context,$funcName,$funcParams);
8298
	}
8299
	public function getCacheKey()
8300
	{
8301
		if($this->_cacheKey===null)
8302
			$this->_cacheKey=$this->calculateCacheKey();
8303
		return $this->_cacheKey;
8304
	}
8305
	protected function calculateCacheKey()
8306
	{
8307
		$key=$this->getBaseCacheKey();
8308
		if($this->_varyBySession)
8309
			$key.=$this->getSession()->getSessionID();
8310
		if($this->_varyByParam!=='')
8311
		{
8312
			$params=array();
8313
			$request=$this->getRequest();
8314
			foreach(explode(',',$this->_varyByParam) as $name)
8315
			{
8316
				$name=trim($name);
8317
				$params[$name]=$request->itemAt($name);
8318
			}
8319
			$key.=serialize($params);
8320
		}
8321
		$param=new TOutputCacheCalculateKeyEventParameter;
8322
		$this->onCalculateKey($param);
8323
		$key.=$param->getCacheKey();
8324
		return $key;
8325
	}
8326
	protected function getBaseCacheKey()
8327
	{
8328
		return self::CACHE_ID_PREFIX.$this->_keyPrefix.$this->getPage()->getPagePath().$this->getUniqueID();
8329
	}
8330
	public function getCacheModuleID()
8331
	{
8332
		return $this->_cacheModuleID;
8333
	}
8334
	public function setCacheModuleID($value)
8335
	{
8336
		$this->_cacheModuleID=$value;
8337
	}
8338
	public function setCacheKeyPrefix($value)
8339
	{
8340
		$this->_keyPrefix=$value;
8341
	}
8342
	public function getCacheTime()
8343
	{
8344
		return $this->_cacheTime;
8345
	}
8346
	protected function getCacheDependency()
8347
	{
8348
		return null;
8349
	}
8350
	public function getContentCached()
8351
	{
8352
		return $this->_dataCached;
8353
	}
8354
	public function getDuration()
8355
	{
8356
		return $this->_duration;
8357
	}
8358
	public function setDuration($value)
8359
	{
8360
		if(($value=TPropertyValue::ensureInteger($value))<0)
8361
			throw new TInvalidDataValueException('outputcache_duration_invalid',get_class($this));
8362
		$this->_duration=$value;
8363
	}
8364
	public function getVaryByParam()
8365
	{
8366
		return $this->_varyByParam;
8367
	}
8368
	public function setVaryByParam($value)
8369
	{
8370
		$this->_varyByParam=trim($value);
8371
	}
8372
	public function getVaryBySession()
8373
	{
8374
		return $this->_varyBySession;
8375
	}
8376
	public function setVaryBySession($value)
8377
	{
8378
		$this->_varyBySession=TPropertyValue::ensureBoolean($value);
8379
	}
8380
	public function getCachingPostBack()
8381
	{
8382
		return $this->_cachePostBack;
8383
	}
8384
	public function setCachingPostBack($value)
8385
	{
8386
		$this->_cachePostBack=TPropertyValue::ensureBoolean($value);
8387
	}
8388
	public function onCheckDependency($param)
8389
	{
8390
		$this->raiseEvent('OnCheckDependency',$this,$param);
8391
	}
8392
	public function onCalculateKey($param)
8393
	{
8394
		$this->raiseEvent('OnCalculateKey',$this,$param);
8395
	}
8396
	public function render($writer)
8397
	{
8398
		if($this->_dataCached)
8399
			$writer->write($this->_contents);
8400
		else if($this->_cacheAvailable)
8401
		{
8402
			$textwriter = new TTextWriter();
8403
			$multiwriter = new TOutputCacheTextWriterMulti(array($writer->getWriter(),$textwriter));
8404
			$htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), $multiwriter);
8405
			$stack=$this->getPage()->getCachingStack();
8406
			$stack->push($this);
8407
			parent::render($htmlWriter);
8408
			$stack->pop();
8409
			$content=$textwriter->flush();
8410
			$data=array($content,$this->_state,$this->_actions,time());
8411
			$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...
8412
		}
8413
		else
8414
			parent::render($writer);
8415
	}
8416
}
8417
class TOutputCacheCheckDependencyEventParameter extends TEventParameter
8418
{
8419
	private $_isValid=true;
8420
	private $_cacheTime=0;
8421
	public function getIsValid()
8422
	{
8423
		return $this->_isValid;
8424
	}
8425
	public function setIsValid($value)
8426
	{
8427
		$this->_isValid=TPropertyValue::ensureBoolean($value);
8428
	}
8429
	public function getCacheTime()
8430
	{
8431
		return $this->_cacheTime;
8432
	}
8433
	public function setCacheTime($value)
8434
	{
8435
		$this->_cacheTime=TPropertyValue::ensureInteger($value);
8436
	}
8437
}
8438
class TOutputCacheCalculateKeyEventParameter extends TEventParameter
8439
{
8440
	private $_cacheKey='';
8441
	public function getCacheKey()
8442
	{
8443
		return $this->_cacheKey;
8444
	}
8445
	public function setCacheKey($value)
8446
	{
8447
		$this->_cacheKey=TPropertyValue::ensureString($value);
8448
	}
8449
}
8450
class TOutputCacheTextWriterMulti extends TTextWriter
8451
{
8452
	protected $_writers;
8453
	public function __construct(Array $writers)
8454
	{
8455
				$this->_writers = $writers;
8456
	}
8457
	public function write($s)
8458
	{
8459
		foreach($this->_writers as $writer)
8460
			$writer->write($s);
8461
	}
8462
	public function flush()
8463
	{
8464
		foreach($this->_writers as $writer)
8465
			$s = $writer->flush();
8466
		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...
8467
	}
8468
}
8469
class TTemplateManager extends TModule
8470
{
8471
	const TEMPLATE_FILE_EXT='.tpl';
8472
	const TEMPLATE_CACHE_PREFIX='prado:template:';
8473
	public function init($config)
8474
	{
8475
		$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...
8476
	}
8477
	public function getTemplateByClassName($className)
8478
	{
8479
		$class=new ReflectionClass($className);
8480
		$tplFile=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$className.self::TEMPLATE_FILE_EXT;
8481
		return $this->getTemplateByFileName($tplFile);
8482
	}
8483
	public function getTemplateByFileName($fileName)
8484
	{
8485
		if(($fileName=$this->getLocalizedTemplate($fileName))!==null)
8486
		{
8487
			if(($cache=$this->getApplication()->getCache())===null)
8488
				return new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
8489
			else
8490
			{
8491
				$array=$cache->get(self::TEMPLATE_CACHE_PREFIX.$fileName);
8492
				if(is_array($array))
8493
				{
8494
					list($template,$timestamps)=$array;
8495
					if($this->getApplication()->getMode()===TApplicationMode::Performance)
8496
						return $template;
8497
					$cacheValid=true;
8498
					foreach($timestamps as $tplFile=>$timestamp)
8499
					{
8500
						if(!is_file($tplFile) || filemtime($tplFile)>$timestamp)
8501
						{
8502
							$cacheValid=false;
8503
							break;
8504
						}
8505
					}
8506
					if($cacheValid)
8507
						return $template;
8508
				}
8509
				$template=new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
8510
				$includedFiles=$template->getIncludedFiles();
8511
				$timestamps=array();
8512
				$timestamps[$fileName]=filemtime($fileName);
8513
				foreach($includedFiles as $includedFile)
8514
					$timestamps[$includedFile]=filemtime($includedFile);
8515
				$cache->set(self::TEMPLATE_CACHE_PREFIX.$fileName,array($template,$timestamps));
8516
				return $template;
8517
			}
8518
		}
8519
		else
8520
			return null;
8521
	}
8522
	protected function getLocalizedTemplate($filename)
8523
	{
8524
		if(($app=$this->getApplication()->getGlobalization(false))===null)
8525
			return is_file($filename)?$filename:null;
8526
		foreach($app->getLocalizedResource($filename) as $file)
8527
		{
8528
			if(($file=realpath($file))!==false && is_file($file))
8529
				return $file;
8530
		}
8531
		return null;
8532
	}
8533
}
8534
class TTemplate extends TApplicationComponent implements ITemplate
8535
{
8536
	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';
8537
	const CONFIG_DATABIND=0;
8538
	const CONFIG_EXPRESSION=1;
8539
	const CONFIG_ASSET=2;
8540
	const CONFIG_PARAMETER=3;
8541
	const CONFIG_LOCALIZATION=4;
8542
	const CONFIG_TEMPLATE=5;
8543
	private $_tpl=array();
8544
	private $_directive=array();
8545
	private $_contextPath;
8546
	private $_tplFile=null;
8547
	private $_startingLine=0;
8548
	private $_content;
8549
	private $_sourceTemplate=true;
8550
	private $_hashCode='';
8551
	private $_tplControl=null;
8552
	private $_includedFiles=array();
8553
	private $_includeAtLine=array();
8554
	private $_includeLines=array();
8555
	public function __construct($template,$contextPath,$tplFile=null,$startingLine=0,$sourceTemplate=true)
8556
	{
8557
		$this->_sourceTemplate=$sourceTemplate;
8558
		$this->_contextPath=$contextPath;
8559
		$this->_tplFile=$tplFile;
8560
		$this->_startingLine=$startingLine;
8561
		$this->_content=$template;
8562
		$this->_hashCode=md5($template);
8563
		$this->parse($template);
8564
		$this->_content=null; 	}
8565
	public function getTemplateFile()
8566
	{
8567
		return $this->_tplFile;
8568
	}
8569
	public function getIsSourceTemplate()
8570
	{
8571
		return $this->_sourceTemplate;
8572
	}
8573
	public function getContextPath()
8574
	{
8575
		return $this->_contextPath;
8576
	}
8577
	public function getDirective()
8578
	{
8579
		return $this->_directive;
8580
	}
8581
	public function getHashCode()
8582
	{
8583
		return $this->_hashCode;
8584
	}
8585
	public function &getItems()
8586
	{
8587
		return $this->_tpl;
8588
	}
8589
	public function instantiateIn($tplControl,$parentControl=null)
8590
	{
8591
		$this->_tplControl=$tplControl;
8592
		if($parentControl===null)
8593
			$parentControl=$tplControl;
8594
		if(($page=$tplControl->getPage())===null)
8595
			$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...
8596
		$controls=array();
8597
		$directChildren=array();
8598
		foreach($this->_tpl as $key=>$object)
8599
		{
8600
			if($object[0]===-1)
8601
				$parent=$parentControl;
8602
			else if(isset($controls[$object[0]]))
8603
				$parent=$controls[$object[0]];
8604
			else
8605
				continue;
8606
			if(isset($object[2]))				{
8607
				$component=Prado::createComponent($object[1]);
8608
				$properties=&$object[2];
8609
				if($component instanceof TControl)
8610
				{
8611
					if($component instanceof TOutputCache)
8612
						$component->setCacheKeyPrefix($this->_hashCode.$key);
8613
					$component->setTemplateControl($tplControl);
8614
					if(isset($properties['id']))
8615
					{
8616
						if(is_array($properties['id']))
8617
							$properties['id']=$component->evaluateExpression($properties['id'][1]);
8618
						$tplControl->registerObject($properties['id'],$component);
8619
					}
8620
					if(isset($properties['skinid']))
8621
					{
8622
						if(is_array($properties['skinid']))
8623
							$component->setSkinID($component->evaluateExpression($properties['skinid'][1]));
8624
						else
8625
							$component->setSkinID($properties['skinid']);
8626
						unset($properties['skinid']);
8627
					}
8628
					$component->trackViewState(false);
8629
					$component->applyStyleSheetSkin($page);
8630
					foreach($properties as $name=>$value)
8631
						$this->configureControl($component,$name,$value);
8632
					$component->trackViewState(true);
8633
					if($parent===$parentControl)
8634
						$directChildren[]=$component;
8635
					else
8636
						$component->createdOnTemplate($parent);
8637
					if($component->getAllowChildControls())
8638
						$controls[$key]=$component;
8639
				}
8640
				else if($component instanceof TComponent)
8641
				{
8642
					$controls[$key]=$component;
8643
					if(isset($properties['id']))
8644
					{
8645
						if(is_array($properties['id']))
8646
							$properties['id']=$component->evaluateExpression($properties['id'][1]);
8647
						$tplControl->registerObject($properties['id'],$component);
8648
						if(!$component->hasProperty('id'))
8649
							unset($properties['id']);
8650
					}
8651
					foreach($properties as $name=>$value)
8652
						$this->configureComponent($component,$name,$value);
8653
					if($parent===$parentControl)
8654
						$directChildren[]=$component;
8655
					else
8656
						$component->createdOnTemplate($parent);
8657
				}
8658
			}
8659
			else
8660
			{
8661
				if($object[1] instanceof TCompositeLiteral)
8662
				{
8663
										$o=clone $object[1];
8664
					$o->setContainer($tplControl);
8665
					if($parent===$parentControl)
8666
						$directChildren[]=$o;
8667
					else
8668
						$parent->addParsedObject($o);
8669
				}
8670
				else
8671
				{
8672
					if($parent===$parentControl)
8673
						$directChildren[]=$object[1];
8674
					else
8675
						$parent->addParsedObject($object[1]);
8676
				}
8677
			}
8678
		}
8679
								foreach($directChildren as $control)
8680
		{
8681
			if($control instanceof TComponent)
8682
				$control->createdOnTemplate($parentControl);
8683
			else
8684
				$parentControl->addParsedObject($control);
8685
		}
8686
	}
8687
	protected function configureControl($control,$name,$value)
8688
	{
8689
		if(strncasecmp($name,'on',2)===0)					$this->configureEvent($control,$name,$value,$control);
8690
		else if(($pos=strrpos($name,'.'))===false)				$this->configureProperty($control,$name,$value);
8691
		else				$this->configureSubProperty($control,$name,$value);
8692
	}
8693
	protected function configureComponent($component,$name,$value)
8694
	{
8695
		if(strpos($name,'.')===false)				$this->configureProperty($component,$name,$value);
8696
		else				$this->configureSubProperty($component,$name,$value);
8697
	}
8698
	protected function configureEvent($control,$name,$value,$contextControl)
8699
	{
8700
		if(strpos($value,'.')===false)
8701
			$control->attachEventHandler($name,array($contextControl,'TemplateControl.'.$value));
8702
		else
8703
			$control->attachEventHandler($name,array($contextControl,$value));
8704
	}
8705
	protected function configureProperty($component,$name,$value)
8706
	{
8707
		if(is_array($value))
8708
		{
8709
			switch($value[0])
8710
			{
8711
				case self::CONFIG_DATABIND:
8712
					$component->bindProperty($name,$value[1]);
8713
					break;
8714
				case self::CONFIG_EXPRESSION:
8715
					if($component instanceof TControl)
8716
						$component->autoBindProperty($name,$value[1]);
8717
					else
8718
					{
8719
						$setter='set'.$name;
8720
						$component->$setter($this->_tplControl->evaluateExpression($value[1]));
8721
					}
8722
					break;
8723
				case self::CONFIG_TEMPLATE:
8724
					$setter='set'.$name;
8725
					$component->$setter($value[1]);
8726
					break;
8727
				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...
8728
					$url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
8729
					$component->$setter($url);
8730
					break;
8731
				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...
8732
					$component->$setter($this->getApplication()->getParameters()->itemAt($value[1]));
8733
					break;
8734
				case self::CONFIG_LOCALIZATION:
8735
					$setter='set'.$name;
8736
					$component->$setter(Prado::localize($value[1]));
8737
					break;
8738
				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...
8739
					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...
8740
			}
8741
		}
8742
		else
8743
		{
8744
			if (substr($name,0,2)=='js')
8745
				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...
8746
					$value = new TJavaScriptLiteral($value);
8747
			$setter='set'.$name;
8748
			$component->$setter($value);
8749
		}
8750
	}
8751
	protected function configureSubProperty($component,$name,$value)
8752
	{
8753
		if(is_array($value))
8754
		{
8755
			switch($value[0])
8756
			{
8757
				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...
8758
					break;
8759
				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...
8760
						$component->autoBindProperty($name,$value[1]);
8761
					else
8762
						$component->setSubProperty($name,$this->_tplControl->evaluateExpression($value[1]));
8763
					break;
8764
				case self::CONFIG_TEMPLATE:
8765
					$component->setSubProperty($name,$value[1]);
8766
					break;
8767
				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...
8768
					$component->setSubProperty($name,$url);
8769
					break;
8770
				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...
8771
					break;
8772
				case self::CONFIG_LOCALIZATION:
8773
					$component->setSubProperty($name,Prado::localize($value[1]));
8774
					break;
8775
				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...
8776
					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...
8777
			}
8778
		}
8779
		else
8780
			$component->setSubProperty($name,$value);
8781
	}
8782
	protected function parse($input)
8783
	{
8784
		$input=$this->preprocess($input);
8785
		$tpl=&$this->_tpl;
8786
		$n=preg_match_all(self::REGEX_RULES,$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
8787
		$expectPropEnd=false;
8788
		$textStart=0;
8789
				$stack=array();
8790
		$container=-1;
8791
		$matchEnd=0;
8792
		$c=0;
8793
		$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...
8794
		try
8795
		{
8796
			for($i=0;$i<$n;++$i)
8797
			{
8798
				$match=&$matches[$i];
8799
				$str=$match[0][0];
8800
				$matchStart=$match[0][1];
8801
				$matchEnd=$matchStart+strlen($str)-1;
8802
				if(strpos($str,'<com:')===0)					{
8803
					if($expectPropEnd)
8804
						continue;
8805
					if($matchStart>$textStart)
8806
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8807
					$textStart=$matchEnd+1;
8808
					$type=$match[1][0];
8809
					$attributes=$this->parseAttributes($match[2][0],$match[2][1]);
8810
					$this->validateAttributes($type,$attributes);
8811
					$tpl[$c++]=array($container,$type,$attributes);
8812
					if($str[strlen($str)-2]!=='/')  					{
8813
						$stack[] = $type;
8814
						$container=$c-1;
8815
					}
8816
				}
8817
				else if(strpos($str,'</com:')===0)					{
8818
					if($expectPropEnd)
8819
						continue;
8820
					if($matchStart>$textStart)
8821
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8822
					$textStart=$matchEnd+1;
8823
					$type=$match[1][0];
8824
					if(empty($stack))
8825
						throw new TConfigurationException('template_closingtag_unexpected',"</com:$type>");
8826
					$name=array_pop($stack);
8827
					if($name!==$type)
8828
					{
8829
						$tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
8830
						throw new TConfigurationException('template_closingtag_expected',$tag);
8831
					}
8832
					$container=$tpl[$container][0];
8833
				}
8834
				else if(strpos($str,'<%@')===0)					{
8835
					if($expectPropEnd)
8836
						continue;
8837
					if($matchStart>$textStart)
8838
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8839
					$textStart=$matchEnd+1;
8840
					if(isset($tpl[0]) || $this->_directive!==null)
8841
						throw new TConfigurationException('template_directive_nonunique');
8842
					$this->_directive=$this->parseAttributes($match[4][0],$match[4][1]);
8843
				}
8844
				else if(strpos($str,'<%')===0)					{
8845
					if($expectPropEnd)
8846
						continue;
8847
					if($matchStart>$textStart)
8848
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8849
					$textStart=$matchEnd+1;
8850
					$literal=trim($match[5][0]);
8851
					if($str[2]==='=')							$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,$literal));
8852
					else if($str[2]==='%')  						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_STATEMENTS,$literal));
8853
					else if($str[2]==='#')
8854
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_DATABINDING,$literal));
8855
					else if($str[2]==='$')
8856
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->getApplication()->getParameters()->itemAt('$literal')"));
8857
					else if($str[2]==='~')
8858
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->publishFilePath('$this->_contextPath/$literal')"));
8859
					else if($str[2]==='/')
8860
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"rtrim(dirname(\$this->getApplication()->getRequest()->getApplicationUrl()), '/').'/$literal'"));
8861
					else if($str[2]==='[')
8862
					{
8863
						$literal=strtr(trim(substr($literal,0,strlen($literal)-1)),array("'"=>"\'","\\"=>"\\\\"));
8864
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"Prado::localize('$literal')"));
8865
					}
8866
				}
8867
				else if(strpos($str,'<prop:')===0)					{
8868
					if(strrpos($str,'/>')===strlen($str)-2)  					{
8869
						if($expectPropEnd)
8870
							continue;
8871
						if($matchStart>$textStart)
8872
							$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8873
						$textStart=$matchEnd+1;
8874
						$prop=strtolower($match[6][0]);
8875
						$attrs=$this->parseAttributes($match[7][0],$match[7][1]);
8876
						$attributes=array();
8877
						foreach($attrs as $name=>$value)
8878
							$attributes[$prop.'.'.$name]=$value;
8879
						$type=$tpl[$container][1];
8880
						$this->validateAttributes($type,$attributes);
8881
						foreach($attributes as $name=>$value)
8882
						{
8883
							if(isset($tpl[$container][2][$name]))
8884
								throw new TConfigurationException('template_property_duplicated',$name);
8885
							$tpl[$container][2][$name]=$value;
8886
						}
8887
					}
8888
					else  					{
8889
						$prop=strtolower($match[3][0]);
8890
						$stack[] = '@'.$prop;
8891
						if(!$expectPropEnd)
8892
						{
8893
							if($matchStart>$textStart)
8894
								$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8895
							$textStart=$matchEnd+1;
8896
							$expectPropEnd=true;
8897
						}
8898
					}
8899
				}
8900
				else if(strpos($str,'</prop:')===0)					{
8901
					$prop=strtolower($match[3][0]);
8902
					if(empty($stack))
8903
						throw new TConfigurationException('template_closingtag_unexpected',"</prop:$prop>");
8904
					$name=array_pop($stack);
8905
					if($name!=='@'.$prop)
8906
					{
8907
						$tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
8908
						throw new TConfigurationException('template_closingtag_expected',$tag);
8909
					}
8910
					if(($last=count($stack))<1 || $stack[$last-1][0]!=='@')
8911
					{
8912
						if($matchStart>$textStart)
8913
						{
8914
							$value=substr($input,$textStart,$matchStart-$textStart);
8915
							if(substr($prop,-8,8)==='template')
8916
								$value=$this->parseTemplateProperty($value,$textStart);
8917
							else
8918
								$value=$this->parseAttribute($value);
8919
							if($container>=0)
8920
							{
8921
								$type=$tpl[$container][1];
8922
								$this->validateAttributes($type,array($prop=>$value));
8923
								if(isset($tpl[$container][2][$prop]))
8924
									throw new TConfigurationException('template_property_duplicated',$prop);
8925
								$tpl[$container][2][$prop]=$value;
8926
							}
8927
							else									$this->_directive[$prop]=$value;
8928
							$textStart=$matchEnd+1;
8929
						}
8930
						$expectPropEnd=false;
8931
					}
8932
				}
8933
				else if(strpos($str,'<!--')===0)					{
8934
					if($expectPropEnd)
8935
						throw new TConfigurationException('template_comments_forbidden');
8936
					if($matchStart>$textStart)
8937
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8938
					$textStart=$matchEnd+1;
8939
				}
8940
				else
8941
					throw new TConfigurationException('template_matching_unexpected',$match);
8942
			}
8943
			if(!empty($stack))
8944
			{
8945
				$name=array_pop($stack);
8946
				$tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
8947
				throw new TConfigurationException('template_closingtag_expected',$tag);
8948
			}
8949
			if($textStart<strlen($input))
8950
				$tpl[$c++]=array($container,substr($input,$textStart));
8951
		}
8952
		catch(Exception $e)
8953
		{
8954
			if(($e instanceof TException) && ($e instanceof TTemplateException))
8955
				throw $e;
8956
			if($matchEnd===0)
8957
				$line=$this->_startingLine+1;
8958
			else
8959
				$line=$this->_startingLine+count(explode("\n",substr($input,0,$matchEnd+1)));
8960
			$this->handleException($e,$line,$input);
8961
		}
8962
		if($this->_directive===null)
8963
			$this->_directive=array();
8964
				$objects=array();
8965
		$parent=null;
8966
		$merged=array();
8967
		foreach($tpl as $id=>$object)
8968
		{
8969
			if(isset($object[2]) || $object[0]!==$parent)
8970
			{
8971
				if($parent!==null)
8972
				{
8973
					if(count($merged[1])===1 && is_string($merged[1][0]))
8974
						$objects[$id-1]=array($merged[0],$merged[1][0]);
8975
					else
8976
						$objects[$id-1]=array($merged[0],new TCompositeLiteral($merged[1]));
8977
				}
8978
				if(isset($object[2]))
8979
				{
8980
					$parent=null;
8981
					$objects[$id]=$object;
8982
				}
8983
				else
8984
				{
8985
					$parent=$object[0];
8986
					$merged=array($parent,array($object[1]));
8987
				}
8988
			}
8989
			else
8990
				$merged[1][]=$object[1];
8991
		}
8992
		if($parent!==null)
8993
		{
8994
			if(count($merged[1])===1 && is_string($merged[1][0]))
8995
				$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 8967. 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...
8996
			else
8997
				$objects[$id]=array($merged[0],new TCompositeLiteral($merged[1]));
8998
		}
8999
		$tpl=$objects;
9000
		return $objects;
9001
	}
9002
	protected function parseAttributes($str,$offset)
9003
	{
9004
		if($str==='')
9005
			return array();
9006
		$pattern='/([\w\.\-]+)\s*=\s*(\'.*?\'|".*?"|<%.*?%>)/msS';
9007
		$attributes=array();
9008
		$n=preg_match_all($pattern,$str,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
9009
		for($i=0;$i<$n;++$i)
9010
		{
9011
			$match=&$matches[$i];
9012
			$name=strtolower($match[1][0]);
9013
			if(isset($attributes[$name]))
9014
				throw new TConfigurationException('template_property_duplicated',$name);
9015
			$value=$match[2][0];
9016
			if(substr($name,-8,8)==='template')
9017
			{
9018
				if($value[0]==='\'' || $value[0]==='"')
9019
					$attributes[$name]=$this->parseTemplateProperty(substr($value,1,strlen($value)-2),$match[2][1]+1);
9020
				else
9021
					$attributes[$name]=$this->parseTemplateProperty($value,$match[2][1]);
9022
			}
9023
			else
9024
			{
9025
				if($value[0]==='\'' || $value[0]==='"')
9026
					$attributes[$name]=$this->parseAttribute(substr($value,1,strlen($value)-2));
9027
				else
9028
					$attributes[$name]=$this->parseAttribute($value);
9029
			}
9030
		}
9031
		return $attributes;
9032
	}
9033
	protected function parseTemplateProperty($content,$offset)
9034
	{
9035
		$line=$this->_startingLine+count(explode("\n",substr($this->_content,0,$offset)))-1;
9036
		return array(self::CONFIG_TEMPLATE,new TTemplate($content,$this->_contextPath,$this->_tplFile,$line,false));
9037
	}
9038
	protected function parseAttribute($value)
9039
	{
9040
		if(($n=preg_match_all('/<%[#=].*?%>/msS',$value,$matches,PREG_OFFSET_CAPTURE))>0)
9041
		{
9042
			$isDataBind=false;
9043
			$textStart=0;
9044
			$expr='';
9045
			for($i=0;$i<$n;++$i)
9046
			{
9047
				$match=$matches[0][$i];
9048
				$token=$match[0];
9049
				$offset=$match[1];
9050
				$length=strlen($token);
9051
				if($token[2]==='#')
9052
					$isDataBind=true;
9053
				if($offset>$textStart)
9054
					$expr.=".'".strtr(substr($value,$textStart,$offset-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
9055
				$expr.='.('.substr($token,3,$length-5).')';
9056
				$textStart=$offset+$length;
9057
			}
9058
			$length=strlen($value);
9059
			if($length>$textStart)
9060
				$expr.=".'".strtr(substr($value,$textStart,$length-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
9061
			if($isDataBind)
9062
				return array(self::CONFIG_DATABIND,ltrim($expr,'.'));
9063
			else
9064
				return array(self::CONFIG_EXPRESSION,ltrim($expr,'.'));
9065
		}
9066
		else if(preg_match('/\\s*(<%~.*?%>|<%\\$.*?%>|<%\\[.*?\\]%>|<%\/.*?%>)\\s*/msS',$value,$matches) && $matches[0]===$value)
9067
		{
9068
			$value=$matches[1];
9069
			if($value[2]==='~')
9070
				return array(self::CONFIG_ASSET,trim(substr($value,3,strlen($value)-5)));
9071
			elseif($value[2]==='[')
9072
				return array(self::CONFIG_LOCALIZATION,trim(substr($value,3,strlen($value)-6)));
9073
			elseif($value[2]==='$')
9074
				return array(self::CONFIG_PARAMETER,trim(substr($value,3,strlen($value)-5)));
9075
			elseif($value[2]==='/') {
9076
				$literal = trim(substr($value,3,strlen($value)-5));
9077
				return array(self::CONFIG_EXPRESSION,"rtrim(dirname(\$this->getApplication()->getRequest()->getApplicationUrl()), '/').'/$literal'");
9078
			}
9079
		}
9080
		else
9081
			return $value;
9082
	}
9083
	protected function validateAttributes($type,$attributes)
9084
	{
9085
		Prado::using($type);
9086
		if(($pos=strrpos($type,'.'))!==false)
9087
			$className=substr($type,$pos+1);
9088
		else
9089
			$className=$type;
9090
		$class=new ReflectionClass($className);
9091
		if(is_subclass_of($className,'TControl') || $className==='TControl')
9092
		{
9093
			foreach($attributes as $name=>$att)
9094
			{
9095
				if(($pos=strpos($name,'.'))!==false)
9096
				{
9097
										$subname=substr($name,0,$pos);
9098
					if(!$class->hasMethod('get'.$subname))
9099
						throw new TConfigurationException('template_property_unknown',$type,$subname);
9100
				}
9101
				else if(strncasecmp($name,'on',2)===0)
9102
				{
9103
										if(!$class->hasMethod($name))
9104
						throw new TConfigurationException('template_event_unknown',$type,$name);
9105
					else if(!is_string($att))
9106
						throw new TConfigurationException('template_eventhandler_invalid',$type,$name);
9107
				}
9108
				else
9109
				{
9110
										if (! ($class->hasMethod('set'.$name) || $class->hasMethod('setjs'.$name) || $this->isClassBehaviorMethod($class,'set'.$name)) )
9111
					{
9112
						if ($class->hasMethod('get'.$name) || $class->hasMethod('getjs'.$name))
9113
							throw new TConfigurationException('template_property_readonly',$type,$name);
9114
						else
9115
							throw new TConfigurationException('template_property_unknown',$type,$name);
9116
					}
9117
					else if(is_array($att) && $att[0]!==self::CONFIG_EXPRESSION)
9118
					{
9119
						if(strcasecmp($name,'id')===0)
9120
							throw new TConfigurationException('template_controlid_invalid',$type);
9121
						else if(strcasecmp($name,'skinid')===0)
9122
							throw new TConfigurationException('template_controlskinid_invalid',$type);
9123
					}
9124
				}
9125
			}
9126
		}
9127
		else if(is_subclass_of($className,'TComponent') || $className==='TComponent')
9128
		{
9129
			foreach($attributes as $name=>$att)
9130
			{
9131
				if(is_array($att) && ($att[0]===self::CONFIG_DATABIND))
9132
					throw new TConfigurationException('template_databind_forbidden',$type,$name);
9133
				if(($pos=strpos($name,'.'))!==false)
9134
				{
9135
										$subname=substr($name,0,$pos);
9136
					if(!$class->hasMethod('get'.$subname))
9137
						throw new TConfigurationException('template_property_unknown',$type,$subname);
9138
				}
9139
				else if(strncasecmp($name,'on',2)===0)
9140
					throw new TConfigurationException('template_event_forbidden',$type,$name);
9141
				else
9142
				{
9143
										if(strcasecmp($name,'id')!==0 && !($class->hasMethod('set'.$name) || $this->isClassBehaviorMethod($class,'set'.$name)))
9144
					{
9145
						if($class->hasMethod('get'.$name))
9146
							throw new TConfigurationException('template_property_readonly',$type,$name);
9147
						else
9148
							throw new TConfigurationException('template_property_unknown',$type,$name);
9149
					}
9150
				}
9151
			}
9152
		}
9153
		else
9154
			throw new TConfigurationException('template_component_required',$type);
9155
	}
9156
	public function getIncludedFiles()
9157
	{
9158
		return $this->_includedFiles;
9159
	}
9160
	protected function handleException($e,$line,$input=null)
9161
	{
9162
		$srcFile=$this->_tplFile;
9163
		if(($n=count($this->_includedFiles))>0) 		{
9164
			for($i=$n-1;$i>=0;--$i)
9165
			{
9166
				if($this->_includeAtLine[$i]<=$line)
9167
				{
9168
					if($line<$this->_includeAtLine[$i]+$this->_includeLines[$i])
9169
					{
9170
						$line=$line-$this->_includeAtLine[$i]+1;
9171
						$srcFile=$this->_includedFiles[$i];
9172
						break;
9173
					}
9174
					else
9175
						$line=$line-$this->_includeLines[$i]+1;
9176
				}
9177
			}
9178
		}
9179
		$exception=new TTemplateException('template_format_invalid',$e->getMessage());
9180
		$exception->setLineNumber($line);
9181
		if(!empty($srcFile))
9182
			$exception->setTemplateFile($srcFile);
9183
		else
9184
			$exception->setTemplateSource($input);
9185
		throw $exception;
9186
	}
9187
	protected function preprocess($input)
9188
	{
9189
		if($n=preg_match_all('/<%include(.*?)%>/',$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE))
9190
		{
9191
			for($i=0;$i<$n;++$i)
9192
			{
9193
				$filePath=Prado::getPathOfNamespace(trim($matches[$i][1][0]),TTemplateManager::TEMPLATE_FILE_EXT);
9194
				if($filePath!==null && is_file($filePath))
9195
					$this->_includedFiles[]=$filePath;
9196
				else
9197
				{
9198
					$errorLine=count(explode("\n",substr($input,0,$matches[$i][0][1]+1)));
9199
					$this->handleException(new TConfigurationException('template_include_invalid',trim($matches[$i][1][0])),$errorLine,$input);
9200
				}
9201
			}
9202
			$base=0;
9203
			for($i=0;$i<$n;++$i)
9204
			{
9205
				$ext=file_get_contents($this->_includedFiles[$i]);
9206
				$length=strlen($matches[$i][0][0]);
9207
				$offset=$base+$matches[$i][0][1];
9208
				$this->_includeAtLine[$i]=count(explode("\n",substr($input,0,$offset)));
9209
				$this->_includeLines[$i]=count(explode("\n",$ext));
9210
				$input=substr_replace($input,$ext,$offset,$length);
9211
				$base+=strlen($ext)-$length;
9212
			}
9213
		}
9214
		return $input;
9215
	}
9216
	protected function isClassBehaviorMethod(ReflectionClass $class,$method)
9217
	{
9218
	  $component=new ReflectionClass('TComponent');
9219
	  $behaviors=$component->getStaticProperties();
9220
	  if(!isset($behaviors['_um']))
9221
	    return false;
9222
	  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...
9223
	  {
9224
	    if(strtolower($class->getShortName())!==$name && !$class->isSubclassOf($name)) continue;
9225
	    foreach($list as $param)
9226
	    {
9227
	      if(method_exists($param->getBehavior(),$method))
9228
	        return true;
9229
	    }
9230
	  }
9231
	  return false;
9232
	}
9233
}
9234
class TThemeManager extends TModule
9235
{
9236
	const DEFAULT_BASEPATH='themes';
9237
	const DEFAULT_THEMECLASS = 'TTheme';
9238
	private $_themeClass=self::DEFAULT_THEMECLASS;
9239
	private $_initialized=false;
9240
	private $_basePath=null;
9241
	private $_baseUrl=null;
9242
	public function init($config)
9243
	{
9244
		$this->_initialized=true;
9245
		$service=$this->getService();
9246
		if($service instanceof TPageService)
9247
			$service->setThemeManager($this);
9248
		else
9249
			throw new TConfigurationException('thememanager_service_unavailable');
9250
	}
9251
	public function getTheme($name)
9252
	{
9253
		$themePath=$this->getBasePath().DIRECTORY_SEPARATOR.$name;
9254
		$themeUrl=rtrim($this->getBaseUrl(),'/').'/'.$name;
9255
		return Prado::createComponent($this->getThemeClass(), $themePath, $themeUrl);
9256
	}
9257
	public function setThemeClass($class) {
9258
		$this->_themeClass = $class===null ? self::DEFAULT_THEMECLASS : (string)$class;
9259
	}
9260
	public function getThemeClass() {
9261
		return $this->_themeClass;
9262
	}
9263
	public function getAvailableThemes()
9264
	{
9265
		$themes=array();
9266
		$basePath=$this->getBasePath();
9267
		$folder=@opendir($basePath);
9268
		while($file=@readdir($folder))
9269
		{
9270
			if($file!=='.' && $file!=='..' && $file!=='.svn' && is_dir($basePath.DIRECTORY_SEPARATOR.$file))
9271
				$themes[]=$file;
9272
		}
9273
		closedir($folder);
9274
		return $themes;
9275
	}
9276
	public function getBasePath()
9277
	{
9278
		if($this->_basePath===null)
9279
		{
9280
			$this->_basePath=dirname($this->getRequest()->getApplicationFilePath()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
9281
			if(($basePath=realpath($this->_basePath))===false || !is_dir($basePath))
9282
				throw new TConfigurationException('thememanager_basepath_invalid2',$this->_basePath);
9283
			$this->_basePath=$basePath;
9284
		}
9285
		return $this->_basePath;
9286
	}
9287
	public function setBasePath($value)
9288
	{
9289
		if($this->_initialized)
9290
			throw new TInvalidOperationException('thememanager_basepath_unchangeable');
9291
		else
9292
		{
9293
			$this->_basePath=Prado::getPathOfNamespace($value);
9294
			if($this->_basePath===null || !is_dir($this->_basePath))
9295
				throw new TInvalidDataValueException('thememanager_basepath_invalid',$value);
9296
		}
9297
	}
9298
	public function getBaseUrl()
9299
	{
9300
		if($this->_baseUrl===null)
9301
		{
9302
			$appPath=dirname($this->getRequest()->getApplicationFilePath());
9303
			$basePath=$this->getBasePath();
9304
			if(strpos($basePath,$appPath)===false)
9305
				throw new TConfigurationException('thememanager_baseurl_required');
9306
			$appUrl=rtrim(dirname($this->getRequest()->getApplicationUrl()),'/\\');
9307
			$this->_baseUrl=$appUrl.strtr(substr($basePath,strlen($appPath)),'\\','/');
9308
		}
9309
		return $this->_baseUrl;
9310
	}
9311
	public function setBaseUrl($value)
9312
	{
9313
		$this->_baseUrl=rtrim($value,'/');
9314
	}
9315
}
9316
class TTheme extends TApplicationComponent implements ITheme
9317
{
9318
	const THEME_CACHE_PREFIX='prado:theme:';
9319
	const SKIN_FILE_EXT='.skin';
9320
	private $_themePath;
9321
	private $_themeUrl;
9322
	private $_skins=null;
9323
	private $_name='';
9324
	private $_cssFiles=array();
9325
	private $_jsFiles=array();
9326
	public function __construct($themePath,$themeUrl)
9327
	{
9328
		$this->_themeUrl=$themeUrl;
9329
		$this->_themePath=realpath($themePath);
9330
		$this->_name=basename($themePath);
9331
		$cacheValid=false;
9332
				if(($cache=$this->getApplication()->getCache())!==null)
9333
		{
9334
			$array=$cache->get(self::THEME_CACHE_PREFIX.$themePath);
9335
			if(is_array($array))
9336
			{
9337
				list($skins,$cssFiles,$jsFiles,$timestamp)=$array;
9338
				if($this->getApplication()->getMode()!==TApplicationMode::Performance)
9339
				{
9340
					if(($dir=opendir($themePath))===false)
9341
						throw new TIOException('theme_path_inexistent',$themePath);
9342
					$cacheValid=true;
9343
					while(($file=readdir($dir))!==false)
9344
					{
9345
						if($file==='.' || $file==='..')
9346
							continue;
9347
						else if(basename($file,'.css')!==$file)
9348
							$this->_cssFiles[]=$themeUrl.'/'.$file;
9349
						else if(basename($file,'.js')!==$file)
9350
							$this->_jsFiles[]=$themeUrl.'/'.$file;
9351
						else if(basename($file,self::SKIN_FILE_EXT)!==$file && filemtime($themePath.DIRECTORY_SEPARATOR.$file)>$timestamp)
9352
						{
9353
							$cacheValid=false;
9354
							break;
9355
						}
9356
					}
9357
					closedir($dir);
9358
					if($cacheValid)
9359
						$this->_skins=$skins;
9360
				}
9361
				else
9362
				{
9363
					$cacheValid=true;
9364
					$this->_cssFiles=$cssFiles;
9365
					$this->_jsFiles=$jsFiles;
9366
					$this->_skins=$skins;
9367
				}
9368
			}
9369
		}
9370
		if(!$cacheValid)
9371
		{
9372
			$this->_cssFiles=array();
9373
			$this->_jsFiles=array();
9374
			$this->_skins=array();
9375
			if(($dir=opendir($themePath))===false)
9376
				throw new TIOException('theme_path_inexistent',$themePath);
9377
			while(($file=readdir($dir))!==false)
9378
			{
9379
				if($file==='.' || $file==='..')
9380
					continue;
9381
				else if(basename($file,'.css')!==$file)
9382
					$this->_cssFiles[]=$themeUrl.'/'.$file;
9383
				else if(basename($file,'.js')!==$file)
9384
					$this->_jsFiles[]=$themeUrl.'/'.$file;
9385
				else if(basename($file,self::SKIN_FILE_EXT)!==$file)
9386
				{
9387
					$template=new TTemplate(file_get_contents($themePath.'/'.$file),$themePath,$themePath.'/'.$file);
9388
					foreach($template->getItems() as $skin)
9389
					{
9390
						if(!isset($skin[2]))  							continue;
9391
						else if($skin[0]!==-1)
9392
							throw new TConfigurationException('theme_control_nested',$skin[1],dirname($themePath));
9393
						$type=$skin[1];
9394
						$id=isset($skin[2]['skinid'])?$skin[2]['skinid']:0;
9395
						unset($skin[2]['skinid']);
9396
						if(isset($this->_skins[$type][$id]))
9397
							throw new TConfigurationException('theme_skinid_duplicated',$type,$id,dirname($themePath));
9398
						$this->_skins[$type][$id]=$skin[2];
9399
					}
9400
				}
9401
			}
9402
			closedir($dir);
9403
			sort($this->_cssFiles);
9404
			sort($this->_jsFiles);
9405
			if($cache!==null)
9406
				$cache->set(self::THEME_CACHE_PREFIX.$themePath,array($this->_skins,$this->_cssFiles,$this->_jsFiles,time()));
9407
		}
9408
	}
9409
	public function getName()
9410
	{
9411
		return $this->_name;
9412
	}
9413
	protected function setName($value)
9414
	{
9415
		$this->_name = $value;
9416
	}
9417
	public function getBaseUrl()
9418
	{
9419
		return $this->_themeUrl;
9420
	}
9421
	protected function setBaseUrl($value)
9422
	{
9423
		$this->_themeUrl=rtrim($value,'/');
9424
	}
9425
	public function getBasePath()
9426
	{
9427
		return $this->_themePath;
9428
	}
9429
	protected function setBasePath($value)
9430
	{
9431
		$this->_themePath=$value;
9432
	}
9433
	public function getSkins()
9434
	{
9435
		return $this->_skins;
9436
	}
9437
	protected function setSkins($value)
9438
	{
9439
		$this->_skins = $value;
9440
	}
9441
	public function applySkin($control)
9442
	{
9443
		$type=get_class($control);
9444
		if(($id=$control->getSkinID())==='')
9445
			$id=0;
9446
		if(isset($this->_skins[$type][$id]))
9447
		{
9448
			foreach($this->_skins[$type][$id] as $name=>$value)
9449
			{
9450
				if(is_array($value))
9451
				{
9452
					switch($value[0])
9453
					{
9454
						case TTemplate::CONFIG_EXPRESSION:
9455
							$value=$this->evaluateExpression($value[1]);
9456
							break;
9457
						case TTemplate::CONFIG_ASSET:
9458
							$value=$this->_themeUrl.'/'.ltrim($value[1],'/');
9459
							break;
9460
						case TTemplate::CONFIG_DATABIND:
9461
							$control->bindProperty($name,$value[1]);
9462
							break;
9463
						case TTemplate::CONFIG_PARAMETER:
9464
							$control->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
9465
							break;
9466
						case TTemplate::CONFIG_TEMPLATE:
9467
							$control->setSubProperty($name,$value[1]);
9468
							break;
9469
						case TTemplate::CONFIG_LOCALIZATION:
9470
							$control->setSubProperty($name,Prado::localize($value[1]));
9471
							break;
9472
						default:
9473
							throw new TConfigurationException('theme_tag_unexpected',$name,$value[0]);
9474
							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...
9475
					}
9476
				}
9477
				if(!is_array($value))
9478
				{
9479
					if(strpos($name,'.')===false)						{
9480
						if($control->hasProperty($name))
9481
						{
9482
							if($control->canSetProperty($name))
9483
							{
9484
								$setter='set'.$name;
9485
								$control->$setter($value);
9486
							}
9487
							else
9488
								throw new TConfigurationException('theme_property_readonly',$type,$name);
9489
						}
9490
						else
9491
							throw new TConfigurationException('theme_property_undefined',$type,$name);
9492
					}
9493
					else							$control->setSubProperty($name,$value);
9494
				}
9495
			}
9496
			return true;
9497
		}
9498
		else
9499
			return false;
9500
	}
9501
	public function getStyleSheetFiles()
9502
	{
9503
		return $this->_cssFiles;
9504
	}
9505
	protected function setStyleSheetFiles($value)
9506
	{
9507
		$this->_cssFiles=$value;
9508
	}
9509
	public function getJavaScriptFiles()
9510
	{
9511
		return $this->_jsFiles;
9512
	}
9513
	protected function setJavaScriptFiles($value)
9514
	{
9515
		$this->_jsFiles=$value;
9516
	}
9517
}
9518
class TPageService extends TService
9519
{
9520
	const CONFIG_FILE_XML='config.xml';
9521
	const CONFIG_FILE_PHP='config.php';
9522
	const DEFAULT_BASEPATH='Pages';
9523
	const FALLBACK_BASEPATH='pages';
9524
	const CONFIG_CACHE_PREFIX='prado:pageservice:';
9525
	const PAGE_FILE_EXT='.page';
9526
	private $_basePath=null;
9527
	private $_basePageClass='TPage';
9528
	private $_clientScriptManagerClass='System.Web.UI.TClientScriptManager';
9529
	private $_defaultPage='Home';
9530
	private $_pagePath=null;
9531
	private $_page=null;
9532
	private $_properties=array();
9533
	private $_initialized=false;
9534
	private $_themeManager=null;
9535
	private $_templateManager=null;
9536
	public function init($config)
9537
	{
9538
		$pageConfig=$this->loadPageConfig($config);
9539
		$this->initPageContext($pageConfig);
9540
		$this->_initialized=true;
9541
	}
9542
	protected function initPageContext($pageConfig)
9543
	{
9544
		$application=$this->getApplication();
9545
		foreach($pageConfig->getApplicationConfigurations() as $appConfig)
9546
			$application->applyConfiguration($appConfig);
9547
		$this->applyConfiguration($pageConfig);
9548
	}
9549
	protected function applyConfiguration($config)
9550
	{
9551
				$this->_properties=array_merge($this->_properties, $config->getProperties());
9552
		$this->getApplication()->getAuthorizationRules()->mergeWith($config->getRules());
9553
		$pagePath=$this->getRequestedPagePath();
9554
				foreach($config->getExternalConfigurations() as $filePath=>$params)
9555
		{
9556
			list($configPagePath,$condition)=$params;
9557
			if($condition!==true)
9558
				$condition=$this->evaluateExpression($condition);
9559
			if($condition)
9560
			{
9561
				if(($path=Prado::getPathOfNamespace($filePath,Prado::getApplication()->getConfigurationFileExt()))===null || !is_file($path))
9562
					throw new TConfigurationException('pageservice_includefile_invalid',$filePath);
9563
				$c=new TPageConfiguration($pagePath);
9564
				$c->loadFromFile($path,$configPagePath);
9565
				$this->applyConfiguration($c);
9566
			}
9567
		}
9568
	}
9569
	protected function determineRequestedPagePath()
9570
	{
9571
		$pagePath=$this->getRequest()->getServiceParameter();
9572
		if(empty($pagePath))
9573
			$pagePath=$this->getDefaultPage();
9574
		return $pagePath;
9575
	}
9576
	protected function loadPageConfig($config)
9577
	{
9578
		$application=$this->getApplication();
9579
		$pagePath=$this->getRequestedPagePath();
9580
		if(($cache=$application->getCache())===null)
9581
		{
9582
			$pageConfig=new TPageConfiguration($pagePath);
9583
			if($config!==null)
9584
			{
9585
				if($application->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
9586
					$pageConfig->loadPageConfigurationFromPhp($config,$application->getBasePath(),'');
9587
				else
9588
					$pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),'');
9589
			}
9590
			$pageConfig->loadFromFiles($this->getBasePath());
9591
		}
9592
		else
9593
		{
9594
			$configCached=true;
9595
			$currentTimestamp=array();
9596
			$arr=$cache->get(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath);
9597
			if(is_array($arr))
9598
			{
9599
				list($pageConfig,$timestamps)=$arr;
9600
				if($application->getMode()!==TApplicationMode::Performance)
9601
				{
9602
					foreach($timestamps as $fileName=>$timestamp)
9603
					{
9604
						if($fileName===0) 						{
9605
							$appConfigFile=$application->getConfigurationFile();
9606
							$currentTimestamp[0]=$appConfigFile===null?0:@filemtime($appConfigFile);
9607
							if($currentTimestamp[0]>$timestamp || ($timestamp>0 && !$currentTimestamp[0]))
9608
								$configCached=false;
9609
						}
9610
						else
9611
						{
9612
							$currentTimestamp[$fileName]=@filemtime($fileName);
9613
							if($currentTimestamp[$fileName]>$timestamp || ($timestamp>0 && !$currentTimestamp[$fileName]))
9614
								$configCached=false;
9615
						}
9616
					}
9617
				}
9618
			}
9619
			else
9620
			{
9621
				$configCached=false;
9622
				$paths=explode('.',$pagePath);
9623
				$configPath=$this->getBasePath();
9624
				$fileName = $this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP
9625
					? self::CONFIG_FILE_PHP
9626
					: self::CONFIG_FILE_XML;
9627
				foreach($paths as $path)
9628
				{
9629
					$configFile=$configPath.DIRECTORY_SEPARATOR.$fileName;
9630
					$currentTimestamp[$configFile]=@filemtime($configFile);
9631
					$configPath.=DIRECTORY_SEPARATOR.$path;
9632
				}
9633
				$appConfigFile=$application->getConfigurationFile();
9634
				$currentTimestamp[0]=$appConfigFile===null?0:@filemtime($appConfigFile);
9635
			}
9636
			if(!$configCached)
9637
			{
9638
				$pageConfig=new TPageConfiguration($pagePath);
9639
				if($config!==null)
9640
				{
9641
					if($application->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
9642
						$pageConfig->loadPageConfigurationFromPhp($config,$application->getBasePath(),'');
9643
					else
9644
						$pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),'');
9645
				}
9646
				$pageConfig->loadFromFiles($this->getBasePath());
9647
				$cache->set(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath,array($pageConfig,$currentTimestamp));
9648
			}
9649
		}
9650
		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...
9651
	}
9652
	public function getTemplateManager()
9653
	{
9654
		if(!$this->_templateManager)
9655
		{
9656
			$this->_templateManager=new TTemplateManager;
9657
			$this->_templateManager->init(null);
9658
		}
9659
		return $this->_templateManager;
9660
	}
9661
	public function setTemplateManager(TTemplateManager $value)
9662
	{
9663
		$this->_templateManager=$value;
9664
	}
9665
	public function getThemeManager()
9666
	{
9667
		if(!$this->_themeManager)
9668
		{
9669
			$this->_themeManager=new TThemeManager;
9670
			$this->_themeManager->init(null);
9671
		}
9672
		return $this->_themeManager;
9673
	}
9674
	public function setThemeManager(TThemeManager $value)
9675
	{
9676
		$this->_themeManager=$value;
9677
	}
9678
	public function getRequestedPagePath()
9679
	{
9680
		if($this->_pagePath===null)
9681
		{
9682
			$this->_pagePath=strtr($this->determineRequestedPagePath(),'/\\','..');
9683
			if(empty($this->_pagePath))
9684
				throw new THttpException(404,'pageservice_page_required');
9685
		}
9686
		return $this->_pagePath;
9687
	}
9688
	public function getRequestedPage()
9689
	{
9690
		return $this->_page;
9691
	}
9692
	public function getDefaultPage()
9693
	{
9694
		return $this->_defaultPage;
9695
	}
9696
	public function setDefaultPage($value)
9697
	{
9698
		if($this->_initialized)
9699
			throw new TInvalidOperationException('pageservice_defaultpage_unchangeable');
9700
		else
9701
			$this->_defaultPage=$value;
9702
	}
9703
	public function getDefaultPageUrl()
9704
	{
9705
		return $this->constructUrl($this->getDefaultPage());
9706
	}
9707
	public function getBasePath()
9708
	{
9709
		if($this->_basePath===null)
9710
		{
9711
			$basePath=$this->getApplication()->getBasePath().DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
9712
			if(($this->_basePath=realpath($basePath))===false || !is_dir($this->_basePath))
9713
			{
9714
				$basePath=$this->getApplication()->getBasePath().DIRECTORY_SEPARATOR.self::FALLBACK_BASEPATH;
9715
				if(($this->_basePath=realpath($basePath))===false || !is_dir($this->_basePath))
9716
					throw new TConfigurationException('pageservice_basepath_invalid',$basePath);
9717
			}
9718
		}
9719
		return $this->_basePath;
9720
	}
9721
	public function setBasePath($value)
9722
	{
9723
		if($this->_initialized)
9724
			throw new TInvalidOperationException('pageservice_basepath_unchangeable');
9725
		else if(($path=Prado::getPathOfNamespace($value))===null || !is_dir($path))
9726
			throw new TConfigurationException('pageservice_basepath_invalid',$value);
9727
		$this->_basePath=realpath($path);
9728
	}
9729
	public function setBasePageClass($value)
9730
	{
9731
		$this->_basePageClass=$value;
9732
	}
9733
	public function getBasePageClass()
9734
	{
9735
		return $this->_basePageClass;
9736
	}
9737
	public function setClientScriptManagerClass($value)
9738
	{
9739
		$this->_clientScriptManagerClass=$value;
9740
	}
9741
	public function getClientScriptManagerClass()
9742
	{
9743
		return $this->_clientScriptManagerClass;
9744
	}
9745
	public function run()
9746
	{
9747
		$this->_page=$this->createPage($this->getRequestedPagePath());
9748
		$this->runPage($this->_page,$this->_properties);
9749
	}
9750
	protected function createPage($pagePath)
9751
	{
9752
		$path=$this->getBasePath().DIRECTORY_SEPARATOR.strtr($pagePath,'.',DIRECTORY_SEPARATOR);
9753
		$hasTemplateFile=is_file($path.self::PAGE_FILE_EXT);
9754
		$hasClassFile=is_file($path.Prado::CLASS_FILE_EXT);
9755
		if(!$hasTemplateFile && !$hasClassFile)
9756
			throw new THttpException(404,'pageservice_page_unknown',$pagePath);
9757
		if($hasClassFile)
9758
		{
9759
			$className=basename($path);
9760
			if(!class_exists($className,false))
9761
				include_once($path.Prado::CLASS_FILE_EXT);
9762
		}
9763
		else
9764
		{
9765
			$className=$this->getBasePageClass();
9766
			Prado::using($className);
9767
			if(($pos=strrpos($className,'.'))!==false)
9768
				$className=substr($className,$pos+1);
9769
		}
9770
 		if(!class_exists($className,false) || ($className!=='TPage' && !is_subclass_of($className,'TPage')))
9771
			throw new THttpException(404,'pageservice_page_unknown',$pagePath);
9772
		$page=Prado::createComponent($className);
9773
		$page->setPagePath($pagePath);
9774
		if($hasTemplateFile)
9775
			$page->setTemplate($this->getTemplateManager()->getTemplateByFileName($path.self::PAGE_FILE_EXT));
9776
		return $page;
9777
	}
9778
	protected function runPage($page,$properties)
9779
	{
9780
		foreach($properties as $name=>$value)
9781
			$page->setSubProperty($name,$value);
9782
		$page->run($this->getResponse()->createHtmlWriter());
9783
	}
9784
	public function constructUrl($pagePath,$getParams=null,$encodeAmpersand=true,$encodeGetItems=true)
9785
	{
9786
		return $this->getRequest()->constructUrl($this->getID(),$pagePath,$getParams,$encodeAmpersand,$encodeGetItems);
9787
	}
9788
}
9789
class TPageConfiguration extends TComponent
9790
{
9791
	private $_appConfigs=array();
9792
	private $_properties=array();
9793
	private $_rules=array();
9794
	private $_includes=array();
9795
	private $_pagePath='';
9796
	public function __construct($pagePath)
9797
	{
9798
		$this->_pagePath=$pagePath;
9799
	}
9800
	public function getExternalConfigurations()
9801
	{
9802
		return $this->_includes;
9803
	}
9804
	public function getProperties()
9805
	{
9806
		return $this->_properties;
9807
	}
9808
	public function getRules()
9809
	{
9810
		return $this->_rules;
9811
	}
9812
	public function getApplicationConfigurations()
9813
	{
9814
		return $this->_appConfigs;
9815
	}
9816
	public function loadFromFiles($basePath)
9817
	{
9818
		$paths=explode('.',$this->_pagePath);
9819
		$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...
9820
		$path=$basePath;
9821
		$configPagePath='';
9822
		$fileName = Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP
9823
			? TPageService::CONFIG_FILE_PHP
9824
			: TPageService::CONFIG_FILE_XML;
9825
		foreach($paths as $p)
9826
		{
9827
			$this->loadFromFile($path.DIRECTORY_SEPARATOR.$fileName,$configPagePath);
9828
			$path.=DIRECTORY_SEPARATOR.$p;
9829
			if($configPagePath==='')
9830
				$configPagePath=$p;
9831
			else
9832
				$configPagePath.='.'.$p;
9833
		}
9834
		$this->loadFromFile($path.DIRECTORY_SEPARATOR.$fileName,$configPagePath);
9835
		$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...
9836
	}
9837
	public function loadFromFile($fname,$configPagePath)
9838
	{
9839
		if(empty($fname) || !is_file($fname))
9840
			return;
9841
		if(Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
9842
		{
9843
			$fcontent = include $fname;
9844
			$this->loadFromPhp($fcontent,dirname($fname),$configPagePath);
9845
		}
9846
		else
9847
		{
9848
			$dom=new TXmlDocument;
9849
			if($dom->loadFromFile($fname))
9850
				$this->loadFromXml($dom,dirname($fname),$configPagePath);
9851
			else
9852
				throw new TConfigurationException('pageserviceconf_file_invalid',$fname);
9853
		}
9854
	}
9855
	public function loadFromPhp($config,$configPath,$configPagePath)
9856
	{
9857
		$this->loadApplicationConfigurationFromPhp($config,$configPath);
9858
		$this->loadPageConfigurationFromPhp($config,$configPath,$configPagePath);
9859
	}
9860
	public function loadFromXml($dom,$configPath,$configPagePath)
9861
	{
9862
		$this->loadApplicationConfigurationFromXml($dom,$configPath);
9863
		$this->loadPageConfigurationFromXml($dom,$configPath,$configPagePath);
9864
	}
9865
	public function loadApplicationConfigurationFromPhp($config,$configPath)
9866
	{
9867
		$appConfig=new TApplicationConfiguration;
9868
		$appConfig->loadFromPhp($config,$configPath);
9869
		$this->_appConfigs[]=$appConfig;
9870
	}
9871
	public function loadApplicationConfigurationFromXml($dom,$configPath)
9872
	{
9873
		$appConfig=new TApplicationConfiguration;
9874
		$appConfig->loadFromXml($dom,$configPath);
9875
		$this->_appConfigs[]=$appConfig;
9876
	}
9877
	public function loadPageConfigurationFromPhp($config, $configPath, $configPagePath)
9878
	{
9879
				if(isset($config['authorization']) && is_array($config['authorization']))
9880
		{
9881
			$rules = array();
9882
			foreach($config['authorization'] as $authorization)
9883
			{
9884
				$patterns=isset($authorization['pages'])?$authorization['pages']:'';
9885
				$ruleApplies=false;
9886
				if(empty($patterns) || trim($patterns)==='*') 					$ruleApplies=true;
9887
				else
9888
				{
9889
					foreach(explode(',',$patterns) as $pattern)
9890
					{
9891
						if(($pattern=trim($pattern))!=='')
9892
						{
9893
														if($configPagePath!=='')  								$pattern=$configPagePath.'.'.$pattern;
9894
							if(strcasecmp($pattern,$this->_pagePath)===0)
9895
							{
9896
								$ruleApplies=true;
9897
								break;
9898
							}
9899
							if($pattern[strlen($pattern)-1]==='*') 							{
9900
								if(strncasecmp($this->_pagePath,$pattern,strlen($pattern)-1)===0)
9901
								{
9902
									$ruleApplies=true;
9903
									break;
9904
								}
9905
							}
9906
						}
9907
					}
9908
				}
9909
				if($ruleApplies)
9910
				{
9911
					$action = isset($authorization['action'])?$authorization['action']:'';
9912
					$users = isset($authorization['users'])?$authorization['users']:'';
9913
					$roles = isset($authorization['roles'])?$authorization['roles']:'';
9914
					$verb = isset($authorization['verb'])?$authorization['verb']:'';
9915
					$ips = isset($authorization['ips'])?$authorization['ips']:'';
9916
					$rules[]=new TAuthorizationRule($action,$users,$roles,$verb,$ips);
9917
				}
9918
			}
9919
			$this->_rules=array_merge($rules,$this->_rules);
9920
		}
9921
				if(isset($config['pages']) && is_array($config['pages']))
9922
		{
9923
			if(isset($config['pages']['properties']))
9924
			{
9925
				$this->_properties = array_merge($this->_properties, $config['pages']['properties']);
9926
				unset($config['pages']['properties']);
9927
			}
9928
			foreach($config['pages'] as $id => $page)
9929
			{
9930
				$properties = array();
9931
				if(isset($page['properties']))
9932
				{
9933
					$properties=$page['properties'];
9934
					unset($page['properties']);
9935
				}
9936
				$matching=false;
9937
				$id=($configPagePath==='')?$id:$configPagePath.'.'.$id;
9938
				if(strcasecmp($id,$this->_pagePath)===0)
9939
					$matching=true;
9940
				else if($id[strlen($id)-1]==='*') 					$matching=strncasecmp($this->_pagePath,$id,strlen($id)-1)===0;
9941
				if($matching)
9942
					$this->_properties=array_merge($this->_properties,$properties);
9943
			}
9944
		}
9945
				if(isset($config['includes']) && is_array($config['includes']))
9946
		{
9947
			foreach($config['includes'] as $include)
9948
			{
9949
				$when = isset($include['when'])?true:false;
9950
				if(!isset($include['file']))
9951
					throw new TConfigurationException('pageserviceconf_includefile_required');
9952
				$filePath = $include['file'];
9953
				if(isset($this->_includes[$filePath]))
9954
					$this->_includes[$filePath]=array($configPagePath,'('.$this->_includes[$filePath][1].') || ('.$when.')');
9955
				else
9956
					$this->_includes[$filePath]=array($configPagePath,$when);
9957
			}
9958
		}
9959
	}
9960
	public function loadPageConfigurationFromXml($dom,$configPath,$configPagePath)
9961
	{
9962
				if(($authorizationNode=$dom->getElementByTagName('authorization'))!==null)
9963
		{
9964
			$rules=array();
9965
			foreach($authorizationNode->getElements() as $node)
9966
			{
9967
				$patterns=$node->getAttribute('pages');
9968
				$ruleApplies=false;
9969
				if(empty($patterns) || trim($patterns)==='*') 					$ruleApplies=true;
9970
				else
9971
				{
9972
					foreach(explode(',',$patterns) as $pattern)
9973
					{
9974
						if(($pattern=trim($pattern))!=='')
9975
						{
9976
														if($configPagePath!=='')  								$pattern=$configPagePath.'.'.$pattern;
9977
							if(strcasecmp($pattern,$this->_pagePath)===0)
9978
							{
9979
								$ruleApplies=true;
9980
								break;
9981
							}
9982
							if($pattern[strlen($pattern)-1]==='*') 							{
9983
								if(strncasecmp($this->_pagePath,$pattern,strlen($pattern)-1)===0)
9984
								{
9985
									$ruleApplies=true;
9986
									break;
9987
								}
9988
							}
9989
						}
9990
					}
9991
				}
9992
				if($ruleApplies)
9993
					$rules[]=new TAuthorizationRule($node->getTagName(),$node->getAttribute('users'),$node->getAttribute('roles'),$node->getAttribute('verb'),$node->getAttribute('ips'));
9994
			}
9995
			$this->_rules=array_merge($rules,$this->_rules);
9996
		}
9997
				if(($pagesNode=$dom->getElementByTagName('pages'))!==null)
9998
		{
9999
			$this->_properties=array_merge($this->_properties,$pagesNode->getAttributes()->toArray());
10000
						foreach($pagesNode->getElementsByTagName('page') as $node)
10001
			{
10002
				$properties=$node->getAttributes();
10003
				$id=$properties->remove('id');
10004
				if(empty($id))
10005
					throw new TConfigurationException('pageserviceconf_page_invalid',$configPath);
10006
				$matching=false;
10007
				$id=($configPagePath==='')?$id:$configPagePath.'.'.$id;
10008
				if(strcasecmp($id,$this->_pagePath)===0)
10009
					$matching=true;
10010
				else if($id[strlen($id)-1]==='*') 					$matching=strncasecmp($this->_pagePath,$id,strlen($id)-1)===0;
10011
				if($matching)
10012
					$this->_properties=array_merge($this->_properties,$properties->toArray());
10013
			}
10014
		}
10015
				foreach($dom->getElementsByTagName('include') as $node)
10016
		{
10017
			if(($when=$node->getAttribute('when'))===null)
10018
				$when=true;
10019
			if(($filePath=$node->getAttribute('file'))===null)
10020
				throw new TConfigurationException('pageserviceconf_includefile_required');
10021
			if(isset($this->_includes[$filePath]))
10022
				$this->_includes[$filePath]=array($configPagePath,'('.$this->_includes[$filePath][1].') || ('.$when.')');
10023
			else
10024
				$this->_includes[$filePath]=array($configPagePath,$when);
10025
		}
10026
	}
10027
}
10028
class TAssetManager extends TModule
10029
{
10030
	const DEFAULT_BASEPATH='assets';
10031
	private $_basePath=null;
10032
	private $_baseUrl=null;
10033
	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...
10034
	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...
10035
	private $_published=array();
10036
	private $_initialized=false;
10037
	public function init($config)
10038
	{
10039
		$application=$this->getApplication();
10040
		if($this->_basePath===null)
10041
			$this->_basePath=dirname($application->getRequest()->getApplicationFilePath()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
10042
		if(!is_writable($this->_basePath) || !is_dir($this->_basePath))
10043
			throw new TConfigurationException('assetmanager_basepath_invalid',$this->_basePath);
10044
		if($this->_baseUrl===null)
10045
			$this->_baseUrl=rtrim(dirname($application->getRequest()->getApplicationUrl()),'/\\').'/'.self::DEFAULT_BASEPATH;
10046
		$application->setAssetManager($this);
10047
		$this->_initialized=true;
10048
	}
10049
	public function getBasePath()
10050
	{
10051
		return $this->_basePath;
10052
	}
10053
	public function setBasePath($value)
10054
	{
10055
		if($this->_initialized)
10056
			throw new TInvalidOperationException('assetmanager_basepath_unchangeable');
10057
		else
10058
		{
10059
			$this->_basePath=Prado::getPathOfNamespace($value);
10060
			if($this->_basePath===null || !is_dir($this->_basePath) || !is_writable($this->_basePath))
10061
				throw new TInvalidDataValueException('assetmanager_basepath_invalid',$value);
10062
		}
10063
	}
10064
	public function getBaseUrl()
10065
	{
10066
		return $this->_baseUrl;
10067
	}
10068
	public function setBaseUrl($value)
10069
	{
10070
		if($this->_initialized)
10071
			throw new TInvalidOperationException('assetmanager_baseurl_unchangeable');
10072
		else
10073
			$this->_baseUrl=rtrim($value,'/');
10074
	}
10075
	public function publishFilePath($path,$checkTimestamp=false)
10076
	{
10077
		if(isset($this->_published[$path]))
10078
			return $this->_published[$path];
10079
		else if(empty($path) || ($fullpath=realpath($path))===false)
10080
			throw new TInvalidDataValueException('assetmanager_filepath_invalid',$path);
10081
		else if(is_file($fullpath))
10082
		{
10083
			$dir=$this->hash(dirname($fullpath));
10084
			$fileName=basename($fullpath);
10085
			$dst=$this->_basePath.DIRECTORY_SEPARATOR.$dir;
10086
			if(!is_file($dst.DIRECTORY_SEPARATOR.$fileName) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
10087
				$this->copyFile($fullpath,$dst);
10088
			return $this->_published[$path]=$this->_baseUrl.'/'.$dir.'/'.$fileName;
10089
		}
10090
		else
10091
		{
10092
			$dir=$this->hash($fullpath);
10093
			if(!is_dir($this->_basePath.DIRECTORY_SEPARATOR.$dir) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
10094
			{
10095
				$this->copyDirectory($fullpath,$this->_basePath.DIRECTORY_SEPARATOR.$dir);
10096
			}
10097
			return $this->_published[$path]=$this->_baseUrl.'/'.$dir;
10098
		}
10099
	}
10100
	public function getPublished()
10101
	{
10102
		return $this->_published;
10103
	}
10104
	protected function setPublished($values=array())
10105
	{
10106
		$this->_published = $values;
10107
	}
10108
	public function getPublishedPath($path)
10109
	{
10110
		$path=realpath($path);
10111
		if(is_file($path))
10112
			return $this->_basePath.DIRECTORY_SEPARATOR.$this->hash(dirname($path)).DIRECTORY_SEPARATOR.basename($path);
10113
		else
10114
			return $this->_basePath.DIRECTORY_SEPARATOR.$this->hash($path);
10115
	}
10116
	public function getPublishedUrl($path)
10117
	{
10118
		$path=realpath($path);
10119
		if(is_file($path))
10120
			return $this->_baseUrl.'/'.$this->hash(dirname($path)).'/'.basename($path);
10121
		else
10122
			return $this->_baseUrl.'/'.$this->hash($path);
10123
	}
10124
	protected function hash($dir)
10125
	{
10126
		return sprintf('%x',crc32($dir.Prado::getVersion()));
10127
	}
10128
	protected function copyFile($src,$dst)
10129
	{
10130
		if(!is_dir($dst))
10131
		{
10132
			@mkdir($dst);
10133
			@chmod($dst, PRADO_CHMOD);
10134
		}
10135
		$dstFile=$dst.DIRECTORY_SEPARATOR.basename($src);
10136
		if(@filemtime($dstFile)<@filemtime($src))
10137
		{
10138
			@copy($src,$dstFile);
10139
		}
10140
	}
10141
	public function copyDirectory($src,$dst)
10142
	{
10143
		if(!is_dir($dst))
10144
		{
10145
			@mkdir($dst);
10146
			@chmod($dst, PRADO_CHMOD);
10147
		}
10148
		if($folder=@opendir($src))
10149
		{
10150
			while($file=@readdir($folder))
10151
			{
10152
				if($file==='.' || $file==='..' || $file==='.svn')
10153
					continue;
10154
				else if(is_file($src.DIRECTORY_SEPARATOR.$file))
10155
				{
10156
					if(@filemtime($dst.DIRECTORY_SEPARATOR.$file)<@filemtime($src.DIRECTORY_SEPARATOR.$file))
10157
					{
10158
						@copy($src.DIRECTORY_SEPARATOR.$file,$dst.DIRECTORY_SEPARATOR.$file);
10159
						@chmod($dst.DIRECTORY_SEPARATOR.$file, PRADO_CHMOD);
10160
					}
10161
				}
10162
				else
10163
					$this->copyDirectory($src.DIRECTORY_SEPARATOR.$file,$dst.DIRECTORY_SEPARATOR.$file);
10164
			}
10165
			closedir($folder);
10166
		} else {
10167
			throw new TInvalidDataValueException('assetmanager_source_directory_invalid', $src);
10168
		}
10169
	}
10170
	public function publishTarFile($tarfile, $md5sum, $checkTimestamp=false)
10171
	{
10172
		if(isset($this->_published[$md5sum]))
10173
			return $this->_published[$md5sum];
10174
		else if(($fullpath=realpath($md5sum))===false || !is_file($fullpath))
10175
			throw new TInvalidDataValueException('assetmanager_tarchecksum_invalid',$md5sum);
10176
		else
10177
		{
10178
			$dir=$this->hash(dirname($fullpath));
10179
			$fileName=basename($fullpath);
10180
			$dst=$this->_basePath.DIRECTORY_SEPARATOR.$dir;
10181
			if(!is_file($dst.DIRECTORY_SEPARATOR.$fileName) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
10182
			{
10183
				if(@filemtime($dst.DIRECTORY_SEPARATOR.$fileName)<@filemtime($fullpath))
10184
				{
10185
					$this->copyFile($fullpath,$dst);
10186
					$this->deployTarFile($tarfile,$dst);
10187
				}
10188
			}
10189
			return $this->_published[$md5sum]=$this->_baseUrl.'/'.$dir;
10190
		}
10191
	}
10192
	protected function deployTarFile($path,$destination)
10193
	{
10194
		if(($fullpath=realpath($path))===false || !is_file($fullpath))
10195
			throw new TIOException('assetmanager_tarfile_invalid',$path);
10196
		else
10197
		{
10198
			Prado::using('System.IO.TTarFileExtractor');
10199
			$tar = new TTarFileExtractor($fullpath);
10200
			return $tar->extract($destination);
10201
		}
10202
	}
10203
}
10204
class TGlobalization extends TModule
10205
{
10206
	private $_defaultCharset = 'UTF-8';
10207
	private $_defaultCulture = 'en';
10208
	private $_charset=null;
10209
	private $_culture=null;
10210
	private $_translation;
10211
	private $_translateDefaultCulture=true;
10212
	public function init($config)
10213
	{
10214
		if($this->_charset===null)
10215
			$this->_charset=$this->getDefaultCharset();
10216
		if($this->_culture===null)
10217
			$this->_culture=$this->getDefaultCulture();
10218
		if($config!==null)
10219
		{
10220
			if($this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
10221
				$translation = isset($config['translate'])?$config['translate']:null;
10222
			else
10223
			{
10224
				$t = $config->getElementByTagName('translation');
10225
				$translation = ($t)?$t->getAttributes():null;
10226
			}
10227
			if($translation)
10228
				$this->setTranslationConfiguration($translation);
10229
		}
10230
		$this->getApplication()->setGlobalization($this);
10231
	}
10232
	public function getTranslateDefaultCulture()
10233
	{
10234
		return $this->_translateDefaultCulture;
10235
	}
10236
	public function setTranslateDefaultCulture($value)
10237
	{
10238
		$this->_translateDefaultCulture = TPropertyValue::ensureBoolean($value);
10239
	}
10240
	public function getDefaultCulture()
10241
	{
10242
		return $this->_defaultCulture;
10243
	}
10244
	public function setDefaultCulture($culture)
10245
	{
10246
		$this->_defaultCulture = str_replace('-','_',$culture);
10247
	}
10248
	public function getDefaultCharset()
10249
	{
10250
		return $this->_defaultCharset;
10251
	}
10252
	public function setDefaultCharset($charset)
10253
	{
10254
		$this->_defaultCharset = $charset;
10255
	}
10256
	public function getCulture()
10257
	{
10258
		return $this->_culture;
10259
	}
10260
	public function setCulture($culture)
10261
	{
10262
		$this->_culture = str_replace('-','_',$culture);
10263
	}
10264
	public function getCharset()
10265
	{
10266
		return $this->_charset;
10267
	}
10268
	public function setCharset($charset)
10269
	{
10270
		$this->_charset = $charset;
10271
	}
10272
	public function getTranslationConfiguration()
10273
	{
10274
		return (!$this->_translateDefaultCulture && ($this->getDefaultCulture() == $this->getCulture()))
10275
			? null
10276
			: $this->_translation;
10277
	}
10278
	protected function setTranslationConfiguration($config)
10279
	{
10280
		if($config['type'] == 'XLIFF' || $config['type'] == 'gettext')
10281
		{
10282
			if($config['source'])
10283
			{
10284
				$config['source'] = Prado::getPathOfNamespace($config['source']);
10285
				if(!is_dir($config['source']))
10286
				{
10287
					if(@mkdir($config['source'])===false)
10288
					throw new TConfigurationException('globalization_source_path_failed',
10289
						$config['source']);
10290
					chmod($config['source'], PRADO_CHMOD); 				}
10291
			}
10292
			else
10293
			{
10294
				throw new TConfigurationException("invalid source dir '{$config['source']}'");
10295
			}
10296
		}
10297
		if(isset($config['cache']) && TPropertyValue::ensureBoolean($config['cache']))
10298
		{
10299
			$config['cache'] = $this->getApplication()->getRunTimePath().'/i18n';
10300
			if(!is_dir($config['cache']))
10301
			{
10302
				if(@mkdir($config['cache'])===false)
10303
					throw new TConfigurationException('globalization_cache_path_failed',
10304
						$config['cache']);
10305
				chmod($config['cache'], PRADO_CHMOD); 			}
10306
		}
10307
        else
10308
        {
10309
            unset($config['cache']);
10310
        }
10311
		$this->_translation = $config;
10312
	}
10313
	public function getTranslationCatalogue()
10314
	{
10315
		return $this->_translation['catalogue'];
10316
	}
10317
	public function setTranslationCatalogue($value)
10318
	{
10319
		$this->_translation['catalogue'] = $value;
10320
	}
10321
	public function getCultureVariants($culture=null)
10322
	{
10323
		if($culture===null) $culture = $this->getCulture();
10324
		$variants = explode('_', $culture);
10325
		$result = array();
10326
		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...
10327
			$result[] = implode('_', $variants);
10328
		return $result;
10329
	}
10330
	public function getLocalizedResource($file,$culture=null)
10331
	{
10332
		$files = array();
10333
		$variants = $this->getCultureVariants($culture);
10334
		$path = pathinfo($file);
10335
		foreach($variants as $variant)
10336
			$files[] = $path['dirname'].DIRECTORY_SEPARATOR.$variant.DIRECTORY_SEPARATOR.$path['basename'];
10337
		$filename = substr($path['basename'],0,strrpos($path['basename'],'.'));
10338
		foreach($variants as $variant)
10339
			$files[] = $path['dirname'].DIRECTORY_SEPARATOR.$filename.'.'.$variant.'.'.$path['extension'];
10340
		$files[] = $file;
10341
		return $files;
10342
	}
10343
}
10344
class TApplication extends TComponent
10345
{
10346
	const STATE_OFF='Off';
10347
	const STATE_DEBUG='Debug';
10348
	const STATE_NORMAL='Normal';
10349
	const STATE_PERFORMANCE='Performance';
10350
	const PAGE_SERVICE_ID='page';
10351
	const CONFIG_FILE_XML='application.xml';
10352
	const CONFIG_FILE_EXT_XML='.xml';
10353
	const CONFIG_TYPE_XML = 'xml';
10354
	const CONFIG_FILE_PHP='application.php';
10355
	const CONFIG_FILE_EXT_PHP='.php';
10356
	const CONFIG_TYPE_PHP = 'php';
10357
	const RUNTIME_PATH='runtime';
10358
	const CONFIGCACHE_FILE='config.cache';
10359
	const GLOBAL_FILE='global.cache';
10360
	private static $_steps=array(
10361
		'onBeginRequest',
10362
		'onLoadState',
10363
		'onLoadStateComplete',
10364
		'onAuthentication',
10365
		'onAuthenticationComplete',
10366
		'onAuthorization',
10367
		'onAuthorizationComplete',
10368
		'onPreRunService',
10369
		'runService',
10370
		'onSaveState',
10371
		'onSaveStateComplete',
10372
		'onPreFlushOutput',
10373
		'flushOutput'
10374
	);
10375
	private $_id;
10376
	private $_uniqueID;
10377
	private $_requestCompleted=false;
10378
	private $_step;
10379
	private $_services;
10380
	private $_service;
10381
	private $_modules=array();
10382
	private $_lazyModules=array();
10383
	private $_parameters;
10384
	private $_configFile;
10385
	private $_configFileExt;
10386
	private $_configType;
10387
	private $_basePath;
10388
	private $_runtimePath;
10389
	private $_stateChanged=false;
10390
	private $_globals=array();
10391
	private $_cacheFile;
10392
	private $_errorHandler;
10393
	private $_request;
10394
	private $_response;
10395
	private $_session;
10396
	private $_cache;
10397
	private $_statePersister;
10398
	private $_user;
10399
	private $_globalization;
10400
	private $_security;
10401
	private $_assetManager;
10402
	private $_authRules;
10403
	private $_mode=TApplicationMode::Debug;
10404
	private $_pageServiceID = self::PAGE_SERVICE_ID;
10405
	public function __construct($basePath='protected',$cacheConfig=true, $configType=self::CONFIG_TYPE_XML)
10406
	{
10407
				Prado::setApplication($this);
10408
		$this->setConfigurationType($configType);
10409
		$this->resolvePaths($basePath);
10410
		if($cacheConfig)
10411
			$this->_cacheFile=$this->_runtimePath.DIRECTORY_SEPARATOR.self::CONFIGCACHE_FILE;
10412
				$this->_uniqueID=md5($this->_runtimePath);
10413
		$this->_parameters=new TMap;
10414
		$this->_services=array($this->getPageServiceID()=>array('TPageService',array(),null));
10415
		Prado::setPathOfAlias('Application',$this->_basePath);
10416
	}
10417
	protected function resolvePaths($basePath)
10418
	{
10419
				if(empty($basePath) || ($basePath=realpath($basePath))===false)
10420
			throw new TConfigurationException('application_basepath_invalid',$basePath);
10421
		if(is_dir($basePath) && is_file($basePath.DIRECTORY_SEPARATOR.$this->getConfigurationFileName()))
10422
			$configFile=$basePath.DIRECTORY_SEPARATOR.$this->getConfigurationFileName();
10423
		else if(is_file($basePath))
10424
		{
10425
			$configFile=$basePath;
10426
			$basePath=dirname($configFile);
10427
		}
10428
		else
10429
			$configFile=null;
10430
				$runtimePath=$basePath.DIRECTORY_SEPARATOR.self::RUNTIME_PATH;
10431
		if(is_writable($runtimePath))
10432
		{
10433
			if($configFile!==null)
10434
			{
10435
				$runtimePath.=DIRECTORY_SEPARATOR.basename($configFile).'-'.Prado::getVersion();
10436
				if(!is_dir($runtimePath))
10437
				{
10438
					if(@mkdir($runtimePath)===false)
10439
						throw new TConfigurationException('application_runtimepath_failed',$runtimePath);
10440
					@chmod($runtimePath, PRADO_CHMOD); 				}
10441
				$this->setConfigurationFile($configFile);
10442
			}
10443
			$this->setBasePath($basePath);
10444
			$this->setRuntimePath($runtimePath);
10445
		}
10446
		else
10447
			throw new TConfigurationException('application_runtimepath_invalid',$runtimePath);
10448
	}
10449
	public function run()
10450
	{
10451
		try
10452
		{
10453
			$this->initApplication();
10454
			$n=count(self::$_steps);
10455
			$this->_step=0;
10456
			$this->_requestCompleted=false;
10457
			while($this->_step<$n)
10458
			{
10459
				if($this->_mode===self::STATE_OFF)
10460
					throw new THttpException(503,'application_unavailable');
10461
				if($this->_requestCompleted)
10462
					break;
10463
				$method=self::$_steps[$this->_step];
10464
				$this->$method();
10465
				$this->_step++;
10466
			}
10467
		}
10468
		catch(Exception $e)
10469
		{
10470
			$this->onError($e);
10471
		}
10472
		$this->onEndRequest();
10473
	}
10474
	public function completeRequest()
10475
	{
10476
		$this->_requestCompleted=true;
10477
	}
10478
	public function getRequestCompleted()
10479
	{
10480
		return $this->_requestCompleted;
10481
	}
10482
	public function getGlobalState($key,$defaultValue=null)
10483
	{
10484
		return isset($this->_globals[$key])?$this->_globals[$key]:$defaultValue;
10485
	}
10486
	public function setGlobalState($key,$value,$defaultValue=null,$forceSave=false)
10487
	{
10488
		$this->_stateChanged=true;
10489
		if($value===$defaultValue)
10490
			unset($this->_globals[$key]);
10491
		else
10492
			$this->_globals[$key]=$value;
10493
		if($forceSave)
10494
			$this->saveGlobals();
10495
	}
10496
	public function clearGlobalState($key)
10497
	{
10498
		$this->_stateChanged=true;
10499
		unset($this->_globals[$key]);
10500
	}
10501
	protected function loadGlobals()
10502
	{
10503
		$this->_globals=$this->getApplicationStatePersister()->load();
10504
	}
10505
	protected function saveGlobals()
10506
	{
10507
		if($this->_stateChanged)
10508
		{
10509
			$this->_stateChanged=false;
10510
			$this->getApplicationStatePersister()->save($this->_globals);
10511
		}
10512
	}
10513
	public function getID()
10514
	{
10515
		return $this->_id;
10516
	}
10517
	public function setID($value)
10518
	{
10519
		$this->_id=$value;
10520
	}
10521
	public function getPageServiceID()
10522
	{
10523
		return $this->_pageServiceID;
10524
	}
10525
	public function setPageServiceID($value)
10526
	{
10527
		$this->_pageServiceID=$value;
10528
	}
10529
	public function getUniqueID()
10530
	{
10531
		return $this->_uniqueID;
10532
	}
10533
	public function getMode()
10534
	{
10535
		return $this->_mode;
10536
	}
10537
	public function setMode($value)
10538
	{
10539
		$this->_mode=TPropertyValue::ensureEnum($value,'TApplicationMode');
10540
	}
10541
	public function getBasePath()
10542
	{
10543
		return $this->_basePath;
10544
	}
10545
	public function setBasePath($value)
10546
	{
10547
		$this->_basePath=$value;
10548
	}
10549
	public function getConfigurationFile()
10550
	{
10551
		return $this->_configFile;
10552
	}
10553
	public function setConfigurationFile($value)
10554
	{
10555
		$this->_configFile=$value;
10556
	}
10557
	public function getConfigurationType()
10558
	{
10559
		return $this->_configType;
10560
	}
10561
	public function setConfigurationType($value)
10562
	{
10563
		$this->_configType = $value;
10564
	}
10565
	public function getConfigurationFileExt()
10566
	{
10567
		if($this->_configFileExt===null)
10568
		{
10569
			switch($this->_configType)
10570
			{
10571
				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...
10572
					$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...
10573
					break;
10574
				default:
10575
					$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...
10576
			}
10577
		}
10578
		return $this->_configFileExt;
10579
	}
10580
	public function getConfigurationFileName()
10581
	{
10582
		static $fileName;
10583
		if($fileName == null)
10584
		{
10585
			switch($this->_configType)
10586
			{
10587
				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...
10588
					$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...
10589
					break;
10590
				default:
10591
					$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...
10592
			}
10593
		}
10594
		return $fileName;
10595
	}
10596
	public function getRuntimePath()
10597
	{
10598
		return $this->_runtimePath;
10599
	}
10600
	public function setRuntimePath($value)
10601
	{
10602
		$this->_runtimePath=$value;
10603
		if($this->_cacheFile)
10604
			$this->_cacheFile=$this->_runtimePath.DIRECTORY_SEPARATOR.self::CONFIGCACHE_FILE;
10605
				$this->_uniqueID=md5($this->_runtimePath);
10606
	}
10607
	public function getService()
10608
	{
10609
		return $this->_service;
10610
	}
10611
	public function setService($value)
10612
	{
10613
		$this->_service=$value;
10614
	}
10615
	public function setModule($id,IModule $module=null)
10616
	{
10617
		if(isset($this->_modules[$id]))
10618
			throw new TConfigurationException('application_moduleid_duplicated',$id);
10619
		else
10620
			$this->_modules[$id]=$module;
10621
	}
10622
	public function getModule($id)
10623
	{
10624
		if(!array_key_exists($id, $this->_modules))
10625
			return null;
10626
				if($this->_modules[$id]===null)
10627
		{
10628
			$module = $this->internalLoadModule($id, true);
10629
			$module[0]->init($module[1]);
10630
		}
10631
		return $this->_modules[$id];
10632
	}
10633
	public function getModules()
10634
	{
10635
		return $this->_modules;
10636
	}
10637
	public function getParameters()
10638
	{
10639
		return $this->_parameters;
10640
	}
10641
	public function getRequest()
10642
	{
10643
		if(!$this->_request)
10644
		{
10645
			$this->_request=new THttpRequest;
10646
			$this->_request->init(null);
10647
		}
10648
		return $this->_request;
10649
	}
10650
	public function setRequest(THttpRequest $request)
10651
	{
10652
		$this->_request=$request;
10653
	}
10654
	public function getResponse()
10655
	{
10656
		if(!$this->_response)
10657
		{
10658
			$this->_response=new THttpResponse;
10659
			$this->_response->init(null);
10660
		}
10661
		return $this->_response;
10662
	}
10663
	public function setResponse(THttpResponse $response)
10664
	{
10665
		$this->_response=$response;
10666
	}
10667
	public function getSession()
10668
	{
10669
		if(!$this->_session)
10670
		{
10671
			$this->_session=new THttpSession;
10672
			$this->_session->init(null);
10673
		}
10674
		return $this->_session;
10675
	}
10676
	public function setSession(THttpSession $session)
10677
	{
10678
		$this->_session=$session;
10679
	}
10680
	public function getErrorHandler()
10681
	{
10682
		if(!$this->_errorHandler)
10683
		{
10684
			$this->_errorHandler=new TErrorHandler;
10685
			$this->_errorHandler->init(null);
10686
		}
10687
		return $this->_errorHandler;
10688
	}
10689
	public function setErrorHandler(TErrorHandler $handler)
10690
	{
10691
		$this->_errorHandler=$handler;
10692
	}
10693
	public function getSecurityManager()
10694
	{
10695
		if(!$this->_security)
10696
		{
10697
			$this->_security=new TSecurityManager;
10698
			$this->_security->init(null);
10699
		}
10700
		return $this->_security;
10701
	}
10702
	public function setSecurityManager(TSecurityManager $sm)
10703
	{
10704
		$this->_security=$sm;
10705
	}
10706
	public function getAssetManager()
10707
	{
10708
		if(!$this->_assetManager)
10709
		{
10710
			$this->_assetManager=new TAssetManager;
10711
			$this->_assetManager->init(null);
10712
		}
10713
		return $this->_assetManager;
10714
	}
10715
	public function setAssetManager(TAssetManager $value)
10716
	{
10717
		$this->_assetManager=$value;
10718
	}
10719
	public function getApplicationStatePersister()
10720
	{
10721
		if(!$this->_statePersister)
10722
		{
10723
			$this->_statePersister=new TApplicationStatePersister;
10724
			$this->_statePersister->init(null);
10725
		}
10726
		return $this->_statePersister;
10727
	}
10728
	public function setApplicationStatePersister(IStatePersister $persister)
10729
	{
10730
		$this->_statePersister=$persister;
10731
	}
10732
	public function getCache()
10733
	{
10734
		return $this->_cache;
10735
	}
10736
	public function setCache(ICache $cache)
10737
	{
10738
		$this->_cache=$cache;
10739
	}
10740
	public function getUser()
10741
	{
10742
		return $this->_user;
10743
	}
10744
	public function setUser(IUser $user)
10745
	{
10746
		$this->_user=$user;
10747
	}
10748
	public function getGlobalization($createIfNotExists=true)
10749
	{
10750
		if($this->_globalization===null && $createIfNotExists)
10751
		{
10752
			$this->_globalization=new TGlobalization;
10753
			$this->_globalization->init(null);
10754
		}
10755
		return $this->_globalization;
10756
	}
10757
	public function setGlobalization(TGlobalization $glob)
10758
	{
10759
		$this->_globalization=$glob;
10760
	}
10761
	public function getAuthorizationRules()
10762
	{
10763
		if($this->_authRules===null)
10764
			$this->_authRules=new TAuthorizationRuleCollection;
10765
		return $this->_authRules;
10766
	}
10767
	protected function getApplicationConfigurationClass()
10768
	{
10769
		return 'TApplicationConfiguration';
10770
	}
10771
	protected function internalLoadModule($id, $force=false)
10772
	{
10773
		list($moduleClass, $initProperties, $configElement)=$this->_lazyModules[$id];
10774
		if(isset($initProperties['lazy']) && $initProperties['lazy'] && !$force)
10775
		{
10776
			$this->setModule($id, null);
10777
			return null;
10778
		}
10779
		$module=Prado::createComponent($moduleClass);
10780
		foreach($initProperties as $name=>$value)
10781
		{
10782
			if($name==='lazy') continue;
10783
			$module->setSubProperty($name,$value);
10784
		}
10785
		$this->setModule($id,$module);
10786
				$this->_lazyModules[$id]=null;
10787
		return array($module,$configElement);
10788
	}
10789
	public function applyConfiguration($config,$withinService=false)
10790
	{
10791
		if($config->getIsEmpty())
10792
			return;
10793
				foreach($config->getAliases() as $alias=>$path)
10794
			Prado::setPathOfAlias($alias,$path);
10795
		foreach($config->getUsings() as $using)
10796
			Prado::using($using);
10797
				if(!$withinService)
10798
		{
10799
			foreach($config->getProperties() as $name=>$value)
10800
				$this->setSubProperty($name,$value);
10801
		}
10802
		if(empty($this->_services))
10803
			$this->_services=array($this->getPageServiceID()=>array('TPageService',array(),null));
10804
				foreach($config->getParameters() as $id=>$parameter)
10805
		{
10806
			if(is_array($parameter))
10807
			{
10808
				$component=Prado::createComponent($parameter[0]);
10809
				foreach($parameter[1] as $name=>$value)
10810
					$component->setSubProperty($name,$value);
10811
				$this->_parameters->add($id,$component);
10812
			}
10813
			else
10814
				$this->_parameters->add($id,$parameter);
10815
		}
10816
				$modules=array();
10817
		foreach($config->getModules() as $id=>$moduleConfig)
10818
		{
10819
			if(!is_string($id))
10820
				$id='_module'.count($this->_lazyModules);
10821
			$this->_lazyModules[$id]=$moduleConfig;
10822
			if($module = $this->internalLoadModule($id))
10823
				$modules[]=$module;
10824
		}
10825
		foreach($modules as $module)
10826
			$module[0]->init($module[1]);
10827
				foreach($config->getServices() as $serviceID=>$serviceConfig)
10828
			$this->_services[$serviceID]=$serviceConfig;
10829
				foreach($config->getExternalConfigurations() as $filePath=>$condition)
10830
		{
10831
			if($condition!==true)
10832
				$condition=$this->evaluateExpression($condition);
10833
			if($condition)
10834
			{
10835
				if(($path=Prado::getPathOfNamespace($filePath,$this->getConfigurationFileExt()))===null || !is_file($path))
10836
					throw new TConfigurationException('application_includefile_invalid',$filePath);
10837
				$cn=$this->getApplicationConfigurationClass();
10838
				$c=new $cn;
10839
				$c->loadFromFile($path);
10840
				$this->applyConfiguration($c,$withinService);
10841
			}
10842
		}
10843
	}
10844
	protected function initApplication()
10845
	{
10846
		if($this->_configFile!==null)
10847
		{
10848
			if($this->_cacheFile===null || @filemtime($this->_cacheFile)<filemtime($this->_configFile))
10849
			{
10850
				$config=new TApplicationConfiguration;
10851
				$config->loadFromFile($this->_configFile);
10852
				if($this->_cacheFile!==null)
10853
					file_put_contents($this->_cacheFile,serialize($config),LOCK_EX);
10854
			}
10855
			else
10856
				$config=unserialize(file_get_contents($this->_cacheFile));
10857
			$this->applyConfiguration($config,false);
10858
		}
10859
		if(($serviceID=$this->getRequest()->resolveRequest(array_keys($this->_services)))===null)
10860
			$serviceID=$this->getPageServiceID();
10861
		$this->startService($serviceID);
10862
	}
10863
	public function startService($serviceID)
10864
	{
10865
		if(isset($this->_services[$serviceID]))
10866
		{
10867
			list($serviceClass,$initProperties,$configElement)=$this->_services[$serviceID];
10868
			$service=Prado::createComponent($serviceClass);
10869
			if(!($service instanceof IService))
10870
				throw new THttpException(500,'application_service_invalid',$serviceClass);
10871
			if(!$service->getEnabled())
10872
				throw new THttpException(500,'application_service_unavailable',$serviceClass);
10873
			$service->setID($serviceID);
10874
			$this->setService($service);
10875
			foreach($initProperties as $name=>$value)
10876
				$service->setSubProperty($name,$value);
10877
			if($configElement!==null)
10878
			{
10879
				$config=new TApplicationConfiguration;
10880
				if($this->getConfigurationType()==self::CONFIG_TYPE_PHP)
10881
					$config->loadFromPhp($configElement,$this->getBasePath());
10882
				else
10883
					$config->loadFromXml($configElement,$this->getBasePath());
10884
				$this->applyConfiguration($config,true);
10885
			}
10886
			$service->init($configElement);
10887
		}
10888
		else
10889
			throw new THttpException(500,'application_service_unknown',$serviceID);
10890
	}
10891
	public function onError($param)
10892
	{
10893
		Prado::log($param->getMessage(),TLogger::ERROR,'System.TApplication');
10894
		$this->raiseEvent('OnError',$this,$param);
10895
		$this->getErrorHandler()->handleError($this,$param);
10896
	}
10897
	public function onBeginRequest()
10898
	{
10899
		$this->raiseEvent('OnBeginRequest',$this,null);
10900
	}
10901
	public function onAuthentication()
10902
	{
10903
		$this->raiseEvent('OnAuthentication',$this,null);
10904
	}
10905
	public function onAuthenticationComplete()
10906
	{
10907
		$this->raiseEvent('OnAuthenticationComplete',$this,null);
10908
	}
10909
	public function onAuthorization()
10910
	{
10911
		$this->raiseEvent('OnAuthorization',$this,null);
10912
	}
10913
	public function onAuthorizationComplete()
10914
	{
10915
		$this->raiseEvent('OnAuthorizationComplete',$this,null);
10916
	}
10917
	public function onLoadState()
10918
	{
10919
		$this->loadGlobals();
10920
		$this->raiseEvent('OnLoadState',$this,null);
10921
	}
10922
	public function onLoadStateComplete()
10923
	{
10924
		$this->raiseEvent('OnLoadStateComplete',$this,null);
10925
	}
10926
	public function onPreRunService()
10927
	{
10928
		$this->raiseEvent('OnPreRunService',$this,null);
10929
	}
10930
	public function runService()
10931
	{
10932
		if($this->_service)
10933
			$this->_service->run();
10934
	}
10935
	public function onSaveState()
10936
	{
10937
		$this->raiseEvent('OnSaveState',$this,null);
10938
		$this->saveGlobals();
10939
	}
10940
	public function onSaveStateComplete()
10941
	{
10942
		$this->raiseEvent('OnSaveStateComplete',$this,null);
10943
	}
10944
	public function onPreFlushOutput()
10945
	{
10946
		$this->raiseEvent('OnPreFlushOutput',$this,null);
10947
	}
10948
	public function flushOutput($continueBuffering = true)
10949
	{
10950
		$this->getResponse()->flush($continueBuffering);
10951
	}
10952
	public function onEndRequest()
10953
	{
10954
		$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...
10955
	}
10956
}
10957
class TApplicationMode extends TEnumerable
10958
{
10959
	const Off='Off';
10960
	const Debug='Debug';
10961
	const Normal='Normal';
10962
	const Performance='Performance';
10963
}
10964
class TApplicationConfiguration extends TComponent
10965
{
10966
	private $_properties=array();
10967
	private $_usings=array();
10968
	private $_aliases=array();
10969
	private $_modules=array();
10970
	private $_services=array();
10971
	private $_parameters=array();
10972
	private $_includes=array();
10973
	private $_empty=true;
10974
	public function loadFromFile($fname)
10975
	{
10976
		if(Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
10977
		{
10978
			$fcontent = include $fname;
10979
			$this->loadFromPhp($fcontent,dirname($fname));
10980
		}
10981
		else
10982
		{
10983
			$dom=new TXmlDocument;
10984
			$dom->loadFromFile($fname);
10985
			$this->loadFromXml($dom,dirname($fname));
10986
		}
10987
	}
10988
	public function getIsEmpty()
10989
	{
10990
		return $this->_empty;
10991
	}
10992
	public function loadFromPhp($config, $configPath)
10993
	{
10994
				if(isset($config['application']))
10995
		{
10996
			foreach($config['application'] as $name=>$value)
10997
			{
10998
				$this->_properties[$name]=$value;
10999
			}
11000
			$this->_empty = false;
11001
		}
11002
		if(isset($config['paths']) && is_array($config['paths']))
11003
			$this->loadPathsPhp($config['paths'],$configPath);
11004
		if(isset($config['modules']) && is_array($config['modules']))
11005
			$this->loadModulesPhp($config['modules'],$configPath);
11006
		if(isset($config['services']) && is_array($config['services']))
11007
			$this->loadServicesPhp($config['services'],$configPath);
11008
		if(isset($config['parameters']) && is_array($config['parameters']))
11009
			$this->loadParametersPhp($config['parameters'], $configPath);
11010
		if(isset($config['includes']) && is_array($config['includes']))
11011
			$this->loadExternalXml($config['includes'],$configPath);
11012
	}
11013
	public function loadFromXml($dom,$configPath)
11014
	{
11015
				foreach($dom->getAttributes() as $name=>$value)
11016
		{
11017
			$this->_properties[$name]=$value;
11018
			$this->_empty=false;
11019
		}
11020
		foreach($dom->getElements() as $element)
11021
		{
11022
			switch($element->getTagName())
11023
			{
11024
				case 'paths':
11025
					$this->loadPathsXml($element,$configPath);
11026
					break;
11027
				case 'modules':
11028
					$this->loadModulesXml($element,$configPath);
11029
					break;
11030
				case 'services':
11031
					$this->loadServicesXml($element,$configPath);
11032
					break;
11033
				case 'parameters':
11034
					$this->loadParametersXml($element,$configPath);
11035
					break;
11036
				case 'include':
11037
					$this->loadExternalXml($element,$configPath);
11038
					break;
11039
				default:
11040
										break;
11041
			}
11042
		}
11043
	}
11044
	protected function loadPathsPhp($pathsNode, $configPath)
11045
	{
11046
		if(isset($pathsNode['aliases']) && is_array($pathsNode['aliases']))
11047
		{
11048
			foreach($pathsNode['aliases'] as $id=>$path)
11049
			{
11050
				$path=str_replace('\\','/',$path);
11051
				if(preg_match('/^\\/|.:\\/|.:\\\\/',$path))						$p=realpath($path);
11052
				else
11053
					$p=realpath($configPath.DIRECTORY_SEPARATOR.$path);
11054
				if($p===false || !is_dir($p))
11055
					throw new TConfigurationException('appconfig_aliaspath_invalid',$id,$path);
11056
				if(isset($this->_aliases[$id]))
11057
					throw new TConfigurationException('appconfig_alias_redefined',$id);
11058
				$this->_aliases[$id]=$p;
11059
			}
11060
		}
11061
		if(isset($pathsNode['using']) && is_array($pathsNode['using']))
11062
		{
11063
			foreach($pathsNode['using'] as $namespace)
11064
			{
11065
				$this->_usings[] = $namespace;
11066
			}
11067
		}
11068
	}
11069
	protected function loadPathsXml($pathsNode,$configPath)
11070
	{
11071
		foreach($pathsNode->getElements() as $element)
11072
		{
11073
			switch($element->getTagName())
11074
			{
11075
				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...
11076
				{
11077
					if(($id=$element->getAttribute('id'))!==null && ($path=$element->getAttribute('path'))!==null)
11078
					{
11079
						$path=str_replace('\\','/',$path);
11080
						if(preg_match('/^\\/|.:\\/|.:\\\\/',$path))								$p=realpath($path);
11081
						else
11082
							$p=realpath($configPath.DIRECTORY_SEPARATOR.$path);
11083
						if($p===false || !is_dir($p))
11084
							throw new TConfigurationException('appconfig_aliaspath_invalid',$id,$path);
11085
						if(isset($this->_aliases[$id]))
11086
							throw new TConfigurationException('appconfig_alias_redefined',$id);
11087
						$this->_aliases[$id]=$p;
11088
					}
11089
					else
11090
						throw new TConfigurationException('appconfig_alias_invalid');
11091
					$this->_empty=false;
11092
					break;
11093
				}
11094
				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...
11095
				{
11096
					if(($namespace=$element->getAttribute('namespace'))!==null)
11097
						$this->_usings[]=$namespace;
11098
					else
11099
						throw new TConfigurationException('appconfig_using_invalid');
11100
					$this->_empty=false;
11101
					break;
11102
				}
11103
				default:
11104
					throw new TConfigurationException('appconfig_paths_invalid',$element->getTagName());
11105
			}
11106
		}
11107
	}
11108
	protected function loadModulesPhp($modulesNode, $configPath)
11109
	{
11110
		foreach($modulesNode as $id=>$module)
11111
		{
11112
			if(!isset($module['class']))
11113
				throw new TConfigurationException('appconfig_moduletype_required',$id);
11114
			$type = $module['class'];
11115
			unset($module['class']);
11116
			$properties = array();
11117
			if(isset($module['properties']))
11118
			{
11119
				$properties = $module['properties'];
11120
				unset($module['properties']);
11121
			}
11122
			$properties['id'] = $id;
11123
			$this->_modules[$id]=array($type,$properties,$module);
11124
			$this->_empty=false;
11125
		}
11126
	}
11127
	protected function loadModulesXml($modulesNode,$configPath)
11128
	{
11129
		foreach($modulesNode->getElements() as $element)
11130
		{
11131
			if($element->getTagName()==='module')
11132
			{
11133
				$properties=$element->getAttributes();
11134
				$id=$properties->itemAt('id');
11135
				$type=$properties->remove('class');
11136
				if($type===null)
11137
					throw new TConfigurationException('appconfig_moduletype_required',$id);
11138
				$element->setParent(null);
11139
				if($id===null)
11140
					$this->_modules[]=array($type,$properties->toArray(),$element);
11141
				else
11142
					$this->_modules[$id]=array($type,$properties->toArray(),$element);
11143
				$this->_empty=false;
11144
			}
11145
			else
11146
				throw new TConfigurationException('appconfig_modules_invalid',$element->getTagName());
11147
		}
11148
	}
11149
	protected function loadServicesPhp($servicesNode,$configPath)
11150
	{
11151
		foreach($servicesNode as $id => $service)
11152
		{
11153
			if(!isset($service['class']))
11154
				throw new TConfigurationException('appconfig_servicetype_required');
11155
			$type = $service['class'];
11156
			$properties = isset($service['properties']) ? $service['properties'] : array();
11157
			unset($service['properties']);
11158
			$properties['id'] = $id;
11159
			$this->_services[$id] = array($type,$properties,$service);
11160
			$this->_empty = false;
11161
		}
11162
	}
11163
	protected function loadServicesXml($servicesNode,$configPath)
11164
	{
11165
		foreach($servicesNode->getElements() as $element)
11166
		{
11167
			if($element->getTagName()==='service')
11168
			{
11169
				$properties=$element->getAttributes();
11170
				if(($id=$properties->itemAt('id'))===null)
11171
					throw new TConfigurationException('appconfig_serviceid_required');
11172
				if(($type=$properties->remove('class'))===null)
11173
					throw new TConfigurationException('appconfig_servicetype_required',$id);
11174
				$element->setParent(null);
11175
				$this->_services[$id]=array($type,$properties->toArray(),$element);
11176
				$this->_empty=false;
11177
			}
11178
			else
11179
				throw new TConfigurationException('appconfig_services_invalid',$element->getTagName());
11180
		}
11181
	}
11182
	protected function loadParametersPhp($parametersNode,$configPath)
11183
	{
11184
		foreach($parametersNode as $id => $parameter)
11185
		{
11186
			if(is_array($parameter))
11187
			{
11188
				if(isset($parameter['class']))
11189
				{
11190
					$type = $parameter['class'];
11191
					unset($parameter['class']);
11192
					$properties = isset($service['properties']) ? $service['properties'] : array();
11193
					$properties['id'] = $id;
11194
					$this->_parameters[$id] = array($type,$properties);
11195
				}
11196
			}
11197
			else
11198
			{
11199
				$this->_parameters[$id] = $parameter;
11200
			}
11201
		}
11202
	}
11203
	protected function loadParametersXml($parametersNode,$configPath)
11204
	{
11205
		foreach($parametersNode->getElements() as $element)
11206
		{
11207
			if($element->getTagName()==='parameter')
11208
			{
11209
				$properties=$element->getAttributes();
11210
				if(($id=$properties->remove('id'))===null)
11211
					throw new TConfigurationException('appconfig_parameterid_required');
11212
				if(($type=$properties->remove('class'))===null)
11213
				{
11214
					if(($value=$properties->remove('value'))===null)
11215
						$this->_parameters[$id]=$element;
11216
					else
11217
						$this->_parameters[$id]=$value;
11218
				}
11219
				else
11220
					$this->_parameters[$id]=array($type,$properties->toArray());
11221
				$this->_empty=false;
11222
			}
11223
			else
11224
				throw new TConfigurationException('appconfig_parameters_invalid',$element->getTagName());
11225
		}
11226
	}
11227
	protected function loadExternalPhp($includeNode,$configPath)
11228
	{
11229
		foreach($includeNode as $include)
11230
		{
11231
			$when = isset($include['when'])?true:false;
11232
			if(!isset($include['file']))
11233
				throw new TConfigurationException('appconfig_includefile_required');
11234
			$filePath = $include['file'];
11235
			if(isset($this->_includes[$filePath]))
11236
				$this->_includes[$filePath]='('.$this->_includes[$filePath].') || ('.$when.')';
11237
			else
11238
				$$this->_includes[$filePath]=$when;
11239
			$this->_empty=false;
11240
		}
11241
	}
11242
	protected function loadExternalXml($includeNode,$configPath)
11243
	{
11244
		if(($when=$includeNode->getAttribute('when'))===null)
11245
			$when=true;
11246
		if(($filePath=$includeNode->getAttribute('file'))===null)
11247
			throw new TConfigurationException('appconfig_includefile_required');
11248
		if(isset($this->_includes[$filePath]))
11249
			$this->_includes[$filePath]='('.$this->_includes[$filePath].') || ('.$when.')';
11250
		else
11251
			$this->_includes[$filePath]=$when;
11252
		$this->_empty=false;
11253
	}
11254
	public function getProperties()
11255
	{
11256
		return $this->_properties;
11257
	}
11258
	public function getAliases()
11259
	{
11260
		return $this->_aliases;
11261
	}
11262
	public function getUsings()
11263
	{
11264
		return $this->_usings;
11265
	}
11266
	public function getModules()
11267
	{
11268
		return $this->_modules;
11269
	}
11270
	public function getServices()
11271
	{
11272
		return $this->_services;
11273
	}
11274
	public function getParameters()
11275
	{
11276
		return $this->_parameters;
11277
	}
11278
	public function getExternalConfigurations()
11279
	{
11280
		return $this->_includes;
11281
	}
11282
}
11283
class TApplicationStatePersister extends TModule implements IStatePersister
11284
{
11285
	const CACHE_NAME='prado:appstate';
11286
	public function init($config)
11287
	{
11288
		$this->getApplication()->setApplicationStatePersister($this);
11289
	}
11290
	protected function getStateFilePath()
11291
	{
11292
		return $this->getApplication()->getRuntimePath().'/global.cache';
11293
	}
11294
	public function load()
11295
	{
11296
		if(($cache=$this->getApplication()->getCache())!==null && ($value=$cache->get(self::CACHE_NAME))!==false)
11297
			return unserialize($value);
11298
		else
11299
		{
11300
			if(($content=@file_get_contents($this->getStateFilePath()))!==false)
11301
				return unserialize($content);
11302
			else
11303
				return null;
11304
		}
11305
	}
11306
	public function save($state)
11307
	{
11308
		$content=serialize($state);
11309
		$saveFile=true;
11310
		if(($cache=$this->getApplication()->getCache())!==null)
11311
		{
11312
			if($cache->get(self::CACHE_NAME)===$content)
11313
				$saveFile=false;
11314
			else
11315
				$cache->set(self::CACHE_NAME,$content);
11316
		}
11317
		if($saveFile)
11318
		{
11319
			$fileName=$this->getStateFilePath();
11320
			file_put_contents($fileName,$content,LOCK_EX);
11321
		}
11322
	}
11323
}
11324
class TShellApplication extends TApplication
11325
{
11326
	public function run()
11327
	{
11328
		$this->initApplication();
11329
	}
11330
}
11331
?>
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...