Completed
Push — prado-3.3 ( f4da81...5dd4b5 )
by Fabio
09:03
created

THttpRequest::getUrlFormat()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * File Name: pradolite.php
4
 * Last Update: 2017/01/23 17:32:51
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.2';
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 getServerSoftware()
0 ignored issues
show
Coding Style introduced by
getServerSoftware 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_SOFTWARE'])?$_SERVER['SERVER_SOFTWARE']:null;
3253
	}
3254
	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...
3255
	{
3256
		return isset($_SERVER['SERVER_PORT'])?$_SERVER['SERVER_PORT']:null;
3257
	}
3258
	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...
3259
	{
3260
		return isset($_SERVER['HTTP_REFERER'])?$_SERVER['HTTP_REFERER']:null;
3261
	}
3262
	public function getBrowser()
3263
	{
3264
		try
3265
		{
3266
			return get_browser();
3267
		}
3268
		catch(TPhpErrorException $e)
3269
		{
3270
			throw new TConfigurationException('httprequest_browscap_required');
3271
		}
3272
	}
3273
	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...
3274
	{
3275
		return isset($_SERVER['HTTP_USER_AGENT'])?$_SERVER['HTTP_USER_AGENT']:null;
3276
	}
3277
	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...
3278
	{
3279
		return isset($_SERVER['REMOTE_ADDR'])?$_SERVER['REMOTE_ADDR']:null;
3280
	}
3281
	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...
3282
	{
3283
		return isset($_SERVER['REMOTE_HOST'])?$_SERVER['REMOTE_HOST']:null;
3284
	}
3285
	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...
3286
	{
3287
				return isset($_SERVER['HTTP_ACCEPT'])?$_SERVER['HTTP_ACCEPT']:null;
3288
	}
3289
	public function getUserLanguages()
3290
	{
3291
		return Prado::getUserLanguages();
3292
	}
3293
	public function getEnableCookieValidation()
3294
	{
3295
		return $this->_enableCookieValidation;
3296
	}
3297
	public function setEnableCookieValidation($value)
3298
	{
3299
		$this->_enableCookieValidation=TPropertyValue::ensureBoolean($value);
3300
	}
3301
	public function getCgiFix()
3302
	{
3303
		return $this->_cgiFix;
3304
	}
3305
	public function setCgiFix($value)
3306
	{
3307
		$this->_cgiFix=TPropertyValue::ensureInteger($value);
3308
	}
3309
	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...
3310
	{
3311
		if($this->_cookies===null)
3312
		{
3313
			$this->_cookies=new THttpCookieCollection;
3314
			if($this->getEnableCookieValidation())
3315
			{
3316
				$sm=$this->getApplication()->getSecurityManager();
3317
				foreach($_COOKIE as $key=>$value)
3318
				{
3319
					if(($value=$sm->validateData($value))!==false)
3320
						$this->_cookies->add(new THttpCookie($key,$value));
3321
				}
3322
			}
3323
			else
3324
			{
3325
				foreach($_COOKIE as $key=>$value)
3326
					$this->_cookies->add(new THttpCookie($key,$value));
3327
			}
3328
		}
3329
		return $this->_cookies;
3330
	}
3331
	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...
3332
	{
3333
		return $_FILES;
3334
	}
3335
	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...
3336
	{
3337
		return $_SERVER;
3338
	}
3339
	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...
3340
	{
3341
		return $_ENV;
3342
	}
3343
	public function constructUrl($serviceID,$serviceParam,$getItems=null,$encodeAmpersand=true,$encodeGetItems=true)
3344
	{
3345
		if ($this->_cookieOnly===null)
3346
				$this->_cookieOnly=(int)ini_get('session.use_cookies') && (int)ini_get('session.use_only_cookies');
3347
		$url=$this->getUrlManagerModule()->constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems);
3348
		if(defined('SID') && SID != '' && !$this->_cookieOnly)
3349
			return $url . (strpos($url,'?')===false? '?' : ($encodeAmpersand?'&amp;':'&')) . SID;
3350
		else
3351
			return $url;
3352
	}
3353
	protected function parseUrl()
3354
	{
3355
		return $this->getUrlManagerModule()->parseUrl();
3356
	}
3357
	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...
3358
	{
3359
		$getParams=$this->parseUrl();
3360
		foreach($getParams as $name=>$value)
3361
			$_GET[$name]=$value;
3362
		$this->_items=array_merge($_GET,$_POST);
3363
		$this->_requestResolved=true;
3364
		foreach($serviceIDs as $serviceID)
3365
		{
3366
			if($this->contains($serviceID))
3367
			{
3368
				$this->setServiceID($serviceID);
3369
				$this->setServiceParameter($this->itemAt($serviceID));
3370
				return $serviceID;
3371
			}
3372
		}
3373
		return null;
3374
	}
3375
	public function getRequestResolved()
3376
	{
3377
		return $this->_requestResolved;
3378
	}
3379
	public function getServiceID()
3380
	{
3381
		return $this->_serviceID;
3382
	}
3383
	public function setServiceID($value)
3384
	{
3385
		$this->_serviceID=$value;
3386
	}
3387
	public function getServiceParameter()
3388
	{
3389
		return $this->_serviceParam;
3390
	}
3391
	public function setServiceParameter($value)
3392
	{
3393
		$this->_serviceParam=$value;
3394
	}
3395
	public function getIterator()
3396
	{
3397
		return new ArrayIterator($this->_items);
3398
	}
3399
	public function getCount()
3400
	{
3401
		return count($this->_items);
3402
	}
3403
	public function count()
3404
	{
3405
		return $this->getCount();
3406
	}
3407
	public function getKeys()
3408
	{
3409
		return array_keys($this->_items);
3410
	}
3411
	public function itemAt($key)
3412
	{
3413
		return isset($this->_items[$key]) ? $this->_items[$key] : null;
3414
	}
3415
	public function add($key,$value)
3416
	{
3417
		$this->_items[$key]=$value;
3418
	}
3419
	public function remove($key)
3420
	{
3421
		if(isset($this->_items[$key]) || array_key_exists($key,$this->_items))
3422
		{
3423
			$value=$this->_items[$key];
3424
			unset($this->_items[$key]);
3425
			return $value;
3426
		}
3427
		else
3428
			return null;
3429
	}
3430
	public function clear()
3431
	{
3432
		foreach(array_keys($this->_items) as $key)
3433
			$this->remove($key);
3434
	}
3435
	public function contains($key)
3436
	{
3437
		return isset($this->_items[$key]) || array_key_exists($key,$this->_items);
3438
	}
3439
	public function toArray()
3440
	{
3441
		return $this->_items;
3442
	}
3443
	public function offsetExists($offset)
3444
	{
3445
		return $this->contains($offset);
3446
	}
3447
	public function offsetGet($offset)
3448
	{
3449
		return $this->itemAt($offset);
3450
	}
3451
	public function offsetSet($offset,$item)
3452
	{
3453
		$this->add($offset,$item);
3454
	}
3455
	public function offsetUnset($offset)
3456
	{
3457
		$this->remove($offset);
3458
	}
3459
}
3460
class THttpCookieCollection extends TList
3461
{
3462
	private $_o;
3463
	public function __construct($owner=null)
3464
	{
3465
		$this->_o=$owner;
3466
	}
3467
	public function insertAt($index,$item)
3468
	{
3469
		if($item instanceof THttpCookie)
3470
		{
3471
			parent::insertAt($index,$item);
3472
			if($this->_o instanceof THttpResponse)
3473
				$this->_o->addCookie($item);
3474
		}
3475
		else
3476
			throw new TInvalidDataTypeException('httpcookiecollection_httpcookie_required');
3477
	}
3478
	public function removeAt($index)
3479
	{
3480
		$item=parent::removeAt($index);
3481
		if($this->_o instanceof THttpResponse)
3482
			$this->_o->removeCookie($item);
3483
		return $item;
3484
	}
3485
	public function itemAt($index)
3486
	{
3487
		if(is_integer($index))
3488
			return parent::itemAt($index);
3489
		else
3490
			return $this->findCookieByName($index);
3491
	}
3492
	public function findCookieByName($name)
3493
	{
3494
		foreach($this as $cookie)
3495
			if($cookie->getName()===$name)
3496
				return $cookie;
3497
		return null;
3498
	}
3499
}
3500
class THttpCookie extends TComponent
3501
{
3502
	private $_domain='';
3503
	private $_name;
3504
	private $_value='';
3505
	private $_expire=0;
3506
	private $_path='/';
3507
	private $_secure=false;
3508
	private $_httpOnly=false;
3509
	public function __construct($name,$value)
3510
	{
3511
		$this->_name=$name;
3512
		$this->_value=$value;
3513
	}
3514
	public function getDomain()
3515
	{
3516
		return $this->_domain;
3517
	}
3518
	public function setDomain($value)
3519
	{
3520
		$this->_domain=$value;
3521
	}
3522
	public function getExpire()
3523
	{
3524
		return $this->_expire;
3525
	}
3526
	public function setExpire($value)
3527
	{
3528
		$this->_expire=TPropertyValue::ensureInteger($value);
3529
	}
3530
	public function getHttpOnly()
3531
	{
3532
		return $this->_httpOnly;
3533
	}
3534
	public function setHttpOnly($value)
3535
	{
3536
		$this->_httpOnly = TPropertyValue::ensureBoolean($value);
3537
	}
3538
	public function getName()
3539
	{
3540
		return $this->_name;
3541
	}
3542
	public function setName($value)
3543
	{
3544
		$this->_name=$value;
3545
	}
3546
	public function getValue()
3547
	{
3548
		return $this->_value;
3549
	}
3550
	public function setValue($value)
3551
	{
3552
		$this->_value=$value;
3553
	}
3554
	public function getPath()
3555
	{
3556
		return $this->_path;
3557
	}
3558
	public function setPath($value)
3559
	{
3560
		$this->_path=$value;
3561
	}
3562
	public function getSecure()
3563
	{
3564
		return $this->_secure;
3565
	}
3566
	public function setSecure($value)
3567
	{
3568
		$this->_secure=TPropertyValue::ensureBoolean($value);
3569
	}
3570
}
3571
class TUri extends TComponent
3572
{
3573
	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...
3574
		'ftp'=>21,
3575
		'gopher'=>70,
3576
		'http'=>80,
3577
		'https'=>443,
3578
		'news'=>119,
3579
		'nntp'=>119,
3580
		'wais'=>210,
3581
		'telnet'=>23
3582
	);
3583
	private $_scheme;
3584
	private $_host;
3585
	private $_port;
3586
	private $_user;
3587
	private $_pass;
3588
	private $_path;
3589
	private $_query;
3590
	private $_fragment;
3591
	private $_uri;
3592
	public function __construct($uri)
3593
	{
3594
		if(($ret=@parse_url($uri))!==false)
3595
		{
3596
						$this->_scheme=isset($ret['scheme'])?$ret['scheme']:'';
3597
			$this->_host=isset($ret['host'])?$ret['host']:'';
3598
			$this->_port=isset($ret['port'])?$ret['port']:'';
3599
			$this->_user=isset($ret['user'])?$ret['user']:'';
3600
			$this->_pass=isset($ret['pass'])?$ret['pass']:'';
3601
			$this->_path=isset($ret['path'])?$ret['path']:'';
3602
			$this->_query=isset($ret['query'])?$ret['query']:'';
3603
			$this->_fragment=isset($ret['fragment'])?$ret['fragment']:'';
3604
			$this->_uri=$uri;
3605
		}
3606
		else
3607
		{
3608
			throw new TInvalidDataValueException('uri_format_invalid',$uri);
3609
		}
3610
	}
3611
	public function getUri()
3612
	{
3613
		return $this->_uri;
3614
	}
3615
	public function getScheme()
3616
	{
3617
		return $this->_scheme;
3618
	}
3619
	public function getHost()
3620
	{
3621
		return $this->_host;
3622
	}
3623
	public function getPort()
3624
	{
3625
		return $this->_port;
3626
	}
3627
	public function getUser()
3628
	{
3629
		return $this->_user;
3630
	}
3631
	public function getPassword()
3632
	{
3633
		return $this->_pass;
3634
	}
3635
	public function getPath()
3636
	{
3637
		return $this->_path;
3638
	}
3639
	public function getQuery()
3640
	{
3641
		return $this->_query;
3642
	}
3643
	public function getFragment()
3644
	{
3645
		return $this->_fragment;
3646
	}
3647
}
3648
class THttpRequestUrlFormat extends TEnumerable
3649
{
3650
	const Get='Get';
3651
	const Path='Path';
3652
	const HiddenPath='HiddenPath';
3653
}
3654
class THttpResponseAdapter extends TApplicationComponent
3655
{
3656
	private $_response;
3657
	public function __construct($response)
3658
	{
3659
		$this->_response=$response;
3660
	}
3661
	public function getResponse()
3662
	{
3663
		return $this->_response;
3664
	}
3665
	public function flushContent()
3666
	{
3667
		$this->_response->flushContent();
3668
	}
3669
	public function httpRedirect($url)
3670
	{
3671
		$this->_response->httpRedirect($url);
3672
	}
3673
	public function createNewHtmlWriter($type, $writer)
3674
	{
3675
		return $this->_response->createNewHtmlWriter($type,$writer);
3676
	}
3677
}
3678
class THttpResponse extends TModule implements ITextWriter
3679
{
3680
	const DEFAULT_CONTENTTYPE	= 'text/html';
3681
	const DEFAULT_CHARSET		= 'UTF-8';
3682
	private static $HTTP_STATUS_CODES = array(
3683
		100 => 'Continue', 101 => 'Switching Protocols',
3684
		200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content',
3685
		300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect',
3686
		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',
3687
		500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported'
3688
	);
3689
	private $_bufferOutput=true;
3690
	private $_initialized=false;
3691
	private $_cookies=null;
3692
	private $_status=200;
3693
	private $_reason='OK';
3694
	private $_htmlWriterType='System.Web.UI.THtmlWriter';
3695
	private $_contentType=null;
3696
	private $_charset='';
3697
	private $_adapter;
3698
	private $_httpHeaderSent;
3699
	private $_contentTypeHeaderSent;
3700
	public function __destruct()
3701
	{
3702
					}
3703
	public function setAdapter(THttpResponseAdapter $adapter)
3704
	{
3705
		$this->_adapter=$adapter;
3706
	}
3707
	public function getAdapter()
3708
	{
3709
		return $this->_adapter;
3710
	}
3711
	public function getHasAdapter()
3712
	{
3713
		return $this->_adapter!==null;
3714
	}
3715
	public function init($config)
3716
	{
3717
		if($this->_bufferOutput)
3718
			ob_start();
3719
		$this->_initialized=true;
3720
		$this->getApplication()->setResponse($this);
3721
	}
3722
	public function getCacheExpire()
3723
	{
3724
		return session_cache_expire();
3725
	}
3726
	public function setCacheExpire($value)
3727
	{
3728
		session_cache_expire(TPropertyValue::ensureInteger($value));
3729
	}
3730
	public function getCacheControl()
3731
	{
3732
		return session_cache_limiter();
3733
	}
3734
	public function setCacheControl($value)
3735
	{
3736
		session_cache_limiter(TPropertyValue::ensureEnum($value,array('none','nocache','private','private_no_expire','public')));
3737
	}
3738
	public function setContentType($type)
3739
	{
3740
		if ($this->_contentTypeHeaderSent)
3741
			throw new Exception('Unable to alter content-type as it has been already sent');
3742
		$this->_contentType = $type;
3743
	}
3744
	public function getContentType()
3745
	{
3746
		return $this->_contentType;
3747
	}
3748
	public function getCharset()
3749
	{
3750
		return $this->_charset;
3751
	}
3752
	public function setCharset($charset)
3753
	{
3754
		$this->_charset = (strToLower($charset) === 'false') ? false : (string)$charset;
3755
	}
3756
	public function getBufferOutput()
3757
	{
3758
		return $this->_bufferOutput;
3759
	}
3760
	public function setBufferOutput($value)
3761
	{
3762
		if($this->_initialized)
3763
			throw new TInvalidOperationException('httpresponse_bufferoutput_unchangeable');
3764
		else
3765
			$this->_bufferOutput=TPropertyValue::ensureBoolean($value);
3766
	}
3767
	public function getStatusCode()
3768
	{
3769
		return $this->_status;
3770
	}
3771
	public function setStatusCode($status, $reason=null)
3772
	{
3773
		if ($this->_httpHeaderSent)
3774
			throw new Exception('Unable to alter response as HTTP header already sent');
3775
		$status=TPropertyValue::ensureInteger($status);
3776
		if(isset(self::$HTTP_STATUS_CODES[$status])) {
3777
			$this->_reason=self::$HTTP_STATUS_CODES[$status];
3778
		}else{
3779
			if($reason===null || $reason==='') {
3780
				throw new TInvalidDataValueException("response_status_reason_missing");
3781
			}
3782
			$reason=TPropertyValue::ensureString($reason);
3783
			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...
3784
				throw new TInvalidDataValueException("response_status_reason_barchars");
3785
			}
3786
			$this->_reason=$reason;
3787
		}
3788
		$this->_status=$status;
3789
	}
3790
	public function getStatusReason() {
3791
		return $this->_reason;
3792
	}
3793
	public function getCookies()
3794
	{
3795
		if($this->_cookies===null)
3796
			$this->_cookies=new THttpCookieCollection($this);
3797
		return $this->_cookies;
3798
	}
3799
	public function write($str)
3800
	{
3801
				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...
3802
			$this->ensureHeadersSent();
3803
		echo $str;
3804
	}
3805
	public function writeFile($fileName,$content=null,$mimeType=null,$headers=null,$forceDownload=true,$clientFileName=null,$fileSize=null)
3806
	{
3807
		static $defaultMimeTypes=array(
3808
			'css'=>'text/css',
3809
			'gif'=>'image/gif',
3810
			'png'=>'image/png',
3811
			'jpg'=>'image/jpeg',
3812
			'jpeg'=>'image/jpeg',
3813
			'htm'=>'text/html',
3814
			'html'=>'text/html',
3815
			'js'=>'javascript/js',
3816
			'pdf'=>'application/pdf',
3817
			'xls'=>'application/vnd.ms-excel',
3818
		);
3819
		if($mimeType===null)
3820
		{
3821
			$mimeType='text/plain';
3822
			if(function_exists('mime_content_type'))
3823
				$mimeType=mime_content_type($fileName);
3824
			else if(($ext=strrchr($fileName,'.'))!==false)
3825
			{
3826
				$ext=substr($ext,1);
3827
				if(isset($defaultMimeTypes[$ext]))
3828
					$mimeType=$defaultMimeTypes[$ext];
3829
			}
3830
		}
3831
		if($clientFileName===null)
3832
			$clientFileName=basename($fileName);
3833
		else
3834
			$clientFileName=basename($clientFileName);
3835
		if($fileSize===null || $fileSize < 0)
3836
			$fileSize = ($content===null?filesize($fileName):strlen($content));
3837
		$this->sendHttpHeader();
3838
		if(is_array($headers))
3839
		{
3840
			foreach($headers as $h)
3841
				header($h);
3842
		}
3843
		else
3844
		{
3845
			header('Pragma: public');
3846
			header('Expires: 0');
3847
			header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
3848
			header("Content-Type: $mimeType");
3849
			$this->_contentTypeHeaderSent = true;
3850
		}
3851
		header('Content-Length: '.$fileSize);
3852
		header("Content-Disposition: " . ($forceDownload ? 'attachment' : 'inline') . "; filename=\"$clientFileName\"");
3853
		header('Content-Transfer-Encoding: binary');
3854
		if($content===null)
3855
			readfile($fileName);
3856
		else
3857
			echo $content;
3858
	}
3859
	public function redirect($url)
3860
	{
3861
		if($this->getHasAdapter())
3862
			$this->_adapter->httpRedirect($url);
3863
		else
3864
			$this->httpRedirect($url);
3865
	}
3866
	public function httpRedirect($url)
3867
	{
3868
		$this->ensureHeadersSent();
3869
						$isIIS = (stripos($this->getRequest()->getServerSoftware(), "microsoft-iis") !== false);
3870
		if($url[0]==='/')
3871
			$url=$this->getRequest()->getBaseUrl().$url;
3872
		if ($this->_status >= 300 && $this->_status < 400)
3873
		{
3874
						if($isIIS)
3875
			{
3876
				header('HTTP/1.1 ' . $this->_status . ' ' . self::$HTTP_STATUS_CODES[
3877
					array_key_exists($this->_status, self::$HTTP_STATUS_CODES)
3878
						? $this->_status
3879
						: 302
3880
					]);
3881
			}
3882
			header('Location: '.str_replace('&amp;','&',$url), true, $this->_status);
3883
		} else {
3884
			if($isIIS)
3885
				header('HTTP/1.1 302 '.self::$HTTP_STATUS_CODES[302]);
3886
			header('Location: '.str_replace('&amp;','&',$url));
3887
		}
3888
		if(!$this->getApplication()->getRequestCompleted())
3889
			$this->getApplication()->onEndRequest();
3890
		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...
3891
	}
3892
	public function reload()
3893
	{
3894
		$this->redirect($this->getRequest()->getRequestUri());
3895
	}
3896
	public function flush($continueBuffering = true)
3897
	{
3898
		if($this->getHasAdapter())
3899
			$this->_adapter->flushContent($continueBuffering);
3900
		else
3901
			$this->flushContent($continueBuffering);
3902
	}
3903
	public function ensureHeadersSent()
3904
	{
3905
		$this->ensureHttpHeaderSent();
3906
		$this->ensureContentTypeHeaderSent();
3907
	}
3908
	public function flushContent($continueBuffering = true)
3909
	{
3910
		$this->ensureHeadersSent();
3911
		if($this->_bufferOutput)
3912
		{
3913
						if (ob_get_length()>0)
3914
			{
3915
				if (!$continueBuffering)
3916
				{
3917
					$this->_bufferOutput = false;
3918
					ob_end_flush();
3919
				}
3920
				else
3921
					ob_flush();
3922
				flush();
3923
			}
3924
		}
3925
		else
3926
			flush();
3927
	}
3928
	protected function ensureHttpHeaderSent()
3929
	{
3930
		if (!$this->_httpHeaderSent)
3931
			$this->sendHttpHeader();
3932
	}
3933
	protected function sendHttpHeader()
3934
	{
3935
		$protocol=$this->getRequest()->getHttpProtocolVersion();
3936
		if($this->getRequest()->getHttpProtocolVersion() === null)
3937
			$protocol='HTTP/1.1';
3938
		$phpSapiName = substr(php_sapi_name(), 0, 3);
3939
		$cgi = $phpSapiName == 'cgi' || $phpSapiName == 'fpm';
3940
		header(($cgi ? 'Status:' : $protocol).' '.$this->_status.' '.$this->_reason, true, TPropertyValue::ensureInteger($this->_status));
3941
		$this->_httpHeaderSent = true;
3942
	}
3943
	protected function ensureContentTypeHeaderSent()
3944
	{
3945
		if (!$this->_contentTypeHeaderSent)
3946
			$this->sendContentTypeHeader();
3947
	}
3948
	protected function sendContentTypeHeader()
3949
	{
3950
		$contentType=$this->_contentType===null?self::DEFAULT_CONTENTTYPE:$this->_contentType;
3951
		$charset=$this->getCharset();
3952
		if($charset === false) {
3953
			$this->appendHeader('Content-Type: '.$contentType);
3954
			return;
3955
		}
3956
		if($charset==='' && ($globalization=$this->getApplication()->getGlobalization(false))!==null)
3957
			$charset=$globalization->getCharset();
3958
		if($charset==='') $charset = self::DEFAULT_CHARSET;
3959
		$this->appendHeader('Content-Type: '.$contentType.';charset='.$charset);
3960
		$this->_contentTypeHeaderSent = true;
3961
	}
3962
	public function getContents()
3963
	{
3964
		return $this->_bufferOutput?ob_get_contents():'';
3965
	}
3966
	public function clear()
3967
	{
3968
		if($this->_bufferOutput)
3969
			ob_clean();
3970
	}
3971
	public function getHeaders($case=null)
3972
	{
3973
		$result = array();
3974
		$headers = headers_list();
3975
		foreach($headers as $header) {
3976
			$tmp = explode(':', $header);
3977
			$key = trim(array_shift($tmp));
3978
			$value = trim(implode(':', $tmp));
3979
			if(isset($result[$key]))
3980
				$result[$key] .= ', ' . $value;
3981
			else
3982
				$result[$key] = $value;
3983
		}
3984
		if($case !== null)
3985
			return array_change_key_case($result, $case);
3986
		return $result;
3987
	}
3988
	public function appendHeader($value, $replace=true)
3989
	{
3990
		header($value, $replace);
3991
	}
3992
	public function appendLog($message,$messageType=0,$destination='',$extraHeaders='')
3993
	{
3994
		error_log($message,$messageType,$destination,$extraHeaders);
3995
	}
3996
	public function addCookie($cookie)
3997
	{
3998
		$request=$this->getRequest();
3999
		if($request->getEnableCookieValidation())
4000
		{
4001
			$value=$this->getApplication()->getSecurityManager()->hashData($cookie->getValue());
4002
			setcookie(
4003
				$cookie->getName(),
4004
				$value,
4005
				$cookie->getExpire(),
4006
				$cookie->getPath(),
4007
				$cookie->getDomain(),
4008
				$cookie->getSecure(),
4009
				$cookie->getHttpOnly()
4010
			);
4011
		}
4012
		else {
4013
			setcookie(
4014
				$cookie->getName(),
4015
				$cookie->getValue(),
4016
				$cookie->getExpire(),
4017
				$cookie->getPath(),
4018
				$cookie->getDomain(),
4019
				$cookie->getSecure(),
4020
				$cookie->getHttpOnly()
4021
			);
4022
		}
4023
	}
4024
	public function removeCookie($cookie)
4025
	{
4026
		setcookie(
4027
			$cookie->getName(),
4028
			null,
4029
			0,
4030
			$cookie->getPath(),
4031
			$cookie->getDomain(),
4032
			$cookie->getSecure(),
4033
			$cookie->getHttpOnly()
4034
		);
4035
	}
4036
	public function getHtmlWriterType()
4037
	{
4038
		return $this->_htmlWriterType;
4039
	}
4040
	public function setHtmlWriterType($value)
4041
	{
4042
		$this->_htmlWriterType=$value;
4043
	}
4044
	public function createHtmlWriter($type=null)
4045
	{
4046
		if($type===null)
4047
			$type=$this->getHtmlWriterType();
4048
		if($this->getHasAdapter())
4049
			return $this->_adapter->createNewHtmlWriter($type, $this);
4050
		else
4051
			return $this->createNewHtmlWriter($type, $this);
4052
	}
4053
	public function createNewHtmlWriter($type, $writer)
4054
	{
4055
		return Prado::createComponent($type, $writer);
4056
	}
4057
}
4058
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...
4059
{
4060
	private $_initialized=false;
4061
	private $_started=false;
4062
	private $_autoStart=false;
4063
	private $_cookie=null;
4064
	private $_id;
4065
	private $_customStorage=false;
4066
	public function getID()
4067
	{
4068
		return $this->_id;
4069
	}
4070
	public function setID($value)
4071
	{
4072
		$this->_id=$value;
4073
	}
4074
	public function init($config)
4075
	{
4076
		if($this->_autoStart)
4077
			$this->open();
4078
		$this->_initialized=true;
4079
		$this->getApplication()->setSession($this);
4080
		register_shutdown_function(array($this, "close"));
4081
	}
4082
	public function open()
4083
	{
4084
		if(!$this->_started)
4085
		{
4086
			if($this->_customStorage)
4087
				session_set_save_handler(array($this,'_open'),array($this,'_close'),array($this,'_read'),array($this,'_write'),array($this,'_destroy'),array($this,'_gc'));
4088
			if($this->_cookie!==null)
4089
				session_set_cookie_params($this->_cookie->getExpire(),$this->_cookie->getPath(),$this->_cookie->getDomain(),$this->_cookie->getSecure(),$this->_cookie->getHttpOnly());
4090
			if(ini_get('session.auto_start')!=='1')
4091
				session_start();
4092
			$this->_started=true;
4093
		}
4094
	}
4095
	public function close()
4096
	{
4097
		if($this->_started)
4098
		{
4099
			session_write_close();
4100
			$this->_started=false;
4101
		}
4102
	}
4103
	public function destroy()
4104
	{
4105
		if($this->_started)
4106
		{
4107
			session_destroy();
4108
			$this->_started=false;
4109
		}
4110
	}
4111
	public function regenerate($deleteOld=false)
4112
	{
4113
		$old = $this->getSessionID();
4114
		session_regenerate_id($deleteOld);
4115
		return $old;
4116
	}
4117
	public function getIsStarted()
4118
	{
4119
		return $this->_started;
4120
	}
4121
	public function getSessionID()
4122
	{
4123
		return session_id();
4124
	}
4125
	public function setSessionID($value)
4126
	{
4127
		if($this->_started)
4128
			throw new TInvalidOperationException('httpsession_sessionid_unchangeable');
4129
		else
4130
			session_id($value);
4131
	}
4132
	public function getSessionName()
4133
	{
4134
		return session_name();
4135
	}
4136
	public function setSessionName($value)
4137
	{
4138
		if($this->_started)
4139
			throw new TInvalidOperationException('httpsession_sessionname_unchangeable');
4140
		else if(ctype_alnum($value))
4141
			session_name($value);
4142
		else
4143
			throw new TInvalidDataValueException('httpsession_sessionname_invalid',$value);
4144
	}
4145
	public function getSavePath()
4146
	{
4147
		return session_save_path();
4148
	}
4149
	public function setSavePath($value)
4150
	{
4151
		if($this->_started)
4152
			throw new TInvalidOperationException('httpsession_savepath_unchangeable');
4153
		else if(is_dir($value))
4154
			session_save_path($value);
4155
		else
4156
			throw new TInvalidDataValueException('httpsession_savepath_invalid',$value);
4157
	}
4158
	public function getUseCustomStorage()
4159
	{
4160
		return $this->_customStorage;
4161
	}
4162
	public function setUseCustomStorage($value)
4163
	{
4164
		$this->_customStorage=TPropertyValue::ensureBoolean($value);
4165
	}
4166
	public function getCookie()
4167
	{
4168
		if($this->_cookie===null)
4169
			$this->_cookie=new THttpCookie($this->getSessionName(),$this->getSessionID());
4170
		return $this->_cookie;
4171
	}
4172
	public function getCookieMode()
4173
	{
4174
		if(ini_get('session.use_cookies')==='0')
4175
			return THttpSessionCookieMode::None;
4176
		else if(ini_get('session.use_only_cookies')==='0')
4177
			return THttpSessionCookieMode::Allow;
4178
		else
4179
			return THttpSessionCookieMode::Only;
4180
	}
4181
	public function setCookieMode($value)
4182
	{
4183
		if($this->_started)
4184
			throw new TInvalidOperationException('httpsession_cookiemode_unchangeable');
4185
		else
4186
		{
4187
			$value=TPropertyValue::ensureEnum($value,'THttpSessionCookieMode');
4188
			if($value===THttpSessionCookieMode::None) 
4189
      {
4190
				ini_set('session.use_cookies','0');
4191
			  ini_set('session.use_only_cookies','0');
4192
      }
4193
			else if($value===THttpSessionCookieMode::Allow)
4194
			{
4195
				ini_set('session.use_cookies','1');
4196
				ini_set('session.use_only_cookies','0');
4197
			}
4198
			else
4199
			{
4200
				ini_set('session.use_cookies','1');
4201
				ini_set('session.use_only_cookies','1');
4202
				ini_set('session.use_trans_sid', 0);
4203
			}
4204
		}
4205
	}
4206
	public function getAutoStart()
4207
	{
4208
		return $this->_autoStart;
4209
	}
4210
	public function setAutoStart($value)
4211
	{
4212
		if($this->_initialized)
4213
			throw new TInvalidOperationException('httpsession_autostart_unchangeable');
4214
		else
4215
			$this->_autoStart=TPropertyValue::ensureBoolean($value);
4216
	}
4217
	public function getGCProbability()
4218
	{
4219
		return TPropertyValue::ensureInteger(ini_get('session.gc_probability'));
4220
	}
4221
	public function setGCProbability($value)
4222
	{
4223
		if($this->_started)
4224
			throw new TInvalidOperationException('httpsession_gcprobability_unchangeable');
4225
		else
4226
		{
4227
			$value=TPropertyValue::ensureInteger($value);
4228
			if($value>=0 && $value<=100)
4229
			{
4230
				ini_set('session.gc_probability',$value);
4231
				ini_set('session.gc_divisor','100');
4232
			}
4233
			else
4234
				throw new TInvalidDataValueException('httpsession_gcprobability_invalid',$value);
4235
		}
4236
	}
4237
	public function getUseTransparentSessionID()
4238
	{
4239
		return ini_get('session.use_trans_sid')==='1';
4240
	}
4241
	public function setUseTransparentSessionID($value)
4242
	{
4243
		if($this->_started)
4244
			throw new TInvalidOperationException('httpsession_transid_unchangeable');
4245
		else
4246
		{
4247
			$value=TPropertyValue::ensureBoolean($value);
4248
			if ($value && $this->getCookieMode()==THttpSessionCookieMode::Only)
4249
					throw new TInvalidOperationException('httpsession_transid_cookieonly');
4250
			ini_set('session.use_trans_sid',$value?'1':'0');
4251
		}
4252
	}
4253
	public function getTimeout()
4254
	{
4255
		return TPropertyValue::ensureInteger(ini_get('session.gc_maxlifetime'));
4256
	}
4257
	public function setTimeout($value)
4258
	{
4259
		if($this->_started)
4260
			throw new TInvalidOperationException('httpsession_maxlifetime_unchangeable');
4261
		else
4262
			ini_set('session.gc_maxlifetime',$value);
4263
	}
4264
	public function _open($savePath,$sessionName)
4265
	{
4266
		return true;
4267
	}
4268
	public function _close()
4269
	{
4270
		return true;
4271
	}
4272
	public function _read($id)
4273
	{
4274
		return '';
4275
	}
4276
	public function _write($id,$data)
4277
	{
4278
		return true;
4279
	}
4280
	public function _destroy($id)
4281
	{
4282
		return true;
4283
	}
4284
	public function _gc($maxLifetime)
4285
	{
4286
		return true;
4287
	}
4288
	public function getIterator()
4289
	{
4290
		return new TSessionIterator;
4291
	}
4292
	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...
4293
	{
4294
		return count($_SESSION);
4295
	}
4296
	public function count()
4297
	{
4298
		return $this->getCount();
4299
	}
4300
	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...
4301
	{
4302
		return array_keys($_SESSION);
4303
	}
4304
	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...
4305
	{
4306
		return isset($_SESSION[$key]) ? $_SESSION[$key] : null;
4307
	}
4308
	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...
4309
	{
4310
		$_SESSION[$key]=$value;
4311
	}
4312
	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...
4313
	{
4314
		if(isset($_SESSION[$key]))
4315
		{
4316
			$value=$_SESSION[$key];
4317
			unset($_SESSION[$key]);
4318
			return $value;
4319
		}
4320
		else
4321
			return null;
4322
	}
4323
	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...
4324
	{
4325
		foreach(array_keys($_SESSION) as $key)
4326
			unset($_SESSION[$key]);
4327
	}
4328
	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...
4329
	{
4330
		return isset($_SESSION[$key]);
4331
	}
4332
	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...
4333
	{
4334
		return $_SESSION;
4335
	}
4336
	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...
4337
	{
4338
		return isset($_SESSION[$offset]);
4339
	}
4340
	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...
4341
	{
4342
		return isset($_SESSION[$offset]) ? $_SESSION[$offset] : null;
4343
	}
4344
	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...
4345
	{
4346
		$_SESSION[$offset]=$item;
4347
	}
4348
	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...
4349
	{
4350
		unset($_SESSION[$offset]);
4351
	}
4352
}
4353
class TSessionIterator implements Iterator
4354
{
4355
	private $_keys;
4356
	private $_key;
4357
	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...
4358
	{
4359
		$this->_keys=array_keys($_SESSION);
4360
	}
4361
	public function rewind()
4362
	{
4363
		$this->_key=reset($this->_keys);
4364
	}
4365
	public function key()
4366
	{
4367
		return $this->_key;
4368
	}
4369
	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...
4370
	{
4371
		return isset($_SESSION[$this->_key])?$_SESSION[$this->_key]:null;
4372
	}
4373
	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...
4374
	{
4375
		do
4376
		{
4377
			$this->_key=next($this->_keys);
4378
		}
4379
		while(!isset($_SESSION[$this->_key]) && $this->_key!==false);
4380
	}
4381
	public function valid()
4382
	{
4383
		return $this->_key!==false;
4384
	}
4385
}
4386
class THttpSessionCookieMode extends TEnumerable
4387
{
4388
	const None='None';
4389
	const Allow='Allow';
4390
	const Only='Only';
4391
}
4392
Prado::using('System.Web.UI.WebControls.*');
4393
class TAttributeCollection extends TMap
4394
{
4395
	private $_caseSensitive=false;
4396
	protected function _getZappableSleepProps(&$exprops)
4397
	{
4398
		parent::_getZappableSleepProps($exprops);
4399
		if ($this->_caseSensitive===false)
4400
			$exprops[] = "\0TAttributeCollection\0_caseSensitive";
4401
	}
4402
	public function __get($name)
4403
	{
4404
		return $this->contains($name)?$this->itemAt($name):parent::__get($name);
4405
	}
4406
	public function __set($name,$value)
4407
	{
4408
		$this->add($name,$value);
4409
	}
4410
	public function getCaseSensitive()
4411
	{
4412
		return $this->_caseSensitive;
4413
	}
4414
	public function setCaseSensitive($value)
4415
	{
4416
		$this->_caseSensitive=TPropertyValue::ensureBoolean($value);
4417
	}
4418
	public function itemAt($key)
4419
	{
4420
		return parent::itemAt($this->_caseSensitive?$key:strtolower($key));
4421
	}
4422
	public function add($key,$value)
4423
	{
4424
		parent::add($this->_caseSensitive?$key:strtolower($key),$value);
4425
	}
4426
	public function remove($key)
4427
	{
4428
		return parent::remove($this->_caseSensitive?$key:strtolower($key));
4429
	}
4430
	public function contains($key)
4431
	{
4432
		return parent::contains($this->_caseSensitive?$key:strtolower($key));
4433
	}
4434
	public function hasProperty($name)
4435
	{
4436
		return $this->contains($name) || parent::canGetProperty($name) || parent::canSetProperty($name);
4437
	}
4438
	public function canGetProperty($name)
4439
	{
4440
		return $this->contains($name) || parent::canGetProperty($name);
4441
	}
4442
	public function canSetProperty($name)
4443
	{
4444
		return true;
4445
	}
4446
}
4447
class TControlAdapter extends TApplicationComponent
4448
{
4449
	protected $_control;
4450
	public function __construct($control)
4451
	{
4452
		$this->_control=$control;
4453
	}
4454
	public function getControl()
4455
	{
4456
		return $this->_control;
4457
	}
4458
	public function getPage()
4459
	{
4460
		return $this->_control?$this->_control->getPage():null;
4461
	}
4462
	public function createChildControls()
4463
	{
4464
		$this->_control->createChildControls();
4465
	}
4466
	public function loadState()
4467
	{
4468
		$this->_control->loadState();
4469
	}
4470
	public function saveState()
4471
	{
4472
		$this->_control->saveState();
4473
	}
4474
	public function onInit($param)
4475
	{
4476
		$this->_control->onInit($param);
4477
	}
4478
	public function onLoad($param)
4479
	{
4480
		$this->_control->onLoad($param);
4481
	}
4482
	public function onPreRender($param)
4483
	{
4484
		$this->_control->onPreRender($param);
4485
	}
4486
	public function onUnload($param)
4487
	{
4488
		$this->_control->onUnload($param);
4489
	}
4490
	public function render($writer)
4491
	{
4492
		$this->_control->render($writer);
4493
	}
4494
	public function renderChildren($writer)
4495
	{
4496
		$this->_control->renderChildren($writer);
4497
	}
4498
}
4499
class TControl extends TApplicationComponent implements IRenderable, IBindable
4500
{
4501
	const ID_FORMAT='/^[a-zA-Z_]\\w*$/';
4502
	const ID_SEPARATOR='$';
4503
	const CLIENT_ID_SEPARATOR='_';
4504
	const AUTOMATIC_ID_PREFIX='ctl';
4505
	const CS_CONSTRUCTED=0;
4506
	const CS_CHILD_INITIALIZED=1;
4507
	const CS_INITIALIZED=2;
4508
	const CS_STATE_LOADED=3;
4509
	const CS_LOADED=4;
4510
	const CS_PRERENDERED=5;
4511
	const IS_ID_SET=0x01;
4512
	const IS_DISABLE_VIEWSTATE=0x02;
4513
	const IS_SKIN_APPLIED=0x04;
4514
	const IS_STYLESHEET_APPLIED=0x08;
4515
	const IS_DISABLE_THEMING=0x10;
4516
	const IS_CHILD_CREATED=0x20;
4517
	const IS_CREATING_CHILD=0x40;
4518
	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...
4519
	private $_id='';
4520
	private $_uid;
4521
	private $_parent;
4522
	private $_page;
4523
	private $_namingContainer;
4524
	private $_tplControl;
4525
	private $_viewState=array();
4526
	private $_tempState=array();
4527
	private $_trackViewState=true;
4528
	private $_stage=0;
4529
	private $_flags=0;
4530
	private $_rf=array();
4531
	public function __get($name)
4532
	{
4533
		if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
4534
			return $this->_rf[self::RF_NAMED_OBJECTS][$name];
4535
		else
4536
			return parent::__get($name);
4537
	}
4538
	public function __isset($name) {
4539
		if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name])) {
4540
			return true;
4541
		} else {
4542
			return parent::__isset($name);
4543
		}
4544
	}
4545
	public function getHasAdapter()
4546
	{
4547
		return isset($this->_rf[self::RF_ADAPTER]);
4548
	}
4549
	public function getAdapter()
4550
	{
4551
		return isset($this->_rf[self::RF_ADAPTER])?$this->_rf[self::RF_ADAPTER]:null;
4552
	}
4553
	public function setAdapter(TControlAdapter $adapter)
4554
	{
4555
		$this->_rf[self::RF_ADAPTER]=$adapter;
4556
	}
4557
	public function getParent()
4558
	{
4559
		return $this->_parent;
4560
	}
4561
	public function getNamingContainer()
4562
	{
4563
		if(!$this->_namingContainer && $this->_parent)
4564
		{
4565
			if($this->_parent instanceof INamingContainer)
4566
				$this->_namingContainer=$this->_parent;
4567
			else
4568
				$this->_namingContainer=$this->_parent->getNamingContainer();
4569
		}
4570
		return $this->_namingContainer;
4571
	}
4572
	public function getPage()
4573
	{
4574
		if(!$this->_page)
4575
		{
4576
			if($this->_parent)
4577
				$this->_page=$this->_parent->getPage();
4578
			else if($this->_tplControl)
4579
				$this->_page=$this->_tplControl->getPage();
4580
		}
4581
		return $this->_page;
4582
	}
4583
	public function setPage($page)
4584
	{
4585
		$this->_page=$page;
4586
	}
4587
	public function setTemplateControl($control)
4588
	{
4589
		$this->_tplControl=$control;
4590
	}
4591
	public function getTemplateControl()
4592
	{
4593
		if(!$this->_tplControl && $this->_parent)
4594
			$this->_tplControl=$this->_parent->getTemplateControl();
4595
		return $this->_tplControl;
4596
	}
4597
	public function getSourceTemplateControl()
4598
	{
4599
		$control=$this;
4600
		while(($control instanceof TControl) && ($control=$control->getTemplateControl())!==null)
4601
		{
4602
			if(($control instanceof TTemplateControl) && $control->getIsSourceTemplateControl())
4603
				return $control;
4604
		}
4605
		return $this->getPage();
4606
	}
4607
	protected function getControlStage()
4608
	{
4609
		return $this->_stage;
4610
	}
4611
	protected function setControlStage($value)
4612
	{
4613
		$this->_stage=$value;
4614
	}
4615
	public function getID($hideAutoID=true)
4616
	{
4617
		if($hideAutoID)
4618
			return ($this->_flags & self::IS_ID_SET) ? $this->_id : '';
4619
		else
4620
			return $this->_id;
4621
	}
4622
	public function setID($id)
4623
	{
4624
		if(!preg_match(self::ID_FORMAT,$id))
4625
			throw new TInvalidDataValueException('control_id_invalid',get_class($this),$id);
4626
		$this->_id=$id;
4627
		$this->_flags |= self::IS_ID_SET;
4628
		$this->clearCachedUniqueID($this instanceof INamingContainer);
4629
		if($this->_namingContainer)
4630
			$this->_namingContainer->clearNameTable();
4631
	}
4632
	public function getUniqueID()
4633
	{
4634
		if($this->_uid==='' || $this->_uid===null)			{
4635
			$this->_uid='';  			if($namingContainer=$this->getNamingContainer())
4636
			{
4637
				if($this->getPage()===$namingContainer)
4638
					return ($this->_uid=$this->_id);
4639
				else if(($prefix=$namingContainer->getUniqueID())==='')
4640
					return $this->_id;
4641
				else
4642
					return ($this->_uid=$prefix.self::ID_SEPARATOR.$this->_id);
4643
			}
4644
			else					return $this->_id;
4645
		}
4646
		else
4647
			return $this->_uid;
4648
	}
4649
	public function focus()
4650
	{
4651
		$this->getPage()->setFocus($this);
4652
	}
4653
	public function getClientID()
4654
	{
4655
		return strtr($this->getUniqueID(),self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
4656
	}
4657
	public static function convertUniqueIdToClientId($uniqueID)
4658
	{
4659
		return strtr($uniqueID,self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
4660
	}
4661
	public function getSkinID()
4662
	{
4663
		return isset($this->_rf[self::RF_SKIN_ID])?$this->_rf[self::RF_SKIN_ID]:'';
4664
	}
4665
	public function setSkinID($value)
4666
	{
4667
		if(($this->_flags & self::IS_SKIN_APPLIED) || $this->_stage>=self::CS_CHILD_INITIALIZED)
4668
			throw new TInvalidOperationException('control_skinid_unchangeable',get_class($this));
4669
		else
4670
			$this->_rf[self::RF_SKIN_ID]=$value;
4671
	}
4672
	public function getIsSkinApplied()
4673
	{
4674
		return ($this->_flags & self::IS_SKIN_APPLIED);
4675
	}
4676
	public function getEnableTheming()
4677
	{
4678
		if($this->_flags & self::IS_DISABLE_THEMING)
4679
			return false;
4680
		else
4681
			return $this->_parent?$this->_parent->getEnableTheming():true;
4682
	}
4683
	public function setEnableTheming($value)
4684
	{
4685
		if($this->_stage>=self::CS_CHILD_INITIALIZED)
4686
			throw new TInvalidOperationException('control_enabletheming_unchangeable',get_class($this),$this->getUniqueID());
4687
		else if(TPropertyValue::ensureBoolean($value))
4688
			$this->_flags &= ~self::IS_DISABLE_THEMING;
4689
		else
4690
			$this->_flags |= self::IS_DISABLE_THEMING;
4691
	}
4692
	public function getCustomData()
4693
	{
4694
		return $this->getViewState('CustomData',null);
4695
	}
4696
	public function setCustomData($value)
4697
	{
4698
		$this->setViewState('CustomData',$value,null);
4699
	}
4700
	public function getHasControls()
4701
	{
4702
		return isset($this->_rf[self::RF_CONTROLS]) && $this->_rf[self::RF_CONTROLS]->getCount()>0;
4703
	}
4704
	public function getControls()
4705
	{
4706
		if(!isset($this->_rf[self::RF_CONTROLS]))
4707
			$this->_rf[self::RF_CONTROLS]=$this->createControlCollection();
4708
		return $this->_rf[self::RF_CONTROLS];
4709
	}
4710
	protected function createControlCollection()
4711
	{
4712
		return $this->getAllowChildControls()?new TControlCollection($this):new TEmptyControlCollection($this);
4713
	}
4714
	public function getVisible($checkParents=true)
4715
	{
4716
		if($checkParents)
4717
		{
4718
			for($control=$this;$control;$control=$control->_parent)
4719
				if(!$control->getVisible(false))
4720
					return false;
4721
			return true;
4722
		}
4723
		else
4724
			return $this->getViewState('Visible',true);
4725
	}
4726
	public function setVisible($value)
4727
	{
4728
		$this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true);
4729
	}
4730
	public function getEnabled($checkParents=false)
4731
	{
4732
		if($checkParents)
4733
		{
4734
			for($control=$this;$control;$control=$control->_parent)
4735
				if(!$control->getViewState('Enabled',true))
4736
					return false;
4737
			return true;
4738
		}
4739
		else
4740
			return $this->getViewState('Enabled',true);
4741
	}
4742
	public function setEnabled($value)
4743
	{
4744
		$this->setViewState('Enabled',TPropertyValue::ensureBoolean($value),true);
4745
	}
4746
	public function getHasAttributes()
4747
	{
4748
		if($attributes=$this->getViewState('Attributes',null))
4749
			return $attributes->getCount()>0;
4750
		else
4751
			return false;
4752
	}
4753
	public function getAttributes()
4754
	{
4755
		if($attributes=$this->getViewState('Attributes',null))
4756
			return $attributes;
4757
		else
4758
		{
4759
			$attributes=new TAttributeCollection;
4760
			$this->setViewState('Attributes',$attributes,null);
4761
			return $attributes;
4762
		}
4763
	}
4764
	public function hasAttribute($name)
4765
	{
4766
		if($attributes=$this->getViewState('Attributes',null))
4767
			return $attributes->contains($name);
4768
		else
4769
			return false;
4770
	}
4771
	public function getAttribute($name)
4772
	{
4773
		if($attributes=$this->getViewState('Attributes',null))
4774
			return $attributes->itemAt($name);
4775
		else
4776
			return null;
4777
	}
4778
	public function setAttribute($name,$value)
4779
	{
4780
		$this->getAttributes()->add($name,$value);
4781
	}
4782
	public function removeAttribute($name)
4783
	{
4784
		if($attributes=$this->getViewState('Attributes',null))
4785
			return $attributes->remove($name);
4786
		else
4787
			return null;
4788
	}
4789
	public function getEnableViewState($checkParents=false)
4790
	{
4791
		if($checkParents)
4792
		{
4793
			for($control=$this;$control!==null;$control=$control->getParent())
4794
				if($control->_flags & self::IS_DISABLE_VIEWSTATE)
4795
					return false;
4796
			return true;
4797
		}
4798
		else
4799
			return !($this->_flags & self::IS_DISABLE_VIEWSTATE);
4800
	}
4801
	public function setEnableViewState($value)
4802
	{
4803
		if(TPropertyValue::ensureBoolean($value))
4804
			$this->_flags &= ~self::IS_DISABLE_VIEWSTATE;
4805
		else
4806
			$this->_flags |= self::IS_DISABLE_VIEWSTATE;
4807
	}
4808
	protected function getControlState($key,$defaultValue=null)
4809
	{
4810
		return isset($this->_rf[self::RF_CONTROLSTATE][$key])?$this->_rf[self::RF_CONTROLSTATE][$key]:$defaultValue;
4811
	}
4812
	protected function setControlState($key,$value,$defaultValue=null)
4813
	{
4814
		if($value===$defaultValue)
4815
			unset($this->_rf[self::RF_CONTROLSTATE][$key]);
4816
		else
4817
			$this->_rf[self::RF_CONTROLSTATE][$key]=$value;
4818
	}
4819
	protected function clearControlState($key)
4820
	{
4821
		unset($this->_rf[self::RF_CONTROLSTATE][$key]);
4822
	}
4823
	public function trackViewState($enabled)
4824
	{
4825
		$this->_trackViewState=TPropertyValue::ensureBoolean($enabled);
4826
	}
4827
	public function getViewState($key,$defaultValue=null)
4828
	{
4829
		if(isset($this->_viewState[$key]))
4830
			return $this->_viewState[$key]!==null?$this->_viewState[$key]:$defaultValue;
4831
		else if(isset($this->_tempState[$key]))
4832
		{
4833
			if(is_object($this->_tempState[$key]) && $this->_trackViewState)
4834
				$this->_viewState[$key]=$this->_tempState[$key];
4835
			return $this->_tempState[$key];
4836
		}
4837
		else
4838
			return $defaultValue;
4839
	}
4840
	public function setViewState($key,$value,$defaultValue=null)
4841
	{
4842
		if($this->_trackViewState)
4843
		{
4844
			unset($this->_tempState[$key]);
4845
			$this->_viewState[$key]=$value;
4846
		}
4847
		else
4848
		{
4849
			unset($this->_viewState[$key]);
4850
			if($value===$defaultValue)
4851
				unset($this->_tempState[$key]);
4852
			else
4853
				$this->_tempState[$key]=$value;
4854
		}
4855
	}
4856
	public function clearViewState($key)
4857
	{
4858
		unset($this->_viewState[$key]);
4859
		unset($this->_tempState[$key]);
4860
	}
4861
	public function bindProperty($name,$expression)
4862
	{
4863
		$this->_rf[self::RF_DATA_BINDINGS][$name]=$expression;
4864
	}
4865
	public function unbindProperty($name)
4866
	{
4867
		unset($this->_rf[self::RF_DATA_BINDINGS][$name]);
4868
	}
4869
	public function autoBindProperty($name,$expression)
4870
	{
4871
		$this->_rf[self::RF_AUTO_BINDINGS][$name]=$expression;
4872
	}
4873
	public function dataBind()
4874
	{
4875
		$this->dataBindProperties();
4876
		$this->onDataBinding(null);
4877
		$this->dataBindChildren();
4878
	}
4879
	protected function dataBindProperties()
4880
	{
4881
		if(isset($this->_rf[self::RF_DATA_BINDINGS]))
4882
		{
4883
			if(($context=$this->getTemplateControl())===null)
4884
				$context=$this;
4885
			foreach($this->_rf[self::RF_DATA_BINDINGS] as $property=>$expression)
4886
				$this->setSubProperty($property,$context->evaluateExpression($expression));
4887
		}
4888
	}
4889
	protected function autoDataBindProperties()
4890
	{
4891
		if(isset($this->_rf[self::RF_AUTO_BINDINGS]))
4892
		{
4893
			if(($context=$this->getTemplateControl())===null)
4894
				$context=$this;
4895
			foreach($this->_rf[self::RF_AUTO_BINDINGS] as $property=>$expression)
4896
				$this->setSubProperty($property,$context->evaluateExpression($expression));
4897
		}
4898
	}
4899
	protected function dataBindChildren()
4900
	{
4901
		if(isset($this->_rf[self::RF_CONTROLS]))
4902
		{
4903
			foreach($this->_rf[self::RF_CONTROLS] as $control)
4904
				if($control instanceof IBindable)
4905
					$control->dataBind();
4906
		}
4907
	}
4908
	final protected function getChildControlsCreated()
4909
	{
4910
		return ($this->_flags & self::IS_CHILD_CREATED)!==0;
4911
	}
4912
	final protected function setChildControlsCreated($value)
4913
	{
4914
		if($value)
4915
			$this->_flags |= self::IS_CHILD_CREATED;
4916
		else
4917
		{
4918
			if($this->getHasControls() && ($this->_flags & self::IS_CHILD_CREATED))
4919
				$this->getControls()->clear();
4920
			$this->_flags &= ~self::IS_CHILD_CREATED;
4921
		}
4922
	}
4923
	public function ensureChildControls()
4924
	{
4925
		if(!($this->_flags & self::IS_CHILD_CREATED) && !($this->_flags & self::IS_CREATING_CHILD))
4926
		{
4927
			try
4928
			{
4929
				$this->_flags |= self::IS_CREATING_CHILD;
4930
				if(isset($this->_rf[self::RF_ADAPTER]))
4931
					$this->_rf[self::RF_ADAPTER]->createChildControls();
4932
				else
4933
					$this->createChildControls();
4934
				$this->_flags &= ~self::IS_CREATING_CHILD;
4935
				$this->_flags |= self::IS_CHILD_CREATED;
4936
			}
4937
			catch(Exception $e)
4938
			{
4939
				$this->_flags &= ~self::IS_CREATING_CHILD;
4940
				$this->_flags |= self::IS_CHILD_CREATED;
4941
				throw $e;
4942
			}
4943
		}
4944
	}
4945
	public function createChildControls()
4946
	{
4947
	}
4948
	public function findControl($id)
4949
	{
4950
		$id=strtr($id,'.',self::ID_SEPARATOR);
4951
		$container=($this instanceof INamingContainer)?$this:$this->getNamingContainer();
4952
		if(!$container || !$container->getHasControls())
4953
			return null;
4954
		if(!isset($container->_rf[self::RF_NAMED_CONTROLS]))
4955
		{
4956
			$container->_rf[self::RF_NAMED_CONTROLS]=array();
4957
			$container->fillNameTable($container,$container->_rf[self::RF_CONTROLS]);
4958
		}
4959
		if(($pos=strpos($id,self::ID_SEPARATOR))===false)
4960
			return isset($container->_rf[self::RF_NAMED_CONTROLS][$id])?$container->_rf[self::RF_NAMED_CONTROLS][$id]:null;
4961
		else
4962
		{
4963
			$cid=substr($id,0,$pos);
4964
			$sid=substr($id,$pos+1);
4965
			if(isset($container->_rf[self::RF_NAMED_CONTROLS][$cid]))
4966
				return $container->_rf[self::RF_NAMED_CONTROLS][$cid]->findControl($sid);
4967
			else
4968
				return null;
4969
		}
4970
	}
4971
	public function findControlsByType($type,$strict=true)
4972
	{
4973
		$controls=array();
4974
		if($this->getHasControls())
4975
		{
4976
			foreach($this->_rf[self::RF_CONTROLS] as $control)
4977
			{
4978
				if(is_object($control) && (get_class($control)===$type || (!$strict && ($control instanceof $type))))
4979
					$controls[]=$control;
4980
				if(($control instanceof TControl) && $control->getHasControls())
4981
					$controls=array_merge($controls,$control->findControlsByType($type,$strict));
4982
			}
4983
		}
4984
		return $controls;
4985
	}
4986
	public function findControlsByID($id)
4987
	{
4988
		$controls=array();
4989
		if($this->getHasControls())
4990
		{
4991
			foreach($this->_rf[self::RF_CONTROLS] as $control)
4992
			{
4993
				if($control instanceof TControl)
4994
				{
4995
					if($control->_id===$id)
4996
						$controls[]=$control;
4997
					$controls=array_merge($controls,$control->findControlsByID($id));
4998
				}
4999
			}
5000
		}
5001
		return $controls;
5002
	}
5003
	public function clearNamingContainer()
5004
	{
5005
		unset($this->_rf[self::RF_NAMED_CONTROLS_ID]);
5006
		$this->clearNameTable();
5007
	}
5008
	public function registerObject($name,$object)
5009
	{
5010
		if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
5011
			throw new TInvalidOperationException('control_object_reregistered',$name);
5012
		$this->_rf[self::RF_NAMED_OBJECTS][$name]=$object;
5013
	}
5014
	public function unregisterObject($name)
5015
	{
5016
		unset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
5017
	}
5018
	public function isObjectRegistered($name)
5019
	{
5020
		return isset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
5021
	}
5022
	public function getHasChildInitialized()
5023
	{
5024
		return $this->getControlStage() >= self::CS_CHILD_INITIALIZED;
5025
	}
5026
	public function getHasInitialized()
5027
	{
5028
		return $this->getControlStage() >= self::CS_INITIALIZED;
5029
	}
5030
	public function getHasLoadedPostData()
5031
	{
5032
		return $this->getControlStage() >= self::CS_STATE_LOADED;
5033
	}
5034
	public function getHasLoaded()
5035
	{
5036
		return $this->getControlStage() >= self::CS_LOADED;
5037
	}
5038
	public function getHasPreRendered()
5039
	{
5040
		return $this->getControlStage() >= self::CS_PRERENDERED;
5041
	}
5042
	public function getRegisteredObject($name)
5043
	{
5044
		return isset($this->_rf[self::RF_NAMED_OBJECTS][$name])?$this->_rf[self::RF_NAMED_OBJECTS][$name]:null;
5045
	}
5046
	public function getAllowChildControls()
5047
	{
5048
		return true;
5049
	}
5050
	public function addParsedObject($object)
5051
	{
5052
		$this->getControls()->add($object);
5053
	}
5054
	final protected function clearChildState()
5055
	{
5056
		unset($this->_rf[self::RF_CHILD_STATE]);
5057
	}
5058
	final protected function isDescendentOf($ancestor)
5059
	{
5060
		$control=$this;
5061
		while($control!==$ancestor && $control->_parent)
5062
			$control=$control->_parent;
5063
		return $control===$ancestor;
5064
	}
5065
	public function addedControl($control)
5066
	{
5067
		if($control->_parent)
5068
			$control->_parent->getControls()->remove($control);
5069
		$control->_parent=$this;
5070
		$control->_page=$this->getPage();
5071
		$namingContainer=($this instanceof INamingContainer)?$this:$this->_namingContainer;
5072
		if($namingContainer)
5073
		{
5074
			$control->_namingContainer=$namingContainer;
5075
			if($control->_id==='')
5076
				$control->generateAutomaticID();
5077
			else
5078
				$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...
5079
			$control->clearCachedUniqueID($control instanceof INamingContainer);
5080
		}
5081
		if($this->_stage>=self::CS_CHILD_INITIALIZED)
5082
		{
5083
			$control->initRecursive($namingContainer);
5084
			if($this->_stage>=self::CS_STATE_LOADED)
5085
			{
5086
				if(isset($this->_rf[self::RF_CHILD_STATE][$control->_id]))
5087
				{
5088
					$state=$this->_rf[self::RF_CHILD_STATE][$control->_id];
5089
					unset($this->_rf[self::RF_CHILD_STATE][$control->_id]);
5090
				}
5091
				else
5092
					$state=null;
5093
				$control->loadStateRecursive($state,!($this->_flags & self::IS_DISABLE_VIEWSTATE));
5094
				if($this->_stage>=self::CS_LOADED)
5095
				{
5096
					$control->loadRecursive();
5097
					if($this->_stage>=self::CS_PRERENDERED)
5098
						$control->preRenderRecursive();
5099
				}
5100
			}
5101
		}
5102
	}
5103
	public function removedControl($control)
5104
	{
5105
		if($this->_namingContainer)
5106
			$this->_namingContainer->clearNameTable();
5107
		$control->unloadRecursive();
5108
		$control->_parent=null;
5109
		$control->_page=null;
5110
		$control->_namingContainer=null;
5111
		$control->_tplControl=null;
5112
				if(!($control->_flags & self::IS_ID_SET))
5113
			$control->_id='';
5114
		else
5115
			unset($this->_rf[self::RF_NAMED_OBJECTS][$control->_id]);
5116
		$control->clearCachedUniqueID(true);
5117
	}
5118
	protected function initRecursive($namingContainer=null)
5119
	{
5120
		$this->ensureChildControls();
5121
		if($this->getHasControls())
5122
		{
5123
			if($this instanceof INamingContainer)
5124
				$namingContainer=$this;
5125
			$page=$this->getPage();
5126
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5127
			{
5128
				if($control instanceof TControl)
5129
				{
5130
					$control->_namingContainer=$namingContainer;
5131
					$control->_page=$page;
5132
					if($control->_id==='' && $namingContainer)
5133
						$control->generateAutomaticID();
5134
					$control->initRecursive($namingContainer);
5135
				}
5136
			}
5137
		}
5138
		if($this->_stage<self::CS_INITIALIZED)
5139
		{
5140
			$this->_stage=self::CS_CHILD_INITIALIZED;
5141
			if(($page=$this->getPage()) && $this->getEnableTheming() && !($this->_flags & self::IS_SKIN_APPLIED))
5142
			{
5143
				$page->applyControlSkin($this);
5144
				$this->_flags |= self::IS_SKIN_APPLIED;
5145
			}
5146
			if(isset($this->_rf[self::RF_ADAPTER]))
5147
				$this->_rf[self::RF_ADAPTER]->onInit(null);
5148
			else
5149
				$this->onInit(null);
5150
			$this->_stage=self::CS_INITIALIZED;
5151
		}
5152
	}
5153
	protected function loadRecursive()
5154
	{
5155
		if($this->_stage<self::CS_LOADED)
5156
		{
5157
			if(isset($this->_rf[self::RF_ADAPTER]))
5158
				$this->_rf[self::RF_ADAPTER]->onLoad(null);
5159
			else
5160
				$this->onLoad(null);
5161
		}
5162
		if($this->getHasControls())
5163
		{
5164
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5165
			{
5166
				if($control instanceof TControl)
5167
					$control->loadRecursive();
5168
			}
5169
		}
5170
		if($this->_stage<self::CS_LOADED)
5171
			$this->_stage=self::CS_LOADED;
5172
	}
5173
	protected function preRenderRecursive()
5174
	{
5175
		$this->autoDataBindProperties();
5176
		if($this->getVisible(false))
5177
		{
5178
			if(isset($this->_rf[self::RF_ADAPTER]))
5179
				$this->_rf[self::RF_ADAPTER]->onPreRender(null);
5180
			else
5181
				$this->onPreRender(null);
5182
			if($this->getHasControls())
5183
			{
5184
				foreach($this->_rf[self::RF_CONTROLS] as $control)
5185
				{
5186
					if($control instanceof TControl)
5187
						$control->preRenderRecursive();
5188
					else if($control instanceof TCompositeLiteral)
5189
						$control->evaluateDynamicContent();
5190
				}
5191
			}
5192
		}
5193
		$this->_stage=self::CS_PRERENDERED;
5194
	}
5195
	protected function unloadRecursive()
5196
	{
5197
		if(!($this->_flags & self::IS_ID_SET))
5198
			$this->_id='';
5199
		if($this->getHasControls())
5200
		{
5201
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5202
				if($control instanceof TControl)
5203
					$control->unloadRecursive();
5204
		}
5205
		if(isset($this->_rf[self::RF_ADAPTER]))
5206
			$this->_rf[self::RF_ADAPTER]->onUnload(null);
5207
		else
5208
			$this->onUnload(null);
5209
	}
5210
	public function onInit($param)
5211
	{
5212
		$this->raiseEvent('OnInit',$this,$param);
5213
	}
5214
	public function onLoad($param)
5215
	{
5216
		$this->raiseEvent('OnLoad',$this,$param);
5217
	}
5218
	public function onDataBinding($param)
5219
	{
5220
		$this->raiseEvent('OnDataBinding',$this,$param);
5221
	}
5222
	public function onUnload($param)
5223
	{
5224
		$this->raiseEvent('OnUnload',$this,$param);
5225
	}
5226
	public function onPreRender($param)
5227
	{
5228
		$this->raiseEvent('OnPreRender',$this,$param);
5229
	}
5230
	protected function raiseBubbleEvent($sender,$param)
5231
	{
5232
		$control=$this;
5233
		while($control=$control->_parent)
5234
		{
5235
			if($control->bubbleEvent($sender,$param))
5236
				break;
5237
		}
5238
	}
5239
	public function bubbleEvent($sender,$param)
5240
	{
5241
		return false;
5242
	}
5243
	public function broadcastEvent($name,$sender,$param)
5244
	{
5245
		$rootControl=(($page=$this->getPage())===null)?$this:$page;
5246
		$rootControl->broadcastEventInternal($name,$sender,new TBroadcastEventParameter($name,$param));
5247
	}
5248
	private function broadcastEventInternal($name,$sender,$param)
5249
	{
5250
		if($this->hasEvent($name))
5251
			$this->raiseEvent($name,$sender,$param->getParameter());
5252
		if($this instanceof IBroadcastEventReceiver)
5253
			$this->broadcastEventReceived($sender,$param);
5254
		if($this->getHasControls())
5255
		{
5256
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5257
			{
5258
				if($control instanceof TControl)
5259
					$control->broadcastEventInternal($name,$sender,$param);
5260
			}
5261
		}
5262
	}
5263
	protected function traverseChildControls($param,$preCallback=null,$postCallback=null)
5264
	{
5265
		if($preCallback!==null)
5266
			call_user_func($preCallback,$this,$param);
5267
		if($this->getHasControls())
5268
		{
5269
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5270
			{
5271
				if($control instanceof TControl)
5272
				{
5273
					$control->traverseChildControls($param,$preCallback,$postCallback);
5274
				}
5275
			}
5276
		}
5277
		if($postCallback!==null)
5278
			call_user_func($postCallback,$this,$param);
5279
	}
5280
	public function renderControl($writer)
5281
	{
5282
		if($this instanceof IActiveControl || $this->getVisible(false))
5283
		{
5284
			if(isset($this->_rf[self::RF_ADAPTER]))
5285
				$this->_rf[self::RF_ADAPTER]->render($writer);
5286
			else
5287
				$this->render($writer);
5288
		}
5289
	}
5290
	public function render($writer)
5291
	{
5292
		$this->renderChildren($writer);
5293
	}
5294
	public function renderChildren($writer)
5295
	{
5296
		if($this->getHasControls())
5297
		{
5298
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5299
			{
5300
				if(is_string($control))
5301
					$writer->write($control);
5302
				else if($control instanceof TControl)
5303
					$control->renderControl($writer);
5304
				else if($control instanceof IRenderable)
5305
					$control->render($writer);
5306
			}
5307
		}
5308
	}
5309
	public function saveState()
5310
	{
5311
	}
5312
	public function loadState()
5313
	{
5314
	}
5315
	protected function loadStateRecursive(&$state,$needViewState=true)
5316
	{
5317
		if(is_array($state))
5318
		{
5319
									$needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
5320
			if(isset($state[1]))
5321
			{
5322
				$this->_rf[self::RF_CONTROLSTATE]=&$state[1];
5323
				unset($state[1]);
5324
			}
5325
			else
5326
				unset($this->_rf[self::RF_CONTROLSTATE]);
5327
			if($needViewState)
5328
			{
5329
				if(isset($state[0]))
5330
					$this->_viewState=&$state[0];
5331
				else
5332
					$this->_viewState=array();
5333
			}
5334
			unset($state[0]);
5335
			if($this->getHasControls())
5336
			{
5337
				foreach($this->_rf[self::RF_CONTROLS] as $control)
5338
				{
5339
					if($control instanceof TControl)
5340
					{
5341
						if(isset($state[$control->_id]))
5342
						{
5343
							$control->loadStateRecursive($state[$control->_id],$needViewState);
5344
							unset($state[$control->_id]);
5345
						}
5346
					}
5347
				}
5348
			}
5349
			if(!empty($state))
5350
				$this->_rf[self::RF_CHILD_STATE]=&$state;
5351
		}
5352
		$this->_stage=self::CS_STATE_LOADED;
5353
		if(isset($this->_rf[self::RF_ADAPTER]))
5354
			$this->_rf[self::RF_ADAPTER]->loadState();
5355
		else
5356
			$this->loadState();
5357
	}
5358
	protected function &saveStateRecursive($needViewState=true)
5359
	{
5360
		if(isset($this->_rf[self::RF_ADAPTER]))
5361
			$this->_rf[self::RF_ADAPTER]->saveState();
5362
		else
5363
			$this->saveState();
5364
		$needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
5365
		$state=array();
5366
		if($this->getHasControls())
5367
		{
5368
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5369
			{
5370
				if($control instanceof TControl)
5371
				{
5372
					if(count($tmp = &$control->saveStateRecursive($needViewState)))
5373
						$state[$control->_id]=$tmp;
5374
				}
5375
			}
5376
		}
5377
		if($needViewState && !empty($this->_viewState))
5378
			$state[0]=&$this->_viewState;
5379
		if(isset($this->_rf[self::RF_CONTROLSTATE]))
5380
			$state[1]=&$this->_rf[self::RF_CONTROLSTATE];
5381
		return $state;
5382
	}
5383
	public function applyStyleSheetSkin($page)
5384
	{
5385
		if($page && !($this->_flags & self::IS_STYLESHEET_APPLIED))
5386
		{
5387
			$page->applyControlStyleSheet($this);
5388
			$this->_flags |= self::IS_STYLESHEET_APPLIED;
5389
		}
5390
		else if($this->_flags & self::IS_STYLESHEET_APPLIED)
5391
			throw new TInvalidOperationException('control_stylesheet_applied',get_class($this));
5392
	}
5393
	private function clearCachedUniqueID($recursive)
5394
	{
5395
		if($recursive && $this->_uid!==null && isset($this->_rf[self::RF_CONTROLS]))
5396
		{
5397
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5398
				if($control instanceof TControl)
5399
					$control->clearCachedUniqueID($recursive);
5400
		}
5401
		$this->_uid=null;
5402
	}
5403
	private function generateAutomaticID()
5404
	{
5405
		$this->_flags &= ~self::IS_ID_SET;
5406
		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...
5407
			$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...
5408
		$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...
5409
		$this->_id=self::AUTOMATIC_ID_PREFIX . $id;
5410
		$this->_namingContainer->clearNameTable();
5411
	}
5412
	private function clearNameTable()
5413
	{
5414
		unset($this->_rf[self::RF_NAMED_CONTROLS]);
5415
	}
5416
	private function fillNameTable($container,$controls)
5417
	{
5418
		foreach($controls as $control)
5419
		{
5420
			if($control instanceof TControl)
5421
			{
5422
				if($control->_id!=='')
5423
				{
5424
					if(isset($container->_rf[self::RF_NAMED_CONTROLS][$control->_id]))
5425
						throw new TInvalidDataValueException('control_id_nonunique',get_class($control),$control->_id);
5426
					else
5427
						$container->_rf[self::RF_NAMED_CONTROLS][$control->_id]=$control;
5428
				}
5429
				if(!($control instanceof INamingContainer) && $control->getHasControls())
5430
					$this->fillNameTable($container,$control->_rf[self::RF_CONTROLS]);
5431
			}
5432
		}
5433
	}
5434
}
5435
class TControlCollection extends TList
5436
{
5437
	private $_o;
5438
	public function __construct(TControl $owner,$readOnly=false)
5439
	{
5440
		$this->_o=$owner;
5441
		parent::__construct(null,$readOnly);
5442
	}
5443
	protected function getOwner()
5444
	{
5445
		return $this->_o;
5446
	}
5447
	public function insertAt($index,$item)
5448
	{
5449
		if($item instanceof TControl)
5450
		{
5451
			parent::insertAt($index,$item);
5452
			$this->_o->addedControl($item);
5453
		}
5454
		else if(is_string($item) || ($item instanceof IRenderable))
5455
			parent::insertAt($index,$item);
5456
		else
5457
			throw new TInvalidDataTypeException('controlcollection_control_required');
5458
	}
5459
	public function removeAt($index)
5460
	{
5461
		$item=parent::removeAt($index);
5462
		if($item instanceof TControl)
5463
			$this->_o->removedControl($item);
5464
		return $item;
5465
	}
5466
	public function clear()
5467
	{
5468
		parent::clear();
5469
		if($this->_o instanceof INamingContainer)
5470
			$this->_o->clearNamingContainer();
5471
	}
5472
}
5473
class TEmptyControlCollection extends TControlCollection
5474
{
5475
	public function __construct(TControl $owner)
5476
	{
5477
		parent::__construct($owner,true);
5478
	}
5479
	public function insertAt($index,$item)
5480
	{
5481
		if(!is_string($item))  			parent::insertAt($index,$item);  	}
5482
}
5483
interface INamingContainer
5484
{
5485
}
5486
interface IPostBackEventHandler
5487
{
5488
	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...
5489
}
5490
interface IPostBackDataHandler
5491
{
5492
	public function loadPostData($key,$values);
5493
	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...
5494
	public function getDataChanged();
5495
}
5496
interface IValidator
5497
{
5498
	public function validate();
5499
	public function getIsValid();
5500
	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...
5501
	public function getErrorMessage();
5502
	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...
5503
}
5504
interface IValidatable
5505
{
5506
	public function getValidationPropertyValue();
5507
	public function getIsValid();
5508
	public function setIsValid($value);
5509
}
5510
interface IBroadcastEventReceiver
5511
{
5512
	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...
5513
}
5514
interface ITheme
5515
{
5516
	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...
5517
}
5518
interface ITemplate
5519
{
5520
	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...
5521
}
5522
interface IButtonControl
5523
{
5524
	public function getText();
5525
	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...
5526
	public function getCausesValidation();
5527
	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...
5528
	public function getCommandName();
5529
	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...
5530
	public function getCommandParameter();
5531
	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...
5532
	public function getValidationGroup();
5533
	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...
5534
	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...
5535
	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...
5536
	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...
5537
	public function getIsDefaultButton();
5538
}
5539
interface ISurroundable
5540
{
5541
	public function getSurroundingTag();
5542
	public function getSurroundingTagID();
5543
}
5544
class TBroadcastEventParameter extends TEventParameter
5545
{
5546
	private $_name;
5547
	private $_param;
5548
	public function __construct($name='',$parameter=null)
5549
	{
5550
		$this->_name=$name;
5551
		$this->_param=$parameter;
5552
	}
5553
	public function getName()
5554
	{
5555
		return $this->_name;
5556
	}
5557
	public function setName($value)
5558
	{
5559
		$this->_name=$value;
5560
	}
5561
	public function getParameter()
5562
	{
5563
		return $this->_param;
5564
	}
5565
	public function setParameter($value)
5566
	{
5567
		$this->_param=$value;
5568
	}
5569
}
5570
class TCommandEventParameter extends TEventParameter
5571
{
5572
	private $_name;
5573
	private $_param;
5574
	public function __construct($name='',$parameter='')
5575
	{
5576
		$this->_name=$name;
5577
		$this->_param=$parameter;
5578
	}
5579
	public function getCommandName()
5580
	{
5581
		return $this->_name;
5582
	}
5583
	public function getCommandParameter()
5584
	{
5585
		return $this->_param;
5586
	}
5587
}
5588
class TCompositeLiteral extends TComponent implements IRenderable, IBindable
5589
{
5590
	const TYPE_EXPRESSION=0;
5591
	const TYPE_STATEMENTS=1;
5592
	const TYPE_DATABINDING=2;
5593
	private $_container=null;
5594
	private $_items=array();
5595
	private $_expressions=array();
5596
	private $_statements=array();
5597
	private $_bindings=array();
5598
	public function __construct($items)
5599
	{
5600
		$this->_items=array();
5601
		$this->_expressions=array();
5602
		$this->_statements=array();
5603
		foreach($items as $id=>$item)
5604
		{
5605
			if(is_array($item))
5606
			{
5607
				if($item[0]===self::TYPE_EXPRESSION)
5608
					$this->_expressions[$id]=$item[1];
5609
				else if($item[0]===self::TYPE_STATEMENTS)
5610
					$this->_statements[$id]=$item[1];
5611
				else if($item[0]===self::TYPE_DATABINDING)
5612
					$this->_bindings[$id]=$item[1];
5613
				$this->_items[$id]='';
5614
			}
5615
			else
5616
				$this->_items[$id]=$item;
5617
		}
5618
	}
5619
	public function getContainer()
5620
	{
5621
		return $this->_container;
5622
	}
5623
	public function setContainer(TComponent $value)
5624
	{
5625
		$this->_container=$value;
5626
	}
5627
	public function evaluateDynamicContent()
5628
	{
5629
		$context=$this->_container===null?$this:$this->_container;
5630
		foreach($this->_expressions as $id=>$expression)
5631
			$this->_items[$id]=$context->evaluateExpression($expression);
5632
		foreach($this->_statements as $id=>$statement)
5633
			$this->_items[$id]=$context->evaluateStatements($statement);
5634
	}
5635
	public function dataBind()
5636
	{
5637
		$context=$this->_container===null?$this:$this->_container;
5638
		foreach($this->_bindings as $id=>$binding)
5639
			$this->_items[$id]=$context->evaluateExpression($binding);
5640
	}
5641
	public function render($writer)
5642
	{
5643
		$writer->write(implode('',$this->_items));
5644
	}
5645
}
5646
class TFont extends TComponent
5647
{
5648
	const IS_BOLD=0x01;
5649
	const IS_ITALIC=0x02;
5650
	const IS_OVERLINE=0x04;
5651
	const IS_STRIKEOUT=0x08;
5652
	const IS_UNDERLINE=0x10;
5653
	const IS_SET_BOLD=0x01000;
5654
	const IS_SET_ITALIC=0x02000;
5655
	const IS_SET_OVERLINE=0x04000;
5656
	const IS_SET_STRIKEOUT=0x08000;
5657
	const IS_SET_UNDERLINE=0x10000;
5658
	const IS_SET_SIZE=0x20000;
5659
	const IS_SET_NAME=0x40000;
5660
	private $_flags=0;
5661
	private $_name='';
5662
	private $_size='';
5663
	protected function _getZappableSleepProps(&$exprops)
5664
	{
5665
		parent::_getZappableSleepProps($exprops);
5666
		if ($this->_flags===0)
5667
			$exprops[] = "\0TFont\0_flags";
5668
		if ($this->_name==='')
5669
			$exprops[] = "\0TFont\0_name";
5670
		if ($this->_size==='')
5671
			$exprops[] = "\0TFont\0_size";
5672
	}
5673
	public function getBold()
5674
	{
5675
		return ($this->_flags & self::IS_BOLD)!==0;
5676
	}
5677
	public function setBold($value)
5678
	{
5679
		$this->_flags |= self::IS_SET_BOLD;
5680
		if(TPropertyValue::ensureBoolean($value))
5681
			$this->_flags |= self::IS_BOLD;
5682
		else
5683
			$this->_flags &= ~self::IS_BOLD;
5684
	}
5685
	public function getItalic()
5686
	{
5687
		return ($this->_flags & self::IS_ITALIC)!==0;
5688
	}
5689
	public function setItalic($value)
5690
	{
5691
		$this->_flags |= self::IS_SET_ITALIC;
5692
		if(TPropertyValue::ensureBoolean($value))
5693
			$this->_flags |= self::IS_ITALIC;
5694
		else
5695
			$this->_flags &= ~self::IS_ITALIC;
5696
	}
5697
	public function getOverline()
5698
	{
5699
		return ($this->_flags & self::IS_OVERLINE)!==0;
5700
	}
5701
	public function setOverline($value)
5702
	{
5703
		$this->_flags |= self::IS_SET_OVERLINE;
5704
		if(TPropertyValue::ensureBoolean($value))
5705
			$this->_flags |= self::IS_OVERLINE;
5706
		else
5707
			$this->_flags &= ~self::IS_OVERLINE;
5708
	}
5709
	public function getSize()
5710
	{
5711
		return $this->_size;
5712
	}
5713
	public function setSize($value)
5714
	{
5715
		$this->_flags |= self::IS_SET_SIZE;
5716
		$this->_size=$value;
5717
	}
5718
	public function getStrikeout()
5719
	{
5720
		return ($this->_flags & self::IS_STRIKEOUT)!==0;
5721
	}
5722
	public function setStrikeout($value)
5723
	{
5724
		$this->_flags |= self::IS_SET_STRIKEOUT;
5725
		if(TPropertyValue::ensureBoolean($value))
5726
			$this->_flags |= self::IS_STRIKEOUT;
5727
		else
5728
			$this->_flags &= ~self::IS_STRIKEOUT;
5729
	}
5730
	public function getUnderline()
5731
	{
5732
		return ($this->_flags & self::IS_UNDERLINE)!==0;
5733
	}
5734
	public function setUnderline($value)
5735
	{
5736
		$this->_flags |= self::IS_SET_UNDERLINE;
5737
		if(TPropertyValue::ensureBoolean($value))
5738
			$this->_flags |= self::IS_UNDERLINE;
5739
		else
5740
			$this->_flags &= ~self::IS_UNDERLINE;
5741
	}
5742
	public function getName()
5743
	{
5744
		return $this->_name;
5745
	}
5746
	public function setName($value)
5747
	{
5748
		$this->_flags |= self::IS_SET_NAME;
5749
		$this->_name=$value;
5750
	}
5751
	public function getIsEmpty()
5752
	{
5753
		return !$this->_flags;
5754
	}
5755
	public function reset()
5756
	{
5757
		$this->_flags=0;
5758
		$this->_name='';
5759
		$this->_size='';
5760
	}
5761
	public function mergeWith($font)
5762
	{
5763
		if($font===null || $font->_flags===0)
5764
			return;
5765
		if(!($this->_flags & self::IS_SET_BOLD) && ($font->_flags & self::IS_SET_BOLD))
5766
			$this->setBold($font->getBold());
5767
		if(!($this->_flags & self::IS_SET_ITALIC) && ($font->_flags & self::IS_SET_ITALIC))
5768
			$this->setItalic($font->getItalic());
5769
		if(!($this->_flags & self::IS_SET_OVERLINE) && ($font->_flags & self::IS_SET_OVERLINE))
5770
			$this->setOverline($font->getOverline());
5771
		if(!($this->_flags & self::IS_SET_STRIKEOUT) && ($font->_flags & self::IS_SET_STRIKEOUT))
5772
			$this->setStrikeout($font->getStrikeout());
5773
		if(!($this->_flags & self::IS_SET_UNDERLINE) && ($font->_flags & self::IS_SET_UNDERLINE))
5774
			$this->setUnderline($font->getUnderline());
5775
		if(!($this->_flags & self::IS_SET_SIZE) && ($font->_flags & self::IS_SET_SIZE))
5776
			$this->setSize($font->getSize());
5777
		if(!($this->_flags & self::IS_SET_NAME) && ($font->_flags & self::IS_SET_NAME))
5778
			$this->setName($font->getName());
5779
	}
5780
	public function copyFrom($font)
5781
	{
5782
		if($font===null || $font->_flags===0)
5783
			return;
5784
		if($font->_flags & self::IS_SET_BOLD)
5785
			$this->setBold($font->getBold());
5786
		if($font->_flags & self::IS_SET_ITALIC)
5787
			$this->setItalic($font->getItalic());
5788
		if($font->_flags & self::IS_SET_OVERLINE)
5789
			$this->setOverline($font->getOverline());
5790
		if($font->_flags & self::IS_SET_STRIKEOUT)
5791
			$this->setStrikeout($font->getStrikeout());
5792
		if($font->_flags & self::IS_SET_UNDERLINE)
5793
			$this->setUnderline($font->getUnderline());
5794
		if($font->_flags & self::IS_SET_SIZE)
5795
			$this->setSize($font->getSize());
5796
		if($font->_flags & self::IS_SET_NAME)
5797
			$this->setName($font->getName());
5798
	}
5799
	public function toString()
5800
	{
5801
		if($this->_flags===0)
5802
			return '';
5803
		$str='';
5804
		if($this->_flags & self::IS_SET_BOLD)
5805
			$str.='font-weight:'.(($this->_flags & self::IS_BOLD)?'bold;':'normal;');
5806
		if($this->_flags & self::IS_SET_ITALIC)
5807
			$str.='font-style:'.(($this->_flags & self::IS_ITALIC)?'italic;':'normal;');
5808
		$textDec='';
5809
		if($this->_flags & self::IS_UNDERLINE)
5810
			$textDec.='underline';
5811
		if($this->_flags & self::IS_OVERLINE)
5812
			$textDec.=' overline';
5813
		if($this->_flags & self::IS_STRIKEOUT)
5814
			$textDec.=' line-through';
5815
		$textDec=ltrim($textDec);
5816
		if($textDec!=='')
5817
			$str.='text-decoration:'.$textDec.';';
5818
		if($this->_size!=='')
5819
			$str.='font-size:'.$this->_size.';';
5820
		if($this->_name!=='')
5821
			$str.='font-family:'.$this->_name.';';
5822
		return $str;
5823
	}
5824
	public function addAttributesToRender($writer)
5825
	{
5826
		if($this->_flags===0)
5827
			return;
5828
		if($this->_flags & self::IS_SET_BOLD)
5829
			$writer->addStyleAttribute('font-weight',(($this->_flags & self::IS_BOLD)?'bold':'normal'));
5830
		if($this->_flags & self::IS_SET_ITALIC)
5831
			$writer->addStyleAttribute('font-style',(($this->_flags & self::IS_ITALIC)?'italic':'normal'));
5832
		$textDec='';
5833
		if($this->_flags & self::IS_UNDERLINE)
5834
			$textDec.='underline';
5835
		if($this->_flags & self::IS_OVERLINE)
5836
			$textDec.=' overline';
5837
		if($this->_flags & self::IS_STRIKEOUT)
5838
			$textDec.=' line-through';
5839
		$textDec=ltrim($textDec);
5840
		if($textDec!=='')
5841
			$writer->addStyleAttribute('text-decoration',$textDec);
5842
		if($this->_size!=='')
5843
			$writer->addStyleAttribute('font-size',$this->_size);
5844
		if($this->_name!=='')
5845
			$writer->addStyleAttribute('font-family',$this->_name);
5846
	}
5847
}
5848
class TStyle extends TComponent
5849
{
5850
	private $_fields=array();
5851
	private $_font=null;
5852
	private $_class=null;
5853
	private $_customStyle=null;
5854
	private $_displayStyle='Fixed';
5855
	protected function _getZappableSleepProps(&$exprops)
5856
	{
5857
		parent::_getZappableSleepProps($exprops);
5858
		if ($this->_fields===array())
5859
			$exprops[] = "\0TStyle\0_fields";
5860
		if($this->_font===null)
5861
			$exprops[] = "\0TStyle\0_font";
5862
		if($this->_class===null)
5863
			$exprops[] = "\0TStyle\0_class";
5864
		if ($this->_customStyle===null)
5865
			$exprops[] = "\0TStyle\0_customStyle";
5866
		if ($this->_displayStyle==='Fixed')
5867
			$exprops[] = "\0TStyle\0_displayStyle";
5868
	}
5869
	public function __construct($style=null)
5870
	{
5871
    parent::__construct();
5872
		if($style!==null)
5873
			$this->copyFrom($style);
5874
	}
5875
	public function __clone()
5876
	{
5877
		if($this->_font!==null)
5878
			$this->_font = clone($this->_font);
5879
	}
5880
	public function getBackColor()
5881
	{
5882
		return isset($this->_fields['background-color'])?$this->_fields['background-color']:'';
5883
	}
5884
	public function setBackColor($value)
5885
	{
5886
		if(trim($value)==='')
5887
			unset($this->_fields['background-color']);
5888
		else
5889
			$this->_fields['background-color']=$value;
5890
	}
5891
	public function getBorderColor()
5892
	{
5893
		return isset($this->_fields['border-color'])?$this->_fields['border-color']:'';
5894
	}
5895
	public function setBorderColor($value)
5896
	{
5897
		if(trim($value)==='')
5898
			unset($this->_fields['border-color']);
5899
		else
5900
			$this->_fields['border-color']=$value;
5901
	}
5902
	public function getBorderStyle()
5903
	{
5904
		return isset($this->_fields['border-style'])?$this->_fields['border-style']:'';
5905
	}
5906
	public function setBorderStyle($value)
5907
	{
5908
		if(trim($value)==='')
5909
			unset($this->_fields['border-style']);
5910
		else
5911
			$this->_fields['border-style']=$value;
5912
	}
5913
	public function getBorderWidth()
5914
	{
5915
		return isset($this->_fields['border-width'])?$this->_fields['border-width']:'';
5916
	}
5917
	public function setBorderWidth($value)
5918
	{
5919
		if(trim($value)==='')
5920
			unset($this->_fields['border-width']);
5921
		else
5922
			$this->_fields['border-width']=$value;
5923
	}
5924
	public function getCssClass()
5925
	{
5926
		return $this->_class===null?'':$this->_class;
5927
	}
5928
	public function hasCssClass()
5929
	{
5930
		return ($this->_class!==null);
5931
	}
5932
	public function setCssClass($value)
5933
	{
5934
		$this->_class=$value;
5935
	}
5936
	public function getFont()
5937
	{
5938
		if($this->_font===null)
5939
			$this->_font=new TFont;
5940
		return $this->_font;
5941
	}
5942
	public function hasFont()
5943
	{
5944
		return $this->_font !== null;
5945
	}
5946
	public function setDisplayStyle($value)
5947
	{
5948
		$this->_displayStyle = TPropertyValue::ensureEnum($value, 'TDisplayStyle');
5949
		switch($this->_displayStyle)
5950
		{
5951
			case TDisplayStyle::None:
5952
				$this->_fields['display'] = 'none';
5953
				break;
5954
			case TDisplayStyle::Dynamic:
5955
				$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...
5956
			case TDisplayStyle::Fixed:
5957
				$this->_fields['visibility'] = 'visible';
5958
				break;
5959
			case TDisplayStyle::Hidden:
5960
				$this->_fields['visibility'] = 'hidden';
5961
				break;
5962
		}
5963
	}
5964
	public function getDisplayStyle()
5965
	{
5966
		return $this->_displayStyle;
5967
	}
5968
	public function getForeColor()
5969
	{
5970
		return isset($this->_fields['color'])?$this->_fields['color']:'';
5971
	}
5972
	public function setForeColor($value)
5973
	{
5974
		if(trim($value)==='')
5975
			unset($this->_fields['color']);
5976
		else
5977
			$this->_fields['color']=$value;
5978
	}
5979
	public function getHeight()
5980
	{
5981
		return isset($this->_fields['height'])?$this->_fields['height']:'';
5982
	}
5983
	public function setHeight($value)
5984
	{
5985
		if(trim($value)==='')
5986
			unset($this->_fields['height']);
5987
		else
5988
			$this->_fields['height']=$value;
5989
	}
5990
	public function getCustomStyle()
5991
	{
5992
		return $this->_customStyle===null?'':$this->_customStyle;
5993
	}
5994
	public function setCustomStyle($value)
5995
	{
5996
		$this->_customStyle=$value;
5997
	}
5998
	public function getStyleField($name)
5999
	{
6000
		return isset($this->_fields[$name])?$this->_fields[$name]:'';
6001
	}
6002
	public function setStyleField($name,$value)
6003
	{
6004
		$this->_fields[$name]=$value;
6005
	}
6006
	public function clearStyleField($name)
6007
	{
6008
		unset($this->_fields[$name]);
6009
	}
6010
	public function hasStyleField($name)
6011
	{
6012
		return isset($this->_fields[$name]);
6013
	}
6014
	public function getWidth()
6015
	{
6016
		return isset($this->_fields['width'])?$this->_fields['width']:'';
6017
	}
6018
	public function setWidth($value)
6019
	{
6020
		$this->_fields['width']=$value;
6021
	}
6022
	public function reset()
6023
	{
6024
		$this->_fields=array();
6025
		$this->_font=null;
6026
		$this->_class=null;
6027
		$this->_customStyle=null;
6028
	}
6029
	public function copyFrom($style)
6030
	{
6031
		if($style instanceof TStyle)
6032
		{
6033
			$this->_fields=array_merge($this->_fields,$style->_fields);
6034
			if($style->_class!==null)
6035
				$this->_class=$style->_class;
6036
			if($style->_customStyle!==null)
6037
				$this->_customStyle=$style->_customStyle;
6038
			if($style->_font!==null)
6039
				$this->getFont()->copyFrom($style->_font);
6040
		}
6041
	}
6042
	public function mergeWith($style)
6043
	{
6044
		if($style instanceof TStyle)
6045
		{
6046
			$this->_fields=array_merge($style->_fields,$this->_fields);
6047
			if($this->_class===null)
6048
				$this->_class=$style->_class;
6049
			if($this->_customStyle===null)
6050
				$this->_customStyle=$style->_customStyle;
6051
			if($style->_font!==null)
6052
				$this->getFont()->mergeWith($style->_font);
6053
		}
6054
	}
6055
	public function addAttributesToRender($writer)
6056
	{
6057
		if($this->_customStyle!==null)
6058
		{
6059
			foreach(explode(';',$this->_customStyle) as $style)
6060
			{
6061
				$arr=explode(':',$style,2);
6062
				if(isset($arr[1]) && trim($arr[0])!=='')
6063
					$writer->addStyleAttribute(trim($arr[0]),trim($arr[1]));
6064
			}
6065
		}
6066
		$writer->addStyleAttributes($this->_fields);
6067
		if($this->_font!==null)
6068
			$this->_font->addAttributesToRender($writer);
6069
		if($this->_class!==null)
6070
			$writer->addAttribute('class',$this->_class);
6071
	}
6072
	public function getStyleFields()
6073
	{
6074
		return $this->_fields;
6075
	}
6076
}
6077
class TDisplayStyle extends TEnumerable
6078
{
6079
	const None='None';
6080
	const Dynamic='Dynamic';
6081
	const Fixed='Fixed';
6082
	const Hidden='Hidden';
6083
}
6084
class TTableStyle extends TStyle
6085
{
6086
	private $_backImageUrl=null;
6087
	private $_horizontalAlign=null;
6088
	private $_cellPadding=null;
6089
	private $_cellSpacing=null;
6090
	private $_gridLines=null;
6091
	private $_borderCollapse=null;
6092
	protected function _getZappableSleepProps(&$exprops)
6093
	{
6094
		parent::_getZappableSleepProps($exprops);
6095
		if ($this->_backImageUrl===null)
6096
			$exprops[] = "\0TTableStyle\0_backImageUrl";
6097
		if ($this->_horizontalAlign===null)
6098
			$exprops[] = "\0TTableStyle\0_horizontalAlign";
6099
		if ($this->_cellPadding===null)
6100
			$exprops[] = "\0TTableStyle\0_cellPadding";
6101
		if ($this->_cellSpacing===null)
6102
			$exprops[] = "\0TTableStyle\0_cellSpacing";
6103
		if ($this->_gridLines===null)
6104
			$exprops[] = "\0TTableStyle\0_gridLines";
6105
		if ($this->_borderCollapse===null)
6106
			$exprops[] = "\0TTableStyle\0_borderCollapse";
6107
	}
6108
	public function reset()
6109
	{
6110
		$this->_backImageUrl=null;
6111
		$this->_horizontalAlign=null;
6112
		$this->_cellPadding=null;
6113
		$this->_cellSpacing=null;
6114
		$this->_gridLines=null;
6115
		$this->_borderCollapse=null;
6116
	}
6117
	public function copyFrom($style)
6118
	{
6119
		parent::copyFrom($style);
6120
		if($style instanceof TTableStyle)
6121
		{
6122
			if($style->_backImageUrl!==null)
6123
				$this->_backImageUrl=$style->_backImageUrl;
6124
			if($style->_horizontalAlign!==null)
6125
				$this->_horizontalAlign=$style->_horizontalAlign;
6126
			if($style->_cellPadding!==null)
6127
				$this->_cellPadding=$style->_cellPadding;
6128
			if($style->_cellSpacing!==null)
6129
				$this->_cellSpacing=$style->_cellSpacing;
6130
			if($style->_gridLines!==null)
6131
				$this->_gridLines=$style->_gridLines;
6132
			if($style->_borderCollapse!==null)
6133
				$this->_borderCollapse=$style->_borderCollapse;
6134
		}
6135
	}
6136
	public function mergeWith($style)
6137
	{
6138
		parent::mergeWith($style);
6139
		if($style instanceof TTableStyle)
6140
		{
6141
			if($this->_backImageUrl===null && $style->_backImageUrl!==null)
6142
				$this->_backImageUrl=$style->_backImageUrl;
6143
			if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
6144
				$this->_horizontalAlign=$style->_horizontalAlign;
6145
			if($this->_cellPadding===null && $style->_cellPadding!==null)
6146
				$this->_cellPadding=$style->_cellPadding;
6147
			if($this->_cellSpacing===null && $style->_cellSpacing!==null)
6148
				$this->_cellSpacing=$style->_cellSpacing;
6149
			if($this->_gridLines===null && $style->_gridLines!==null)
6150
				$this->_gridLines=$style->_gridLines;
6151
			if($this->_borderCollapse===null && $style->_borderCollapse!==null)
6152
				$this->_borderCollapse=$style->_borderCollapse;
6153
		}
6154
	}
6155
	public function addAttributesToRender($writer)
6156
	{
6157
		if(($url=trim($this->getBackImageUrl()))!=='')
6158
			$writer->addStyleAttribute('background-image','url('.$url.')');
6159
		if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
6160
			$writer->addStyleAttribute('text-align',strtolower($horizontalAlign));
6161
		if(($cellPadding=$this->getCellPadding())>=0)
6162
			$writer->addAttribute('cellpadding',"$cellPadding");
6163
		if(($cellSpacing=$this->getCellSpacing())>=0)
6164
			$writer->addAttribute('cellspacing',"$cellSpacing");
6165
		if($this->getBorderCollapse())
6166
			$writer->addStyleAttribute('border-collapse','collapse');
6167
		switch($this->getGridLines())
6168
		{
6169
			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...
6170
			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...
6171
			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...
6172
		}
6173
		parent::addAttributesToRender($writer);
6174
	}
6175
	public function getBackImageUrl()
6176
	{
6177
		return $this->_backImageUrl===null?'':$this->_backImageUrl;
6178
	}
6179
	public function setBackImageUrl($value)
6180
	{
6181
		$this->_backImageUrl=$value;
6182
	}
6183
	public function getHorizontalAlign()
6184
	{
6185
		return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
6186
	}
6187
	public function setHorizontalAlign($value)
6188
	{
6189
		$this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
6190
	}
6191
	public function getCellPadding()
6192
	{
6193
		return $this->_cellPadding===null?-1:$this->_cellPadding;
6194
	}
6195
	public function setCellPadding($value)
6196
	{
6197
		if(($this->_cellPadding=TPropertyValue::ensureInteger($value))<-1)
6198
			throw new TInvalidDataValueException('tablestyle_cellpadding_invalid');
6199
	}
6200
	public function getCellSpacing()
6201
	{
6202
		return $this->_cellSpacing===null?-1:$this->_cellSpacing;
6203
	}
6204
	public function setCellSpacing($value)
6205
	{
6206
		if(($this->_cellSpacing=TPropertyValue::ensureInteger($value))<-1)
6207
			throw new TInvalidDataValueException('tablestyle_cellspacing_invalid');
6208
	}
6209
	public function getGridLines()
6210
	{
6211
		return $this->_gridLines===null?TTableGridLines::None:$this->_gridLines;
6212
	}
6213
	public function setGridLines($value)
6214
	{
6215
		$this->_gridLines=TPropertyValue::ensureEnum($value,'TTableGridLines');
6216
	}
6217
	public function getBorderCollapse()
6218
	{
6219
		return $this->_borderCollapse===null?false:$this->_borderCollapse;
6220
	}
6221
	public function setBorderCollapse($value)
6222
	{
6223
		$this->_borderCollapse=TPropertyValue::ensureBoolean($value);
6224
	}
6225
}
6226
class TTableItemStyle extends TStyle
6227
{
6228
	private $_horizontalAlign=null;
6229
	private $_verticalAlign=null;
6230
	private $_wrap=null;
6231
	protected function _getZappableSleepProps(&$exprops)
6232
	{
6233
		parent::_getZappableSleepProps($exprops);
6234
		if ($this->_horizontalAlign===null)
6235
			$exprops[] = "\0TTableItemStyle\0_horizontalAlign";
6236
		if ($this->_verticalAlign===null)
6237
			$exprops[] = "\0TTableItemStyle\0_verticalAlign";
6238
		if ($this->_wrap===null)
6239
			$exprops[] = "\0TTableItemStyle\0_wrap";
6240
	}
6241
	public function reset()
6242
	{
6243
		parent::reset();
6244
		$this->_verticalAlign=null;
6245
		$this->_horizontalAlign=null;
6246
		$this->_wrap=null;
6247
	}
6248
	public function copyFrom($style)
6249
	{
6250
		parent::copyFrom($style);
6251
		if($style instanceof TTableItemStyle)
6252
		{
6253
			if($this->_verticalAlign===null && $style->_verticalAlign!==null)
6254
				$this->_verticalAlign=$style->_verticalAlign;
6255
			if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
6256
				$this->_horizontalAlign=$style->_horizontalAlign;
6257
			if($this->_wrap===null && $style->_wrap!==null)
6258
				$this->_wrap=$style->_wrap;
6259
		}
6260
	}
6261
	public function mergeWith($style)
6262
	{
6263
		parent::mergeWith($style);
6264
		if($style instanceof TTableItemStyle)
6265
		{
6266
			if($style->_verticalAlign!==null)
6267
				$this->_verticalAlign=$style->_verticalAlign;
6268
			if($style->_horizontalAlign!==null)
6269
				$this->_horizontalAlign=$style->_horizontalAlign;
6270
			if($style->_wrap!==null)
6271
				$this->_wrap=$style->_wrap;
6272
		}
6273
	}
6274
	public function addAttributesToRender($writer)
6275
	{
6276
		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...
6277
			$writer->addStyleAttribute('white-space','nowrap');
6278
		if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
6279
			$writer->addAttribute('align',strtolower($horizontalAlign));
6280
		if(($verticalAlign=$this->getVerticalAlign())!==TVerticalAlign::NotSet)
6281
			$writer->addAttribute('valign',strtolower($verticalAlign));
6282
		parent::addAttributesToRender($writer);
6283
	}
6284
	public function getHorizontalAlign()
6285
	{
6286
		return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
6287
	}
6288
	public function setHorizontalAlign($value)
6289
	{
6290
		$this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
6291
	}
6292
	public function getVerticalAlign()
6293
	{
6294
		return $this->_verticalAlign===null?TVerticalAlign::NotSet:$this->_verticalAlign;
6295
	}
6296
	public function setVerticalAlign($value)
6297
	{
6298
		$this->_verticalAlign=TPropertyValue::ensureEnum($value,'TVerticalAlign');
6299
	}
6300
	public function getWrap()
6301
	{
6302
		return $this->_wrap===null?true:$this->_wrap;
6303
	}
6304
	public function setWrap($value)
6305
	{
6306
		$this->_wrap=TPropertyValue::ensureBoolean($value);
6307
	}
6308
}
6309
class THorizontalAlign extends TEnumerable
6310
{
6311
	const NotSet='NotSet';
6312
	const Left='Left';
6313
	const Right='Right';
6314
	const Center='Center';
6315
	const Justify='Justify';
6316
}
6317
class TVerticalAlign extends TEnumerable
6318
{
6319
	const NotSet='NotSet';
6320
	const Top='Top';
6321
	const Bottom='Bottom';
6322
	const Middle='Middle';
6323
}
6324
class TTableGridLines extends TEnumerable
6325
{
6326
	const None='None';
6327
	const Horizontal='Horizontal';
6328
	const Vertical='Vertical';
6329
	const Both='Both';
6330
}
6331
class TWebControlAdapter extends TControlAdapter
6332
{
6333
	public function render($writer)
6334
	{
6335
		$this->renderBeginTag($writer);
6336
		$this->renderContents($writer);
6337
		$this->renderEndTag($writer);
6338
	}
6339
	public function renderBeginTag($writer)
6340
	{
6341
		$this->getControl()->renderBeginTag($writer);
6342
	}
6343
	public function renderContents($writer)
6344
	{
6345
		$this->getControl()->renderContents($writer);
6346
	}
6347
	public function renderEndTag($writer)
6348
	{
6349
		$this->getControl()->renderEndTag($writer);
6350
	}
6351
}
6352
class TWebControlDecorator extends TComponent {
6353
	private $_internalonly;
6354
	private $_usestate = false;
6355
	private $_control;
6356
	private $_outercontrol;
6357
	private $_addedTemplateDecoration=false;
6358
	private $_pretagtext = '';
6359
	private $_precontentstext = '';
6360
	private $_postcontentstext = '';
6361
	private $_posttagtext = '';
6362
	private $_pretagtemplate;
6363
	private $_precontentstemplate;
6364
	private $_postcontentstemplate;
6365
	private $_posttagtemplate;
6366
	public function __construct($control, $onlyinternal = false) {
6367
		$this->_control = $control;
6368
		$this->_internalonly = $onlyinternal;
6369
	}
6370
	public function getUseState()
6371
	{
6372
		return $this->_usestate;
6373
	}
6374
	public function setUseState($value)
6375
	{
6376
		$this->_usestate = TPropertyValue::ensureBoolean($value);
6377
	}
6378
	public function getPreTagText() {
6379
		return $this->_pretagtext;
6380
	}
6381
	public function setPreTagText($value) {
6382
		if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
6383
			$this->_pretagtext = TPropertyValue::ensureString($value);
6384
	}
6385
	public function getPreContentsText() {
6386
		return $this->_precontentstext;
6387
	}
6388
	public function setPreContentsText($value) {
6389
		if(!$this->_control->getIsSkinApplied())
6390
			$this->_precontentstext = TPropertyValue::ensureString($value);
6391
	}
6392
	public function getPostContentsText() {
6393
		return $this->_postcontentstext;
6394
	}
6395
	public function setPostContentsText($value) {
6396
		if(!$this->_control->getIsSkinApplied())
6397
			$this->_postcontentstext = TPropertyValue::ensureString($value);
6398
	}
6399
	public function getPostTagText() {
6400
		return $this->_posttagtext;
6401
	}
6402
	public function setPostTagText($value) {
6403
		if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
6404
			$this->_posttagtext = TPropertyValue::ensureString($value);
6405
	}
6406
	public function getPreTagTemplate() {
6407
		return $this->_pretagtemplate;
6408
	}
6409
	public function setPreTagTemplate($value) {
6410
		if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
6411
			$this->_pretagtemplate = $value;
6412
	}
6413
	public function getPreContentsTemplate() {
6414
		return $this->_precontentstemplate;
6415
	}
6416
	public function setPreContentsTemplate($value) {
6417
		if(!$this->_control->getIsSkinApplied())
6418
			$this->_precontentstemplate = $value;
6419
	}
6420
	public function getPostContentsTemplate() {
6421
		return $this->_postcontentstemplate;
6422
	}
6423
	public function setPostContentsTemplate($value) {
6424
		if(!$this->_control->getIsSkinApplied())
6425
			$this->_postcontentstemplate = $value;
6426
	}
6427
	public function getPostTagTemplate() {
6428
		return $this->_posttagtemplate;
6429
	}
6430
	public function setPostTagTemplate($value) {
6431
		if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
6432
			$this->_posttagtemplate = $value;
6433
	}
6434
	public function instantiate($outercontrol = null) {
6435
		if($this->getPreTagTemplate() || $this->getPreContentsTemplate() ||
6436
			$this->getPostContentsTemplate() || $this->getPostTagTemplate()) {
6437
			$this->_outercontrol = $outercontrol;
6438
			if($this->getUseState())
6439
				$this->ensureTemplateDecoration();
6440
			else
6441
				$this->_control->getPage()->onSaveStateComplete[] = array($this, 'ensureTemplateDecoration');
6442
		}
6443
	}
6444
	public function ensureTemplateDecoration($sender=null, $param=null) {
6445
		$control = $this->_control;
6446
		$outercontrol = $this->_outercontrol;
6447
		if($outercontrol === null)
6448
			$outercontrol = $control;
6449
		if($this->_addedTemplateDecoration)
6450
			return $this->_addedTemplateDecoration;
6451
		$this->_addedTemplateDecoration = true;
6452
		if($this->getPreContentsTemplate())
6453
		{
6454
			$precontents = Prado::createComponent('TCompositeControl');
6455
			$this->getPreContentsTemplate()->instantiateIn($precontents);
6456
			$control->getControls()->insertAt(0, $precontents);
6457
		}
6458
		if($this->getPostContentsTemplate())
6459
		{
6460
			$postcontents = Prado::createComponent('TCompositeControl');
6461
			$this->getPostContentsTemplate()->instantiateIn($postcontents);
6462
			$control->getControls()->add($postcontents);
6463
		}
6464
		if(!$outercontrol->getParent())
6465
			return $this->_addedTemplateDecoration;
6466
		if($this->getPreTagTemplate())
6467
		{
6468
			$pretag = Prado::createComponent('TCompositeControl');
6469
			$this->getPreTagTemplate()->instantiateIn($pretag);
6470
			$outercontrol->getParent()->getControls()->insertBefore($outercontrol, $pretag);
6471
		}
6472
		if($this->getPostTagTemplate())
6473
		{
6474
			$posttag = Prado::createComponent('TCompositeControl');
6475
			$this->getPostTagTemplate()->instantiateIn($posttag);
6476
			$outercontrol->getParent()->getControls()->insertAfter($outercontrol, $posttag);
6477
		}
6478
		return true;
6479
	}
6480
	public function renderPreTagText($writer) {
6481
		$writer->write($this->getPreTagText());
6482
	}
6483
	public function renderPreContentsText($writer) {
6484
		$writer->write($this->getPreContentsText());
6485
	}
6486
	public function renderPostContentsText($writer) {
6487
		$writer->write($this->getPostContentsText());
6488
	}
6489
	public function renderPostTagText($writer) {
6490
		$writer->write($this->getPostTagText());
6491
	}
6492
}
6493
class TWebControl extends TControl implements IStyleable
6494
{
6495
	private $_ensureid=false;
6496
	protected $_decorator;
6497
	public function setEnsureId($value)
6498
	{
6499
		$this->_ensureid |= TPropertyValue::ensureBoolean($value);
6500
	}
6501
	public function getEnsureId()
6502
	{
6503
		return $this->_ensureid;
6504
	}
6505
	public function getDecorator($create=true)
6506
	{
6507
		if($create && !$this->_decorator)
6508
			$this->_decorator = Prado::createComponent('TWebControlDecorator', $this);
6509
		return $this->_decorator;
6510
	}
6511
	public function copyBaseAttributes(TWebControl $control)
6512
	{
6513
		$this->setAccessKey($control->getAccessKey());
6514
		$this->setToolTip($control->getToolTip());
6515
		$this->setTabIndex($control->getTabIndex());
6516
		if(!$control->getEnabled())
6517
			$this->setEnabled(false);
6518
		if($control->getHasAttributes())
6519
			$this->getAttributes()->copyFrom($control->getAttributes());
6520
	}
6521
	public function getAccessKey()
6522
	{
6523
		return $this->getViewState('AccessKey','');
6524
	}
6525
	public function setAccessKey($value)
6526
	{
6527
		if(strlen($value)>1)
6528
			throw new TInvalidDataValueException('webcontrol_accesskey_invalid',get_class($this),$value);
6529
		$this->setViewState('AccessKey',$value,'');
6530
	}
6531
	public function getBackColor()
6532
	{
6533
		if($style=$this->getViewState('Style',null))
6534
			return $style->getBackColor();
6535
		else
6536
			return '';
6537
	}
6538
	public function setBackColor($value)
6539
	{
6540
		$this->getStyle()->setBackColor($value);
6541
	}
6542
	public function getBorderColor()
6543
	{
6544
		if($style=$this->getViewState('Style',null))
6545
			return $style->getBorderColor();
6546
		else
6547
			return '';
6548
	}
6549
	public function setBorderColor($value)
6550
	{
6551
		$this->getStyle()->setBorderColor($value);
6552
	}
6553
	public function getBorderStyle()
6554
	{
6555
		if($style=$this->getViewState('Style',null))
6556
			return $style->getBorderStyle();
6557
		else
6558
			return '';
6559
	}
6560
	public function setBorderStyle($value)
6561
	{
6562
		$this->getStyle()->setBorderStyle($value);
6563
	}
6564
	public function getBorderWidth()
6565
	{
6566
		if($style=$this->getViewState('Style',null))
6567
			return $style->getBorderWidth();
6568
		else
6569
			return '';
6570
	}
6571
	public function setBorderWidth($value)
6572
	{
6573
		$this->getStyle()->setBorderWidth($value);
6574
	}
6575
	public function getFont()
6576
	{
6577
		return $this->getStyle()->getFont();
6578
	}
6579
	public function getForeColor()
6580
	{
6581
		if($style=$this->getViewState('Style',null))
6582
			return $style->getForeColor();
6583
		else
6584
			return '';
6585
	}
6586
	public function setForeColor($value)
6587
	{
6588
		$this->getStyle()->setForeColor($value);
6589
	}
6590
	public function getHeight()
6591
	{
6592
		if($style=$this->getViewState('Style',null))
6593
			return $style->getHeight();
6594
		else
6595
			return '';
6596
	}
6597
	public function setDisplay($value)
6598
	{
6599
		$this->getStyle()->setDisplayStyle($value);
6600
	}
6601
	public function getDisplay()
6602
	{
6603
		return $this->getStyle()->getDisplayStyle();
6604
	}
6605
	public function setCssClass($value)
6606
	{
6607
		$this->getStyle()->setCssClass($value);
6608
	}
6609
	public function getCssClass()
6610
	{
6611
		if($style=$this->getViewState('Style',null))
6612
			return $style->getCssClass();
6613
		else
6614
			return '';
6615
	}
6616
	public function setHeight($value)
6617
	{
6618
		$this->getStyle()->setHeight($value);
6619
	}
6620
	public function getHasStyle()
6621
	{
6622
		return $this->getViewState('Style',null)!==null;
6623
	}
6624
	protected function createStyle()
6625
	{
6626
		return new TStyle;
6627
	}
6628
	public function getStyle()
6629
	{
6630
		if($style=$this->getViewState('Style',null))
6631
			return $style;
6632
		else
6633
		{
6634
			$style=$this->createStyle();
6635
			$this->setViewState('Style',$style,null);
6636
			return $style;
6637
		}
6638
	}
6639
	public function setStyle($value)
6640
	{
6641
		if(is_string($value))
6642
			$this->getStyle()->setCustomStyle($value);
6643
		else
6644
			throw new TInvalidDataValueException('webcontrol_style_invalid',get_class($this));
6645
	}
6646
	public function clearStyle()
6647
	{
6648
		$this->clearViewState('Style');
6649
	}
6650
	public function getTabIndex()
6651
	{
6652
		return $this->getViewState('TabIndex',0);
6653
	}
6654
	public function setTabIndex($value)
6655
	{
6656
		$this->setViewState('TabIndex',TPropertyValue::ensureInteger($value),0);
6657
	}
6658
	protected function getTagName()
6659
	{
6660
		return 'span';
6661
	}
6662
	public function getToolTip()
6663
	{
6664
		return $this->getViewState('ToolTip','');
6665
	}
6666
	public function setToolTip($value)
6667
	{
6668
		$this->setViewState('ToolTip',$value,'');
6669
	}
6670
	public function getWidth()
6671
	{
6672
		if($style=$this->getViewState('Style',null))
6673
			return $style->getWidth();
6674
		else
6675
			return '';
6676
	}
6677
	public function setWidth($value)
6678
	{
6679
		$this->getStyle()->setWidth($value);
6680
	}
6681
	public function onPreRender($param) {
6682
		if($decorator = $this->getDecorator(false))
6683
			$decorator->instantiate();
6684
		parent::onPreRender($param);
6685
	}
6686
	protected function addAttributesToRender($writer)
6687
	{
6688
		if($this->getID()!=='' || $this->getEnsureId())
6689
			$writer->addAttribute('id',$this->getClientID());
6690
		if(($accessKey=$this->getAccessKey())!=='')
6691
			$writer->addAttribute('accesskey',$accessKey);
6692
		if(!$this->getEnabled())
6693
			$writer->addAttribute('disabled','disabled');
6694
		if(($tabIndex=$this->getTabIndex())>0)
6695
			$writer->addAttribute('tabindex',"$tabIndex");
6696
		if(($toolTip=$this->getToolTip())!=='')
6697
			$writer->addAttribute('title',$toolTip);
6698
		if($style=$this->getViewState('Style',null))
6699
			$style->addAttributesToRender($writer);
6700
		if($this->getHasAttributes())
6701
		{
6702
			foreach($this->getAttributes() as $name=>$value)
6703
				$writer->addAttribute($name,$value);
6704
		}
6705
	}
6706
	public function render($writer)
6707
	{
6708
		$this->renderBeginTag($writer);
6709
		$this->renderContents($writer);
6710
		$this->renderEndTag($writer);
6711
	}
6712
	public function renderBeginTag($writer)
6713
	{
6714
		if($decorator = $this->getDecorator(false)) {
6715
			$decorator->renderPreTagText($writer);
6716
			$this->addAttributesToRender($writer);
6717
			$writer->renderBeginTag($this->getTagName());
6718
			$decorator->renderPreContentsText($writer);
6719
		} else {
6720
			$this->addAttributesToRender($writer);
6721
			$writer->renderBeginTag($this->getTagName());
6722
		}
6723
	}
6724
	public function renderContents($writer)
6725
	{
6726
		parent::renderChildren($writer);
6727
	}
6728
	public function renderEndTag($writer)
6729
	{
6730
		if($decorator = $this->getDecorator(false)) {
6731
			$decorator->renderPostContentsText($writer);
6732
			$writer->renderEndTag();
6733
			$decorator->renderPostTagText($writer);
6734
		} else
6735
			$writer->renderEndTag($writer);
6736
	}
6737
}
6738
class TCompositeControl extends TControl implements INamingContainer
6739
{
6740
	protected function initRecursive($namingContainer=null)
6741
	{
6742
		$this->ensureChildControls();
6743
		parent::initRecursive($namingContainer);
6744
	}
6745
}
6746
class TTemplateControl extends TCompositeControl
6747
{
6748
	const EXT_TEMPLATE='.tpl';
6749
	private static $_template=array();
6750
	private $_localTemplate=null;
6751
	private $_master=null;
6752
	private $_masterClass='';
6753
	private $_contents=array();
6754
	private $_placeholders=array();
6755
	public function getTemplate()
6756
	{
6757
		if($this->_localTemplate===null)
6758
		{
6759
			$class=get_class($this);
6760
			if(!isset(self::$_template[$class]))
6761
				self::$_template[$class]=$this->loadTemplate();
6762
			return self::$_template[$class];
6763
		}
6764
		else
6765
			return $this->_localTemplate;
6766
	}
6767
	public function setTemplate($value)
6768
	{
6769
		$this->_localTemplate=$value;
6770
	}
6771
	public function getIsSourceTemplateControl()
6772
	{
6773
		if(($template=$this->getTemplate())!==null)
6774
			return $template->getIsSourceTemplate();
6775
		else
6776
			return false;
6777
	}
6778
	public function getTemplateDirectory()
6779
	{
6780
		if(($template=$this->getTemplate())!==null)
6781
			return $template->getContextPath();
6782
		else
6783
			return '';
6784
	}
6785
	protected function loadTemplate()
6786
	{
6787
		$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...
6788
		return $template;
6789
	}
6790
	public function createChildControls()
6791
	{
6792
		if($tpl=$this->getTemplate())
6793
		{
6794
			foreach($tpl->getDirective() as $name=>$value)
6795
			{
6796
				if(is_string($value))
6797
					$this->setSubProperty($name,$value);
6798
				else
6799
					throw new TConfigurationException('templatecontrol_directive_invalid',get_class($this),$name);
6800
			}
6801
			$tpl->instantiateIn($this);
6802
		}
6803
	}
6804
	public function registerContent($id,TContent $object)
6805
	{
6806
		if(isset($this->_contents[$id]))
6807
			throw new TConfigurationException('templatecontrol_contentid_duplicated',$id);
6808
		else
6809
			$this->_contents[$id]=$object;
6810
	}
6811
	public function registerContentPlaceHolder($id,TContentPlaceHolder $object)
6812
	{
6813
		if(isset($this->_placeholders[$id]))
6814
			throw new TConfigurationException('templatecontrol_placeholderid_duplicated',$id);
6815
		else
6816
			$this->_placeholders[$id]=$object;
6817
	}
6818
	public function getMasterClass()
6819
	{
6820
		return $this->_masterClass;
6821
	}
6822
	public function setMasterClass($value)
6823
	{
6824
		$this->_masterClass=$value;
6825
	}
6826
	public function getMaster()
6827
	{
6828
		return $this->_master;
6829
	}
6830
	public function injectContent($id,$content)
6831
	{
6832
		if(isset($this->_placeholders[$id]))
6833
		{
6834
			$placeholder=$this->_placeholders[$id];
6835
			$controls=$placeholder->getParent()->getControls();
6836
			$loc=$controls->remove($placeholder);
6837
			$controls->insertAt($loc,$content);
6838
		}
6839
		else
6840
			throw new TConfigurationException('templatecontrol_placeholder_inexistent',$id);
6841
	}
6842
	protected function initRecursive($namingContainer=null)
6843
	{
6844
		$this->ensureChildControls();
6845
		if($this->_masterClass!=='')
6846
		{
6847
			$master=Prado::createComponent($this->_masterClass);
6848
			if(!($master instanceof TTemplateControl))
6849
				throw new TInvalidDataValueException('templatecontrol_mastercontrol_invalid');
6850
			$this->_master=$master;
6851
			$this->getControls()->clear();
6852
			$this->getControls()->add($master);
6853
			$master->ensureChildControls();
6854
			foreach($this->_contents as $id=>$content)
6855
				$master->injectContent($id,$content);
6856
		}
6857
		else if(!empty($this->_contents))
6858
			throw new TConfigurationException('templatecontrol_mastercontrol_required',get_class($this));
6859
		parent::initRecursive($namingContainer);
6860
	}
6861
        public function tryToUpdateView($arObj, $throwExceptions = false)
6862
        {
6863
                $objAttrs = get_class_vars(get_class($arObj));
6864
                foreach (array_keys($objAttrs) as $key)
6865
                {
6866
                        try
6867
                        {
6868
                                if ($key != "RELATIONS")
6869
                                {
6870
                                        $control = $this->{$key};
6871
                                        if ($control instanceof TTextBox)
6872
                                                $control->Text = $arObj->{$key};
6873
                                        elseif ($control instanceof TCheckBox)
6874
                                                $control->Checked = (boolean) $arObj->{$key};
6875
                                        elseif ($control instanceof TDatePicker)
6876
                                                $control->Date = $arObj->{$key};
6877
                                }
6878
                                else
6879
                                {
6880
                                        foreach ($objAttrs["RELATIONS"] as $relKey => $relValues)
6881
                                        {
6882
                                                $relControl = $this->{$relKey};
6883
                                                switch ($relValues[0])
6884
                                                {
6885
                                                        case TActiveRecord::BELONGS_TO:
6886
                                                        case TActiveRecord::HAS_ONE:
6887
                                                                $relControl->Text = $arObj->{$relKey};
6888
                                                                break;
6889
                                                        case TActiveRecord::HAS_MANY:
6890
                                                                if ($relControl instanceof TListControl)
6891
                                                                {
6892
                                                                        $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...
6893
                                                                        $relControl->dataBind();
6894
                                                                }
6895
                                                                break;
6896
                                                }
6897
                                        }
6898
                                        break;
6899
                                }
6900
                        } 
6901
                        catch (Exception $ex)
6902
                        {
6903
                                if ($throwExceptions)
6904
                                        throw $ex;
6905
                        }
6906
                }
6907
        }
6908
        public function tryToUpdateAR($arObj, $throwExceptions = false)
6909
        {
6910
                $objAttrs = get_class_vars(get_class($arObj));
6911
                foreach (array_keys($objAttrs) as $key)
6912
                {
6913
                        try
6914
                        {
6915
                                if ($key == "RELATIONS")
6916
                                        break;
6917
                                $control = $this->{$key};
6918
                                if ($control instanceof TTextBox)
6919
                                        $arObj->{$key} = $control->Text;
6920
                                elseif ($control instanceof TCheckBox)
6921
                                        $arObj->{$key} = $control->Checked;
6922
                                elseif ($control instanceof TDatePicker)
6923
                                        $arObj->{$key} = $control->Date;
6924
                        } 
6925
                        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...
6926
                        {
6927
                                if ($throwExceptions)
6928
                                        throw $ex;
6929
                        }
6930
                }
6931
        }
6932
}
6933
class TForm extends TControl
6934
{
6935
	public function onInit($param)
6936
	{
6937
		parent::onInit($param);
6938
		$this->getPage()->setForm($this);
6939
	}
6940
	protected function addAttributesToRender($writer)
6941
	{
6942
		$writer->addAttribute('id',$this->getClientID());
6943
		$writer->addAttribute('method',$this->getMethod());
6944
		$uri=$this->getRequest()->getRequestURI();
6945
		$writer->addAttribute('action',str_replace('&','&amp;',str_replace('&amp;','&',$uri)));
6946
		if(($enctype=$this->getEnctype())!=='')
6947
			$writer->addAttribute('enctype',$enctype);
6948
		$attributes=$this->getAttributes();
6949
		$attributes->remove('action');
6950
		$writer->addAttributes($attributes);
6951
		if(($butt=$this->getDefaultButton())!=='')
6952
		{
6953
			if(($button=$this->findControl($butt))!==null)
6954
				$this->getPage()->getClientScript()->registerDefaultButton($this, $button);
6955
			else
6956
				throw new TInvalidDataValueException('form_defaultbutton_invalid',$butt);
6957
		}
6958
	}
6959
	public function render($writer)
6960
	{
6961
		$page=$this->getPage();
6962
		$this->addAttributesToRender($writer);
6963
		$writer->renderBeginTag('form');
6964
		$cs=$page->getClientScript();
6965
		if($page->getClientSupportsJavaScript())
6966
		{
6967
			$cs->renderHiddenFieldsBegin($writer);
6968
			$cs->renderScriptFilesBegin($writer);
6969
			$cs->renderBeginScripts($writer);
6970
 			$page->beginFormRender($writer);
6971
 			$this->renderChildren($writer);
6972
			$cs->renderHiddenFieldsEnd($writer);
6973
 			$page->endFormRender($writer);
6974
			$cs->renderScriptFilesEnd($writer);
6975
			$cs->renderEndScripts($writer);
6976
		}
6977
		else
6978
		{
6979
			$cs->renderHiddenFieldsBegin($writer);
6980
			$page->beginFormRender($writer);
6981
			$this->renderChildren($writer);
6982
			$page->endFormRender($writer);
6983
			$cs->renderHiddenFieldsEnd($writer);
6984
		}
6985
		$writer->renderEndTag();
6986
	}
6987
	public function getDefaultButton()
6988
	{
6989
		return $this->getViewState('DefaultButton','');
6990
	}
6991
	public function setDefaultButton($value)
6992
	{
6993
		$this->setViewState('DefaultButton',$value,'');
6994
	}
6995
	public function getMethod()
6996
	{
6997
		return $this->getViewState('Method','post');
6998
	}
6999
	public function setMethod($value)
7000
	{
7001
		$this->setViewState('Method',TPropertyValue::ensureEnum($value,'post','get'),'post');
7002
	}
7003
	public function getEnctype()
7004
	{
7005
		return $this->getViewState('Enctype','');
7006
	}
7007
	public function setEnctype($value)
7008
	{
7009
		$this->setViewState('Enctype',$value,'');
7010
	}
7011
	public function getName()
7012
	{
7013
		return $this->getUniqueID();
7014
	}
7015
}
7016
class TClientScriptManager extends TApplicationComponent
7017
{
7018
	const SCRIPT_PATH='Web/Javascripts/source';
7019
	const PACKAGES_FILE='Web/Javascripts/packages.php';
7020
	const CSS_PACKAGES_FILE='Web/Javascripts/css-packages.php';
7021
	private $_page;
7022
	private $_hiddenFields=array();
7023
	private $_beginScripts=array();
7024
	private $_endScripts=array();
7025
	private $_scriptFiles=array();
7026
	private $_headScriptFiles=array();
7027
	private $_headScripts=array();
7028
	private $_styleSheetFiles=array();
7029
	private $_styleSheets=array();
7030
	private $_registeredPradoScripts=array();
7031
	private static $_pradoScripts;
7032
	private static $_pradoPackages;
7033
	private $_registeredPradoStyles=array();
7034
	private static $_pradoStyles;
7035
	private static $_pradoStylePackages;
7036
	private $_renderedHiddenFields;
7037
	private $_renderedScriptFiles=array();
7038
	private $_expandedPradoScripts;
7039
	private $_expandedPradoStyles;
7040
	public function __construct(TPage $owner)
7041
	{
7042
		$this->_page=$owner;
7043
	}
7044
	public function getRequiresHead()
7045
	{
7046
		return count($this->_styleSheetFiles) || count($this->_styleSheets)
7047
			|| count($this->_headScriptFiles) || count($this->_headScripts);
7048
	}
7049
	public static function getPradoPackages()
7050
	{
7051
		return self::$_pradoPackages;
7052
	}
7053
	public static function getPradoScripts()
7054
	{
7055
		return self::$_pradoScripts;
7056
	}
7057
	public function registerPradoScript($name)
7058
	{
7059
		$this->registerPradoScriptInternal($name);
7060
		$params=func_get_args();
7061
		$this->_page->registerCachingAction('Page.ClientScript','registerPradoScript',$params);
7062
	}
7063
	protected function registerPradoScriptInternal($name)
7064
	{
7065
				if(!isset($this->_registeredPradoScripts[$name]))
7066
		{
7067
			if(self::$_pradoScripts === null)
7068
			{
7069
				$packageFile = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::PACKAGES_FILE;
7070
				list($packages,$deps)= include($packageFile);
7071
				self::$_pradoScripts = $deps;
7072
				self::$_pradoPackages = $packages;
7073
			}
7074
			if (isset(self::$_pradoScripts[$name]))
7075
				$this->_registeredPradoScripts[$name]=true;
7076
			else
7077
				throw new TInvalidOperationException('csmanager_pradoscript_invalid',$name);
7078
			if(($packages=array_keys($this->_registeredPradoScripts))!==array())
7079
			{
7080
				$base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
7081
				list($path,$baseUrl)=$this->getPackagePathUrl($base);
7082
				$packagesUrl=array();
7083
				$isDebug=$this->getApplication()->getMode()===TApplicationMode::Debug;
7084
				foreach ($packages as $p)
7085
				{
7086
					foreach (self::$_pradoScripts[$p] as $dep)
7087
					{
7088
						foreach (self::$_pradoPackages[$dep] as $script)
7089
						if (!isset($this->_expandedPradoScripts[$script]))
7090
						{
7091
							$this->_expandedPradoScripts[$script] = true;
7092
							if($isDebug)
7093
							{
7094
								if (!in_array($url=$baseUrl.'/'.$script,$packagesUrl))
7095
									$packagesUrl[]=$url;
7096
							} else {
7097
								if (!in_array($url=$baseUrl.'/min/'.$script,$packagesUrl))
7098
								{
7099
									if(!is_file($filePath=$path.'/min/'.$script))
7100
									{
7101
										$dirPath=dirname($filePath);
7102
										if(!is_dir($dirPath))
7103
											mkdir($dirPath, PRADO_CHMOD, true);
7104
										file_put_contents($filePath, TJavaScript::JSMin(file_get_contents($base.'/'.$script)));
7105
										chmod($filePath, PRADO_CHMOD);
7106
									}
7107
									$packagesUrl[]=$url;
7108
								}
7109
							}
7110
						}
7111
					}
7112
				}
7113
				foreach($packagesUrl as $url)
7114
					$this->registerScriptFile($url,$url);
7115
			}
7116
		}
7117
	}
7118
	public function getPradoScriptAssetUrl()
7119
	{
7120
		$base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
7121
		$assets = Prado::getApplication()->getAssetManager();
7122
		return $assets->getPublishedUrl($base);
7123
	}
7124
	public function getScriptUrls()
7125
	{
7126
		$scripts = array_values($this->_headScriptFiles);
7127
		$scripts = array_merge($scripts, array_values($this->_scriptFiles));
7128
		$scripts = array_unique($scripts);
7129
		return $scripts;
7130
	}
7131
	protected function getPackagePathUrl($base)
7132
	{
7133
		$assets = Prado::getApplication()->getAssetManager();
7134
		if(strpos($base, $assets->getBaseUrl())===false)
7135
		{
7136
			if(($dir = Prado::getPathOfNameSpace($base)) !== null) {
7137
				$base = $dir;
7138
			}
7139
			return array($assets->getPublishedPath($base), $assets->publishFilePath($base));
7140
		}
7141
		else
7142
		{
7143
			return array($assets->getBasePath().str_replace($assets->getBaseUrl(),'',$base), $base);
7144
		}
7145
	}
7146
	public function getCallbackReference(ICallbackEventHandler $callbackHandler, $options=null)
7147
	{
7148
		$options = !is_array($options) ? array() : $options;
7149
		$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...
7150
		$clientSide = $callbackHandler->getActiveControl()->getClientSide();
7151
		$options = array_merge($options, $clientSide->getOptions()->toArray());
7152
		$optionString = TJavaScript::encode($options);
7153
		$this->registerPradoScriptInternal('ajax');
7154
		$id = $callbackHandler->getUniqueID();
7155
		return "new Prado.CallbackRequest('{$id}',{$optionString})";
7156
	}
7157
	public function registerCallbackControl($class, $options)
7158
	{
7159
		$optionString=TJavaScript::encode($options);
7160
		$code="new {$class}({$optionString});";
7161
		$this->_endScripts[sprintf('%08X', crc32($code))]=$code;
7162
		$this->registerPradoScriptInternal('ajax');
7163
		$params=func_get_args();
7164
		$this->_page->registerCachingAction('Page.ClientScript','registerCallbackControl',$params);
7165
	}
7166
	public function registerPostBackControl($class,$options)
7167
	{
7168
		if($class === null) {
7169
			return;
7170
		}
7171
		if(!isset($options['FormID']) && ($form=$this->_page->getForm())!==null)
7172
			$options['FormID']=$form->getClientID();
7173
		$optionString=TJavaScript::encode($options);
7174
		$code="new {$class}({$optionString});";
7175
		$this->_endScripts[sprintf('%08X', crc32($code))]=$code;
7176
		$this->registerPradoScriptInternal('prado');
7177
		$params=func_get_args();
7178
		$this->_page->registerCachingAction('Page.ClientScript','registerPostBackControl',$params);
7179
	}
7180
	public function registerDefaultButton($panel, $button)
7181
	{
7182
		$panelID=is_string($panel)?$panel:$panel->getUniqueID();
7183
		if(is_string($button))
7184
			$buttonID=$button;
7185
		else
7186
		{
7187
			$button->setIsDefaultButton(true);
7188
			$buttonID=$button->getUniqueID();
7189
		}
7190
		$options = TJavaScript::encode($this->getDefaultButtonOptions($panelID, $buttonID));
7191
		$code = "new Prado.WebUI.DefaultButton($options);";
7192
		$this->_endScripts['prado:'.$panelID]=$code;
7193
		$this->registerPradoScriptInternal('prado');
7194
		$params=array($panelID,$buttonID);
7195
		$this->_page->registerCachingAction('Page.ClientScript','registerDefaultButton',$params);
7196
	}
7197
	protected function getDefaultButtonOptions($panelID, $buttonID)
7198
	{
7199
		$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...
7200
		$options['Panel'] = TControl::convertUniqueIdToClientId($panelID);
7201
		$options['Target'] = TControl::convertUniqueIdToClientId($buttonID);
7202
		$options['EventTarget'] = $buttonID;
7203
		$options['Event'] = 'click';
7204
		return $options;
7205
	}
7206
	public function registerFocusControl($target)
7207
	{
7208
		$this->registerPradoScriptInternal('jquery');
7209
		if($target instanceof TControl)
7210
			$target=$target->getClientID();
7211
		$this->_endScripts['prado:focus'] = 'jQuery(\'#'.$target.'\').focus();';
7212
		$params=func_get_args();
7213
		$this->_page->registerCachingAction('Page.ClientScript','registerFocusControl',$params);
7214
	}
7215
	public function registerPradoStyle($name)
7216
	{
7217
		$this->registerPradoStyleInternal($name);
7218
		$params=func_get_args();
7219
		$this->_page->registerCachingAction('Page.ClientScript','registerPradoStyle',$params);
7220
	}
7221
	protected function registerPradoStyleInternal($name)
7222
	{
7223
				if(!isset($this->_registeredPradoStyles[$name]))
7224
		{
7225
			$base = $this->getPradoScriptAssetUrl();
7226
			if(self::$_pradoStyles === null)
7227
			{
7228
				$packageFile = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::CSS_PACKAGES_FILE;
7229
				list($packages,$deps)= include($packageFile);
7230
				self::$_pradoStyles = $deps;
7231
				self::$_pradoStylePackages = $packages;
7232
			}
7233
			if (isset(self::$_pradoStyles[$name]))
7234
				$this->_registeredPradoStyles[$name]=true;
7235
			else
7236
				throw new TInvalidOperationException('csmanager_pradostyle_invalid',$name);
7237
			if(($packages=array_keys($this->_registeredPradoStyles))!==array())
7238
			{
7239
				$base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
7240
				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...
7241
				$packagesUrl=array();
7242
				$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...
7243
				foreach ($packages as $p)
7244
				{
7245
					foreach (self::$_pradoStyles[$p] as $dep)
7246
					{
7247
						foreach (self::$_pradoStylePackages[$dep] as $style)
7248
						if (!isset($this->_expandedPradoStyles[$style]))
7249
						{
7250
							$this->_expandedPradoStyles[$style] = true;
7251
														if (!in_array($url=$baseUrl.'/'.$style,$packagesUrl))
7252
								$packagesUrl[]=$url;
7253
						}
7254
					}
7255
				}
7256
				foreach($packagesUrl as $url)
7257
					$this->registerStyleSheetFile($url,$url);
7258
			}
7259
		}
7260
	}
7261
	public function registerStyleSheetFile($key,$url,$media='')
7262
	{
7263
		if($media==='')
7264
			$this->_styleSheetFiles[$key]=$url;
7265
		else
7266
			$this->_styleSheetFiles[$key]=array($url,$media);
7267
		$params=func_get_args();
7268
		$this->_page->registerCachingAction('Page.ClientScript','registerStyleSheetFile',$params);
7269
	}
7270
	public function registerStyleSheet($key,$css,$media='')
7271
	{
7272
		$this->_styleSheets[$key]=$css;
7273
		$params=func_get_args();
7274
		$this->_page->registerCachingAction('Page.ClientScript','registerStyleSheet',$params);
7275
	}
7276
	public function getStyleSheetUrls()
7277
	{
7278
		$stylesheets = array_values(
7279
			array_map(function($e) {
7280
				return is_array($e) ? $e[0] : $e;
7281
			}, $this->_styleSheetFiles)
7282
		);
7283
		foreach(Prado::getApplication()->getAssetManager()->getPublished() as $path=>$url)
7284
			if (substr($url,strlen($url)-4)=='.css')
7285
				$stylesheets[] = $url;
7286
		$stylesheets = array_unique($stylesheets);
7287
		return $stylesheets;
7288
	}
7289
	public function getStyleSheetCodes()
7290
	{
7291
		return array_unique(array_values($this->_styleSheets));
7292
	}
7293
	public function registerHeadScriptFile($key,$url)
7294
	{
7295
		$this->checkIfNotInRender();
7296
		$this->_headScriptFiles[$key]=$url;
7297
		$params=func_get_args();
7298
		$this->_page->registerCachingAction('Page.ClientScript','registerHeadScriptFile',$params);
7299
	}
7300
	public function registerHeadScript($key,$script)
7301
	{
7302
		$this->checkIfNotInRender();
7303
		$this->_headScripts[$key]=$script;
7304
		$params=func_get_args();
7305
		$this->_page->registerCachingAction('Page.ClientScript','registerHeadScript',$params);
7306
	}
7307
	public function registerScriptFile($key, $url)
7308
	{
7309
		$this->_scriptFiles[$key]=$url;
7310
		$params=func_get_args();
7311
		$this->_page->registerCachingAction('Page.ClientScript','registerScriptFile',$params);
7312
	}
7313
	public function registerBeginScript($key,$script)
7314
	{
7315
		$this->checkIfNotInRender();
7316
		$this->_beginScripts[$key]=$script;
7317
		$params=func_get_args();
7318
		$this->_page->registerCachingAction('Page.ClientScript','registerBeginScript',$params);
7319
	}
7320
	public function registerEndScript($key,$script)
7321
	{
7322
		$this->_endScripts[$key]=$script;
7323
		$params=func_get_args();
7324
		$this->_page->registerCachingAction('Page.ClientScript','registerEndScript',$params);
7325
	}
7326
	public function registerHiddenField($name,$value)
7327
	{
7328
		$this->_hiddenFields[$name]=$value;
7329
		$params=func_get_args();
7330
		$this->_page->registerCachingAction('Page.ClientScript','registerHiddenField',$params);
7331
	}
7332
	public function isStyleSheetFileRegistered($key)
7333
	{
7334
		return isset($this->_styleSheetFiles[$key]);
7335
	}
7336
	public function isStyleSheetRegistered($key)
7337
	{
7338
		return isset($this->_styleSheets[$key]);
7339
	}
7340
	public function isHeadScriptFileRegistered($key)
7341
	{
7342
		return isset($this->_headScriptFiles[$key]);
7343
	}
7344
	public function isHeadScriptRegistered($key)
7345
	{
7346
		return isset($this->_headScripts[$key]);
7347
	}
7348
	public function isScriptFileRegistered($key)
7349
	{
7350
		return isset($this->_scriptFiles[$key]);
7351
	}
7352
	public function isBeginScriptRegistered($key)
7353
	{
7354
		return isset($this->_beginScripts[$key]);
7355
	}
7356
	public function isEndScriptRegistered($key)
7357
	{
7358
		return isset($this->_endScripts[$key]);
7359
	}
7360
	public function hasEndScripts()
7361
	{
7362
		return count($this->_endScripts) > 0;
7363
	}
7364
	public function hasBeginScripts()
7365
	{
7366
		return count($this->_beginScripts) > 0;
7367
	}
7368
	public function isHiddenFieldRegistered($key)
7369
	{
7370
		return isset($this->_hiddenFields[$key]);
7371
	}
7372
	public function renderStyleSheetFiles($writer)
7373
	{
7374
		$str='';
7375
		foreach($this->_styleSheetFiles as $url)
7376
		{
7377
			if(is_array($url))
7378
				$str.="<link rel=\"stylesheet\" type=\"text/css\" media=\"{$url[1]}\" href=\"".THttpUtility::htmlEncode($url[0])."\" />\n";
7379
			else
7380
				$str.="<link rel=\"stylesheet\" type=\"text/css\" href=\"".THttpUtility::htmlEncode($url)."\" />\n";
7381
		}
7382
		$writer->write($str);
7383
	}
7384
	public function renderStyleSheets($writer)
7385
	{
7386
		if(count($this->_styleSheets))
7387
			$writer->write("<style type=\"text/css\">\n/*<![CDATA[*/\n".implode("\n",$this->_styleSheets)."\n/*]]>*/\n</style>\n");
7388
	}
7389
	public function renderHeadScriptFiles($writer)
7390
	{
7391
		$this->renderScriptFiles($writer,$this->_headScriptFiles);
7392
	}
7393
	public function renderHeadScripts($writer)
7394
	{
7395
		$writer->write(TJavaScript::renderScriptBlocks($this->_headScripts));
7396
	}
7397
	public function renderScriptFilesBegin($writer)
7398
	{
7399
		$this->renderAllPendingScriptFiles($writer);
7400
	}
7401
	public function renderScriptFilesEnd($writer)
7402
	{
7403
		$this->renderAllPendingScriptFiles($writer);
7404
	}
7405
	public function markScriptFileAsRendered($url)
7406
	{
7407
		$this->_renderedScriptFiles[$url] = $url;
7408
		$params=func_get_args();
7409
		$this->_page->registerCachingAction('Page.ClientScript','markScriptFileAsRendered',$params);
7410
	}
7411
	protected function renderScriptFiles($writer, Array $scripts)
7412
	{
7413
		foreach($scripts as $script)
7414
		{
7415
			$writer->write(TJavaScript::renderScriptFile($script));
7416
			$this->markScriptFileAsRendered($script);
7417
		}
7418
	}
7419
	protected function getRenderedScriptFiles()
7420
	{
7421
		return $this->_renderedScriptFiles;
7422
	}
7423
	public function renderAllPendingScriptFiles($writer)
7424
	{
7425
		if(!empty($this->_scriptFiles))
7426
		{
7427
			$addedScripts = array_diff($this->_scriptFiles,$this->getRenderedScriptFiles());
7428
			$this->renderScriptFiles($writer,$addedScripts);
7429
		}
7430
	}
7431
	public function renderBeginScripts($writer)
7432
	{
7433
		$writer->write(TJavaScript::renderScriptBlocks($this->_beginScripts));
7434
	}
7435
	public function renderEndScripts($writer)
7436
	{
7437
		$writer->write(TJavaScript::renderScriptBlocks($this->_endScripts));
7438
	}
7439
	public function renderBeginScriptsCallback($writer)
7440
	{
7441
		$writer->write(TJavaScript::renderScriptBlocksCallback($this->_beginScripts));
7442
	}
7443
	public function renderEndScriptsCallback($writer)
7444
	{
7445
		$writer->write(TJavaScript::renderScriptBlocksCallback($this->_endScripts));
7446
	}
7447
	public function renderHiddenFieldsBegin($writer)
7448
	{
7449
		$this->renderHiddenFieldsInt($writer,true);
7450
	}
7451
	public function renderHiddenFieldsEnd($writer)
7452
	{
7453
		$this->renderHiddenFieldsInt($writer,false);
7454
	}
7455
	public function flushScriptFiles($writer, $control=null)
7456
	{
7457
		if(!$this->_page->getIsCallback())
7458
		{
7459
			$this->_page->ensureRenderInForm($control);
7460
			$this->renderAllPendingScriptFiles($writer);
7461
		}
7462
	}
7463
	protected function renderHiddenFieldsInt($writer, $initial)
7464
 	{
7465
		if ($initial) $this->_renderedHiddenFields = array();
7466
		$str='';
7467
		foreach($this->_hiddenFields as $name=>$value)
7468
		{
7469
			if (in_array($name,$this->_renderedHiddenFields)) continue;
7470
			$id=strtr($name,':','_');
7471
			if(is_array($value))
7472
			{
7473
				foreach($value as $v)
7474
					$str.='<input type="hidden" name="'.$name.'[]" id="'.$id.'" value="'.THttpUtility::htmlEncode($value)."\" />\n";
7475
			}
7476
			else
7477
			{
7478
				$str.='<input type="hidden" name="'.$name.'" id="'.$id.'" value="'.THttpUtility::htmlEncode($value)."\" />\n";
7479
			}
7480
			$this->_renderedHiddenFields[] = $name;
7481
		}
7482
		if($str!=='')
7483
			$writer->write("<div style=\"visibility:hidden;\">\n".$str."</div>\n");
7484
	}
7485
	public function getHiddenFields()
7486
	{
7487
		return $this->_hiddenFields;
7488
	}
7489
	protected function checkIfNotInRender()
7490
	{
7491
		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...
7492
			throw new Exception('Operation invalid when page is already rendering');
7493
	}
7494
}
7495
abstract class TClientSideOptions extends TComponent
7496
{
7497
	private $_options;
7498
	protected function setFunction($name, $code)
7499
	{
7500
		if(!TJavaScript::isJsLiteral($code))
7501
			$code = TJavaScript::quoteJsLiteral($this->ensureFunction($code));
7502
		$this->setOption($name, $code);
7503
	}
7504
	protected function getOption($name)
7505
	{
7506
		if ($this->_options)
7507
			return $this->_options->itemAt($name);
7508
		else
7509
			return null;
7510
	}
7511
	protected function setOption($name, $value)
7512
	{
7513
		$this->getOptions()->add($name, $value);
7514
	}
7515
	public function getOptions()
7516
	{
7517
		if (!$this->_options)
7518
			$this->_options = Prado::createComponent('System.Collections.TMap');
7519
		return $this->_options;
7520
	}
7521
	protected function ensureFunction($javascript)
7522
	{
7523
		return "function(sender, parameter){ {$javascript} }";
7524
	}
7525
}
7526
class TPage extends TTemplateControl
7527
{
7528
	const FIELD_POSTBACK_TARGET='PRADO_POSTBACK_TARGET';
7529
	const FIELD_POSTBACK_PARAMETER='PRADO_POSTBACK_PARAMETER';
7530
	const FIELD_LASTFOCUS='PRADO_LASTFOCUS';
7531
	const FIELD_PAGESTATE='PRADO_PAGESTATE';
7532
	const FIELD_CALLBACK_TARGET='PRADO_CALLBACK_TARGET';
7533
	const FIELD_CALLBACK_PARAMETER='PRADO_CALLBACK_PARAMETER';
7534
	private static $_systemPostFields=array(
7535
		'PRADO_POSTBACK_TARGET'=>true,
7536
		'PRADO_POSTBACK_PARAMETER'=>true,
7537
		'PRADO_LASTFOCUS'=>true,
7538
		'PRADO_PAGESTATE'=>true,
7539
		'PRADO_CALLBACK_TARGET'=>true,
7540
		'PRADO_CALLBACK_PARAMETER'=>true
7541
	);
7542
	private $_form;
7543
	private $_head;
7544
	private $_validators=array();
7545
	private $_validated=false;
7546
	private $_theme;
7547
	private $_title;
7548
	private $_styleSheet;
7549
	private $_clientScript;
7550
	protected $_postData;
7551
	protected $_restPostData;
7552
	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...
7553
	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...
7554
	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...
7555
	private $_postBackEventTarget;
7556
	private $_postBackEventParameter;
7557
	protected $_formRendered=false;
7558
	protected $_inFormRender=false;
7559
	private $_focus;
7560
	private $_pagePath='';
7561
	private $_enableStateValidation=true;
7562
	private $_enableStateEncryption=false;
7563
	private $_enableStateCompression=true;
7564
	private $_statePersisterClass='System.Web.UI.TPageStatePersister';
7565
	private $_statePersister;
7566
	private $_cachingStack;
7567
	private $_clientState='';
7568
	protected $_isLoadingPostData=false;
7569
	private $_enableJavaScript=true;
7570
	private $_writer;
7571
	public function __construct()
7572
	{
7573
		$this->setPage($this);
7574
	}
7575
	public function run($writer)
7576
	{
7577
		$this->_writer = $writer;
7578
		$this->determinePostBackMode();
7579
		if($this->getIsPostBack())
7580
		{
7581
			if($this->getIsCallback())
7582
				$this->processCallbackRequest($writer);
7583
			else
7584
				$this->processPostBackRequest($writer);
7585
		}
7586
		else
7587
			$this->processNormalRequest($writer);
7588
		$this->_writer = null;
7589
	}
7590
	protected function processNormalRequest($writer)
7591
	{
7592
		$this->onPreInit(null);
7593
		$this->initRecursive();
7594
		$this->onInitComplete(null);
7595
		$this->onPreLoad(null);
7596
		$this->loadRecursive();
7597
		$this->onLoadComplete(null);
7598
		$this->preRenderRecursive();
7599
		$this->onPreRenderComplete(null);
7600
		$this->savePageState();
7601
		$this->onSaveStateComplete(null);
7602
		$this->renderControl($writer);
7603
		$this->unloadRecursive();
7604
	}
7605
	protected function processPostBackRequest($writer)
7606
	{
7607
		$this->onPreInit(null);
7608
		$this->initRecursive();
7609
		$this->onInitComplete(null);
7610
		$this->_restPostData=new TMap;
7611
		$this->loadPageState();
7612
		$this->processPostData($this->_postData,true);
7613
		$this->onPreLoad(null);
7614
		$this->loadRecursive();
7615
		$this->processPostData($this->_restPostData,false);
7616
		$this->raiseChangedEvents();
7617
		$this->raisePostBackEvent();
7618
		$this->onLoadComplete(null);
7619
		$this->preRenderRecursive();
7620
		$this->onPreRenderComplete(null);
7621
		$this->savePageState();
7622
		$this->onSaveStateComplete(null);
7623
		$this->renderControl($writer);
7624
		$this->unloadRecursive();
7625
	}
7626
	protected static function decodeUTF8($data, $enc)
7627
	{
7628
		if(is_array($data))
7629
		{
7630
			foreach($data as $k=>$v)
7631
				$data[$k]=self::decodeUTF8($v, $enc);
7632
			return $data;
7633
		} elseif(is_string($data)) {
7634
			return iconv('UTF-8',$enc.'//IGNORE',$data);
7635
		} else {
7636
			return $data;
7637
		}
7638
	}
7639
	protected function processCallbackRequest($writer)
7640
	{
7641
		Prado::using('System.Web.UI.ActiveControls.TActivePageAdapter');
7642
		Prado::using('System.Web.UI.JuiControls.TJuiControlOptions');
7643
		$this->setAdapter(new TActivePageAdapter($this));
7644
        $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...
7645
        if(strlen($callbackEventParameter) > 0)
7646
            $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...
7647
                if (($g=$this->getApplication()->getGlobalization(false))!==null &&
7648
            strtoupper($enc=$g->getCharset())!='UTF-8')
7649
                foreach ($this->_postData as $k=>$v)
7650
                	$this->_postData[$k]=self::decodeUTF8($v, $enc);
7651
		$this->onPreInit(null);
7652
		$this->initRecursive();
7653
		$this->onInitComplete(null);
7654
		$this->_restPostData=new TMap;
7655
		$this->loadPageState();
7656
		$this->processPostData($this->_postData,true);
7657
		$this->onPreLoad(null);
7658
		$this->loadRecursive();
7659
		$this->processPostData($this->_restPostData,false);
7660
		$this->raiseChangedEvents();
7661
		$this->getAdapter()->processCallbackEvent($writer);
7662
		$this->onLoadComplete(null);
7663
		$this->preRenderRecursive();
7664
		$this->onPreRenderComplete(null);
7665
		$this->savePageState();
7666
		$this->onSaveStateComplete(null);
7667
		$this->getAdapter()->renderCallbackResponse($writer);
7668
		$this->unloadRecursive();
7669
	}
7670
	public function getCallbackClient()
7671
	{
7672
		if($this->getAdapter() !== null)
7673
			return $this->getAdapter()->getCallbackClientHandler();
7674
		else
7675
			return new TCallbackClientScript();
7676
	}
7677
	public function setCallbackClient($client)
7678
	{
7679
		$this->getAdapter()->setCallbackClientHandler($client);
7680
	}
7681
	public function getCallbackEventTarget()
7682
	{
7683
		return $this->getAdapter()->getCallbackEventTarget();
7684
	}
7685
	public function setCallbackEventTarget(TControl $control)
7686
	{
7687
		$this->getAdapter()->setCallbackEventTarget($control);
7688
	}
7689
	public function getCallbackEventParameter()
7690
	{
7691
		return $this->getAdapter()->getCallbackEventParameter();
7692
	}
7693
	public function setCallbackEventParameter($value)
7694
	{
7695
		$this->getAdapter()->setCallbackEventParameter($value);
7696
	}
7697
	public function getForm()
7698
	{
7699
		return $this->_form;
7700
	}
7701
	public function setForm(TForm $form)
7702
	{
7703
		if($this->_form===null)
7704
			$this->_form=$form;
7705
		else
7706
			throw new TInvalidOperationException('page_form_duplicated');
7707
	}
7708
	public function getValidators($validationGroup=null)
7709
	{
7710
		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...
7711
			$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...
7712
		if(empty($validationGroup) === true)
7713
			return $this->_validators;
7714
		else
7715
		{
7716
			$list=new TList;
7717
			foreach($this->_validators as $validator)
7718
				if($validator->getValidationGroup()===$validationGroup)
7719
					$list->add($validator);
7720
			return $list;
7721
		}
7722
	}
7723
	public function validate($validationGroup=null)
7724
	{
7725
		$this->_validated=true;
7726
		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...
7727
		{
7728
			if($validationGroup===null)
7729
			{
7730
				foreach($this->_validators as $validator)
7731
					$validator->validate();
7732
			}
7733
			else
7734
			{
7735
				foreach($this->_validators as $validator)
7736
				{
7737
					if($validator->getValidationGroup()===$validationGroup)
7738
						$validator->validate();
7739
				}
7740
			}
7741
		}
7742
	}
7743
	public function getIsValid()
7744
	{
7745
		if($this->_validated)
7746
		{
7747
			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...
7748
			{
7749
				foreach($this->_validators as $validator)
7750
					if(!$validator->getIsValid())
7751
						return false;
7752
			}
7753
			return true;
7754
		}
7755
		else
7756
			throw new TInvalidOperationException('page_isvalid_unknown');
7757
	}
7758
	public function getTheme()
7759
	{
7760
		if(is_string($this->_theme))
7761
			$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...
7762
		return $this->_theme;
7763
	}
7764
	public function setTheme($value)
7765
	{
7766
		$this->_theme=empty($value)?null:$value;
7767
	}
7768
	public function getStyleSheetTheme()
7769
	{
7770
		if(is_string($this->_styleSheet))
7771
			$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...
7772
		return $this->_styleSheet;
7773
	}
7774
	public function setStyleSheetTheme($value)
7775
	{
7776
		$this->_styleSheet=empty($value)?null:$value;
7777
	}
7778
	public function applyControlSkin($control)
7779
	{
7780
		if(($theme=$this->getTheme())!==null)
7781
			$theme->applySkin($control);
7782
	}
7783
	public function applyControlStyleSheet($control)
7784
	{
7785
		if(($theme=$this->getStyleSheetTheme())!==null)
7786
			$theme->applySkin($control);
7787
	}
7788
	public function getClientScript()
7789
	{
7790
		if(!$this->_clientScript) {
7791
			$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...
7792
			Prado::using($className);
7793
			if(($pos=strrpos($className,'.'))!==false)
7794
				$className=substr($className,$pos+1);
7795
 			if(!class_exists($className,false) || ($className!=='TClientScriptManager' && !is_subclass_of($className,'TClientScriptManager')))
7796
				throw new THttpException(404,'page_csmanagerclass_invalid',$classPath);
7797
			$this->_clientScript=new $className($this);
7798
		}
7799
		return $this->_clientScript;
7800
	}
7801
	public function onPreInit($param)
7802
	{
7803
		$this->raiseEvent('OnPreInit',$this,$param);
7804
	}
7805
	public function onInitComplete($param)
7806
	{
7807
		$this->raiseEvent('OnInitComplete',$this,$param);
7808
	}
7809
	public function onPreLoad($param)
7810
	{
7811
		$this->raiseEvent('OnPreLoad',$this,$param);
7812
	}
7813
	public function onLoadComplete($param)
7814
	{
7815
		$this->raiseEvent('OnLoadComplete',$this,$param);
7816
	}
7817
	public function onPreRenderComplete($param)
7818
	{
7819
		$this->raiseEvent('OnPreRenderComplete',$this,$param);
7820
		$cs=$this->getClientScript();
7821
		$theme=$this->getTheme();
7822
		if($theme instanceof ITheme)
7823
		{
7824
			foreach($theme->getStyleSheetFiles() as $url)
7825
				$cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
7826
			foreach($theme->getJavaScriptFiles() as $url)
7827
				$cs->registerHeadScriptFile($url,$url);
7828
		}
7829
		$styleSheet=$this->getStyleSheetTheme();
7830
		if($styleSheet instanceof ITheme)
7831
		{
7832
			foreach($styleSheet->getStyleSheetFiles() as $url)
7833
				$cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
7834
			foreach($styleSheet->getJavaScriptFiles() as $url)
7835
				$cs->registerHeadScriptFile($url,$url);
7836
		}
7837
		if($cs->getRequiresHead() && $this->getHead()===null)
7838
			throw new TConfigurationException('page_head_required');
7839
	}
7840
	private function getCssMediaType($url)
7841
	{
7842
		$segs=explode('.',basename($url));
7843
		if(isset($segs[2]))
7844
			return $segs[count($segs)-2];
7845
		else
7846
			return '';
7847
	}
7848
	public function onSaveStateComplete($param)
7849
	{
7850
		$this->raiseEvent('OnSaveStateComplete',$this,$param);
7851
	}
7852
	private function determinePostBackMode()
7853
	{
7854
		$postData=$this->getRequest();
7855
		if($postData->contains(self::FIELD_PAGESTATE) || $postData->contains(self::FIELD_POSTBACK_TARGET))
7856
			$this->_postData=$postData;
7857
	}
7858
	public function getIsPostBack()
7859
	{
7860
		return $this->_postData!==null;
7861
	}
7862
	public function getIsCallback()
7863
	{
7864
		return $this->getIsPostBack() && $this->getRequest()->contains(self::FIELD_CALLBACK_TARGET);
7865
	}
7866
	public function saveState()
7867
	{
7868
		parent::saveState();
7869
		$this->setViewState('ControlsRequiringPostBack',$this->_controlsRegisteredForPostData,array());
7870
	}
7871
	public function loadState()
7872
	{
7873
		parent::loadState();
7874
		$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...
7875
	}
7876
	protected function loadPageState()
7877
	{
7878
		$state=$this->getStatePersister()->load();
7879
		$this->loadStateRecursive($state,$this->getEnableViewState());
7880
	}
7881
	protected function savePageState()
7882
	{
7883
		$state=&$this->saveStateRecursive($this->getEnableViewState());
7884
		$this->getStatePersister()->save($state);
7885
	}
7886
	protected function isSystemPostField($field)
7887
	{
7888
		return isset(self::$_systemPostFields[$field]);
7889
	}
7890
	public function registerRequiresPostData($control)
7891
	{
7892
		$id=is_string($control)?$control:$control->getUniqueID();
7893
		$this->_controlsRegisteredForPostData[$id]=true;
7894
		$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...
7895
		foreach($this->getCachingStack() as $item)
7896
			$item->registerAction('Page','registerRequiresPostData',array($id));
7897
	}
7898
	public function getPostBackEventTarget()
7899
	{
7900
		if($this->_postBackEventTarget===null && $this->_postData!==null)
7901
		{
7902
			$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...
7903
			if(!empty($eventTarget))
7904
				$this->_postBackEventTarget=$this->findControl($eventTarget);
7905
		}
7906
		return $this->_postBackEventTarget;
7907
	}
7908
	public function setPostBackEventTarget(TControl $control)
7909
	{
7910
		$this->_postBackEventTarget=$control;
7911
	}
7912
	public function getPostBackEventParameter()
7913
	{
7914
		if($this->_postBackEventParameter===null && $this->_postData!==null)
7915
		{
7916
			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...
7917
				$this->_postBackEventParameter='';
7918
		}
7919
		return $this->_postBackEventParameter;
7920
	}
7921
	public function setPostBackEventParameter($value)
7922
	{
7923
		$this->_postBackEventParameter=$value;
7924
	}
7925
	protected function processPostData($postData,$beforeLoad)
7926
	{
7927
		$this->_isLoadingPostData=true;
7928
		if($beforeLoad)
7929
			$this->_restPostData=new TMap;
7930
		foreach($postData as $key=>$value)
7931
		{
7932
			if($this->isSystemPostField($key))
7933
				continue;
7934
			else if($control=$this->findControl($key))
7935
			{
7936
				if($control instanceof IPostBackDataHandler)
7937
				{
7938
					if($control->loadPostData($key,$postData))
7939
						$this->_controlsPostDataChanged[]=$control;
7940
				}
7941
				else if($control instanceof IPostBackEventHandler &&
7942
					empty($this->_postData[self::FIELD_POSTBACK_TARGET]))
7943
				{
7944
					$this->_postData->add(self::FIELD_POSTBACK_TARGET,$key);  				}
7945
				unset($this->_controlsRequiringPostData[$key]);
7946
			}
7947
			else if($beforeLoad)
7948
				$this->_restPostData->add($key,$value);
7949
		}
7950
		foreach($this->_controlsRequiringPostData as $key=>$value)
7951
		{
7952
			if($control=$this->findControl($key))
7953
			{
7954
				if($control instanceof IPostBackDataHandler)
7955
				{
7956
					if($control->loadPostData($key,$this->_postData))
7957
						$this->_controlsPostDataChanged[]=$control;
7958
				}
7959
				else
7960
					throw new TInvalidDataValueException('page_postbackcontrol_invalid',$key);
7961
				unset($this->_controlsRequiringPostData[$key]);
7962
			}
7963
		}
7964
		$this->_isLoadingPostData=false;
7965
	}
7966
	public function getIsLoadingPostData()
7967
	{
7968
		return $this->_isLoadingPostData;
7969
	}
7970
	protected function raiseChangedEvents()
7971
	{
7972
		foreach($this->_controlsPostDataChanged as $control)
7973
			$control->raisePostDataChangedEvent();
7974
	}
7975
	protected function raisePostBackEvent()
7976
	{
7977
		if(($postBackHandler=$this->getPostBackEventTarget())===null)
7978
			$this->validate();
7979
		else if($postBackHandler instanceof IPostBackEventHandler)
7980
			$postBackHandler->raisePostBackEvent($this->getPostBackEventParameter());
7981
	}
7982
	public function getInFormRender()
7983
	{
7984
		return $this->_inFormRender;
7985
	}
7986
	public function ensureRenderInForm($control)
7987
	{
7988
		if(!$this->getIsCallback() && !$this->_inFormRender)
7989
			throw new TConfigurationException('page_control_outofform',get_class($control), $control ? $control->getUniqueID() : null);
7990
	}
7991
	public function beginFormRender($writer)
7992
	{
7993
		if($this->_formRendered)
7994
			throw new TConfigurationException('page_form_duplicated');
7995
		$this->_formRendered=true;
7996
		$this->getClientScript()->registerHiddenField(self::FIELD_PAGESTATE,$this->getClientState());
7997
		$this->_inFormRender=true;
7998
	}
7999
	public function endFormRender($writer)
8000
	{
8001
		if($this->_focus)
8002
		{
8003
			if(($this->_focus instanceof TControl) && $this->_focus->getVisible(true))
8004
				$focus=$this->_focus->getClientID();
8005
			else
8006
				$focus=$this->_focus;
8007
			$this->getClientScript()->registerFocusControl($focus);
8008
		}
8009
		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...
8010
			$this->getClientScript()->registerFocusControl($lastFocus);
8011
		$this->_inFormRender=false;
8012
	}
8013
	public function setFocus($value)
8014
	{
8015
		$this->_focus=$value;
8016
	}
8017
	public function getClientSupportsJavaScript()
8018
	{
8019
		return $this->_enableJavaScript;
8020
	}
8021
	public function setClientSupportsJavaScript($value)
8022
	{
8023
		$this->_enableJavaScript=TPropertyValue::ensureBoolean($value);
8024
	}
8025
	public function getHead()
8026
	{
8027
		return $this->_head;
8028
	}
8029
	public function setHead(THead $value)
8030
	{
8031
		if($this->_head)
8032
			throw new TInvalidOperationException('page_head_duplicated');
8033
		$this->_head=$value;
8034
		if($this->_title!==null)
8035
		{
8036
			$this->_head->setTitle($this->_title);
8037
			$this->_title=null;
8038
		}
8039
	}
8040
	public function getTitle()
8041
	{
8042
		if($this->_head)
8043
			return $this->_head->getTitle();
8044
		else
8045
			return $this->_title===null ? '' : $this->_title;
8046
	}
8047
	public function setTitle($value)
8048
	{
8049
		if($this->_head)
8050
			$this->_head->setTitle($value);
8051
		else
8052
			$this->_title=$value;
8053
	}
8054
	public function getClientState()
8055
	{
8056
		return $this->_clientState;
8057
	}
8058
	public function setClientState($state)
8059
	{
8060
		$this->_clientState=$state;
8061
	}
8062
	public function getRequestClientState()
8063
	{
8064
		return $this->getRequest()->itemAt(self::FIELD_PAGESTATE);
8065
	}
8066
	public function getStatePersisterClass()
8067
	{
8068
		return $this->_statePersisterClass;
8069
	}
8070
	public function setStatePersisterClass($value)
8071
	{
8072
		$this->_statePersisterClass=$value;
8073
	}
8074
	public function getStatePersister()
8075
	{
8076
		if($this->_statePersister===null)
8077
		{
8078
			$this->_statePersister=Prado::createComponent($this->_statePersisterClass);
8079
			if(!($this->_statePersister instanceof IPageStatePersister))
8080
				throw new TInvalidDataTypeException('page_statepersister_invalid');
8081
			$this->_statePersister->setPage($this);
8082
		}
8083
		return $this->_statePersister;
8084
	}
8085
	public function getEnableStateValidation()
8086
	{
8087
		return $this->_enableStateValidation;
8088
	}
8089
	public function setEnableStateValidation($value)
8090
	{
8091
		$this->_enableStateValidation=TPropertyValue::ensureBoolean($value);
8092
	}
8093
	public function getEnableStateEncryption()
8094
	{
8095
		return $this->_enableStateEncryption;
8096
	}
8097
	public function setEnableStateEncryption($value)
8098
	{
8099
		$this->_enableStateEncryption=TPropertyValue::ensureBoolean($value);
8100
	}
8101
	public function getEnableStateCompression()
8102
	{
8103
		return $this->_enableStateCompression;
8104
	}
8105
	public function setEnableStateCompression($value)
8106
	{
8107
		$this->_enableStateCompression=TPropertyValue::ensureBoolean($value);
8108
	}
8109
	public function getPagePath()
8110
	{
8111
		return $this->_pagePath;
8112
	}
8113
	public function setPagePath($value)
8114
	{
8115
		$this->_pagePath=$value;
8116
	}
8117
	public function registerCachingAction($context,$funcName,$funcParams)
8118
	{
8119
		if($this->_cachingStack)
8120
		{
8121
			foreach($this->_cachingStack as $cache)
8122
				$cache->registerAction($context,$funcName,$funcParams);
8123
		}
8124
	}
8125
	public function getCachingStack()
8126
	{
8127
		if(!$this->_cachingStack)
8128
			$this->_cachingStack=new TStack;
8129
		return $this->_cachingStack;
8130
	}
8131
	public function flushWriter()
8132
	{
8133
		if ($this->_writer)
8134
			$this->Response->write($this->_writer->flush());
8135
	}
8136
}
8137
interface IPageStatePersister
8138
{
8139
	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...
8140
	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...
8141
	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...
8142
	public function load();
8143
}
8144
class TPageStateFormatter
8145
{
8146
	public static function serialize($page,$data)
8147
	{
8148
		$sm=$page->getApplication()->getSecurityManager();
8149
		if($page->getEnableStateValidation())
8150
			$str=$sm->hashData(serialize($data));
8151
		else
8152
			$str=serialize($data);
8153
		if($page->getEnableStateCompression() && extension_loaded('zlib'))
8154
			$str=gzcompress($str);
8155
		if($page->getEnableStateEncryption())
8156
			$str=$sm->encrypt($str);
8157
		return base64_encode($str);
8158
	}
8159
	public static function unserialize($page,$data)
8160
	{
8161
		$str=base64_decode($data);
8162
		if($str==='')
8163
			return null;
8164
		if($str!==false)
8165
		{
8166
			$sm=$page->getApplication()->getSecurityManager();
8167
			if($page->getEnableStateEncryption())
8168
				$str=$sm->decrypt($str);
8169
			if($page->getEnableStateCompression() && extension_loaded('zlib'))
8170
				$str=@gzuncompress($str);
8171
			if($page->getEnableStateValidation())
8172
			{
8173
				if(($str=$sm->validateData($str))!==false)
8174
					return unserialize($str);
8175
			}
8176
			else
8177
				return unserialize($str);
8178
		}
8179
		return null;
8180
	}
8181
}
8182
class TOutputCache extends TControl implements INamingContainer
8183
{
8184
	const CACHE_ID_PREFIX='prado:outputcache';
8185
	private $_cacheModuleID='';
8186
	private $_dataCached=false;
8187
	private $_cacheAvailable=false;
8188
	private $_cacheChecked=false;
8189
	private $_cacheKey=null;
8190
	private $_duration=60;
8191
	private $_cache=null;
8192
	private $_contents;
8193
	private $_state;
8194
	private $_actions=array();
8195
	private $_varyByParam='';
8196
	private $_keyPrefix='';
8197
	private $_varyBySession=false;
8198
	private $_cachePostBack=false;
8199
	private $_cacheTime=0;
8200
	public function getAllowChildControls()
8201
	{
8202
		$this->determineCacheability();
8203
		return !$this->_dataCached;
8204
	}
8205
	private function determineCacheability()
8206
	{
8207
		if(!$this->_cacheChecked)
8208
		{
8209
			$this->_cacheChecked=true;
8210
			if($this->_duration>0 && ($this->_cachePostBack || !$this->getPage()->getIsPostBack()))
8211
			{
8212
				if($this->_cacheModuleID!=='')
8213
				{
8214
					$this->_cache=$this->getApplication()->getModule($this->_cacheModuleID);
8215
					if(!($this->_cache instanceof ICache))
8216
						throw new TConfigurationException('outputcache_cachemoduleid_invalid',$this->_cacheModuleID);
8217
				}
8218
				else
8219
					$this->_cache=$this->getApplication()->getCache();
8220
				if($this->_cache!==null)
8221
				{
8222
					$this->_cacheAvailable=true;
8223
					$data=$this->_cache->get($this->getCacheKey());
8224
					if(is_array($data))
8225
					{
8226
						$param=new TOutputCacheCheckDependencyEventParameter;
8227
						$param->setCacheTime(isset($data[3])?$data[3]:0);
8228
						$this->onCheckDependency($param);
8229
						$this->_dataCached=$param->getIsValid();
8230
					}
8231
					else
8232
						$this->_dataCached=false;
8233
					if($this->_dataCached)
8234
						list($this->_contents,$this->_state,$this->_actions,$this->_cacheTime)=$data;
8235
				}
8236
			}
8237
		}
8238
	}
8239
	protected function initRecursive($namingContainer=null)
8240
	{
8241
		if($this->_cacheAvailable && !$this->_dataCached)
8242
		{
8243
			$stack=$this->getPage()->getCachingStack();
8244
			$stack->push($this);
8245
			parent::initRecursive($namingContainer);
8246
			$stack->pop();
8247
		}
8248
		else
8249
			parent::initRecursive($namingContainer);
8250
	}
8251
	protected function loadRecursive()
8252
	{
8253
		if($this->_cacheAvailable && !$this->_dataCached)
8254
		{
8255
			$stack=$this->getPage()->getCachingStack();
8256
			$stack->push($this);
8257
			parent::loadRecursive();
8258
			$stack->pop();
8259
		}
8260
		else
8261
		{
8262
			if($this->_dataCached)
8263
				$this->performActions();
8264
			parent::loadRecursive();
8265
		}
8266
	}
8267
	private function performActions()
8268
	{
8269
		$page=$this->getPage();
8270
		$cs=$page->getClientScript();
8271
		foreach($this->_actions as $action)
8272
		{
8273
			if($action[0]==='Page.ClientScript')
8274
				call_user_func_array(array($cs,$action[1]),$action[2]);
8275
			else if($action[0]==='Page')
8276
				call_user_func_array(array($page,$action[1]),$action[2]);
8277
			else
8278
				call_user_func_array(array($this->getSubProperty($action[0]),$action[1]),$action[2]);
8279
		}
8280
	}
8281
	protected function preRenderRecursive()
8282
	{
8283
		if($this->_cacheAvailable && !$this->_dataCached)
8284
		{
8285
			$stack=$this->getPage()->getCachingStack();
8286
			$stack->push($this);
8287
			parent::preRenderRecursive();
8288
			$stack->pop();
8289
		}
8290
		else
8291
			parent::preRenderRecursive();
8292
	}
8293
	protected function loadStateRecursive(&$state,$needViewState=true)
8294
	{
8295
		$st=unserialize($state);
8296
		parent::loadStateRecursive($st,$needViewState);
8297
	}
8298
	protected function &saveStateRecursive($needViewState=true)
8299
	{
8300
		if($this->_dataCached)
8301
			return $this->_state;
8302
		else
8303
		{
8304
			$st=parent::saveStateRecursive($needViewState);
8305
						$this->_state=serialize($st);
8306
			return $this->_state;
8307
		}
8308
	}
8309
	public function registerAction($context,$funcName,$funcParams)
8310
	{
8311
		$this->_actions[]=array($context,$funcName,$funcParams);
8312
	}
8313
	public function getCacheKey()
8314
	{
8315
		if($this->_cacheKey===null)
8316
			$this->_cacheKey=$this->calculateCacheKey();
8317
		return $this->_cacheKey;
8318
	}
8319
	protected function calculateCacheKey()
8320
	{
8321
		$key=$this->getBaseCacheKey();
8322
		if($this->_varyBySession)
8323
			$key.=$this->getSession()->getSessionID();
8324
		if($this->_varyByParam!=='')
8325
		{
8326
			$params=array();
8327
			$request=$this->getRequest();
8328
			foreach(explode(',',$this->_varyByParam) as $name)
8329
			{
8330
				$name=trim($name);
8331
				$params[$name]=$request->itemAt($name);
8332
			}
8333
			$key.=serialize($params);
8334
		}
8335
		$param=new TOutputCacheCalculateKeyEventParameter;
8336
		$this->onCalculateKey($param);
8337
		$key.=$param->getCacheKey();
8338
		return $key;
8339
	}
8340
	protected function getBaseCacheKey()
8341
	{
8342
		return self::CACHE_ID_PREFIX.$this->_keyPrefix.$this->getPage()->getPagePath().$this->getUniqueID();
8343
	}
8344
	public function getCacheModuleID()
8345
	{
8346
		return $this->_cacheModuleID;
8347
	}
8348
	public function setCacheModuleID($value)
8349
	{
8350
		$this->_cacheModuleID=$value;
8351
	}
8352
	public function setCacheKeyPrefix($value)
8353
	{
8354
		$this->_keyPrefix=$value;
8355
	}
8356
	public function getCacheTime()
8357
	{
8358
		return $this->_cacheTime;
8359
	}
8360
	protected function getCacheDependency()
8361
	{
8362
		return null;
8363
	}
8364
	public function getContentCached()
8365
	{
8366
		return $this->_dataCached;
8367
	}
8368
	public function getDuration()
8369
	{
8370
		return $this->_duration;
8371
	}
8372
	public function setDuration($value)
8373
	{
8374
		if(($value=TPropertyValue::ensureInteger($value))<0)
8375
			throw new TInvalidDataValueException('outputcache_duration_invalid',get_class($this));
8376
		$this->_duration=$value;
8377
	}
8378
	public function getVaryByParam()
8379
	{
8380
		return $this->_varyByParam;
8381
	}
8382
	public function setVaryByParam($value)
8383
	{
8384
		$this->_varyByParam=trim($value);
8385
	}
8386
	public function getVaryBySession()
8387
	{
8388
		return $this->_varyBySession;
8389
	}
8390
	public function setVaryBySession($value)
8391
	{
8392
		$this->_varyBySession=TPropertyValue::ensureBoolean($value);
8393
	}
8394
	public function getCachingPostBack()
8395
	{
8396
		return $this->_cachePostBack;
8397
	}
8398
	public function setCachingPostBack($value)
8399
	{
8400
		$this->_cachePostBack=TPropertyValue::ensureBoolean($value);
8401
	}
8402
	public function onCheckDependency($param)
8403
	{
8404
		$this->raiseEvent('OnCheckDependency',$this,$param);
8405
	}
8406
	public function onCalculateKey($param)
8407
	{
8408
		$this->raiseEvent('OnCalculateKey',$this,$param);
8409
	}
8410
	public function render($writer)
8411
	{
8412
		if($this->_dataCached)
8413
			$writer->write($this->_contents);
8414
		else if($this->_cacheAvailable)
8415
		{
8416
			$textwriter = new TTextWriter();
8417
			$multiwriter = new TOutputCacheTextWriterMulti(array($writer->getWriter(),$textwriter));
8418
			$htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), $multiwriter);
8419
			$stack=$this->getPage()->getCachingStack();
8420
			$stack->push($this);
8421
			parent::render($htmlWriter);
8422
			$stack->pop();
8423
			$content=$textwriter->flush();
8424
			$data=array($content,$this->_state,$this->_actions,time());
8425
			$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...
8426
		}
8427
		else
8428
			parent::render($writer);
8429
	}
8430
}
8431
class TOutputCacheCheckDependencyEventParameter extends TEventParameter
8432
{
8433
	private $_isValid=true;
8434
	private $_cacheTime=0;
8435
	public function getIsValid()
8436
	{
8437
		return $this->_isValid;
8438
	}
8439
	public function setIsValid($value)
8440
	{
8441
		$this->_isValid=TPropertyValue::ensureBoolean($value);
8442
	}
8443
	public function getCacheTime()
8444
	{
8445
		return $this->_cacheTime;
8446
	}
8447
	public function setCacheTime($value)
8448
	{
8449
		$this->_cacheTime=TPropertyValue::ensureInteger($value);
8450
	}
8451
}
8452
class TOutputCacheCalculateKeyEventParameter extends TEventParameter
8453
{
8454
	private $_cacheKey='';
8455
	public function getCacheKey()
8456
	{
8457
		return $this->_cacheKey;
8458
	}
8459
	public function setCacheKey($value)
8460
	{
8461
		$this->_cacheKey=TPropertyValue::ensureString($value);
8462
	}
8463
}
8464
class TOutputCacheTextWriterMulti extends TTextWriter
8465
{
8466
	protected $_writers;
8467
	public function __construct(Array $writers)
8468
	{
8469
				$this->_writers = $writers;
8470
	}
8471
	public function write($s)
8472
	{
8473
		foreach($this->_writers as $writer)
8474
			$writer->write($s);
8475
	}
8476
	public function flush()
8477
	{
8478
		foreach($this->_writers as $writer)
8479
			$s = $writer->flush();
8480
		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...
8481
	}
8482
}
8483
class TTemplateManager extends TModule
8484
{
8485
	const TEMPLATE_FILE_EXT='.tpl';
8486
	const TEMPLATE_CACHE_PREFIX='prado:template:';
8487
	public function init($config)
8488
	{
8489
		$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...
8490
	}
8491
	public function getTemplateByClassName($className)
8492
	{
8493
		$class=new ReflectionClass($className);
8494
		$tplFile=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$className.self::TEMPLATE_FILE_EXT;
8495
		return $this->getTemplateByFileName($tplFile);
8496
	}
8497
	public function getTemplateByFileName($fileName)
8498
	{
8499
		if(($fileName=$this->getLocalizedTemplate($fileName))!==null)
8500
		{
8501
			if(($cache=$this->getApplication()->getCache())===null)
8502
				return new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
8503
			else
8504
			{
8505
				$array=$cache->get(self::TEMPLATE_CACHE_PREFIX.$fileName);
8506
				if(is_array($array))
8507
				{
8508
					list($template,$timestamps)=$array;
8509
					if($this->getApplication()->getMode()===TApplicationMode::Performance)
8510
						return $template;
8511
					$cacheValid=true;
8512
					foreach($timestamps as $tplFile=>$timestamp)
8513
					{
8514
						if(!is_file($tplFile) || filemtime($tplFile)>$timestamp)
8515
						{
8516
							$cacheValid=false;
8517
							break;
8518
						}
8519
					}
8520
					if($cacheValid)
8521
						return $template;
8522
				}
8523
				$template=new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
8524
				$includedFiles=$template->getIncludedFiles();
8525
				$timestamps=array();
8526
				$timestamps[$fileName]=filemtime($fileName);
8527
				foreach($includedFiles as $includedFile)
8528
					$timestamps[$includedFile]=filemtime($includedFile);
8529
				$cache->set(self::TEMPLATE_CACHE_PREFIX.$fileName,array($template,$timestamps));
8530
				return $template;
8531
			}
8532
		}
8533
		else
8534
			return null;
8535
	}
8536
	protected function getLocalizedTemplate($filename)
8537
	{
8538
		if(($app=$this->getApplication()->getGlobalization(false))===null)
8539
			return is_file($filename)?$filename:null;
8540
		foreach($app->getLocalizedResource($filename) as $file)
8541
		{
8542
			if(($file=realpath($file))!==false && is_file($file))
8543
				return $file;
8544
		}
8545
		return null;
8546
	}
8547
}
8548
class TTemplate extends TApplicationComponent implements ITemplate
8549
{
8550
	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';
8551
	const CONFIG_DATABIND=0;
8552
	const CONFIG_EXPRESSION=1;
8553
	const CONFIG_ASSET=2;
8554
	const CONFIG_PARAMETER=3;
8555
	const CONFIG_LOCALIZATION=4;
8556
	const CONFIG_TEMPLATE=5;
8557
	private $_tpl=array();
8558
	private $_directive=array();
8559
	private $_contextPath;
8560
	private $_tplFile=null;
8561
	private $_startingLine=0;
8562
	private $_content;
8563
	private $_sourceTemplate=true;
8564
	private $_hashCode='';
8565
	private $_tplControl=null;
8566
	private $_includedFiles=array();
8567
	private $_includeAtLine=array();
8568
	private $_includeLines=array();
8569
	public function __construct($template,$contextPath,$tplFile=null,$startingLine=0,$sourceTemplate=true)
8570
	{
8571
		$this->_sourceTemplate=$sourceTemplate;
8572
		$this->_contextPath=$contextPath;
8573
		$this->_tplFile=$tplFile;
8574
		$this->_startingLine=$startingLine;
8575
		$this->_content=$template;
8576
		$this->_hashCode=md5($template);
8577
		$this->parse($template);
8578
		$this->_content=null; 	}
8579
	public function getTemplateFile()
8580
	{
8581
		return $this->_tplFile;
8582
	}
8583
	public function getIsSourceTemplate()
8584
	{
8585
		return $this->_sourceTemplate;
8586
	}
8587
	public function getContextPath()
8588
	{
8589
		return $this->_contextPath;
8590
	}
8591
	public function getDirective()
8592
	{
8593
		return $this->_directive;
8594
	}
8595
	public function getHashCode()
8596
	{
8597
		return $this->_hashCode;
8598
	}
8599
	public function &getItems()
8600
	{
8601
		return $this->_tpl;
8602
	}
8603
	public function instantiateIn($tplControl,$parentControl=null)
8604
	{
8605
		$this->_tplControl=$tplControl;
8606
		if($parentControl===null)
8607
			$parentControl=$tplControl;
8608
		if(($page=$tplControl->getPage())===null)
8609
			$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...
8610
		$controls=array();
8611
		$directChildren=array();
8612
		foreach($this->_tpl as $key=>$object)
8613
		{
8614
			if($object[0]===-1)
8615
				$parent=$parentControl;
8616
			else if(isset($controls[$object[0]]))
8617
				$parent=$controls[$object[0]];
8618
			else
8619
				continue;
8620
			if(isset($object[2]))				{
8621
				$component=Prado::createComponent($object[1]);
8622
				$properties=&$object[2];
8623
				if($component instanceof TControl)
8624
				{
8625
					if($component instanceof TOutputCache)
8626
						$component->setCacheKeyPrefix($this->_hashCode.$key);
8627
					$component->setTemplateControl($tplControl);
8628
					if(isset($properties['id']))
8629
					{
8630
						if(is_array($properties['id']))
8631
							$properties['id']=$component->evaluateExpression($properties['id'][1]);
8632
						$tplControl->registerObject($properties['id'],$component);
8633
					}
8634
					if(isset($properties['skinid']))
8635
					{
8636
						if(is_array($properties['skinid']))
8637
							$component->setSkinID($component->evaluateExpression($properties['skinid'][1]));
8638
						else
8639
							$component->setSkinID($properties['skinid']);
8640
						unset($properties['skinid']);
8641
					}
8642
					$component->trackViewState(false);
8643
					$component->applyStyleSheetSkin($page);
8644
					foreach($properties as $name=>$value)
8645
						$this->configureControl($component,$name,$value);
8646
					$component->trackViewState(true);
8647
					if($parent===$parentControl)
8648
						$directChildren[]=$component;
8649
					else
8650
						$component->createdOnTemplate($parent);
8651
					if($component->getAllowChildControls())
8652
						$controls[$key]=$component;
8653
				}
8654
				else if($component instanceof TComponent)
8655
				{
8656
					$controls[$key]=$component;
8657
					if(isset($properties['id']))
8658
					{
8659
						if(is_array($properties['id']))
8660
							$properties['id']=$component->evaluateExpression($properties['id'][1]);
8661
						$tplControl->registerObject($properties['id'],$component);
8662
						if(!$component->hasProperty('id'))
8663
							unset($properties['id']);
8664
					}
8665
					foreach($properties as $name=>$value)
8666
						$this->configureComponent($component,$name,$value);
8667
					if($parent===$parentControl)
8668
						$directChildren[]=$component;
8669
					else
8670
						$component->createdOnTemplate($parent);
8671
				}
8672
			}
8673
			else
8674
			{
8675
				if($object[1] instanceof TCompositeLiteral)
8676
				{
8677
										$o=clone $object[1];
8678
					$o->setContainer($tplControl);
8679
					if($parent===$parentControl)
8680
						$directChildren[]=$o;
8681
					else
8682
						$parent->addParsedObject($o);
8683
				}
8684
				else
8685
				{
8686
					if($parent===$parentControl)
8687
						$directChildren[]=$object[1];
8688
					else
8689
						$parent->addParsedObject($object[1]);
8690
				}
8691
			}
8692
		}
8693
								foreach($directChildren as $control)
8694
		{
8695
			if($control instanceof TComponent)
8696
				$control->createdOnTemplate($parentControl);
8697
			else
8698
				$parentControl->addParsedObject($control);
8699
		}
8700
	}
8701
	protected function configureControl($control,$name,$value)
8702
	{
8703
		if(strncasecmp($name,'on',2)===0)					$this->configureEvent($control,$name,$value,$control);
8704
		else if(($pos=strrpos($name,'.'))===false)				$this->configureProperty($control,$name,$value);
8705
		else				$this->configureSubProperty($control,$name,$value);
8706
	}
8707
	protected function configureComponent($component,$name,$value)
8708
	{
8709
		if(strpos($name,'.')===false)				$this->configureProperty($component,$name,$value);
8710
		else				$this->configureSubProperty($component,$name,$value);
8711
	}
8712
	protected function configureEvent($control,$name,$value,$contextControl)
8713
	{
8714
		if(strpos($value,'.')===false)
8715
			$control->attachEventHandler($name,array($contextControl,'TemplateControl.'.$value));
8716
		else
8717
			$control->attachEventHandler($name,array($contextControl,$value));
8718
	}
8719
	protected function configureProperty($component,$name,$value)
8720
	{
8721
		if(is_array($value))
8722
		{
8723
			switch($value[0])
8724
			{
8725
				case self::CONFIG_DATABIND:
8726
					$component->bindProperty($name,$value[1]);
8727
					break;
8728
				case self::CONFIG_EXPRESSION:
8729
					if($component instanceof TControl)
8730
						$component->autoBindProperty($name,$value[1]);
8731
					else
8732
					{
8733
						$setter='set'.$name;
8734
						$component->$setter($this->_tplControl->evaluateExpression($value[1]));
8735
					}
8736
					break;
8737
				case self::CONFIG_TEMPLATE:
8738
					$setter='set'.$name;
8739
					$component->$setter($value[1]);
8740
					break;
8741
				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...
8742
					$url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
8743
					$component->$setter($url);
8744
					break;
8745
				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...
8746
					$component->$setter($this->getApplication()->getParameters()->itemAt($value[1]));
8747
					break;
8748
				case self::CONFIG_LOCALIZATION:
8749
					$setter='set'.$name;
8750
					$component->$setter(Prado::localize($value[1]));
8751
					break;
8752
				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...
8753
					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...
8754
			}
8755
		}
8756
		else
8757
		{
8758
			if (substr($name,0,2)=='js')
8759
				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...
8760
					$value = new TJavaScriptLiteral($value);
8761
			$setter='set'.$name;
8762
			$component->$setter($value);
8763
		}
8764
	}
8765
	protected function configureSubProperty($component,$name,$value)
8766
	{
8767
		if(is_array($value))
8768
		{
8769
			switch($value[0])
8770
			{
8771
				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...
8772
					break;
8773
				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...
8774
						$component->autoBindProperty($name,$value[1]);
8775
					else
8776
						$component->setSubProperty($name,$this->_tplControl->evaluateExpression($value[1]));
8777
					break;
8778
				case self::CONFIG_TEMPLATE:
8779
					$component->setSubProperty($name,$value[1]);
8780
					break;
8781
				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...
8782
					$component->setSubProperty($name,$url);
8783
					break;
8784
				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...
8785
					break;
8786
				case self::CONFIG_LOCALIZATION:
8787
					$component->setSubProperty($name,Prado::localize($value[1]));
8788
					break;
8789
				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...
8790
					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...
8791
			}
8792
		}
8793
		else
8794
			$component->setSubProperty($name,$value);
8795
	}
8796
	protected function parse($input)
8797
	{
8798
		$input=$this->preprocess($input);
8799
		$tpl=&$this->_tpl;
8800
		$n=preg_match_all(self::REGEX_RULES,$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
8801
		$expectPropEnd=false;
8802
		$textStart=0;
8803
				$stack=array();
8804
		$container=-1;
8805
		$matchEnd=0;
8806
		$c=0;
8807
		$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...
8808
		try
8809
		{
8810
			for($i=0;$i<$n;++$i)
8811
			{
8812
				$match=&$matches[$i];
8813
				$str=$match[0][0];
8814
				$matchStart=$match[0][1];
8815
				$matchEnd=$matchStart+strlen($str)-1;
8816
				if(strpos($str,'<com:')===0)					{
8817
					if($expectPropEnd)
8818
						continue;
8819
					if($matchStart>$textStart)
8820
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8821
					$textStart=$matchEnd+1;
8822
					$type=$match[1][0];
8823
					$attributes=$this->parseAttributes($match[2][0],$match[2][1]);
8824
					$this->validateAttributes($type,$attributes);
8825
					$tpl[$c++]=array($container,$type,$attributes);
8826
					if($str[strlen($str)-2]!=='/')  					{
8827
						$stack[] = $type;
8828
						$container=$c-1;
8829
					}
8830
				}
8831
				else if(strpos($str,'</com:')===0)					{
8832
					if($expectPropEnd)
8833
						continue;
8834
					if($matchStart>$textStart)
8835
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8836
					$textStart=$matchEnd+1;
8837
					$type=$match[1][0];
8838
					if(empty($stack))
8839
						throw new TConfigurationException('template_closingtag_unexpected',"</com:$type>");
8840
					$name=array_pop($stack);
8841
					if($name!==$type)
8842
					{
8843
						$tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
8844
						throw new TConfigurationException('template_closingtag_expected',$tag);
8845
					}
8846
					$container=$tpl[$container][0];
8847
				}
8848
				else if(strpos($str,'<%@')===0)					{
8849
					if($expectPropEnd)
8850
						continue;
8851
					if($matchStart>$textStart)
8852
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8853
					$textStart=$matchEnd+1;
8854
					if(isset($tpl[0]) || $this->_directive!==null)
8855
						throw new TConfigurationException('template_directive_nonunique');
8856
					$this->_directive=$this->parseAttributes($match[4][0],$match[4][1]);
8857
				}
8858
				else if(strpos($str,'<%')===0)					{
8859
					if($expectPropEnd)
8860
						continue;
8861
					if($matchStart>$textStart)
8862
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8863
					$textStart=$matchEnd+1;
8864
					$literal=trim($match[5][0]);
8865
					if($str[2]==='=')							$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,$literal));
8866
					else if($str[2]==='%')  						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_STATEMENTS,$literal));
8867
					else if($str[2]==='#')
8868
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_DATABINDING,$literal));
8869
					else if($str[2]==='$')
8870
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->getApplication()->getParameters()->itemAt('$literal')"));
8871
					else if($str[2]==='~')
8872
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->publishFilePath('$this->_contextPath/$literal')"));
8873
					else if($str[2]==='/')
8874
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"rtrim(dirname(\$this->getApplication()->getRequest()->getApplicationUrl()), '\/').'/$literal'"));
8875
					else if($str[2]==='[')
8876
					{
8877
						$literal=strtr(trim(substr($literal,0,strlen($literal)-1)),array("'"=>"\'","\\"=>"\\\\"));
8878
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"Prado::localize('$literal')"));
8879
					}
8880
				}
8881
				else if(strpos($str,'<prop:')===0)					{
8882
					if(strrpos($str,'/>')===strlen($str)-2)  					{
8883
						if($expectPropEnd)
8884
							continue;
8885
						if($matchStart>$textStart)
8886
							$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8887
						$textStart=$matchEnd+1;
8888
						$prop=strtolower($match[6][0]);
8889
						$attrs=$this->parseAttributes($match[7][0],$match[7][1]);
8890
						$attributes=array();
8891
						foreach($attrs as $name=>$value)
8892
							$attributes[$prop.'.'.$name]=$value;
8893
						$type=$tpl[$container][1];
8894
						$this->validateAttributes($type,$attributes);
8895
						foreach($attributes as $name=>$value)
8896
						{
8897
							if(isset($tpl[$container][2][$name]))
8898
								throw new TConfigurationException('template_property_duplicated',$name);
8899
							$tpl[$container][2][$name]=$value;
8900
						}
8901
					}
8902
					else  					{
8903
						$prop=strtolower($match[3][0]);
8904
						$stack[] = '@'.$prop;
8905
						if(!$expectPropEnd)
8906
						{
8907
							if($matchStart>$textStart)
8908
								$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8909
							$textStart=$matchEnd+1;
8910
							$expectPropEnd=true;
8911
						}
8912
					}
8913
				}
8914
				else if(strpos($str,'</prop:')===0)					{
8915
					$prop=strtolower($match[3][0]);
8916
					if(empty($stack))
8917
						throw new TConfigurationException('template_closingtag_unexpected',"</prop:$prop>");
8918
					$name=array_pop($stack);
8919
					if($name!=='@'.$prop)
8920
					{
8921
						$tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
8922
						throw new TConfigurationException('template_closingtag_expected',$tag);
8923
					}
8924
					if(($last=count($stack))<1 || $stack[$last-1][0]!=='@')
8925
					{
8926
						if($matchStart>$textStart)
8927
						{
8928
							$value=substr($input,$textStart,$matchStart-$textStart);
8929
							if(substr($prop,-8,8)==='template')
8930
								$value=$this->parseTemplateProperty($value,$textStart);
8931
							else
8932
								$value=$this->parseAttribute($value);
8933
							if($container>=0)
8934
							{
8935
								$type=$tpl[$container][1];
8936
								$this->validateAttributes($type,array($prop=>$value));
8937
								if(isset($tpl[$container][2][$prop]))
8938
									throw new TConfigurationException('template_property_duplicated',$prop);
8939
								$tpl[$container][2][$prop]=$value;
8940
							}
8941
							else									$this->_directive[$prop]=$value;
8942
							$textStart=$matchEnd+1;
8943
						}
8944
						$expectPropEnd=false;
8945
					}
8946
				}
8947
				else if(strpos($str,'<!--')===0)					{
8948
					if($expectPropEnd)
8949
						throw new TConfigurationException('template_comments_forbidden');
8950
					if($matchStart>$textStart)
8951
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8952
					$textStart=$matchEnd+1;
8953
				}
8954
				else
8955
					throw new TConfigurationException('template_matching_unexpected',$match);
8956
			}
8957
			if(!empty($stack))
8958
			{
8959
				$name=array_pop($stack);
8960
				$tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
8961
				throw new TConfigurationException('template_closingtag_expected',$tag);
8962
			}
8963
			if($textStart<strlen($input))
8964
				$tpl[$c++]=array($container,substr($input,$textStart));
8965
		}
8966
		catch(Exception $e)
8967
		{
8968
			if(($e instanceof TException) && ($e instanceof TTemplateException))
8969
				throw $e;
8970
			if($matchEnd===0)
8971
				$line=$this->_startingLine+1;
8972
			else
8973
				$line=$this->_startingLine+count(explode("\n",substr($input,0,$matchEnd+1)));
8974
			$this->handleException($e,$line,$input);
8975
		}
8976
		if($this->_directive===null)
8977
			$this->_directive=array();
8978
				$objects=array();
8979
		$parent=null;
8980
		$merged=array();
8981
		foreach($tpl as $id=>$object)
8982
		{
8983
			if(isset($object[2]) || $object[0]!==$parent)
8984
			{
8985
				if($parent!==null)
8986
				{
8987
					if(count($merged[1])===1 && is_string($merged[1][0]))
8988
						$objects[$id-1]=array($merged[0],$merged[1][0]);
8989
					else
8990
						$objects[$id-1]=array($merged[0],new TCompositeLiteral($merged[1]));
8991
				}
8992
				if(isset($object[2]))
8993
				{
8994
					$parent=null;
8995
					$objects[$id]=$object;
8996
				}
8997
				else
8998
				{
8999
					$parent=$object[0];
9000
					$merged=array($parent,array($object[1]));
9001
				}
9002
			}
9003
			else
9004
				$merged[1][]=$object[1];
9005
		}
9006
		if($parent!==null)
9007
		{
9008
			if(count($merged[1])===1 && is_string($merged[1][0]))
9009
				$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 8981. 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...
9010
			else
9011
				$objects[$id]=array($merged[0],new TCompositeLiteral($merged[1]));
9012
		}
9013
		$tpl=$objects;
9014
		return $objects;
9015
	}
9016
	protected function parseAttributes($str,$offset)
9017
	{
9018
		if($str==='')
9019
			return array();
9020
		$pattern='/([\w\.\-]+)\s*=\s*(\'.*?\'|".*?"|<%.*?%>)/msS';
9021
		$attributes=array();
9022
		$n=preg_match_all($pattern,$str,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
9023
		for($i=0;$i<$n;++$i)
9024
		{
9025
			$match=&$matches[$i];
9026
			$name=strtolower($match[1][0]);
9027
			if(isset($attributes[$name]))
9028
				throw new TConfigurationException('template_property_duplicated',$name);
9029
			$value=$match[2][0];
9030
			if(substr($name,-8,8)==='template')
9031
			{
9032
				if($value[0]==='\'' || $value[0]==='"')
9033
					$attributes[$name]=$this->parseTemplateProperty(substr($value,1,strlen($value)-2),$match[2][1]+1);
9034
				else
9035
					$attributes[$name]=$this->parseTemplateProperty($value,$match[2][1]);
9036
			}
9037
			else
9038
			{
9039
				if($value[0]==='\'' || $value[0]==='"')
9040
					$attributes[$name]=$this->parseAttribute(substr($value,1,strlen($value)-2));
9041
				else
9042
					$attributes[$name]=$this->parseAttribute($value);
9043
			}
9044
		}
9045
		return $attributes;
9046
	}
9047
	protected function parseTemplateProperty($content,$offset)
9048
	{
9049
		$line=$this->_startingLine+count(explode("\n",substr($this->_content,0,$offset)))-1;
9050
		return array(self::CONFIG_TEMPLATE,new TTemplate($content,$this->_contextPath,$this->_tplFile,$line,false));
9051
	}
9052
	protected function parseAttribute($value)
9053
	{
9054
		if(($n=preg_match_all('/<%[#=].*?%>/msS',$value,$matches,PREG_OFFSET_CAPTURE))>0)
9055
		{
9056
			$isDataBind=false;
9057
			$textStart=0;
9058
			$expr='';
9059
			for($i=0;$i<$n;++$i)
9060
			{
9061
				$match=$matches[0][$i];
9062
				$token=$match[0];
9063
				$offset=$match[1];
9064
				$length=strlen($token);
9065
				if($token[2]==='#')
9066
					$isDataBind=true;
9067
				if($offset>$textStart)
9068
					$expr.=".'".strtr(substr($value,$textStart,$offset-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
9069
				$expr.='.('.substr($token,3,$length-5).')';
9070
				$textStart=$offset+$length;
9071
			}
9072
			$length=strlen($value);
9073
			if($length>$textStart)
9074
				$expr.=".'".strtr(substr($value,$textStart,$length-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
9075
			if($isDataBind)
9076
				return array(self::CONFIG_DATABIND,ltrim($expr,'.'));
9077
			else
9078
				return array(self::CONFIG_EXPRESSION,ltrim($expr,'.'));
9079
		}
9080
		else if(preg_match('/\\s*(<%~.*?%>|<%\\$.*?%>|<%\\[.*?\\]%>|<%\/.*?%>)\\s*/msS',$value,$matches) && $matches[0]===$value)
9081
		{
9082
			$value=$matches[1];
9083
			if($value[2]==='~')
9084
				return array(self::CONFIG_ASSET,trim(substr($value,3,strlen($value)-5)));
9085
			elseif($value[2]==='[')
9086
				return array(self::CONFIG_LOCALIZATION,trim(substr($value,3,strlen($value)-6)));
9087
			elseif($value[2]==='$')
9088
				return array(self::CONFIG_PARAMETER,trim(substr($value,3,strlen($value)-5)));
9089
			elseif($value[2]==='/') {
9090
				$literal = trim(substr($value,3,strlen($value)-5));
9091
				return array(self::CONFIG_EXPRESSION,"rtrim(dirname(\$this->getApplication()->getRequest()->getApplicationUrl()), '\/').'/$literal'");
9092
			}
9093
		}
9094
		else
9095
			return $value;
9096
	}
9097
	protected function validateAttributes($type,$attributes)
9098
	{
9099
		Prado::using($type);
9100
		if(($pos=strrpos($type,'.'))!==false)
9101
			$className=substr($type,$pos+1);
9102
		else
9103
			$className=$type;
9104
		$class=new ReflectionClass($className);
9105
		if(is_subclass_of($className,'TControl') || $className==='TControl')
9106
		{
9107
			foreach($attributes as $name=>$att)
9108
			{
9109
				if(($pos=strpos($name,'.'))!==false)
9110
				{
9111
										$subname=substr($name,0,$pos);
9112
					if(!$class->hasMethod('get'.$subname))
9113
						throw new TConfigurationException('template_property_unknown',$type,$subname);
9114
				}
9115
				else if(strncasecmp($name,'on',2)===0)
9116
				{
9117
										if(!$class->hasMethod($name))
9118
						throw new TConfigurationException('template_event_unknown',$type,$name);
9119
					else if(!is_string($att))
9120
						throw new TConfigurationException('template_eventhandler_invalid',$type,$name);
9121
				}
9122
				else
9123
				{
9124
										if (! ($class->hasMethod('set'.$name) || $class->hasMethod('setjs'.$name) || $this->isClassBehaviorMethod($class,'set'.$name)) )
9125
					{
9126
						if ($class->hasMethod('get'.$name) || $class->hasMethod('getjs'.$name))
9127
							throw new TConfigurationException('template_property_readonly',$type,$name);
9128
						else
9129
							throw new TConfigurationException('template_property_unknown',$type,$name);
9130
					}
9131
					else if(is_array($att) && $att[0]!==self::CONFIG_EXPRESSION)
9132
					{
9133
						if(strcasecmp($name,'id')===0)
9134
							throw new TConfigurationException('template_controlid_invalid',$type);
9135
						else if(strcasecmp($name,'skinid')===0)
9136
							throw new TConfigurationException('template_controlskinid_invalid',$type);
9137
					}
9138
				}
9139
			}
9140
		}
9141
		else if(is_subclass_of($className,'TComponent') || $className==='TComponent')
9142
		{
9143
			foreach($attributes as $name=>$att)
9144
			{
9145
				if(is_array($att) && ($att[0]===self::CONFIG_DATABIND))
9146
					throw new TConfigurationException('template_databind_forbidden',$type,$name);
9147
				if(($pos=strpos($name,'.'))!==false)
9148
				{
9149
										$subname=substr($name,0,$pos);
9150
					if(!$class->hasMethod('get'.$subname))
9151
						throw new TConfigurationException('template_property_unknown',$type,$subname);
9152
				}
9153
				else if(strncasecmp($name,'on',2)===0)
9154
					throw new TConfigurationException('template_event_forbidden',$type,$name);
9155
				else
9156
				{
9157
										if(strcasecmp($name,'id')!==0 && !($class->hasMethod('set'.$name) || $this->isClassBehaviorMethod($class,'set'.$name)))
9158
					{
9159
						if($class->hasMethod('get'.$name))
9160
							throw new TConfigurationException('template_property_readonly',$type,$name);
9161
						else
9162
							throw new TConfigurationException('template_property_unknown',$type,$name);
9163
					}
9164
				}
9165
			}
9166
		}
9167
		else
9168
			throw new TConfigurationException('template_component_required',$type);
9169
	}
9170
	public function getIncludedFiles()
9171
	{
9172
		return $this->_includedFiles;
9173
	}
9174
	protected function handleException($e,$line,$input=null)
9175
	{
9176
		$srcFile=$this->_tplFile;
9177
		if(($n=count($this->_includedFiles))>0) 		{
9178
			for($i=$n-1;$i>=0;--$i)
9179
			{
9180
				if($this->_includeAtLine[$i]<=$line)
9181
				{
9182
					if($line<$this->_includeAtLine[$i]+$this->_includeLines[$i])
9183
					{
9184
						$line=$line-$this->_includeAtLine[$i]+1;
9185
						$srcFile=$this->_includedFiles[$i];
9186
						break;
9187
					}
9188
					else
9189
						$line=$line-$this->_includeLines[$i]+1;
9190
				}
9191
			}
9192
		}
9193
		$exception=new TTemplateException('template_format_invalid',$e->getMessage());
9194
		$exception->setLineNumber($line);
9195
		if(!empty($srcFile))
9196
			$exception->setTemplateFile($srcFile);
9197
		else
9198
			$exception->setTemplateSource($input);
9199
		throw $exception;
9200
	}
9201
	protected function preprocess($input)
9202
	{
9203
		if($n=preg_match_all('/<%include(.*?)%>/',$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE))
9204
		{
9205
			for($i=0;$i<$n;++$i)
9206
			{
9207
				$filePath=Prado::getPathOfNamespace(trim($matches[$i][1][0]),TTemplateManager::TEMPLATE_FILE_EXT);
9208
				if($filePath!==null && is_file($filePath))
9209
					$this->_includedFiles[]=$filePath;
9210
				else
9211
				{
9212
					$errorLine=count(explode("\n",substr($input,0,$matches[$i][0][1]+1)));
9213
					$this->handleException(new TConfigurationException('template_include_invalid',trim($matches[$i][1][0])),$errorLine,$input);
9214
				}
9215
			}
9216
			$base=0;
9217
			for($i=0;$i<$n;++$i)
9218
			{
9219
				$ext=file_get_contents($this->_includedFiles[$i]);
9220
				$length=strlen($matches[$i][0][0]);
9221
				$offset=$base+$matches[$i][0][1];
9222
				$this->_includeAtLine[$i]=count(explode("\n",substr($input,0,$offset)));
9223
				$this->_includeLines[$i]=count(explode("\n",$ext));
9224
				$input=substr_replace($input,$ext,$offset,$length);
9225
				$base+=strlen($ext)-$length;
9226
			}
9227
		}
9228
		return $input;
9229
	}
9230
	protected function isClassBehaviorMethod(ReflectionClass $class,$method)
9231
	{
9232
	  $component=new ReflectionClass('TComponent');
9233
	  $behaviors=$component->getStaticProperties();
9234
	  if(!isset($behaviors['_um']))
9235
	    return false;
9236
	  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...
9237
	  {
9238
	    if(strtolower($class->getShortName())!==$name && !$class->isSubclassOf($name)) continue;
9239
	    foreach($list as $param)
9240
	    {
9241
	      if(method_exists($param->getBehavior(),$method))
9242
	        return true;
9243
	    }
9244
	  }
9245
	  return false;
9246
	}
9247
}
9248
class TThemeManager extends TModule
9249
{
9250
	const DEFAULT_BASEPATH='themes';
9251
	const DEFAULT_THEMECLASS = 'TTheme';
9252
	private $_themeClass=self::DEFAULT_THEMECLASS;
9253
	private $_initialized=false;
9254
	private $_basePath=null;
9255
	private $_baseUrl=null;
9256
	public function init($config)
9257
	{
9258
		$this->_initialized=true;
9259
		$service=$this->getService();
9260
		if($service instanceof TPageService)
9261
			$service->setThemeManager($this);
9262
		else
9263
			throw new TConfigurationException('thememanager_service_unavailable');
9264
	}
9265
	public function getTheme($name)
9266
	{
9267
		$themePath=$this->getBasePath().DIRECTORY_SEPARATOR.$name;
9268
		$themeUrl=rtrim($this->getBaseUrl(),'/').'/'.$name;
9269
		return Prado::createComponent($this->getThemeClass(), $themePath, $themeUrl);
9270
	}
9271
	public function setThemeClass($class) {
9272
		$this->_themeClass = $class===null ? self::DEFAULT_THEMECLASS : (string)$class;
9273
	}
9274
	public function getThemeClass() {
9275
		return $this->_themeClass;
9276
	}
9277
	public function getAvailableThemes()
9278
	{
9279
		$themes=array();
9280
		$basePath=$this->getBasePath();
9281
		$folder=@opendir($basePath);
9282
		while($file=@readdir($folder))
9283
		{
9284
			if($file!=='.' && $file!=='..' && $file!=='.svn' && is_dir($basePath.DIRECTORY_SEPARATOR.$file))
9285
				$themes[]=$file;
9286
		}
9287
		closedir($folder);
9288
		return $themes;
9289
	}
9290
	public function getBasePath()
9291
	{
9292
		if($this->_basePath===null)
9293
		{
9294
			$this->_basePath=dirname($this->getRequest()->getApplicationFilePath()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
9295
			if(($basePath=realpath($this->_basePath))===false || !is_dir($basePath))
9296
				throw new TConfigurationException('thememanager_basepath_invalid2',$this->_basePath);
9297
			$this->_basePath=$basePath;
9298
		}
9299
		return $this->_basePath;
9300
	}
9301
	public function setBasePath($value)
9302
	{
9303
		if($this->_initialized)
9304
			throw new TInvalidOperationException('thememanager_basepath_unchangeable');
9305
		else
9306
		{
9307
			$this->_basePath=Prado::getPathOfNamespace($value);
9308
			if($this->_basePath===null || !is_dir($this->_basePath))
9309
				throw new TInvalidDataValueException('thememanager_basepath_invalid',$value);
9310
		}
9311
	}
9312
	public function getBaseUrl()
9313
	{
9314
		if($this->_baseUrl===null)
9315
		{
9316
			$appPath=dirname($this->getRequest()->getApplicationFilePath());
9317
			$basePath=$this->getBasePath();
9318
			if(strpos($basePath,$appPath)===false)
9319
				throw new TConfigurationException('thememanager_baseurl_required');
9320
			$appUrl=rtrim(dirname($this->getRequest()->getApplicationUrl()),'/\\');
9321
			$this->_baseUrl=$appUrl.strtr(substr($basePath,strlen($appPath)),'\\','/');
9322
		}
9323
		return $this->_baseUrl;
9324
	}
9325
	public function setBaseUrl($value)
9326
	{
9327
		$this->_baseUrl=rtrim($value,'/');
9328
	}
9329
}
9330
class TTheme extends TApplicationComponent implements ITheme
9331
{
9332
	const THEME_CACHE_PREFIX='prado:theme:';
9333
	const SKIN_FILE_EXT='.skin';
9334
	private $_themePath;
9335
	private $_themeUrl;
9336
	private $_skins=null;
9337
	private $_name='';
9338
	private $_cssFiles=array();
9339
	private $_jsFiles=array();
9340
	public function __construct($themePath,$themeUrl)
9341
	{
9342
		$this->_themeUrl=$themeUrl;
9343
		$this->_themePath=realpath($themePath);
9344
		$this->_name=basename($themePath);
9345
		$cacheValid=false;
9346
				if(($cache=$this->getApplication()->getCache())!==null)
9347
		{
9348
			$array=$cache->get(self::THEME_CACHE_PREFIX.$themePath);
9349
			if(is_array($array))
9350
			{
9351
				list($skins,$cssFiles,$jsFiles,$timestamp)=$array;
9352
				if($this->getApplication()->getMode()!==TApplicationMode::Performance)
9353
				{
9354
					if(($dir=opendir($themePath))===false)
9355
						throw new TIOException('theme_path_inexistent',$themePath);
9356
					$cacheValid=true;
9357
					while(($file=readdir($dir))!==false)
9358
					{
9359
						if($file==='.' || $file==='..')
9360
							continue;
9361
						else if(basename($file,'.css')!==$file)
9362
							$this->_cssFiles[]=$themeUrl.'/'.$file;
9363
						else if(basename($file,'.js')!==$file)
9364
							$this->_jsFiles[]=$themeUrl.'/'.$file;
9365
						else if(basename($file,self::SKIN_FILE_EXT)!==$file && filemtime($themePath.DIRECTORY_SEPARATOR.$file)>$timestamp)
9366
						{
9367
							$cacheValid=false;
9368
							break;
9369
						}
9370
					}
9371
					closedir($dir);
9372
					if($cacheValid)
9373
						$this->_skins=$skins;
9374
				}
9375
				else
9376
				{
9377
					$cacheValid=true;
9378
					$this->_cssFiles=$cssFiles;
9379
					$this->_jsFiles=$jsFiles;
9380
					$this->_skins=$skins;
9381
				}
9382
			}
9383
		}
9384
		if(!$cacheValid)
9385
		{
9386
			$this->_cssFiles=array();
9387
			$this->_jsFiles=array();
9388
			$this->_skins=array();
9389
			if(($dir=opendir($themePath))===false)
9390
				throw new TIOException('theme_path_inexistent',$themePath);
9391
			while(($file=readdir($dir))!==false)
9392
			{
9393
				if($file==='.' || $file==='..')
9394
					continue;
9395
				else if(basename($file,'.css')!==$file)
9396
					$this->_cssFiles[]=$themeUrl.'/'.$file;
9397
				else if(basename($file,'.js')!==$file)
9398
					$this->_jsFiles[]=$themeUrl.'/'.$file;
9399
				else if(basename($file,self::SKIN_FILE_EXT)!==$file)
9400
				{
9401
					$template=new TTemplate(file_get_contents($themePath.'/'.$file),$themePath,$themePath.'/'.$file);
9402
					foreach($template->getItems() as $skin)
9403
					{
9404
						if(!isset($skin[2]))  							continue;
9405
						else if($skin[0]!==-1)
9406
							throw new TConfigurationException('theme_control_nested',$skin[1],dirname($themePath));
9407
						$type=$skin[1];
9408
						$id=isset($skin[2]['skinid'])?$skin[2]['skinid']:0;
9409
						unset($skin[2]['skinid']);
9410
						if(isset($this->_skins[$type][$id]))
9411
							throw new TConfigurationException('theme_skinid_duplicated',$type,$id,dirname($themePath));
9412
						$this->_skins[$type][$id]=$skin[2];
9413
					}
9414
				}
9415
			}
9416
			closedir($dir);
9417
			sort($this->_cssFiles);
9418
			sort($this->_jsFiles);
9419
			if($cache!==null)
9420
				$cache->set(self::THEME_CACHE_PREFIX.$themePath,array($this->_skins,$this->_cssFiles,$this->_jsFiles,time()));
9421
		}
9422
	}
9423
	public function getName()
9424
	{
9425
		return $this->_name;
9426
	}
9427
	protected function setName($value)
9428
	{
9429
		$this->_name = $value;
9430
	}
9431
	public function getBaseUrl()
9432
	{
9433
		return $this->_themeUrl;
9434
	}
9435
	protected function setBaseUrl($value)
9436
	{
9437
		$this->_themeUrl=rtrim($value,'/');
9438
	}
9439
	public function getBasePath()
9440
	{
9441
		return $this->_themePath;
9442
	}
9443
	protected function setBasePath($value)
9444
	{
9445
		$this->_themePath=$value;
9446
	}
9447
	public function getSkins()
9448
	{
9449
		return $this->_skins;
9450
	}
9451
	protected function setSkins($value)
9452
	{
9453
		$this->_skins = $value;
9454
	}
9455
	public function applySkin($control)
9456
	{
9457
		$type=get_class($control);
9458
		if(($id=$control->getSkinID())==='')
9459
			$id=0;
9460
		if(isset($this->_skins[$type][$id]))
9461
		{
9462
			foreach($this->_skins[$type][$id] as $name=>$value)
9463
			{
9464
				if(is_array($value))
9465
				{
9466
					switch($value[0])
9467
					{
9468
						case TTemplate::CONFIG_EXPRESSION:
9469
							$value=$this->evaluateExpression($value[1]);
9470
							break;
9471
						case TTemplate::CONFIG_ASSET:
9472
							$value=$this->_themeUrl.'/'.ltrim($value[1],'/');
9473
							break;
9474
						case TTemplate::CONFIG_DATABIND:
9475
							$control->bindProperty($name,$value[1]);
9476
							break;
9477
						case TTemplate::CONFIG_PARAMETER:
9478
							$control->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
9479
							break;
9480
						case TTemplate::CONFIG_TEMPLATE:
9481
							$control->setSubProperty($name,$value[1]);
9482
							break;
9483
						case TTemplate::CONFIG_LOCALIZATION:
9484
							$control->setSubProperty($name,Prado::localize($value[1]));
9485
							break;
9486
						default:
9487
							throw new TConfigurationException('theme_tag_unexpected',$name,$value[0]);
9488
							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...
9489
					}
9490
				}
9491
				if(!is_array($value))
9492
				{
9493
					if(strpos($name,'.')===false)						{
9494
						if($control->hasProperty($name))
9495
						{
9496
							if($control->canSetProperty($name))
9497
							{
9498
								$setter='set'.$name;
9499
								$control->$setter($value);
9500
							}
9501
							else
9502
								throw new TConfigurationException('theme_property_readonly',$type,$name);
9503
						}
9504
						else
9505
							throw new TConfigurationException('theme_property_undefined',$type,$name);
9506
					}
9507
					else							$control->setSubProperty($name,$value);
9508
				}
9509
			}
9510
			return true;
9511
		}
9512
		else
9513
			return false;
9514
	}
9515
	public function getStyleSheetFiles()
9516
	{
9517
		return $this->_cssFiles;
9518
	}
9519
	protected function setStyleSheetFiles($value)
9520
	{
9521
		$this->_cssFiles=$value;
9522
	}
9523
	public function getJavaScriptFiles()
9524
	{
9525
		return $this->_jsFiles;
9526
	}
9527
	protected function setJavaScriptFiles($value)
9528
	{
9529
		$this->_jsFiles=$value;
9530
	}
9531
}
9532
class TPageService extends TService
9533
{
9534
	const CONFIG_FILE_XML='config.xml';
9535
	const CONFIG_FILE_PHP='config.php';
9536
	const DEFAULT_BASEPATH='Pages';
9537
	const FALLBACK_BASEPATH='pages';
9538
	const CONFIG_CACHE_PREFIX='prado:pageservice:';
9539
	const PAGE_FILE_EXT='.page';
9540
	private $_basePath=null;
9541
	private $_basePageClass='TPage';
9542
	private $_clientScriptManagerClass='System.Web.UI.TClientScriptManager';
9543
	private $_defaultPage='Home';
9544
	private $_pagePath=null;
9545
	private $_page=null;
9546
	private $_properties=array();
9547
	private $_initialized=false;
9548
	private $_themeManager=null;
9549
	private $_templateManager=null;
9550
	public function init($config)
9551
	{
9552
		$pageConfig=$this->loadPageConfig($config);
9553
		$this->initPageContext($pageConfig);
9554
		$this->_initialized=true;
9555
	}
9556
	protected function initPageContext($pageConfig)
9557
	{
9558
		$application=$this->getApplication();
9559
		foreach($pageConfig->getApplicationConfigurations() as $appConfig)
9560
			$application->applyConfiguration($appConfig);
9561
		$this->applyConfiguration($pageConfig);
9562
	}
9563
	protected function applyConfiguration($config)
9564
	{
9565
				$this->_properties=array_merge($this->_properties, $config->getProperties());
9566
		$this->getApplication()->getAuthorizationRules()->mergeWith($config->getRules());
9567
		$pagePath=$this->getRequestedPagePath();
9568
				foreach($config->getExternalConfigurations() as $filePath=>$params)
9569
		{
9570
			list($configPagePath,$condition)=$params;
9571
			if($condition!==true)
9572
				$condition=$this->evaluateExpression($condition);
9573
			if($condition)
9574
			{
9575
				if(($path=Prado::getPathOfNamespace($filePath,Prado::getApplication()->getConfigurationFileExt()))===null || !is_file($path))
9576
					throw new TConfigurationException('pageservice_includefile_invalid',$filePath);
9577
				$c=new TPageConfiguration($pagePath);
9578
				$c->loadFromFile($path,$configPagePath);
9579
				$this->applyConfiguration($c);
9580
			}
9581
		}
9582
	}
9583
	protected function determineRequestedPagePath()
9584
	{
9585
		$pagePath=$this->getRequest()->getServiceParameter();
9586
		if(empty($pagePath))
9587
			$pagePath=$this->getDefaultPage();
9588
		return $pagePath;
9589
	}
9590
	protected function loadPageConfig($config)
9591
	{
9592
		$application=$this->getApplication();
9593
		$pagePath=$this->getRequestedPagePath();
9594
		if(($cache=$application->getCache())===null)
9595
		{
9596
			$pageConfig=new TPageConfiguration($pagePath);
9597
			if($config!==null)
9598
			{
9599
				if($application->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
9600
					$pageConfig->loadPageConfigurationFromPhp($config,$application->getBasePath(),'');
9601
				else
9602
					$pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),'');
9603
			}
9604
			$pageConfig->loadFromFiles($this->getBasePath());
9605
		}
9606
		else
9607
		{
9608
			$configCached=true;
9609
			$currentTimestamp=array();
9610
			$arr=$cache->get(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath);
9611
			if(is_array($arr))
9612
			{
9613
				list($pageConfig,$timestamps)=$arr;
9614
				if($application->getMode()!==TApplicationMode::Performance)
9615
				{
9616
					foreach($timestamps as $fileName=>$timestamp)
9617
					{
9618
						if($fileName===0) 						{
9619
							$appConfigFile=$application->getConfigurationFile();
9620
							$currentTimestamp[0]=$appConfigFile===null?0:@filemtime($appConfigFile);
9621
							if($currentTimestamp[0]>$timestamp || ($timestamp>0 && !$currentTimestamp[0]))
9622
								$configCached=false;
9623
						}
9624
						else
9625
						{
9626
							$currentTimestamp[$fileName]=@filemtime($fileName);
9627
							if($currentTimestamp[$fileName]>$timestamp || ($timestamp>0 && !$currentTimestamp[$fileName]))
9628
								$configCached=false;
9629
						}
9630
					}
9631
				}
9632
			}
9633
			else
9634
			{
9635
				$configCached=false;
9636
				$paths=explode('.',$pagePath);
9637
				$configPath=$this->getBasePath();
9638
				$fileName = $this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP
9639
					? self::CONFIG_FILE_PHP
9640
					: self::CONFIG_FILE_XML;
9641
				foreach($paths as $path)
9642
				{
9643
					$configFile=$configPath.DIRECTORY_SEPARATOR.$fileName;
9644
					$currentTimestamp[$configFile]=@filemtime($configFile);
9645
					$configPath.=DIRECTORY_SEPARATOR.$path;
9646
				}
9647
				$appConfigFile=$application->getConfigurationFile();
9648
				$currentTimestamp[0]=$appConfigFile===null?0:@filemtime($appConfigFile);
9649
			}
9650
			if(!$configCached)
9651
			{
9652
				$pageConfig=new TPageConfiguration($pagePath);
9653
				if($config!==null)
9654
				{
9655
					if($application->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
9656
						$pageConfig->loadPageConfigurationFromPhp($config,$application->getBasePath(),'');
9657
					else
9658
						$pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),'');
9659
				}
9660
				$pageConfig->loadFromFiles($this->getBasePath());
9661
				$cache->set(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath,array($pageConfig,$currentTimestamp));
9662
			}
9663
		}
9664
		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...
9665
	}
9666
	public function getTemplateManager()
9667
	{
9668
		if(!$this->_templateManager)
9669
		{
9670
			$this->_templateManager=new TTemplateManager;
9671
			$this->_templateManager->init(null);
9672
		}
9673
		return $this->_templateManager;
9674
	}
9675
	public function setTemplateManager(TTemplateManager $value)
9676
	{
9677
		$this->_templateManager=$value;
9678
	}
9679
	public function getThemeManager()
9680
	{
9681
		if(!$this->_themeManager)
9682
		{
9683
			$this->_themeManager=new TThemeManager;
9684
			$this->_themeManager->init(null);
9685
		}
9686
		return $this->_themeManager;
9687
	}
9688
	public function setThemeManager(TThemeManager $value)
9689
	{
9690
		$this->_themeManager=$value;
9691
	}
9692
	public function getRequestedPagePath()
9693
	{
9694
		if($this->_pagePath===null)
9695
		{
9696
			$this->_pagePath=strtr($this->determineRequestedPagePath(),'/\\','..');
9697
			if(empty($this->_pagePath))
9698
				throw new THttpException(404,'pageservice_page_required');
9699
		}
9700
		return $this->_pagePath;
9701
	}
9702
	public function getRequestedPage()
9703
	{
9704
		return $this->_page;
9705
	}
9706
	public function getDefaultPage()
9707
	{
9708
		return $this->_defaultPage;
9709
	}
9710
	public function setDefaultPage($value)
9711
	{
9712
		if($this->_initialized)
9713
			throw new TInvalidOperationException('pageservice_defaultpage_unchangeable');
9714
		else
9715
			$this->_defaultPage=$value;
9716
	}
9717
	public function getDefaultPageUrl()
9718
	{
9719
		return $this->constructUrl($this->getDefaultPage());
9720
	}
9721
	public function getBasePath()
9722
	{
9723
		if($this->_basePath===null)
9724
		{
9725
			$basePath=$this->getApplication()->getBasePath().DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
9726
			if(($this->_basePath=realpath($basePath))===false || !is_dir($this->_basePath))
9727
			{
9728
				$basePath=$this->getApplication()->getBasePath().DIRECTORY_SEPARATOR.self::FALLBACK_BASEPATH;
9729
				if(($this->_basePath=realpath($basePath))===false || !is_dir($this->_basePath))
9730
					throw new TConfigurationException('pageservice_basepath_invalid',$basePath);
9731
			}
9732
		}
9733
		return $this->_basePath;
9734
	}
9735
	public function setBasePath($value)
9736
	{
9737
		if($this->_initialized)
9738
			throw new TInvalidOperationException('pageservice_basepath_unchangeable');
9739
		else if(($path=Prado::getPathOfNamespace($value))===null || !is_dir($path))
9740
			throw new TConfigurationException('pageservice_basepath_invalid',$value);
9741
		$this->_basePath=realpath($path);
9742
	}
9743
	public function setBasePageClass($value)
9744
	{
9745
		$this->_basePageClass=$value;
9746
	}
9747
	public function getBasePageClass()
9748
	{
9749
		return $this->_basePageClass;
9750
	}
9751
	public function setClientScriptManagerClass($value)
9752
	{
9753
		$this->_clientScriptManagerClass=$value;
9754
	}
9755
	public function getClientScriptManagerClass()
9756
	{
9757
		return $this->_clientScriptManagerClass;
9758
	}
9759
	public function run()
9760
	{
9761
		$this->_page=$this->createPage($this->getRequestedPagePath());
9762
		$this->runPage($this->_page,$this->_properties);
9763
	}
9764
	protected function createPage($pagePath)
9765
	{
9766
		$path=$this->getBasePath().DIRECTORY_SEPARATOR.strtr($pagePath,'.',DIRECTORY_SEPARATOR);
9767
		$hasTemplateFile=is_file($path.self::PAGE_FILE_EXT);
9768
		$hasClassFile=is_file($path.Prado::CLASS_FILE_EXT);
9769
		if(!$hasTemplateFile && !$hasClassFile)
9770
			throw new THttpException(404,'pageservice_page_unknown',$pagePath);
9771
		if($hasClassFile)
9772
		{
9773
			$className=basename($path);
9774
			if(!class_exists($className,false))
9775
				include_once($path.Prado::CLASS_FILE_EXT);
9776
		}
9777
		else
9778
		{
9779
			$className=$this->getBasePageClass();
9780
			Prado::using($className);
9781
			if(($pos=strrpos($className,'.'))!==false)
9782
				$className=substr($className,$pos+1);
9783
		}
9784
 		if(!class_exists($className,false) || ($className!=='TPage' && !is_subclass_of($className,'TPage')))
9785
			throw new THttpException(404,'pageservice_page_unknown',$pagePath);
9786
		$page=Prado::createComponent($className);
9787
		$page->setPagePath($pagePath);
9788
		if($hasTemplateFile)
9789
			$page->setTemplate($this->getTemplateManager()->getTemplateByFileName($path.self::PAGE_FILE_EXT));
9790
		return $page;
9791
	}
9792
	protected function runPage($page,$properties)
9793
	{
9794
		foreach($properties as $name=>$value)
9795
			$page->setSubProperty($name,$value);
9796
		$page->run($this->getResponse()->createHtmlWriter());
9797
	}
9798
	public function constructUrl($pagePath,$getParams=null,$encodeAmpersand=true,$encodeGetItems=true)
9799
	{
9800
		return $this->getRequest()->constructUrl($this->getID(),$pagePath,$getParams,$encodeAmpersand,$encodeGetItems);
9801
	}
9802
}
9803
class TPageConfiguration extends TComponent
9804
{
9805
	private $_appConfigs=array();
9806
	private $_properties=array();
9807
	private $_rules=array();
9808
	private $_includes=array();
9809
	private $_pagePath='';
9810
	public function __construct($pagePath)
9811
	{
9812
		$this->_pagePath=$pagePath;
9813
	}
9814
	public function getExternalConfigurations()
9815
	{
9816
		return $this->_includes;
9817
	}
9818
	public function getProperties()
9819
	{
9820
		return $this->_properties;
9821
	}
9822
	public function getRules()
9823
	{
9824
		return $this->_rules;
9825
	}
9826
	public function getApplicationConfigurations()
9827
	{
9828
		return $this->_appConfigs;
9829
	}
9830
	public function loadFromFiles($basePath)
9831
	{
9832
		$paths=explode('.',$this->_pagePath);
9833
		$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...
9834
		$path=$basePath;
9835
		$configPagePath='';
9836
		$fileName = Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP
9837
			? TPageService::CONFIG_FILE_PHP
9838
			: TPageService::CONFIG_FILE_XML;
9839
		foreach($paths as $p)
9840
		{
9841
			$this->loadFromFile($path.DIRECTORY_SEPARATOR.$fileName,$configPagePath);
9842
			$path.=DIRECTORY_SEPARATOR.$p;
9843
			if($configPagePath==='')
9844
				$configPagePath=$p;
9845
			else
9846
				$configPagePath.='.'.$p;
9847
		}
9848
		$this->loadFromFile($path.DIRECTORY_SEPARATOR.$fileName,$configPagePath);
9849
		$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...
9850
	}
9851
	public function loadFromFile($fname,$configPagePath)
9852
	{
9853
		if(empty($fname) || !is_file($fname))
9854
			return;
9855
		if(Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
9856
		{
9857
			$fcontent = include $fname;
9858
			$this->loadFromPhp($fcontent,dirname($fname),$configPagePath);
9859
		}
9860
		else
9861
		{
9862
			$dom=new TXmlDocument;
9863
			if($dom->loadFromFile($fname))
9864
				$this->loadFromXml($dom,dirname($fname),$configPagePath);
9865
			else
9866
				throw new TConfigurationException('pageserviceconf_file_invalid',$fname);
9867
		}
9868
	}
9869
	public function loadFromPhp($config,$configPath,$configPagePath)
9870
	{
9871
		$this->loadApplicationConfigurationFromPhp($config,$configPath);
9872
		$this->loadPageConfigurationFromPhp($config,$configPath,$configPagePath);
9873
	}
9874
	public function loadFromXml($dom,$configPath,$configPagePath)
9875
	{
9876
		$this->loadApplicationConfigurationFromXml($dom,$configPath);
9877
		$this->loadPageConfigurationFromXml($dom,$configPath,$configPagePath);
9878
	}
9879
	public function loadApplicationConfigurationFromPhp($config,$configPath)
9880
	{
9881
		$appConfig=new TApplicationConfiguration;
9882
		$appConfig->loadFromPhp($config,$configPath);
9883
		$this->_appConfigs[]=$appConfig;
9884
	}
9885
	public function loadApplicationConfigurationFromXml($dom,$configPath)
9886
	{
9887
		$appConfig=new TApplicationConfiguration;
9888
		$appConfig->loadFromXml($dom,$configPath);
9889
		$this->_appConfigs[]=$appConfig;
9890
	}
9891
	public function loadPageConfigurationFromPhp($config, $configPath, $configPagePath)
9892
	{
9893
				if(isset($config['authorization']) && is_array($config['authorization']))
9894
		{
9895
			$rules = array();
9896
			foreach($config['authorization'] as $authorization)
9897
			{
9898
				$patterns=isset($authorization['pages'])?$authorization['pages']:'';
9899
				$ruleApplies=false;
9900
				if(empty($patterns) || trim($patterns)==='*') 					$ruleApplies=true;
9901
				else
9902
				{
9903
					foreach(explode(',',$patterns) as $pattern)
9904
					{
9905
						if(($pattern=trim($pattern))!=='')
9906
						{
9907
														if($configPagePath!=='')  								$pattern=$configPagePath.'.'.$pattern;
9908
							if(strcasecmp($pattern,$this->_pagePath)===0)
9909
							{
9910
								$ruleApplies=true;
9911
								break;
9912
							}
9913
							if($pattern[strlen($pattern)-1]==='*') 							{
9914
								if(strncasecmp($this->_pagePath,$pattern,strlen($pattern)-1)===0)
9915
								{
9916
									$ruleApplies=true;
9917
									break;
9918
								}
9919
							}
9920
						}
9921
					}
9922
				}
9923
				if($ruleApplies)
9924
				{
9925
					$action = isset($authorization['action'])?$authorization['action']:'';
9926
					$users = isset($authorization['users'])?$authorization['users']:'';
9927
					$roles = isset($authorization['roles'])?$authorization['roles']:'';
9928
					$verb = isset($authorization['verb'])?$authorization['verb']:'';
9929
					$ips = isset($authorization['ips'])?$authorization['ips']:'';
9930
					$rules[]=new TAuthorizationRule($action,$users,$roles,$verb,$ips);
9931
				}
9932
			}
9933
			$this->_rules=array_merge($rules,$this->_rules);
9934
		}
9935
				if(isset($config['pages']) && is_array($config['pages']))
9936
		{
9937
			if(isset($config['pages']['properties']))
9938
			{
9939
				$this->_properties = array_merge($this->_properties, $config['pages']['properties']);
9940
				unset($config['pages']['properties']);
9941
			}
9942
			foreach($config['pages'] as $id => $page)
9943
			{
9944
				$properties = array();
9945
				if(isset($page['properties']))
9946
				{
9947
					$properties=$page['properties'];
9948
					unset($page['properties']);
9949
				}
9950
				$matching=false;
9951
				$id=($configPagePath==='')?$id:$configPagePath.'.'.$id;
9952
				if(strcasecmp($id,$this->_pagePath)===0)
9953
					$matching=true;
9954
				else if($id[strlen($id)-1]==='*') 					$matching=strncasecmp($this->_pagePath,$id,strlen($id)-1)===0;
9955
				if($matching)
9956
					$this->_properties=array_merge($this->_properties,$properties);
9957
			}
9958
		}
9959
				if(isset($config['includes']) && is_array($config['includes']))
9960
		{
9961
			foreach($config['includes'] as $include)
9962
			{
9963
				$when = isset($include['when'])?true:false;
9964
				if(!isset($include['file']))
9965
					throw new TConfigurationException('pageserviceconf_includefile_required');
9966
				$filePath = $include['file'];
9967
				if(isset($this->_includes[$filePath]))
9968
					$this->_includes[$filePath]=array($configPagePath,'('.$this->_includes[$filePath][1].') || ('.$when.')');
9969
				else
9970
					$this->_includes[$filePath]=array($configPagePath,$when);
9971
			}
9972
		}
9973
	}
9974
	public function loadPageConfigurationFromXml($dom,$configPath,$configPagePath)
9975
	{
9976
				if(($authorizationNode=$dom->getElementByTagName('authorization'))!==null)
9977
		{
9978
			$rules=array();
9979
			foreach($authorizationNode->getElements() as $node)
9980
			{
9981
				$patterns=$node->getAttribute('pages');
9982
				$ruleApplies=false;
9983
				if(empty($patterns) || trim($patterns)==='*') 					$ruleApplies=true;
9984
				else
9985
				{
9986
					foreach(explode(',',$patterns) as $pattern)
9987
					{
9988
						if(($pattern=trim($pattern))!=='')
9989
						{
9990
														if($configPagePath!=='')  								$pattern=$configPagePath.'.'.$pattern;
9991
							if(strcasecmp($pattern,$this->_pagePath)===0)
9992
							{
9993
								$ruleApplies=true;
9994
								break;
9995
							}
9996
							if($pattern[strlen($pattern)-1]==='*') 							{
9997
								if(strncasecmp($this->_pagePath,$pattern,strlen($pattern)-1)===0)
9998
								{
9999
									$ruleApplies=true;
10000
									break;
10001
								}
10002
							}
10003
						}
10004
					}
10005
				}
10006
				if($ruleApplies)
10007
					$rules[]=new TAuthorizationRule($node->getTagName(),$node->getAttribute('users'),$node->getAttribute('roles'),$node->getAttribute('verb'),$node->getAttribute('ips'));
10008
			}
10009
			$this->_rules=array_merge($rules,$this->_rules);
10010
		}
10011
				if(($pagesNode=$dom->getElementByTagName('pages'))!==null)
10012
		{
10013
			$this->_properties=array_merge($this->_properties,$pagesNode->getAttributes()->toArray());
10014
						foreach($pagesNode->getElementsByTagName('page') as $node)
10015
			{
10016
				$properties=$node->getAttributes();
10017
				$id=$properties->remove('id');
10018
				if(empty($id))
10019
					throw new TConfigurationException('pageserviceconf_page_invalid',$configPath);
10020
				$matching=false;
10021
				$id=($configPagePath==='')?$id:$configPagePath.'.'.$id;
10022
				if(strcasecmp($id,$this->_pagePath)===0)
10023
					$matching=true;
10024
				else if($id[strlen($id)-1]==='*') 					$matching=strncasecmp($this->_pagePath,$id,strlen($id)-1)===0;
10025
				if($matching)
10026
					$this->_properties=array_merge($this->_properties,$properties->toArray());
10027
			}
10028
		}
10029
				foreach($dom->getElementsByTagName('include') as $node)
10030
		{
10031
			if(($when=$node->getAttribute('when'))===null)
10032
				$when=true;
10033
			if(($filePath=$node->getAttribute('file'))===null)
10034
				throw new TConfigurationException('pageserviceconf_includefile_required');
10035
			if(isset($this->_includes[$filePath]))
10036
				$this->_includes[$filePath]=array($configPagePath,'('.$this->_includes[$filePath][1].') || ('.$when.')');
10037
			else
10038
				$this->_includes[$filePath]=array($configPagePath,$when);
10039
		}
10040
	}
10041
}
10042
class TAssetManager extends TModule
10043
{
10044
	const DEFAULT_BASEPATH='assets';
10045
	private $_basePath=null;
10046
	private $_baseUrl=null;
10047
	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...
10048
	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...
10049
	private $_published=array();
10050
	private $_initialized=false;
10051
	public function init($config)
10052
	{
10053
		$application=$this->getApplication();
10054
		if($this->_basePath===null)
10055
			$this->_basePath=dirname($application->getRequest()->getApplicationFilePath()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
10056
		if(!is_writable($this->_basePath) || !is_dir($this->_basePath))
10057
			throw new TConfigurationException('assetmanager_basepath_invalid',$this->_basePath);
10058
		if($this->_baseUrl===null)
10059
			$this->_baseUrl=rtrim(dirname($application->getRequest()->getApplicationUrl()),'/\\').'/'.self::DEFAULT_BASEPATH;
10060
		$application->setAssetManager($this);
10061
		$this->_initialized=true;
10062
	}
10063
	public function getBasePath()
10064
	{
10065
		return $this->_basePath;
10066
	}
10067
	public function setBasePath($value)
10068
	{
10069
		if($this->_initialized)
10070
			throw new TInvalidOperationException('assetmanager_basepath_unchangeable');
10071
		else
10072
		{
10073
			$this->_basePath=Prado::getPathOfNamespace($value);
10074
			if($this->_basePath===null || !is_dir($this->_basePath) || !is_writable($this->_basePath))
10075
				throw new TInvalidDataValueException('assetmanager_basepath_invalid',$value);
10076
		}
10077
	}
10078
	public function getBaseUrl()
10079
	{
10080
		return $this->_baseUrl;
10081
	}
10082
	public function setBaseUrl($value)
10083
	{
10084
		if($this->_initialized)
10085
			throw new TInvalidOperationException('assetmanager_baseurl_unchangeable');
10086
		else
10087
			$this->_baseUrl=rtrim($value,'/');
10088
	}
10089
	public function publishFilePath($path,$checkTimestamp=false)
10090
	{
10091
		if(isset($this->_published[$path]))
10092
			return $this->_published[$path];
10093
		else if(empty($path) || ($fullpath=realpath($path))===false)
10094
			throw new TInvalidDataValueException('assetmanager_filepath_invalid',$path);
10095
		else if(is_file($fullpath))
10096
		{
10097
			$dir=$this->hash(dirname($fullpath));
10098
			$fileName=basename($fullpath);
10099
			$dst=$this->_basePath.DIRECTORY_SEPARATOR.$dir;
10100
			if(!is_file($dst.DIRECTORY_SEPARATOR.$fileName) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
10101
				$this->copyFile($fullpath,$dst);
10102
			return $this->_published[$path]=$this->_baseUrl.'/'.$dir.'/'.$fileName;
10103
		}
10104
		else
10105
		{
10106
			$dir=$this->hash($fullpath);
10107
			if(!is_dir($this->_basePath.DIRECTORY_SEPARATOR.$dir) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
10108
			{
10109
				$this->copyDirectory($fullpath,$this->_basePath.DIRECTORY_SEPARATOR.$dir);
10110
			}
10111
			return $this->_published[$path]=$this->_baseUrl.'/'.$dir;
10112
		}
10113
	}
10114
	public function getPublished()
10115
	{
10116
		return $this->_published;
10117
	}
10118
	protected function setPublished($values=array())
10119
	{
10120
		$this->_published = $values;
10121
	}
10122
	public function getPublishedPath($path)
10123
	{
10124
		$path=realpath($path);
10125
		if(is_file($path))
10126
			return $this->_basePath.DIRECTORY_SEPARATOR.$this->hash(dirname($path)).DIRECTORY_SEPARATOR.basename($path);
10127
		else
10128
			return $this->_basePath.DIRECTORY_SEPARATOR.$this->hash($path);
10129
	}
10130
	public function getPublishedUrl($path)
10131
	{
10132
		$path=realpath($path);
10133
		if(is_file($path))
10134
			return $this->_baseUrl.'/'.$this->hash(dirname($path)).'/'.basename($path);
10135
		else
10136
			return $this->_baseUrl.'/'.$this->hash($path);
10137
	}
10138
	protected function hash($dir)
10139
	{
10140
		return sprintf('%x',crc32($dir.Prado::getVersion()));
10141
	}
10142
	protected function copyFile($src,$dst)
10143
	{
10144
		if(!is_dir($dst))
10145
		{
10146
			@mkdir($dst);
10147
			@chmod($dst, PRADO_CHMOD);
10148
		}
10149
		$dstFile=$dst.DIRECTORY_SEPARATOR.basename($src);
10150
		if(@filemtime($dstFile)<@filemtime($src))
10151
		{
10152
			@copy($src,$dstFile);
10153
		}
10154
	}
10155
	public function copyDirectory($src,$dst)
10156
	{
10157
		if(!is_dir($dst))
10158
		{
10159
			@mkdir($dst);
10160
			@chmod($dst, PRADO_CHMOD);
10161
		}
10162
		if($folder=@opendir($src))
10163
		{
10164
			while($file=@readdir($folder))
10165
			{
10166
				if($file==='.' || $file==='..' || $file==='.svn')
10167
					continue;
10168
				else if(is_file($src.DIRECTORY_SEPARATOR.$file))
10169
				{
10170
					if(@filemtime($dst.DIRECTORY_SEPARATOR.$file)<@filemtime($src.DIRECTORY_SEPARATOR.$file))
10171
					{
10172
						@copy($src.DIRECTORY_SEPARATOR.$file,$dst.DIRECTORY_SEPARATOR.$file);
10173
						@chmod($dst.DIRECTORY_SEPARATOR.$file, PRADO_CHMOD);
10174
					}
10175
				}
10176
				else
10177
					$this->copyDirectory($src.DIRECTORY_SEPARATOR.$file,$dst.DIRECTORY_SEPARATOR.$file);
10178
			}
10179
			closedir($folder);
10180
		} else {
10181
			throw new TInvalidDataValueException('assetmanager_source_directory_invalid', $src);
10182
		}
10183
	}
10184
	public function publishTarFile($tarfile, $md5sum, $checkTimestamp=false)
10185
	{
10186
		if(isset($this->_published[$md5sum]))
10187
			return $this->_published[$md5sum];
10188
		else if(($fullpath=realpath($md5sum))===false || !is_file($fullpath))
10189
			throw new TInvalidDataValueException('assetmanager_tarchecksum_invalid',$md5sum);
10190
		else
10191
		{
10192
			$dir=$this->hash(dirname($fullpath));
10193
			$fileName=basename($fullpath);
10194
			$dst=$this->_basePath.DIRECTORY_SEPARATOR.$dir;
10195
			if(!is_file($dst.DIRECTORY_SEPARATOR.$fileName) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
10196
			{
10197
				if(@filemtime($dst.DIRECTORY_SEPARATOR.$fileName)<@filemtime($fullpath))
10198
				{
10199
					$this->copyFile($fullpath,$dst);
10200
					$this->deployTarFile($tarfile,$dst);
10201
				}
10202
			}
10203
			return $this->_published[$md5sum]=$this->_baseUrl.'/'.$dir;
10204
		}
10205
	}
10206
	protected function deployTarFile($path,$destination)
10207
	{
10208
		if(($fullpath=realpath($path))===false || !is_file($fullpath))
10209
			throw new TIOException('assetmanager_tarfile_invalid',$path);
10210
		else
10211
		{
10212
			Prado::using('System.IO.TTarFileExtractor');
10213
			$tar = new TTarFileExtractor($fullpath);
10214
			return $tar->extract($destination);
10215
		}
10216
	}
10217
}
10218
class TGlobalization extends TModule
10219
{
10220
	private $_defaultCharset = 'UTF-8';
10221
	private $_defaultCulture = 'en';
10222
	private $_charset=null;
10223
	private $_culture=null;
10224
	private $_translation;
10225
	private $_translateDefaultCulture=true;
10226
	public function init($config)
10227
	{
10228
		if($this->_charset===null)
10229
			$this->_charset=$this->getDefaultCharset();
10230
		if($this->_culture===null)
10231
			$this->_culture=$this->getDefaultCulture();
10232
		if($config!==null)
10233
		{
10234
			if($this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
10235
				$translation = isset($config['translate'])?$config['translate']:null;
10236
			else
10237
			{
10238
				$t = $config->getElementByTagName('translation');
10239
				$translation = ($t)?$t->getAttributes():null;
10240
			}
10241
			if($translation)
10242
				$this->setTranslationConfiguration($translation);
10243
		}
10244
		$this->getApplication()->setGlobalization($this);
10245
	}
10246
	public function getTranslateDefaultCulture()
10247
	{
10248
		return $this->_translateDefaultCulture;
10249
	}
10250
	public function setTranslateDefaultCulture($value)
10251
	{
10252
		$this->_translateDefaultCulture = TPropertyValue::ensureBoolean($value);
10253
	}
10254
	public function getDefaultCulture()
10255
	{
10256
		return $this->_defaultCulture;
10257
	}
10258
	public function setDefaultCulture($culture)
10259
	{
10260
		$this->_defaultCulture = str_replace('-','_',$culture);
10261
	}
10262
	public function getDefaultCharset()
10263
	{
10264
		return $this->_defaultCharset;
10265
	}
10266
	public function setDefaultCharset($charset)
10267
	{
10268
		$this->_defaultCharset = $charset;
10269
	}
10270
	public function getCulture()
10271
	{
10272
		return $this->_culture;
10273
	}
10274
	public function setCulture($culture)
10275
	{
10276
		$this->_culture = str_replace('-','_',$culture);
10277
	}
10278
	public function getCharset()
10279
	{
10280
		return $this->_charset;
10281
	}
10282
	public function setCharset($charset)
10283
	{
10284
		$this->_charset = $charset;
10285
	}
10286
	public function getTranslationConfiguration()
10287
	{
10288
		return (!$this->_translateDefaultCulture && ($this->getDefaultCulture() == $this->getCulture()))
10289
			? null
10290
			: $this->_translation;
10291
	}
10292
	protected function setTranslationConfiguration($config)
10293
	{
10294
		if($config['type'] == 'XLIFF' || $config['type'] == 'gettext')
10295
		{
10296
			if($config['source'])
10297
			{
10298
				$config['source'] = Prado::getPathOfNamespace($config['source']);
10299
				if(!is_dir($config['source']))
10300
				{
10301
					if(@mkdir($config['source'])===false)
10302
					throw new TConfigurationException('globalization_source_path_failed',
10303
						$config['source']);
10304
					chmod($config['source'], PRADO_CHMOD); 				}
10305
			}
10306
			else
10307
			{
10308
				throw new TConfigurationException("invalid source dir '{$config['source']}'");
10309
			}
10310
		}
10311
		if(isset($config['cache']) && TPropertyValue::ensureBoolean($config['cache']))
10312
		{
10313
			$config['cache'] = $this->getApplication()->getRunTimePath().'/i18n';
10314
			if(!is_dir($config['cache']))
10315
			{
10316
				if(@mkdir($config['cache'])===false)
10317
					throw new TConfigurationException('globalization_cache_path_failed',
10318
						$config['cache']);
10319
				chmod($config['cache'], PRADO_CHMOD); 			}
10320
		}
10321
		else
10322
		{
10323
			unset($config['cache']);
10324
		}
10325
		$this->_translation = $config;
10326
	}
10327
	public function getTranslationCatalogue()
10328
	{
10329
		return $this->_translation['catalogue'];
10330
	}
10331
	public function setTranslationCatalogue($value)
10332
	{
10333
		$this->_translation['catalogue'] = $value;
10334
	}
10335
	public function getCultureVariants($culture=null)
10336
	{
10337
		if($culture===null) $culture = $this->getCulture();
10338
		$variants = explode('_', $culture);
10339
		$result = array();
10340
		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...
10341
			$result[] = implode('_', $variants);
10342
		return $result;
10343
	}
10344
	public function getLocalizedResource($file,$culture=null)
10345
	{
10346
		$files = array();
10347
		$variants = $this->getCultureVariants($culture);
10348
		$path = pathinfo($file);
10349
		foreach($variants as $variant)
10350
			$files[] = $path['dirname'].DIRECTORY_SEPARATOR.$variant.DIRECTORY_SEPARATOR.$path['basename'];
10351
		$filename = substr($path['basename'],0,strrpos($path['basename'],'.'));
10352
		foreach($variants as $variant)
10353
			$files[] = $path['dirname'].DIRECTORY_SEPARATOR.$filename.'.'.$variant.'.'.$path['extension'];
10354
		$files[] = $file;
10355
		return $files;
10356
	}
10357
}
10358
class TApplication extends TComponent
10359
{
10360
	const STATE_OFF='Off';
10361
	const STATE_DEBUG='Debug';
10362
	const STATE_NORMAL='Normal';
10363
	const STATE_PERFORMANCE='Performance';
10364
	const PAGE_SERVICE_ID='page';
10365
	const CONFIG_FILE_XML='application.xml';
10366
	const CONFIG_FILE_EXT_XML='.xml';
10367
	const CONFIG_TYPE_XML = 'xml';
10368
	const CONFIG_FILE_PHP='application.php';
10369
	const CONFIG_FILE_EXT_PHP='.php';
10370
	const CONFIG_TYPE_PHP = 'php';
10371
	const RUNTIME_PATH='runtime';
10372
	const CONFIGCACHE_FILE='config.cache';
10373
	const GLOBAL_FILE='global.cache';
10374
	private static $_steps=array(
10375
		'onBeginRequest',
10376
		'onLoadState',
10377
		'onLoadStateComplete',
10378
		'onAuthentication',
10379
		'onAuthenticationComplete',
10380
		'onAuthorization',
10381
		'onAuthorizationComplete',
10382
		'onPreRunService',
10383
		'runService',
10384
		'onSaveState',
10385
		'onSaveStateComplete',
10386
		'onPreFlushOutput',
10387
		'flushOutput'
10388
	);
10389
	private $_id;
10390
	private $_uniqueID;
10391
	private $_requestCompleted=false;
10392
	private $_step;
10393
	private $_services;
10394
	private $_service;
10395
	private $_modules=array();
10396
	private $_lazyModules=array();
10397
	private $_parameters;
10398
	private $_configFile;
10399
	private $_configFileExt;
10400
	private $_configType;
10401
	private $_basePath;
10402
	private $_runtimePath;
10403
	private $_stateChanged=false;
10404
	private $_globals=array();
10405
	private $_cacheFile;
10406
	private $_errorHandler;
10407
	private $_request;
10408
	private $_response;
10409
	private $_session;
10410
	private $_cache;
10411
	private $_statePersister;
10412
	private $_user;
10413
	private $_globalization;
10414
	private $_security;
10415
	private $_assetManager;
10416
	private $_authRules;
10417
	private $_mode=TApplicationMode::Debug;
10418
	private $_pageServiceID = self::PAGE_SERVICE_ID;
10419
	public function __construct($basePath='protected',$cacheConfig=true, $configType=self::CONFIG_TYPE_XML)
10420
	{
10421
				Prado::setApplication($this);
10422
		$this->setConfigurationType($configType);
10423
		$this->resolvePaths($basePath);
10424
		if($cacheConfig)
10425
			$this->_cacheFile=$this->_runtimePath.DIRECTORY_SEPARATOR.self::CONFIGCACHE_FILE;
10426
				$this->_uniqueID=md5($this->_runtimePath);
10427
		$this->_parameters=new TMap;
10428
		$this->_services=array($this->getPageServiceID()=>array('TPageService',array(),null));
10429
		Prado::setPathOfAlias('Application',$this->_basePath);
10430
	}
10431
	protected function resolvePaths($basePath)
10432
	{
10433
				if(empty($basePath) || ($basePath=realpath($basePath))===false)
10434
			throw new TConfigurationException('application_basepath_invalid',$basePath);
10435
		if(is_dir($basePath) && is_file($basePath.DIRECTORY_SEPARATOR.$this->getConfigurationFileName()))
10436
			$configFile=$basePath.DIRECTORY_SEPARATOR.$this->getConfigurationFileName();
10437
		else if(is_file($basePath))
10438
		{
10439
			$configFile=$basePath;
10440
			$basePath=dirname($configFile);
10441
		}
10442
		else
10443
			$configFile=null;
10444
				$runtimePath=$basePath.DIRECTORY_SEPARATOR.self::RUNTIME_PATH;
10445
		if(is_writable($runtimePath))
10446
		{
10447
			if($configFile!==null)
10448
			{
10449
				$runtimePath.=DIRECTORY_SEPARATOR.basename($configFile).'-'.Prado::getVersion();
10450
				if(!is_dir($runtimePath))
10451
				{
10452
					if(@mkdir($runtimePath)===false)
10453
						throw new TConfigurationException('application_runtimepath_failed',$runtimePath);
10454
					@chmod($runtimePath, PRADO_CHMOD); 				}
10455
				$this->setConfigurationFile($configFile);
10456
			}
10457
			$this->setBasePath($basePath);
10458
			$this->setRuntimePath($runtimePath);
10459
		}
10460
		else
10461
			throw new TConfigurationException('application_runtimepath_invalid',$runtimePath);
10462
	}
10463
	public function run()
10464
	{
10465
		try
10466
		{
10467
			$this->initApplication();
10468
			$n=count(self::$_steps);
10469
			$this->_step=0;
10470
			$this->_requestCompleted=false;
10471
			while($this->_step<$n)
10472
			{
10473
				if($this->_mode===self::STATE_OFF)
10474
					throw new THttpException(503,'application_unavailable');
10475
				if($this->_requestCompleted)
10476
					break;
10477
				$method=self::$_steps[$this->_step];
10478
				$this->$method();
10479
				$this->_step++;
10480
			}
10481
		}
10482
		catch(Exception $e)
10483
		{
10484
			$this->onError($e);
10485
		}
10486
		$this->onEndRequest();
10487
	}
10488
	public function completeRequest()
10489
	{
10490
		$this->_requestCompleted=true;
10491
	}
10492
	public function getRequestCompleted()
10493
	{
10494
		return $this->_requestCompleted;
10495
	}
10496
	public function getGlobalState($key,$defaultValue=null)
10497
	{
10498
		return isset($this->_globals[$key])?$this->_globals[$key]:$defaultValue;
10499
	}
10500
	public function setGlobalState($key,$value,$defaultValue=null,$forceSave=false)
10501
	{
10502
		$this->_stateChanged=true;
10503
		if($value===$defaultValue)
10504
			unset($this->_globals[$key]);
10505
		else
10506
			$this->_globals[$key]=$value;
10507
		if($forceSave)
10508
			$this->saveGlobals();
10509
	}
10510
	public function clearGlobalState($key)
10511
	{
10512
		$this->_stateChanged=true;
10513
		unset($this->_globals[$key]);
10514
	}
10515
	protected function loadGlobals()
10516
	{
10517
		$this->_globals=$this->getApplicationStatePersister()->load();
10518
	}
10519
	protected function saveGlobals()
10520
	{
10521
		if($this->_stateChanged)
10522
		{
10523
			$this->_stateChanged=false;
10524
			$this->getApplicationStatePersister()->save($this->_globals);
10525
		}
10526
	}
10527
	public function getID()
10528
	{
10529
		return $this->_id;
10530
	}
10531
	public function setID($value)
10532
	{
10533
		$this->_id=$value;
10534
	}
10535
	public function getPageServiceID()
10536
	{
10537
		return $this->_pageServiceID;
10538
	}
10539
	public function setPageServiceID($value)
10540
	{
10541
		$this->_pageServiceID=$value;
10542
	}
10543
	public function getUniqueID()
10544
	{
10545
		return $this->_uniqueID;
10546
	}
10547
	public function getMode()
10548
	{
10549
		return $this->_mode;
10550
	}
10551
	public function setMode($value)
10552
	{
10553
		$this->_mode=TPropertyValue::ensureEnum($value,'TApplicationMode');
10554
	}
10555
	public function getBasePath()
10556
	{
10557
		return $this->_basePath;
10558
	}
10559
	public function setBasePath($value)
10560
	{
10561
		$this->_basePath=$value;
10562
	}
10563
	public function getConfigurationFile()
10564
	{
10565
		return $this->_configFile;
10566
	}
10567
	public function setConfigurationFile($value)
10568
	{
10569
		$this->_configFile=$value;
10570
	}
10571
	public function getConfigurationType()
10572
	{
10573
		return $this->_configType;
10574
	}
10575
	public function setConfigurationType($value)
10576
	{
10577
		$this->_configType = $value;
10578
	}
10579
	public function getConfigurationFileExt()
10580
	{
10581
		if($this->_configFileExt===null)
10582
		{
10583
			switch($this->_configType)
10584
			{
10585
				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...
10586
					$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...
10587
					break;
10588
				default:
10589
					$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...
10590
			}
10591
		}
10592
		return $this->_configFileExt;
10593
	}
10594
	public function getConfigurationFileName()
10595
	{
10596
		static $fileName;
10597
		if($fileName == null)
10598
		{
10599
			switch($this->_configType)
10600
			{
10601
				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...
10602
					$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...
10603
					break;
10604
				default:
10605
					$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...
10606
			}
10607
		}
10608
		return $fileName;
10609
	}
10610
	public function getRuntimePath()
10611
	{
10612
		return $this->_runtimePath;
10613
	}
10614
	public function setRuntimePath($value)
10615
	{
10616
		$this->_runtimePath=$value;
10617
		if($this->_cacheFile)
10618
			$this->_cacheFile=$this->_runtimePath.DIRECTORY_SEPARATOR.self::CONFIGCACHE_FILE;
10619
				$this->_uniqueID=md5($this->_runtimePath);
10620
	}
10621
	public function getService()
10622
	{
10623
		return $this->_service;
10624
	}
10625
	public function setService($value)
10626
	{
10627
		$this->_service=$value;
10628
	}
10629
	public function setModule($id,IModule $module=null)
10630
	{
10631
		if(isset($this->_modules[$id]))
10632
			throw new TConfigurationException('application_moduleid_duplicated',$id);
10633
		else
10634
			$this->_modules[$id]=$module;
10635
	}
10636
	public function getModule($id)
10637
	{
10638
		if(!array_key_exists($id, $this->_modules))
10639
			return null;
10640
				if($this->_modules[$id]===null)
10641
		{
10642
			$module = $this->internalLoadModule($id, true);
10643
			$module[0]->init($module[1]);
10644
		}
10645
		return $this->_modules[$id];
10646
	}
10647
	public function getModules()
10648
	{
10649
		return $this->_modules;
10650
	}
10651
	public function getParameters()
10652
	{
10653
		return $this->_parameters;
10654
	}
10655
	public function getRequest()
10656
	{
10657
		if(!$this->_request)
10658
		{
10659
			$this->_request=new THttpRequest;
10660
			$this->_request->init(null);
10661
		}
10662
		return $this->_request;
10663
	}
10664
	public function setRequest(THttpRequest $request)
10665
	{
10666
		$this->_request=$request;
10667
	}
10668
	public function getResponse()
10669
	{
10670
		if(!$this->_response)
10671
		{
10672
			$this->_response=new THttpResponse;
10673
			$this->_response->init(null);
10674
		}
10675
		return $this->_response;
10676
	}
10677
	public function setResponse(THttpResponse $response)
10678
	{
10679
		$this->_response=$response;
10680
	}
10681
	public function getSession()
10682
	{
10683
		if(!$this->_session)
10684
		{
10685
			$this->_session=new THttpSession;
10686
			$this->_session->init(null);
10687
		}
10688
		return $this->_session;
10689
	}
10690
	public function setSession(THttpSession $session)
10691
	{
10692
		$this->_session=$session;
10693
	}
10694
	public function getErrorHandler()
10695
	{
10696
		if(!$this->_errorHandler)
10697
		{
10698
			$this->_errorHandler=new TErrorHandler;
10699
			$this->_errorHandler->init(null);
10700
		}
10701
		return $this->_errorHandler;
10702
	}
10703
	public function setErrorHandler(TErrorHandler $handler)
10704
	{
10705
		$this->_errorHandler=$handler;
10706
	}
10707
	public function getSecurityManager()
10708
	{
10709
		if(!$this->_security)
10710
		{
10711
			$this->_security=new TSecurityManager;
10712
			$this->_security->init(null);
10713
		}
10714
		return $this->_security;
10715
	}
10716
	public function setSecurityManager(TSecurityManager $sm)
10717
	{
10718
		$this->_security=$sm;
10719
	}
10720
	public function getAssetManager()
10721
	{
10722
		if(!$this->_assetManager)
10723
		{
10724
			$this->_assetManager=new TAssetManager;
10725
			$this->_assetManager->init(null);
10726
		}
10727
		return $this->_assetManager;
10728
	}
10729
	public function setAssetManager(TAssetManager $value)
10730
	{
10731
		$this->_assetManager=$value;
10732
	}
10733
	public function getApplicationStatePersister()
10734
	{
10735
		if(!$this->_statePersister)
10736
		{
10737
			$this->_statePersister=new TApplicationStatePersister;
10738
			$this->_statePersister->init(null);
10739
		}
10740
		return $this->_statePersister;
10741
	}
10742
	public function setApplicationStatePersister(IStatePersister $persister)
10743
	{
10744
		$this->_statePersister=$persister;
10745
	}
10746
	public function getCache()
10747
	{
10748
		return $this->_cache;
10749
	}
10750
	public function setCache(ICache $cache)
10751
	{
10752
		$this->_cache=$cache;
10753
	}
10754
	public function getUser()
10755
	{
10756
		return $this->_user;
10757
	}
10758
	public function setUser(IUser $user)
10759
	{
10760
		$this->_user=$user;
10761
	}
10762
	public function getGlobalization($createIfNotExists=true)
10763
	{
10764
		if($this->_globalization===null && $createIfNotExists)
10765
		{
10766
			$this->_globalization=new TGlobalization;
10767
			$this->_globalization->init(null);
10768
		}
10769
		return $this->_globalization;
10770
	}
10771
	public function setGlobalization(TGlobalization $glob)
10772
	{
10773
		$this->_globalization=$glob;
10774
	}
10775
	public function getAuthorizationRules()
10776
	{
10777
		if($this->_authRules===null)
10778
			$this->_authRules=new TAuthorizationRuleCollection;
10779
		return $this->_authRules;
10780
	}
10781
	protected function getApplicationConfigurationClass()
10782
	{
10783
		return 'TApplicationConfiguration';
10784
	}
10785
	protected function internalLoadModule($id, $force=false)
10786
	{
10787
		list($moduleClass, $initProperties, $configElement)=$this->_lazyModules[$id];
10788
		if(isset($initProperties['lazy']) && $initProperties['lazy'] && !$force)
10789
		{
10790
			$this->setModule($id, null);
10791
			return null;
10792
		}
10793
		$module=Prado::createComponent($moduleClass);
10794
		foreach($initProperties as $name=>$value)
10795
		{
10796
			if($name==='lazy') continue;
10797
			$module->setSubProperty($name,$value);
10798
		}
10799
		$this->setModule($id,$module);
10800
				$this->_lazyModules[$id]=null;
10801
		return array($module,$configElement);
10802
	}
10803
	public function applyConfiguration($config,$withinService=false)
10804
	{
10805
		if($config->getIsEmpty())
10806
			return;
10807
				foreach($config->getAliases() as $alias=>$path)
10808
			Prado::setPathOfAlias($alias,$path);
10809
		foreach($config->getUsings() as $using)
10810
			Prado::using($using);
10811
				if(!$withinService)
10812
		{
10813
			foreach($config->getProperties() as $name=>$value)
10814
				$this->setSubProperty($name,$value);
10815
		}
10816
		if(empty($this->_services))
10817
			$this->_services=array($this->getPageServiceID()=>array('TPageService',array(),null));
10818
				foreach($config->getParameters() as $id=>$parameter)
10819
		{
10820
			if(is_array($parameter))
10821
			{
10822
				$component=Prado::createComponent($parameter[0]);
10823
				foreach($parameter[1] as $name=>$value)
10824
					$component->setSubProperty($name,$value);
10825
				$this->_parameters->add($id,$component);
10826
			}
10827
			else
10828
				$this->_parameters->add($id,$parameter);
10829
		}
10830
				$modules=array();
10831
		foreach($config->getModules() as $id=>$moduleConfig)
10832
		{
10833
			if(!is_string($id))
10834
				$id='_module'.count($this->_lazyModules);
10835
			$this->_lazyModules[$id]=$moduleConfig;
10836
			if($module = $this->internalLoadModule($id))
10837
				$modules[]=$module;
10838
		}
10839
		foreach($modules as $module)
10840
			$module[0]->init($module[1]);
10841
				foreach($config->getServices() as $serviceID=>$serviceConfig)
10842
			$this->_services[$serviceID]=$serviceConfig;
10843
				foreach($config->getExternalConfigurations() as $filePath=>$condition)
10844
		{
10845
			if($condition!==true)
10846
				$condition=$this->evaluateExpression($condition);
10847
			if($condition)
10848
			{
10849
				if(($path=Prado::getPathOfNamespace($filePath,$this->getConfigurationFileExt()))===null || !is_file($path))
10850
					throw new TConfigurationException('application_includefile_invalid',$filePath);
10851
				$cn=$this->getApplicationConfigurationClass();
10852
				$c=new $cn;
10853
				$c->loadFromFile($path);
10854
				$this->applyConfiguration($c,$withinService);
10855
			}
10856
		}
10857
	}
10858
	protected function initApplication()
10859
	{
10860
		if($this->_configFile!==null)
10861
		{
10862
			if($this->_cacheFile===null || @filemtime($this->_cacheFile)<filemtime($this->_configFile))
10863
			{
10864
				$config=new TApplicationConfiguration;
10865
				$config->loadFromFile($this->_configFile);
10866
				if($this->_cacheFile!==null)
10867
					file_put_contents($this->_cacheFile,serialize($config),LOCK_EX);
10868
			}
10869
			else
10870
				$config=unserialize(file_get_contents($this->_cacheFile));
10871
			$this->applyConfiguration($config,false);
10872
		}
10873
		if(($serviceID=$this->getRequest()->resolveRequest(array_keys($this->_services)))===null)
10874
			$serviceID=$this->getPageServiceID();
10875
		$this->startService($serviceID);
10876
	}
10877
	public function startService($serviceID)
10878
	{
10879
		if(isset($this->_services[$serviceID]))
10880
		{
10881
			list($serviceClass,$initProperties,$configElement)=$this->_services[$serviceID];
10882
			$service=Prado::createComponent($serviceClass);
10883
			if(!($service instanceof IService))
10884
				throw new THttpException(500,'application_service_invalid',$serviceClass);
10885
			if(!$service->getEnabled())
10886
				throw new THttpException(500,'application_service_unavailable',$serviceClass);
10887
			$service->setID($serviceID);
10888
			$this->setService($service);
10889
			foreach($initProperties as $name=>$value)
10890
				$service->setSubProperty($name,$value);
10891
			if($configElement!==null)
10892
			{
10893
				$config=new TApplicationConfiguration;
10894
				if($this->getConfigurationType()==self::CONFIG_TYPE_PHP)
10895
					$config->loadFromPhp($configElement,$this->getBasePath());
10896
				else
10897
					$config->loadFromXml($configElement,$this->getBasePath());
10898
				$this->applyConfiguration($config,true);
10899
			}
10900
			$service->init($configElement);
10901
		}
10902
		else
10903
			throw new THttpException(500,'application_service_unknown',$serviceID);
10904
	}
10905
	public function onError($param)
10906
	{
10907
		Prado::log($param->getMessage(),TLogger::ERROR,'System.TApplication');
10908
		$this->raiseEvent('OnError',$this,$param);
10909
		$this->getErrorHandler()->handleError($this,$param);
10910
	}
10911
	public function onBeginRequest()
10912
	{
10913
		$this->raiseEvent('OnBeginRequest',$this,null);
10914
	}
10915
	public function onAuthentication()
10916
	{
10917
		$this->raiseEvent('OnAuthentication',$this,null);
10918
	}
10919
	public function onAuthenticationComplete()
10920
	{
10921
		$this->raiseEvent('OnAuthenticationComplete',$this,null);
10922
	}
10923
	public function onAuthorization()
10924
	{
10925
		$this->raiseEvent('OnAuthorization',$this,null);
10926
	}
10927
	public function onAuthorizationComplete()
10928
	{
10929
		$this->raiseEvent('OnAuthorizationComplete',$this,null);
10930
	}
10931
	public function onLoadState()
10932
	{
10933
		$this->loadGlobals();
10934
		$this->raiseEvent('OnLoadState',$this,null);
10935
	}
10936
	public function onLoadStateComplete()
10937
	{
10938
		$this->raiseEvent('OnLoadStateComplete',$this,null);
10939
	}
10940
	public function onPreRunService()
10941
	{
10942
		$this->raiseEvent('OnPreRunService',$this,null);
10943
	}
10944
	public function runService()
10945
	{
10946
		if($this->_service)
10947
			$this->_service->run();
10948
	}
10949
	public function onSaveState()
10950
	{
10951
		$this->raiseEvent('OnSaveState',$this,null);
10952
		$this->saveGlobals();
10953
	}
10954
	public function onSaveStateComplete()
10955
	{
10956
		$this->raiseEvent('OnSaveStateComplete',$this,null);
10957
	}
10958
	public function onPreFlushOutput()
10959
	{
10960
		$this->raiseEvent('OnPreFlushOutput',$this,null);
10961
	}
10962
	public function flushOutput($continueBuffering = true)
10963
	{
10964
		$this->getResponse()->flush($continueBuffering);
10965
	}
10966
	public function onEndRequest()
10967
	{
10968
		$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...
10969
	}
10970
}
10971
class TApplicationMode extends TEnumerable
10972
{
10973
	const Off='Off';
10974
	const Debug='Debug';
10975
	const Normal='Normal';
10976
	const Performance='Performance';
10977
}
10978
class TApplicationConfiguration extends TComponent
10979
{
10980
	private $_properties=array();
10981
	private $_usings=array();
10982
	private $_aliases=array();
10983
	private $_modules=array();
10984
	private $_services=array();
10985
	private $_parameters=array();
10986
	private $_includes=array();
10987
	private $_empty=true;
10988
	public function loadFromFile($fname)
10989
	{
10990
		if(Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
10991
		{
10992
			$fcontent = include $fname;
10993
			$this->loadFromPhp($fcontent,dirname($fname));
10994
		}
10995
		else
10996
		{
10997
			$dom=new TXmlDocument;
10998
			$dom->loadFromFile($fname);
10999
			$this->loadFromXml($dom,dirname($fname));
11000
		}
11001
	}
11002
	public function getIsEmpty()
11003
	{
11004
		return $this->_empty;
11005
	}
11006
	public function loadFromPhp($config, $configPath)
11007
	{
11008
				if(isset($config['application']))
11009
		{
11010
			foreach($config['application'] as $name=>$value)
11011
			{
11012
				$this->_properties[$name]=$value;
11013
			}
11014
			$this->_empty = false;
11015
		}
11016
		if(isset($config['paths']) && is_array($config['paths']))
11017
			$this->loadPathsPhp($config['paths'],$configPath);
11018
		if(isset($config['modules']) && is_array($config['modules']))
11019
			$this->loadModulesPhp($config['modules'],$configPath);
11020
		if(isset($config['services']) && is_array($config['services']))
11021
			$this->loadServicesPhp($config['services'],$configPath);
11022
		if(isset($config['parameters']) && is_array($config['parameters']))
11023
			$this->loadParametersPhp($config['parameters'], $configPath);
11024
		if(isset($config['includes']) && is_array($config['includes']))
11025
			$this->loadExternalXml($config['includes'],$configPath);
11026
	}
11027
	public function loadFromXml($dom,$configPath)
11028
	{
11029
				foreach($dom->getAttributes() as $name=>$value)
11030
		{
11031
			$this->_properties[$name]=$value;
11032
			$this->_empty=false;
11033
		}
11034
		foreach($dom->getElements() as $element)
11035
		{
11036
			switch($element->getTagName())
11037
			{
11038
				case 'paths':
11039
					$this->loadPathsXml($element,$configPath);
11040
					break;
11041
				case 'modules':
11042
					$this->loadModulesXml($element,$configPath);
11043
					break;
11044
				case 'services':
11045
					$this->loadServicesXml($element,$configPath);
11046
					break;
11047
				case 'parameters':
11048
					$this->loadParametersXml($element,$configPath);
11049
					break;
11050
				case 'include':
11051
					$this->loadExternalXml($element,$configPath);
11052
					break;
11053
				default:
11054
										break;
11055
			}
11056
		}
11057
	}
11058
	protected function loadPathsPhp($pathsNode, $configPath)
11059
	{
11060
		if(isset($pathsNode['aliases']) && is_array($pathsNode['aliases']))
11061
		{
11062
			foreach($pathsNode['aliases'] as $id=>$path)
11063
			{
11064
				$path=str_replace('\\','/',$path);
11065
				if(preg_match('/^\\/|.:\\/|.:\\\\/',$path))						$p=realpath($path);
11066
				else
11067
					$p=realpath($configPath.DIRECTORY_SEPARATOR.$path);
11068
				if($p===false || !is_dir($p))
11069
					throw new TConfigurationException('appconfig_aliaspath_invalid',$id,$path);
11070
				if(isset($this->_aliases[$id]))
11071
					throw new TConfigurationException('appconfig_alias_redefined',$id);
11072
				$this->_aliases[$id]=$p;
11073
			}
11074
		}
11075
		if(isset($pathsNode['using']) && is_array($pathsNode['using']))
11076
		{
11077
			foreach($pathsNode['using'] as $namespace)
11078
			{
11079
				$this->_usings[] = $namespace;
11080
			}
11081
		}
11082
	}
11083
	protected function loadPathsXml($pathsNode,$configPath)
11084
	{
11085
		foreach($pathsNode->getElements() as $element)
11086
		{
11087
			switch($element->getTagName())
11088
			{
11089
				case 'alias':
0 ignored issues
show
Coding Style introduced by
case statements should 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.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

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

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

Loading history...
11090
				{
11091
					if(($id=$element->getAttribute('id'))!==null && ($path=$element->getAttribute('path'))!==null)
11092
					{
11093
						$path=str_replace('\\','/',$path);
11094
						if(preg_match('/^\\/|.:\\/|.:\\\\/',$path))								$p=realpath($path);
11095
						else
11096
							$p=realpath($configPath.DIRECTORY_SEPARATOR.$path);
11097
						if($p===false || !is_dir($p))
11098
							throw new TConfigurationException('appconfig_aliaspath_invalid',$id,$path);
11099
						if(isset($this->_aliases[$id]))
11100
							throw new TConfigurationException('appconfig_alias_redefined',$id);
11101
						$this->_aliases[$id]=$p;
11102
					}
11103
					else
11104
						throw new TConfigurationException('appconfig_alias_invalid');
11105
					$this->_empty=false;
11106
					break;
11107
				}
11108
				case 'using':
0 ignored issues
show
Coding Style introduced by
case statements should 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.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

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

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

Loading history...
11109
				{
11110
					if(($namespace=$element->getAttribute('namespace'))!==null)
11111
						$this->_usings[]=$namespace;
11112
					else
11113
						throw new TConfigurationException('appconfig_using_invalid');
11114
					$this->_empty=false;
11115
					break;
11116
				}
11117
				default:
11118
					throw new TConfigurationException('appconfig_paths_invalid',$element->getTagName());
11119
			}
11120
		}
11121
	}
11122
	protected function loadModulesPhp($modulesNode, $configPath)
11123
	{
11124
		foreach($modulesNode as $id=>$module)
11125
		{
11126
			if(!isset($module['class']))
11127
				throw new TConfigurationException('appconfig_moduletype_required',$id);
11128
			$type = $module['class'];
11129
			unset($module['class']);
11130
			$properties = array();
11131
			if(isset($module['properties']))
11132
			{
11133
				$properties = $module['properties'];
11134
				unset($module['properties']);
11135
			}
11136
			$properties['id'] = $id;
11137
			$this->_modules[$id]=array($type,$properties,$module);
11138
			$this->_empty=false;
11139
		}
11140
	}
11141
	protected function loadModulesXml($modulesNode,$configPath)
11142
	{
11143
		foreach($modulesNode->getElements() as $element)
11144
		{
11145
			if($element->getTagName()==='module')
11146
			{
11147
				$properties=$element->getAttributes();
11148
				$id=$properties->itemAt('id');
11149
				$type=$properties->remove('class');
11150
				if($type===null)
11151
					throw new TConfigurationException('appconfig_moduletype_required',$id);
11152
				$element->setParent(null);
11153
				if($id===null)
11154
					$this->_modules[]=array($type,$properties->toArray(),$element);
11155
				else
11156
					$this->_modules[$id]=array($type,$properties->toArray(),$element);
11157
				$this->_empty=false;
11158
			}
11159
			else
11160
				throw new TConfigurationException('appconfig_modules_invalid',$element->getTagName());
11161
		}
11162
	}
11163
	protected function loadServicesPhp($servicesNode,$configPath)
11164
	{
11165
		foreach($servicesNode as $id => $service)
11166
		{
11167
			if(!isset($service['class']))
11168
				throw new TConfigurationException('appconfig_servicetype_required');
11169
			$type = $service['class'];
11170
			$properties = isset($service['properties']) ? $service['properties'] : array();
11171
			unset($service['properties']);
11172
			$properties['id'] = $id;
11173
			$this->_services[$id] = array($type,$properties,$service);
11174
			$this->_empty = false;
11175
		}
11176
	}
11177
	protected function loadServicesXml($servicesNode,$configPath)
11178
	{
11179
		foreach($servicesNode->getElements() as $element)
11180
		{
11181
			if($element->getTagName()==='service')
11182
			{
11183
				$properties=$element->getAttributes();
11184
				if(($id=$properties->itemAt('id'))===null)
11185
					throw new TConfigurationException('appconfig_serviceid_required');
11186
				if(($type=$properties->remove('class'))===null)
11187
					throw new TConfigurationException('appconfig_servicetype_required',$id);
11188
				$element->setParent(null);
11189
				$this->_services[$id]=array($type,$properties->toArray(),$element);
11190
				$this->_empty=false;
11191
			}
11192
			else
11193
				throw new TConfigurationException('appconfig_services_invalid',$element->getTagName());
11194
		}
11195
	}
11196
	protected function loadParametersPhp($parametersNode,$configPath)
11197
	{
11198
		foreach($parametersNode as $id => $parameter)
11199
		{
11200
			if(is_array($parameter))
11201
			{
11202
				if(isset($parameter['class']))
11203
				{
11204
					$type = $parameter['class'];
11205
					unset($parameter['class']);
11206
					$properties = isset($service['properties']) ? $service['properties'] : array();
11207
					$properties['id'] = $id;
11208
					$this->_parameters[$id] = array($type,$properties);
11209
				}
11210
			}
11211
			else
11212
			{
11213
				$this->_parameters[$id] = $parameter;
11214
			}
11215
		}
11216
	}
11217
	protected function loadParametersXml($parametersNode,$configPath)
11218
	{
11219
		foreach($parametersNode->getElements() as $element)
11220
		{
11221
			if($element->getTagName()==='parameter')
11222
			{
11223
				$properties=$element->getAttributes();
11224
				if(($id=$properties->remove('id'))===null)
11225
					throw new TConfigurationException('appconfig_parameterid_required');
11226
				if(($type=$properties->remove('class'))===null)
11227
				{
11228
					if(($value=$properties->remove('value'))===null)
11229
						$this->_parameters[$id]=$element;
11230
					else
11231
						$this->_parameters[$id]=$value;
11232
				}
11233
				else
11234
					$this->_parameters[$id]=array($type,$properties->toArray());
11235
				$this->_empty=false;
11236
			}
11237
			else
11238
				throw new TConfigurationException('appconfig_parameters_invalid',$element->getTagName());
11239
		}
11240
	}
11241
	protected function loadExternalPhp($includeNode,$configPath)
11242
	{
11243
		foreach($includeNode as $include)
11244
		{
11245
			$when = isset($include['when'])?true:false;
11246
			if(!isset($include['file']))
11247
				throw new TConfigurationException('appconfig_includefile_required');
11248
			$filePath = $include['file'];
11249
			if(isset($this->_includes[$filePath]))
11250
				$this->_includes[$filePath]='('.$this->_includes[$filePath].') || ('.$when.')';
11251
			else
11252
				$$this->_includes[$filePath]=$when;
11253
			$this->_empty=false;
11254
		}
11255
	}
11256
	protected function loadExternalXml($includeNode,$configPath)
11257
	{
11258
		if(($when=$includeNode->getAttribute('when'))===null)
11259
			$when=true;
11260
		if(($filePath=$includeNode->getAttribute('file'))===null)
11261
			throw new TConfigurationException('appconfig_includefile_required');
11262
		if(isset($this->_includes[$filePath]))
11263
			$this->_includes[$filePath]='('.$this->_includes[$filePath].') || ('.$when.')';
11264
		else
11265
			$this->_includes[$filePath]=$when;
11266
		$this->_empty=false;
11267
	}
11268
	public function getProperties()
11269
	{
11270
		return $this->_properties;
11271
	}
11272
	public function getAliases()
11273
	{
11274
		return $this->_aliases;
11275
	}
11276
	public function getUsings()
11277
	{
11278
		return $this->_usings;
11279
	}
11280
	public function getModules()
11281
	{
11282
		return $this->_modules;
11283
	}
11284
	public function getServices()
11285
	{
11286
		return $this->_services;
11287
	}
11288
	public function getParameters()
11289
	{
11290
		return $this->_parameters;
11291
	}
11292
	public function getExternalConfigurations()
11293
	{
11294
		return $this->_includes;
11295
	}
11296
}
11297
class TApplicationStatePersister extends TModule implements IStatePersister
11298
{
11299
	const CACHE_NAME='prado:appstate';
11300
	public function init($config)
11301
	{
11302
		$this->getApplication()->setApplicationStatePersister($this);
11303
	}
11304
	protected function getStateFilePath()
11305
	{
11306
		return $this->getApplication()->getRuntimePath().'/global.cache';
11307
	}
11308
	public function load()
11309
	{
11310
		if(($cache=$this->getApplication()->getCache())!==null && ($value=$cache->get(self::CACHE_NAME))!==false)
11311
			return unserialize($value);
11312
		else
11313
		{
11314
			if(($content=@file_get_contents($this->getStateFilePath()))!==false)
11315
				return unserialize($content);
11316
			else
11317
				return null;
11318
		}
11319
	}
11320
	public function save($state)
11321
	{
11322
		$content=serialize($state);
11323
		$saveFile=true;
11324
		if(($cache=$this->getApplication()->getCache())!==null)
11325
		{
11326
			if($cache->get(self::CACHE_NAME)===$content)
11327
				$saveFile=false;
11328
			else
11329
				$cache->set(self::CACHE_NAME,$content);
11330
		}
11331
		if($saveFile)
11332
		{
11333
			$fileName=$this->getStateFilePath();
11334
			file_put_contents($fileName,$content,LOCK_EX);
11335
		}
11336
	}
11337
}
11338
class TShellApplication extends TApplication
11339
{
11340
	public function run()
11341
	{
11342
		$this->initApplication();
11343
	}
11344
}
11345
?>
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...