Completed
Branch master (4dc390)
by Fabio
30:44
created

TControl::getCustomData()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
/**
3
 * File Name: pradolite.php
4
 * Last Update: 2015/12/07 15:35:09
5
 * Generated By: buildscripts/phpbuilder/build.php
6
 *
7
 * This file is used in lieu of prado.php to boost PRADO application performance.
8
 * It is generated by expanding prado.php with included files.
9
 * Comments and trace statements are stripped off.
10
 *
11
 * Do not modify this file manually.
12
 */
13
14
if(!defined('PRADO_DIR'))
15
	define('PRADO_DIR',dirname(__FILE__));
16
if(!defined('PRADO_CHMOD'))
17
	define('PRADO_CHMOD',0777);
18
class PradoBase
19
{
20
	const CLASS_FILE_EXT='.php';
21
	private static $_aliases=array('System'=>PRADO_DIR);
22
	private static $_usings=array();
23
	private static $_application=null;
24
	private static $_logger=null;
25
	protected static $classExists = array();
26
	public static function getVersion()
27
	{
28
		return '3.3.0';
29
	}
30
	public static function initErrorHandlers()
31
	{
32
		set_error_handler(array('PradoBase','phpErrorHandler'));
33
		set_exception_handler(array('PradoBase','exceptionHandler'));
34
	}
35
	public static function autoload($className)
36
	{
37
		include_once($className.self::CLASS_FILE_EXT);
38
		if(!class_exists($className,false) && !interface_exists($className,false))
39
			self::fatalError("Class file for '$className' cannot be found.");
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 exceptionHandler($exception)
59
	{
60
		if(self::$_application!==null && ($errorHandler=self::$_application->getErrorHandler())!==null)
61
		{
62
			$errorHandler->handleError(null,$exception);
63
		}
64
		else
65
		{
66
			echo $exception;
67
		}
68
		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...
69
	}
70
	public static function setApplication($application)
71
	{
72
		if(self::$_application!==null && !defined('PRADO_TEST_RUN'))
73
			throw new TInvalidOperationException('prado_application_singleton_required');
74
		self::$_application=$application;
75
	}
76
	public static function getApplication()
77
	{
78
		return self::$_application;
79
	}
80
	public static function getFrameworkPath()
81
	{
82
		return PRADO_DIR;
83
	}
84
	public static function createComponent($type)
85
	{
86
		if(!isset(self::$classExists[$type]))
87
			self::$classExists[$type] = class_exists($type, false);
88
		if( !isset(self::$_usings[$type]) && !self::$classExists[$type]) {
89
			self::using($type);
90
			self::$classExists[$type] = class_exists($type, false);
91
		}
92
		if( ($pos = strrpos($type, '.')) !== false)
93
			$type = substr($type,$pos+1);
94
		if(($n=func_num_args())>1)
95
		{
96
			$args = func_get_args();
97
			switch($n) {
98
				case 2:
99
					return new $type($args[1]);
100
				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...
101
				case 3:
102
					return new $type($args[1], $args[2]);
103
				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...
104
				case 4:
105
					return new $type($args[1], $args[2], $args[3]);
106
				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...
107
				case 5:
108
					return new $type($args[1], $args[2], $args[3], $args[4]);
109
				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...
110
				default:
111
					$s='$args[1]';
112
					for($i=2;$i<$n;++$i)
113
						$s.=",\$args[$i]";
114
					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...
115
					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...
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
			}
118
		}
119
		else
120
			return new $type;
121
	}
122
	public static function using($namespace,$checkClassExistence=true)
123
	{
124
		if(isset(self::$_usings[$namespace]) || class_exists($namespace,false))
125
			return;
126
		if(($pos=strrpos($namespace,'.'))===false)  		{
127
			try
128
			{
129
				include_once($namespace.self::CLASS_FILE_EXT);
130
			}
131
			catch(Exception $e)
132
			{
133
				if($checkClassExistence && !class_exists($namespace,false))
134
					throw new TInvalidOperationException('prado_component_unknown',$namespace,$e->getMessage());
135
				else
136
					throw $e;
137
			}
138
		}
139
		else if(($path=self::getPathOfNamespace($namespace,self::CLASS_FILE_EXT))!==null)
140
		{
141
			$className=substr($namespace,$pos+1);
142
			if($className==='*')  			{
143
				self::$_usings[$namespace]=$path;
144
				set_include_path(get_include_path().PATH_SEPARATOR.$path);
145
			}
146
			else  			{
147
				self::$_usings[$namespace]=$path;
148
				if(!$checkClassExistence || !class_exists($className,false))
149
				{
150
					try
151
					{
152
						include_once($path);
153
					}
154
					catch(Exception $e)
155
					{
156
						if($checkClassExistence && !class_exists($className,false))
157
							throw new TInvalidOperationException('prado_component_unknown',$className,$e->getMessage());
158
						else
159
							throw $e;
160
					}
161
				}
162
			}
163
		}
164
		else
165
			throw new TInvalidDataValueException('prado_using_invalid',$namespace);
166
	}
167
	public static function getPathOfNamespace($namespace, $ext='')
168
	{
169
		if(self::CLASS_FILE_EXT === $ext || empty($ext))
170
		{
171
			if(isset(self::$_usings[$namespace]))
172
				return self::$_usings[$namespace];
173
			if(isset(self::$_aliases[$namespace]))
174
				return self::$_aliases[$namespace];
175
		}
176
		$segs = explode('.',$namespace);
177
		$alias = array_shift($segs);
178
		if(null !== ($file = array_pop($segs)) && null !== ($root = self::getPathOfAlias($alias)))
179
			return rtrim($root.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR ,$segs),'/\\').(($file === '*') ? '' : DIRECTORY_SEPARATOR.$file.$ext);
180
		return null;
181
	}
182
	public static function getPathOfAlias($alias)
183
	{
184
		return isset(self::$_aliases[$alias])?self::$_aliases[$alias]:null;
185
	}
186
	protected static function getPathAliases()
187
	{
188
		return self::$_aliases;
189
	}
190
	public static function setPathOfAlias($alias,$path)
191
	{
192
		if(isset(self::$_aliases[$alias]) && !defined('PRADO_TEST_RUN'))
193
			throw new TInvalidOperationException('prado_alias_redefined',$alias);
194
		else if(($rp=realpath($path))!==false && is_dir($rp))
195
		{
196
			if(strpos($alias,'.')===false)
197
				self::$_aliases[$alias]=$rp;
198
			else
199
				throw new TInvalidDataValueException('prado_aliasname_invalid',$alias);
200
		}
201
		else
202
			throw new TInvalidDataValueException('prado_alias_invalid',$alias,$path);
203
	}
204
	public static function fatalError($msg)
205
	{
206
		echo '<h1>Fatal Error</h1>';
207
		echo '<p>'.$msg.'</p>';
208
		if(!function_exists('debug_backtrace'))
209
			return;
210
		echo '<h2>Debug Backtrace</h2>';
211
		echo '<pre>';
212
		$index=-1;
213
		foreach(debug_backtrace() as $t)
214
		{
215
			$index++;
216
			if($index==0)  				continue;
217
			echo '#'.$index.' ';
218
			if(isset($t['file']))
219
				echo basename($t['file']) . ':' . $t['line'];
220
			else
221
				 echo '<PHP inner-code>';
222
			echo ' -- ';
223
			if(isset($t['class']))
224
				echo $t['class'] . $t['type'];
225
			echo $t['function'] . '(';
226
			if(isset($t['args']) && sizeof($t['args']) > 0)
227
			{
228
				$count=0;
229
				foreach($t['args'] as $item)
230
				{
231
					if(is_string($item))
232
					{
233
						$str=htmlentities(str_replace("\r\n", "", $item), ENT_QUOTES);
234
						if (strlen($item) > 70)
235
							echo "'". substr($str, 0, 70) . "...'";
236
						else
237
							echo "'" . $str . "'";
238
					}
239
					else if (is_int($item) || is_float($item))
240
						echo $item;
241
					else if (is_object($item))
242
						echo get_class($item);
243
					else if (is_array($item))
244
						echo 'array(' . count($item) . ')';
245
					else if (is_bool($item))
246
						echo $item ? 'true' : 'false';
247
					else if ($item === null)
248
						echo 'NULL';
249
					else if (is_resource($item))
250
						echo get_resource_type($item);
251
					$count++;
252
					if (count($t['args']) > $count)
253
						echo ', ';
254
				}
255
			}
256
			echo ")\n";
257
		}
258
		echo '</pre>';
259
		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...
260
	}
261
	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...
262
	{
263
		static $languages=null;
264
		if($languages===null)
265
		{
266
			if(!isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
267
				$languages[0]='en';
268
			else
269
			{
270
				$languages=array();
271
				foreach(explode(',',$_SERVER['HTTP_ACCEPT_LANGUAGE']) as $language)
272
				{
273
					$array=explode(';q=',trim($language));
274
					$languages[trim($array[0])]=isset($array[1])?(float)$array[1]:1.0;
275
				}
276
				arsort($languages);
277
				$languages=array_keys($languages);
278
				if(empty($languages))
279
					$languages[0]='en';
280
			}
281
		}
282
		return $languages;
283
	}
284
	public static function getPreferredLanguage()
285
	{
286
		static $language=null;
287
		if($language===null)
288
		{
289
			$langs=Prado::getUserLanguages();
290
			$lang=explode('-',$langs[0]);
291
			if(empty($lang[0]) || !ctype_alpha($lang[0]))
292
				$language='en';
293
			else
294
				$language=$lang[0];
295
		}
296
		return $language;
297
	}
298
	public static function trace($msg,$category='Uncategorized',$ctl=null)
299
	{
300
		if(self::$_application && self::$_application->getMode()===TApplicationMode::Performance)
301
			return;
302
		if(!self::$_application || self::$_application->getMode()===TApplicationMode::Debug)
303
		{
304
			$trace=debug_backtrace();
305
			if(isset($trace[0]['file']) && isset($trace[0]['line']))
306
				$msg.=" (line {$trace[0]['line']}, {$trace[0]['file']})";
307
			$level=TLogger::DEBUG;
308
		}
309
		else
310
			$level=TLogger::INFO;
311
		self::log($msg,$level,$category,$ctl);
312
	}
313
	public static function log($msg,$level=TLogger::INFO,$category='Uncategorized',$ctl=null)
314
	{
315
		if(self::$_logger===null)
316
			self::$_logger=new TLogger;
317
		self::$_logger->log($msg,$level,$category,$ctl);
318
	}
319
	public static function getLogger()
320
	{
321
		if(self::$_logger===null)
322
			self::$_logger=new TLogger;
323
		return self::$_logger;
324
	}
325
	public static function varDump($var,$depth=10,$highlight=false)
326
	{
327
		Prado::using('System.Util.TVarDumper');
328
		return TVarDumper::dump($var,$depth,$highlight);
329
	}
330
	public static function localize($text, $parameters=array(), $catalogue=null, $charset=null)
331
	{
332
		Prado::using('System.I18N.Translation');
333
		$app = Prado::getApplication()->getGlobalization(false);
334
		$params = array();
335
		foreach($parameters as $key => $value)
336
			$params['{'.$key.'}'] = $value;
337
				if($app===null || ($config = $app->getTranslationConfiguration())===null)
338
			return strtr($text, $params);
339
		if ($catalogue===null)
340
			$catalogue=isset($config['catalogue'])?$config['catalogue']:'messages';
341
		Translation::init($catalogue);
342
				$appCharset = $app===null ? '' : $app->getCharset();
343
				$defaultCharset = ($app===null) ? 'UTF-8' : $app->getDefaultCharset();
344
				if(empty($charset)) $charset = $appCharset;
345
		if(empty($charset)) $charset = $defaultCharset;
346
		return Translation::formatter($catalogue)->format($text,$params,$catalogue,$charset);
347
	}
348
}
349
PradoBase::using('System.TComponent');
350
PradoBase::using('System.Exceptions.TException');
351
PradoBase::using('System.Util.TLogger');
352
if(!class_exists('Prado',false))
353
{
354
	class Prado extends PradoBase
355
	{
356
	}
357
}
358
spl_autoload_register(array('Prado','autoload'));
359
Prado::initErrorHandlers();
360
interface IModule
361
{
362
	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...
363
	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...
364
	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...
365
}
366
interface IService
367
{
368
	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...
369
	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...
370
	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...
371
	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...
372
	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...
373
	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...
374
}
375
interface ITextWriter
376
{
377
	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...
378
	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...
379
}
380
interface IUser
381
{
382
	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...
383
	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...
384
	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...
385
	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...
386
	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...
387
	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...
388
	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...
389
	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...
390
	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...
391
}
392
interface IStatePersister
393
{
394
	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...
395
	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...
396
}
397
interface ICache
398
{
399
	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...
400
	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...
401
	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...
402
	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...
403
	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...
404
}
405
interface ICacheDependency
406
{
407
	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...
408
}
409
interface IRenderable
410
{
411
	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...
412
}
413
interface IBindable
414
{
415
	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...
416
}
417
interface IStyleable
418
{
419
	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...
420
	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...
421
	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...
422
}
423
interface IActiveControl
424
{
425
	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...
426
}
427
interface ICallbackEventHandler
428
{
429
	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...
430
}
431
interface IDataRenderer
432
{
433
	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...
434
	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...
435
}
436
class TApplicationComponent extends TComponent
437
{
438
	public function getApplication()
439
	{
440
		return Prado::getApplication();
441
	}
442
	public function getService()
443
	{
444
		return Prado::getApplication()->getService();
445
	}
446
	public function getRequest()
447
	{
448
		return Prado::getApplication()->getRequest();
449
	}
450
	public function getResponse()
451
	{
452
		return Prado::getApplication()->getResponse();
453
	}
454
	public function getSession()
455
	{
456
		return Prado::getApplication()->getSession();
457
	}
458
	public function getUser()
459
	{
460
		return Prado::getApplication()->getUser();
461
	}
462
	public function publishAsset($assetPath,$className=null)
463
	{
464
		if($className===null)
465
			$className=get_class($this);
466
		$class=new ReflectionClass($className);
467
		$fullPath=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$assetPath;
468
		return $this->publishFilePath($fullPath);
469
	}
470
	public function publishFilePath($fullPath, $checkTimestamp=false)
471
	{
472
		return Prado::getApplication()->getAssetManager()->publishFilePath($fullPath, $checkTimestamp);
473
	}
474
}
475
abstract class TModule extends TApplicationComponent implements IModule
476
{
477
	private $_id;
478
	public function init($config)
479
	{
480
	}
481
	public function getID()
482
	{
483
		return $this->_id;
484
	}
485
	public function setID($value)
486
	{
487
		$this->_id=$value;
488
	}
489
}
490
abstract class TService extends TApplicationComponent implements IService
491
{
492
	private $_id;
493
	private $_enabled=true;
494
	public function init($config)
495
	{
496
	}
497
	public function getID()
498
	{
499
		return $this->_id;
500
	}
501
	public function setID($value)
502
	{
503
		$this->_id=$value;
504
	}
505
	public function getEnabled()
506
	{
507
		return $this->_enabled;
508
	}
509
	public function setEnabled($value)
510
	{
511
		$this->_enabled=TPropertyValue::ensureBoolean($value);
512
	}
513
	public function run()
514
	{
515
	}
516
}
517
class TErrorHandler extends TModule
518
{
519
	const ERROR_FILE_NAME='error';
520
	const EXCEPTION_FILE_NAME='exception';
521
	const SOURCE_LINES=12;
522
	private $_templatePath=null;
523
	public function init($config)
524
	{
525
		$this->getApplication()->setErrorHandler($this);
526
	}
527
	public function getErrorTemplatePath()
528
	{
529
		if($this->_templatePath===null)
530
			$this->_templatePath=Prado::getFrameworkPath().'/Exceptions/templates';
531
		return $this->_templatePath;
532
	}
533
	public function setErrorTemplatePath($value)
534
	{
535
		if(($templatePath=Prado::getPathOfNamespace($value))!==null && is_dir($templatePath))
536
			$this->_templatePath=$templatePath;
537
		else
538
			throw new TConfigurationException('errorhandler_errortemplatepath_invalid',$value);
539
	}
540
	public function handleError($sender,$param)
541
	{
542
		static $handling=false;
543
								restore_error_handler();
544
		restore_exception_handler();
545
				if($handling)
546
			$this->handleRecursiveError($param);
547
		else
548
		{
549
			$handling=true;
550
			if(($response=$this->getResponse())!==null)
551
				$response->clear();
552
			if(!headers_sent())
553
				header('Content-Type: text/html; charset=UTF-8');
554
			if($param instanceof THttpException)
555
				$this->handleExternalError($param->getStatusCode(),$param);
556
			else if($this->getApplication()->getMode()===TApplicationMode::Debug)
557
				$this->displayException($param);
558
			else
559
				$this->handleExternalError(500,$param);
560
		}
561
	}
562
	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...
563
	{
564
		$aRpl = array();
565
		if($exception !== null && $exception instanceof Exception)
566
		{
567
			$aTrace = $exception->getTrace();
568
			foreach($aTrace as $item)
569
			{
570
				if(isset($item['file']))
571
					$aRpl[dirname($item['file']) . DIRECTORY_SEPARATOR] = '<hidden>' . DIRECTORY_SEPARATOR;
572
			}
573
		}
574
		$aRpl[$_SERVER['DOCUMENT_ROOT']] = '${DocumentRoot}';
575
		$aRpl[str_replace('/', DIRECTORY_SEPARATOR, $_SERVER['DOCUMENT_ROOT'])] = '${DocumentRoot}';
576
		$aRpl[PRADO_DIR . DIRECTORY_SEPARATOR] = '${PradoFramework}' . DIRECTORY_SEPARATOR;
577
		if(isset($aRpl[DIRECTORY_SEPARATOR])) unset($aRpl[DIRECTORY_SEPARATOR]);
578
		$aRpl = array_reverse($aRpl, true);
579
		return str_replace(array_keys($aRpl), $aRpl, $value);
580
	}
581
	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...
582
	{
583
		if(!($exception instanceof THttpException))
584
			error_log($exception->__toString());
585
		$content=$this->getErrorTemplate($statusCode,$exception);
586
		$serverAdmin=isset($_SERVER['SERVER_ADMIN'])?$_SERVER['SERVER_ADMIN']:'';
587
		$isDebug = $this->getApplication()->getMode()===TApplicationMode::Debug;
588
		$errorMessage = $exception->getMessage();
589
		if($isDebug)
590
			$version=$_SERVER['SERVER_SOFTWARE'].' <a href="https://github.com/pradosoft/prado">PRADO</a>/'.Prado::getVersion();
591
		else
592
		{
593
			$version='';
594
			$errorMessage = self::hideSecurityRelated($errorMessage, $exception);
595
		}
596
		$tokens=array(
597
			'%%StatusCode%%' => "$statusCode",
598
			'%%ErrorMessage%%' => htmlspecialchars($errorMessage),
599
			'%%ServerAdmin%%' => $serverAdmin,
600
			'%%Version%%' => $version,
601
			'%%Time%%' => @strftime('%Y-%m-%d %H:%M',time())
602
		);
603
		$this->getApplication()->getResponse()->setStatusCode($statusCode, $isDebug ? $exception->getMessage() : null);
604
		echo strtr($content,$tokens);
605
	}
606
	protected function handleRecursiveError($exception)
607
	{
608
		if($this->getApplication()->getMode()===TApplicationMode::Debug)
609
		{
610
			echo "<html><head><title>Recursive Error</title></head>\n";
611
			echo "<body><h1>Recursive Error</h1>\n";
612
			echo "<pre>".$exception->__toString()."</pre>\n";
613
			echo "</body></html>";
614
		}
615
		else
616
		{
617
			error_log("Error happened while processing an existing error:\n".$exception->__toString());
618
			header('HTTP/1.0 500 Internal Error');
619
		}
620
	}
621
	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...
622
	{
623
		if(php_sapi_name()==='cli')
624
		{
625
			echo $exception->getMessage()."\n";
626
			echo $exception->getTraceAsString();
627
			return;
628
		}
629
		if($exception instanceof TTemplateException)
630
		{
631
			$fileName=$exception->getTemplateFile();
632
			$lines=empty($fileName)?explode("\n",$exception->getTemplateSource()):@file($fileName);
633
			$source=$this->getSourceCode($lines,$exception->getLineNumber());
634
			if($fileName==='')
635
				$fileName='---embedded template---';
636
			$errorLine=$exception->getLineNumber();
637
		}
638
		else
639
		{
640
			if(($trace=$this->getExactTrace($exception))!==null)
641
			{
642
				$fileName=$trace['file'];
643
				$errorLine=$trace['line'];
644
			}
645
			else
646
			{
647
				$fileName=$exception->getFile();
648
				$errorLine=$exception->getLine();
649
			}
650
			$source=$this->getSourceCode(@file($fileName),$errorLine);
651
		}
652
		if($this->getApplication()->getMode()===TApplicationMode::Debug)
653
			$version=$_SERVER['SERVER_SOFTWARE'].' <a href="https://github.com/pradosoft/prado">PRADO</a>/'.Prado::getVersion();
654
		else
655
			$version='';
656
		$tokens=array(
657
			'%%ErrorType%%' => get_class($exception),
658
			'%%ErrorMessage%%' => $this->addLink(htmlspecialchars($exception->getMessage())),
659
			'%%SourceFile%%' => htmlspecialchars($fileName).' ('.$errorLine.')',
660
			'%%SourceCode%%' => $source,
661
			'%%StackTrace%%' => htmlspecialchars($exception->getTraceAsString()),
662
			'%%Version%%' => $version,
663
			'%%Time%%' => @strftime('%Y-%m-%d %H:%M',time())
664
		);
665
		$content=$this->getExceptionTemplate($exception);
666
		echo strtr($content,$tokens);
667
	}
668
	protected function getExceptionTemplate($exception)
669
	{
670
		$lang=Prado::getPreferredLanguage();
671
		$exceptionFile=Prado::getFrameworkPath().'/Exceptions/templates/'.self::EXCEPTION_FILE_NAME.'-'.$lang.'.html';
672
		if(!is_file($exceptionFile))
673
			$exceptionFile=Prado::getFrameworkPath().'/Exceptions/templates/'.self::EXCEPTION_FILE_NAME.'.html';
674
		if(($content=@file_get_contents($exceptionFile))===false)
675
			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...
676
		return $content;
677
	}
678
	protected function getErrorTemplate($statusCode,$exception)
679
	{
680
		$base=$this->getErrorTemplatePath().DIRECTORY_SEPARATOR.self::ERROR_FILE_NAME;
681
		$lang=Prado::getPreferredLanguage();
682
		if(is_file("$base$statusCode-$lang.html"))
683
			$errorFile="$base$statusCode-$lang.html";
684
		else if(is_file("$base$statusCode.html"))
685
			$errorFile="$base$statusCode.html";
686
		else if(is_file("$base-$lang.html"))
687
			$errorFile="$base-$lang.html";
688
		else
689
			$errorFile="$base.html";
690
		if(($content=@file_get_contents($errorFile))===false)
691
			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...
692
		return $content;
693
	}
694
	private function getExactTrace($exception)
695
	{
696
		$trace=$exception->getTrace();
697
		$result=null;
698
						if($exception instanceof TPhpErrorException)
699
			$result=isset($trace[0]['file'])?$trace[0]:$trace[1];
700
		else if($exception instanceof TInvalidOperationException)
701
		{
702
						if(($result=$this->getPropertyAccessTrace($trace,'__get'))===null)
703
				$result=$this->getPropertyAccessTrace($trace,'__set');
704
		}
705
		if($result!==null && strpos($result['file'],': eval()\'d code')!==false)
706
			return null;
707
		return $result;
708
	}
709
	private function getPropertyAccessTrace($trace,$pattern)
710
	{
711
		$result=null;
712
		foreach($trace as $t)
713
		{
714
			if(isset($t['function']) && $t['function']===$pattern)
715
				$result=$t;
716
			else
717
				break;
718
		}
719
		return $result;
720
	}
721
	private function getSourceCode($lines,$errorLine)
722
	{
723
		$beginLine=$errorLine-self::SOURCE_LINES>=0?$errorLine-self::SOURCE_LINES:0;
724
		$endLine=$errorLine+self::SOURCE_LINES<=count($lines)?$errorLine+self::SOURCE_LINES:count($lines);
725
		$source='';
726
		for($i=$beginLine;$i<$endLine;++$i)
727
		{
728
			if($i===$errorLine-1)
729
			{
730
				$line=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",'    ',$lines[$i])));
731
				$source.="<div class=\"error\">".$line."</div>";
732
			}
733
			else
734
				$source.=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",'    ',$lines[$i])));
735
		}
736
		return $source;
737
	}
738
	private function addLink($message)
739
	{
740
		$baseUrl='http://pradosoft.github.io/docs/manual/class-';
741
		return preg_replace('/\b(T[A-Z]\w+)\b/',"<a href=\"$baseUrl/\${1}\" target=\"_blank\">\${1}</a>",$message);
742
	}
743
}
744
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...
745
{
746
	private $_d=array();
747
	private $_c=0;
748
	private $_r=false;
749
	public function __construct($data=null,$readOnly=false)
750
	{
751
		if($data!==null)
752
			$this->copyFrom($data);
753
		$this->setReadOnly($readOnly);
754
	}
755
	public function getReadOnly()
756
	{
757
		return $this->_r;
758
	}
759
	protected function setReadOnly($value)
760
	{
761
		$this->_r=TPropertyValue::ensureBoolean($value);
762
	}
763
	public function getIterator()
764
	{
765
		return new ArrayIterator( $this->_d );
766
	}
767
	public function count()
768
	{
769
		return $this->getCount();
770
	}
771
	public function getCount()
772
	{
773
		return $this->_c;
774
	}
775
	public function itemAt($index)
776
	{
777
		if($index>=0 && $index<$this->_c)
778
			return $this->_d[$index];
779
		else
780
			throw new TInvalidDataValueException('list_index_invalid',$index);
781
	}
782
	public function add($item)
783
	{
784
		$this->insertAt($this->_c,$item);
785
		return $this->_c-1;
786
	}
787
	public function insertAt($index,$item)
788
	{
789
		if(!$this->_r)
790
		{
791
			if($index===$this->_c)
792
				$this->_d[$this->_c++]=$item;
793
			else if($index>=0 && $index<$this->_c)
794
			{
795
				array_splice($this->_d,$index,0,array($item));
796
				$this->_c++;
797
			}
798
			else
799
				throw new TInvalidDataValueException('list_index_invalid',$index);
800
		}
801
		else
802
			throw new TInvalidOperationException('list_readonly',get_class($this));
803
	}
804
	public function remove($item)
805
	{
806
		if(!$this->_r)
807
		{
808
			if(($index=$this->indexOf($item))>=0)
809
			{
810
				$this->removeAt($index);
811
				return $index;
812
			}
813
			else
814
				throw new TInvalidDataValueException('list_item_inexistent');
815
		}
816
		else
817
			throw new TInvalidOperationException('list_readonly',get_class($this));
818
	}
819
	public function removeAt($index)
820
	{
821
		if(!$this->_r)
822
		{
823
			if($index>=0 && $index<$this->_c)
824
			{
825
				$this->_c--;
826
				if($index===$this->_c)
827
					return array_pop($this->_d);
828
				else
829
				{
830
					$item=$this->_d[$index];
831
					array_splice($this->_d,$index,1);
832
					return $item;
833
				}
834
			}
835
			else
836
				throw new TInvalidDataValueException('list_index_invalid',$index);
837
		}
838
		else
839
			throw new TInvalidOperationException('list_readonly',get_class($this));
840
	}
841
	public function clear()
842
	{
843
		for($i=$this->_c-1;$i>=0;--$i)
844
			$this->removeAt($i);
845
	}
846
	public function contains($item)
847
	{
848
		return $this->indexOf($item)>=0;
849
	}
850
	public function indexOf($item)
851
	{
852
		if(($index=array_search($item,$this->_d,true))===false)
853
			return -1;
854
		else
855
			return $index;
856
	}
857
	public function insertBefore($baseitem, $item)
858
	{
859
		if(!$this->_r)
860
		{
861
			if(($index = $this->indexOf($baseitem)) == -1)
862
				throw new TInvalidDataValueException('list_item_inexistent');
863
			$this->insertAt($index, $item);
864
			return $index;
865
		}
866
		else
867
			throw new TInvalidOperationException('list_readonly',get_class($this));
868
	}
869
	public function insertAfter($baseitem, $item)
870
	{
871
		if(!$this->_r)
872
		{
873
			if(($index = $this->indexOf($baseitem)) == -1)
874
				throw new TInvalidDataValueException('list_item_inexistent');
875
			$this->insertAt($index + 1, $item);
876
			return $index + 1;
877
		}
878
		else
879
			throw new TInvalidOperationException('list_readonly',get_class($this));
880
	}
881
	public function toArray()
882
	{
883
		return $this->_d;
884
	}
885
	public function copyFrom($data)
886
	{
887
		if(is_array($data) || ($data instanceof Traversable))
888
		{
889
			if($this->_c>0)
890
				$this->clear();
891
			foreach($data as $item)
892
				$this->add($item);
893
		}
894
		else if($data!==null)
895
			throw new TInvalidDataTypeException('list_data_not_iterable');
896
	}
897
	public function mergeWith($data)
898
	{
899
		if(is_array($data) || ($data instanceof Traversable))
900
		{
901
			foreach($data as $item)
902
				$this->add($item);
903
		}
904
		else if($data!==null)
905
			throw new TInvalidDataTypeException('list_data_not_iterable');
906
	}
907
	public function offsetExists($offset)
908
	{
909
		return ($offset>=0 && $offset<$this->_c);
910
	}
911
	public function offsetGet($offset)
912
	{
913
		return $this->itemAt($offset);
914
	}
915
	public function offsetSet($offset,$item)
916
	{
917
		if($offset===null || $offset===$this->_c)
918
			$this->insertAt($this->_c,$item);
919
		else
920
		{
921
			$this->removeAt($offset);
922
			$this->insertAt($offset,$item);
923
		}
924
	}
925
	public function offsetUnset($offset)
926
	{
927
		$this->removeAt($offset);
928
	}
929
}
930
class TListIterator implements Iterator
931
{
932
	private $_d;
933
	private $_i;
934
	private $_c;
935
	public function __construct(&$data)
936
	{
937
		$this->_d=&$data;
938
		$this->_i=0;
939
		$this->_c=count($this->_d);
940
	}
941
	public function rewind()
942
	{
943
		$this->_i=0;
944
	}
945
	public function key()
946
	{
947
		return $this->_i;
948
	}
949
	public function current()
950
	{
951
		return $this->_d[$this->_i];
952
	}
953
	public function next()
954
	{
955
		$this->_i++;
956
	}
957
	public function valid()
958
	{
959
		return $this->_i<$this->_c;
960
	}
961
}
962
abstract class TCache extends TModule implements ICache, ArrayAccess
963
{
964
	private $_prefix=null;
965
	private $_primary=true;
966
	public function init($config)
967
	{
968
		if($this->_prefix===null)
969
			$this->_prefix=$this->getApplication()->getUniqueID();
970
		if($this->_primary)
971
		{
972
			if($this->getApplication()->getCache()===null)
973
				$this->getApplication()->setCache($this);
974
			else
975
				throw new TConfigurationException('cache_primary_duplicated',get_class($this));
976
		}
977
	}
978
	public function getPrimaryCache()
979
	{
980
		return $this->_primary;
981
	}
982
	public function setPrimaryCache($value)
983
	{
984
		$this->_primary=TPropertyValue::ensureBoolean($value);
985
	}
986
	public function getKeyPrefix()
987
	{
988
		return $this->_prefix;
989
	}
990
	public function setKeyPrefix($value)
991
	{
992
		$this->_prefix=$value;
993
	}
994
	protected function generateUniqueKey($key)
995
	{
996
		return md5($this->_prefix.$key);
997
	}
998
	public function get($id)
999
	{
1000
		if(($data=$this->getValue($this->generateUniqueKey($id)))!==false)
1001
		{
1002
			if(!is_array($data))
1003
				return false;
1004
			if(!($data[1] instanceof ICacheDependency) || !$data[1]->getHasChanged())
1005
				return $data[0];
1006
		}
1007
		return false;
1008
	}
1009
	public function set($id,$value,$expire=0,$dependency=null)
1010
	{
1011
		if(empty($value) && $expire === 0)
1012
			$this->delete($id);
1013
		else
1014
		{
1015
			$data=array($value,$dependency);
1016
			return $this->setValue($this->generateUniqueKey($id),$data,$expire);
1017
		}
1018
	}
1019
	public function add($id,$value,$expire=0,$dependency=null)
1020
	{
1021
		if(empty($value) && $expire === 0)
1022
			return false;
1023
		$data=array($value,$dependency);
1024
		return $this->addValue($this->generateUniqueKey($id),$data,$expire);
1025
	}
1026
	public function delete($id)
1027
	{
1028
		return $this->deleteValue($this->generateUniqueKey($id));
1029
	}
1030
	public function flush()
1031
	{
1032
		throw new TNotSupportedException('cache_flush_unsupported');
1033
	}
1034
	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...
1035
	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...
1036
	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...
1037
	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...
1038
	public function offsetExists($id)
1039
	{
1040
		return $this->get($id) !== false;
1041
	}
1042
	public function offsetGet($id)
1043
	{
1044
		return $this->get($id);
1045
	}
1046
	public function offsetSet($id, $value)
1047
	{
1048
		$this->set($id, $value);
1049
	}
1050
	public function offsetUnset($id)
1051
	{
1052
		$this->delete($id);
1053
	}
1054
}
1055
abstract class TCacheDependency extends TComponent implements ICacheDependency
1056
{
1057
}
1058
class TFileCacheDependency extends TCacheDependency
1059
{
1060
	private $_fileName;
1061
	private $_timestamp;
1062
	public function __construct($fileName)
1063
	{
1064
		$this->setFileName($fileName);
1065
	}
1066
	public function getFileName()
1067
	{
1068
		return $this->_fileName;
1069
	}
1070
	public function setFileName($value)
1071
	{
1072
		$this->_fileName=$value;
1073
		$this->_timestamp=@filemtime($value);
1074
	}
1075
	public function getTimestamp()
1076
	{
1077
		return $this->_timestamp;
1078
	}
1079
	public function getHasChanged()
1080
	{
1081
		return @filemtime($this->_fileName)!==$this->_timestamp;
1082
	}
1083
}
1084
class TDirectoryCacheDependency extends TCacheDependency
1085
{
1086
	private $_recursiveCheck=true;
1087
	private $_recursiveLevel=-1;
1088
	private $_timestamps;
1089
	private $_directory;
1090
	public function __construct($directory)
1091
	{
1092
		$this->setDirectory($directory);
1093
	}
1094
	public function getDirectory()
1095
	{
1096
		return $this->_directory;
1097
	}
1098
	public function setDirectory($directory)
1099
	{
1100
		if(($path=realpath($directory))===false || !is_dir($path))
1101
			throw new TInvalidDataValueException('directorycachedependency_directory_invalid',$directory);
1102
		$this->_directory=$path;
1103
		$this->_timestamps=$this->generateTimestamps($path);
1104
	}
1105
	public function getRecursiveCheck()
1106
	{
1107
		return $this->_recursiveCheck;
1108
	}
1109
	public function setRecursiveCheck($value)
1110
	{
1111
		$this->_recursiveCheck=TPropertyValue::ensureBoolean($value);
1112
	}
1113
	public function getRecursiveLevel()
1114
	{
1115
		return $this->_recursiveLevel;
1116
	}
1117
	public function setRecursiveLevel($value)
1118
	{
1119
		$this->_recursiveLevel=TPropertyValue::ensureInteger($value);
1120
	}
1121
	public function getHasChanged()
1122
	{
1123
		return $this->generateTimestamps($this->_directory)!=$this->_timestamps;
1124
	}
1125
	protected function validateFile($fileName)
1126
	{
1127
		return true;
1128
	}
1129
	protected function validateDirectory($directory)
1130
	{
1131
		return true;
1132
	}
1133
	protected function generateTimestamps($directory,$level=0)
1134
	{
1135
		if(($dir=opendir($directory))===false)
1136
			throw new TIOException('directorycachedependency_directory_invalid',$directory);
1137
		$timestamps=array();
1138
		while(($file=readdir($dir))!==false)
1139
		{
1140
			$path=$directory.DIRECTORY_SEPARATOR.$file;
1141
			if($file==='.' || $file==='..')
1142
				continue;
1143
			else if(is_dir($path))
1144
			{
1145
				if(($this->_recursiveLevel<0 || $level<$this->_recursiveLevel) && $this->validateDirectory($path))
1146
					$timestamps=array_merge($this->generateTimestamps($path,$level+1));
1147
			}
1148
			else if($this->validateFile($path))
1149
				$timestamps[$path]=filemtime($path);
1150
		}
1151
		closedir($dir);
1152
		return $timestamps;
1153
	}
1154
}
1155
class TGlobalStateCacheDependency extends TCacheDependency
1156
{
1157
	private $_stateName;
1158
	private $_stateValue;
1159
	public function __construct($name)
1160
	{
1161
		$this->setStateName($name);
1162
	}
1163
	public function getStateName()
1164
	{
1165
		return $this->_stateName;
1166
	}
1167
	public function setStateName($value)
1168
	{
1169
		$this->_stateName=$value;
1170
		$this->_stateValue=Prado::getApplication()->getGlobalState($value);
1171
	}
1172
	public function getHasChanged()
1173
	{
1174
		return $this->_stateValue!==Prado::getApplication()->getGlobalState($this->_stateName);
1175
	}
1176
}
1177
class TChainedCacheDependency extends TCacheDependency
1178
{
1179
	private $_dependencies=null;
1180
	public function getDependencies()
1181
	{
1182
		if($this->_dependencies===null)
1183
			$this->_dependencies=new TCacheDependencyList;
1184
		return $this->_dependencies;
1185
	}
1186
	public function getHasChanged()
1187
	{
1188
		if($this->_dependencies!==null)
1189
		{
1190
			foreach($this->_dependencies as $dependency)
1191
				if($dependency->getHasChanged())
1192
					return true;
1193
		}
1194
		return false;
1195
	}
1196
}
1197
class TApplicationStateCacheDependency extends TCacheDependency
1198
{
1199
	public function getHasChanged()
1200
	{
1201
		return Prado::getApplication()->getMode()!==TApplicationMode::Performance;
1202
	}
1203
}
1204
class TCacheDependencyList extends TList
1205
{
1206
	public function insertAt($index,$item)
1207
	{
1208
		if($item instanceof ICacheDependency)
1209
			parent::insertAt($index,$item);
1210
		else
1211
			throw new TInvalidDataTypeException('cachedependencylist_cachedependency_required');
1212
	}
1213
}
1214
class TTextWriter extends TComponent implements ITextWriter
1215
{
1216
	private $_str='';
1217
	public function flush()
1218
	{
1219
		$str=$this->_str;
1220
		$this->_str='';
1221
		return $str;
1222
	}
1223
	public function write($str)
1224
	{
1225
		$this->_str.=$str;
1226
	}
1227
	public function writeLine($str='')
1228
	{
1229
		$this->write($str."\n");
1230
	}
1231
}
1232
class TPriorityList extends TList
1233
{
1234
	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...
1235
	private $_o=false;
1236
	private $_fd=null;
1237
	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...
1238
	private $_dp=10;
1239
	private $_p=8;
1240
	public function __construct($data=null,$readOnly=false,$defaultPriority=10,$precision=8)
1241
	{
1242
		parent::__construct();
1243
		if($data!==null)
1244
			$this->copyFrom($data);
1245
		$this->setReadOnly($readOnly);
1246
		$this->setPrecision($precision);
1247
		$this->setDefaultPriority($defaultPriority);
1248
	}
1249
	public function count()
1250
	{
1251
		return $this->getCount();
1252
	}
1253
	public function getCount()
1254
	{
1255
		return $this->_c;
1256
	}
1257
	public function getPriorityCount($priority=null)
1258
	{
1259
		if($priority===null)
1260
			$priority=$this->getDefaultPriority();
1261
		$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1262
		if(!isset($this->_d[$priority]) || !is_array($this->_d[$priority]))
1263
			return false;
1264
		return count($this->_d[$priority]);
1265
	}
1266
	public function getDefaultPriority()
1267
	{
1268
		return $this->_dp;
1269
	}
1270
	protected function setDefaultPriority($value)
1271
	{
1272
		$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...
1273
	}
1274
	public function getPrecision()
1275
	{
1276
		return $this->_p;
1277
	}
1278
	protected function setPrecision($value)
1279
	{
1280
		$this->_p=TPropertyValue::ensureInteger($value);
1281
	}
1282
	public function getIterator()
1283
	{
1284
		return new ArrayIterator($this->flattenPriorities());
1285
	}
1286
	public function getPriorities()
1287
	{
1288
		$this->sortPriorities();
1289
		return array_keys($this->_d);
1290
	}
1291
	protected function sortPriorities() {
1292
		if(!$this->_o) {
1293
			ksort($this->_d,SORT_NUMERIC);
1294
			$this->_o=true;
1295
		}
1296
	}
1297
	protected function flattenPriorities() {
1298
		if(is_array($this->_fd))
1299
			return $this->_fd;
1300
		$this->sortPriorities();
1301
		$this->_fd=array();
1302
		foreach($this->_d as $priority => $itemsatpriority)
1303
			$this->_fd=array_merge($this->_fd,$itemsatpriority);
1304
		return $this->_fd;
1305
	}
1306
	public function itemAt($index)
1307
	{
1308
		if($index>=0&&$index<$this->getCount()) {
1309
			$arr=$this->flattenPriorities();
1310
			return $arr[$index];
1311
		} else
1312
			throw new TInvalidDataValueException('list_index_invalid',$index);
1313
	}
1314
	public function itemsAtPriority($priority=null)
1315
	{
1316
		if($priority===null)
1317
			$priority=$this->getDefaultPriority();
1318
		$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1319
		return isset($this->_d[$priority])?$this->_d[$priority]:null;
1320
	}
1321
	public function itemAtIndexInPriority($index,$priority=null)
1322
	{
1323
		if($priority===null)
1324
			$priority=$this->getDefaultPriority();
1325
		$priority=(string)round(TPropertyValue::ensureFloat($priority), $this->_p);
1326
		return !isset($this->_d[$priority])?false:(
1327
				isset($this->_d[$priority][$index])?$this->_d[$priority][$index]:false
1328
			);
1329
	}
1330
	public function add($item,$priority=null)
1331
	{
1332
		if($this->getReadOnly())
1333
			throw new TInvalidOperationException('list_readonly',get_class($this));
1334
		return $this->insertAtIndexInPriority($item,false,$priority,true);
1335
	}
1336
	public function insertAt($index,$item)
1337
	{
1338
		if($this->getReadOnly())
1339
			throw new TInvalidOperationException('list_readonly',get_class($this));
1340
		if(($priority=$this->priorityAt($index,true))!==false)
1341
			$this->insertAtIndexInPriority($item,$priority[1],$priority[0]);
1342
		else
1343
			throw new TInvalidDataValueException('list_index_invalid',$index);
1344
	}
1345
	public function insertAtIndexInPriority($item,$index=false,$priority=null,$preserveCache=false)
1346
	{
1347
		if($this->getReadOnly())
1348
			throw new TInvalidOperationException('list_readonly',get_class($this));
1349
		if($priority===null)
1350
			$priority=$this->getDefaultPriority();
1351
		$priority=(string)round(TPropertyValue::ensureFloat($priority), $this->_p);
1352
		if($preserveCache) {
1353
			$this->sortPriorities();
1354
			$cc=0;
1355
			foreach($this->_d as $prioritykey=>$items)
1356
				if($prioritykey>=$priority)
1357
					break;
1358
				else
1359
					$cc+=count($items);
1360
			if($index===false&&isset($this->_d[$priority])) {
1361
				$c=count($this->_d[$priority]);
1362
				$c+=$cc;
1363
				$this->_d[$priority][]=$item;
1364
			} else if(isset($this->_d[$priority])) {
1365
				$c=$index+$cc;
1366
				array_splice($this->_d[$priority],$index,0,array($item));
1367
			} else {
1368
				$c = $cc;
1369
				$this->_o = false;
1370
				$this->_d[$priority]=array($item);
1371
			}
1372
			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...
1373
		} else {
1374
			$c=null;
1375
			if($index===false&&isset($this->_d[$priority])) {
1376
				$cc=count($this->_d[$priority]);
1377
				$this->_d[$priority][]=$item;
1378
			} else if(isset($this->_d[$priority])) {
1379
				$cc=$index;
1380
				array_splice($this->_d[$priority],$index,0,array($item));
1381
			} else {
1382
				$cc=0;
1383
				$this->_o=false;
1384
				$this->_d[$priority]=array($item);
1385
			}
1386
			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...
1387
				array_splice($this->_fd,$cc,0,array($item));
1388
			else
1389
				$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...
1390
		}
1391
		$this->_c++;
1392
		return $c;
1393
	}
1394
	public function remove($item,$priority=false)
1395
	{
1396
		if($this->getReadOnly())
1397
			throw new TInvalidOperationException('list_readonly',get_class($this));
1398
		if(($p=$this->priorityOf($item,true))!==false)
1399
		{
1400
			if($priority!==false) {
1401
				if($priority===null)
1402
					$priority=$this->getDefaultPriority();
1403
				$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1404
				if($p[0]!=$priority)
1405
					throw new TInvalidDataValueException('list_item_inexistent');
1406
			}
1407
			$this->removeAtIndexInPriority($p[1],$p[0]);
1408
			return $p[2];
1409
		}
1410
		else
1411
			throw new TInvalidDataValueException('list_item_inexistent');
1412
	}
1413
	public function removeAt($index)
1414
	{
1415
		if($this->getReadOnly())
1416
			throw new TInvalidOperationException('list_readonly',get_class($this));
1417
		if(($priority=$this->priorityAt($index, true))!==false)
1418
			return $this->removeAtIndexInPriority($priority[1],$priority[0]);
1419
		throw new TInvalidDataValueException('list_index_invalid',$index);
1420
	}
1421
	public function removeAtIndexInPriority($index, $priority=null)
1422
	{
1423
		if($this->getReadOnly())
1424
			throw new TInvalidOperationException('list_readonly',get_class($this));
1425
		if($priority===null)
1426
			$priority=$this->getDefaultPriority();
1427
		$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1428
		if(!isset($this->_d[$priority])||$index<0||$index>=count($this->_d[$priority]))
1429
			throw new TInvalidDataValueException('list_item_inexistent');
1430
				$value=array_splice($this->_d[$priority],$index,1);
1431
		$value=$value[0];
1432
		if(!count($this->_d[$priority]))
1433
			unset($this->_d[$priority]);
1434
		$this->_c--;
1435
		$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...
1436
		return $value;
1437
	}
1438
	public function clear()
1439
	{
1440
		if($this->getReadOnly())
1441
			throw new TInvalidOperationException('list_readonly',get_class($this));
1442
		$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...
1443
		foreach($this->_d as $priority=>$items) {
1444
			for($index=count($items)-1;$index>=0;$index--)
1445
				$this->removeAtIndexInPriority($index,$priority);
1446
			unset($this->_d[$priority]);
1447
		}
1448
	}
1449
	public function contains($item)
1450
	{
1451
		return $this->indexOf($item)>=0;
1452
	}
1453
	public function indexOf($item)
1454
	{
1455
		if(($index=array_search($item,$this->flattenPriorities(),true))===false)
1456
			return -1;
1457
		else
1458
			return $index;
1459
	}
1460
	public function priorityOf($item,$withindex = false)
1461
	{
1462
		$this->sortPriorities();
1463
		$absindex = 0;
1464
		foreach($this->_d as $priority=>$items) {
1465
			if(($index=array_search($item,$items,true))!==false) {
1466
				$absindex+=$index;
1467
				return $withindex?array($priority,$index,$absindex,
1468
						'priority'=>$priority,'index'=>$index,'absindex'=>$absindex):$priority;
1469
			} else
1470
				$absindex+=count($items);
1471
		}
1472
		return false;
1473
	}
1474
	public function priorityAt($index,$withindex = false)
1475
	{
1476
		if($index<0||$index>=$this->getCount())
1477
			throw new TInvalidDataValueException('list_index_invalid',$index);
1478
		$absindex=$index;
1479
		$this->sortPriorities();
1480
		foreach($this->_d as $priority=>$items) {
1481
			if($index>=($c=count($items)))
1482
				$index-=$c;
1483
			else
1484
				return $withindex?array($priority,$index,$absindex,
1485
						'priority'=>$priority,'index'=>$index,'absindex'=>$absindex):$priority;
1486
		}
1487
		return false;
1488
	}
1489
	public function insertBefore($indexitem, $item)
1490
	{
1491
		if($this->getReadOnly())
1492
			throw new TInvalidOperationException('list_readonly',get_class($this));
1493
		if(($priority=$this->priorityOf($indexitem,true))===false)
1494
			throw new TInvalidDataValueException('list_item_inexistent');
1495
		$this->insertAtIndexInPriority($item,$priority[1],$priority[0]);
1496
		return $priority[2];
1497
	}
1498
	public function insertAfter($indexitem, $item)
1499
	{
1500
		if($this->getReadOnly())
1501
			throw new TInvalidOperationException('list_readonly',get_class($this));
1502
		if(($priority=$this->priorityOf($indexitem,true))===false)
1503
			throw new TInvalidDataValueException('list_item_inexistent');
1504
		$this->insertAtIndexInPriority($item,$priority[1]+1,$priority[0]);
1505
		return $priority[2]+1;
1506
	}
1507
	public function toArray()
1508
	{
1509
		return $this->flattenPriorities();
1510
	}
1511
	public function toPriorityArray()
1512
	{
1513
		$this->sortPriorities();
1514
		return $this->_d;
1515
	}
1516
	public function toArrayBelowPriority($priority,$inclusive=false)
1517
	{
1518
		$this->sortPriorities();
1519
		$items=array();
1520
		foreach($this->_d as $itemspriority=>$itemsatpriority)
1521
		{
1522
			if((!$inclusive&&$itemspriority>=$priority)||$itemspriority>$priority)
1523
				break;
1524
			$items=array_merge($items,$itemsatpriority);
1525
		}
1526
		return $items;
1527
	}
1528
	public function toArrayAbovePriority($priority,$inclusive=true)
1529
	{
1530
		$this->sortPriorities();
1531
		$items=array();
1532
		foreach($this->_d as $itemspriority=>$itemsatpriority)
1533
		{
1534
			if((!$inclusive&&$itemspriority<=$priority)||$itemspriority<$priority)
1535
				continue;
1536
			$items=array_merge($items,$itemsatpriority);
1537
		}
1538
		return $items;
1539
	}
1540
	public function copyFrom($data)
1541
	{
1542
		if($data instanceof TPriorityList)
1543
		{
1544
			if($this->getCount()>0)
1545
				$this->clear();
1546
			foreach($data->getPriorities() as $priority)
1547
			{
1548
				foreach($data->itemsAtPriority($priority) as $index=>$item)
1549
					$this->insertAtIndexInPriority($item,$index,$priority);
1550
			}
1551
		} else if(is_array($data)||$data instanceof Traversable) {
1552
			if($this->getCount()>0)
1553
				$this->clear();
1554
			foreach($data as $key=>$item)
1555
				$this->add($item);
1556
		} else if($data!==null)
1557
			throw new TInvalidDataTypeException('map_data_not_iterable');
1558
	}
1559
	public function mergeWith($data)
1560
	{
1561
		if($data instanceof TPriorityList)
1562
		{
1563
			foreach($data->getPriorities() as $priority)
1564
			{
1565
				foreach($data->itemsAtPriority($priority) as $index=>$item)
1566
					$this->insertAtIndexInPriority($item,false,$priority);
1567
			}
1568
		}
1569
		else if(is_array($data)||$data instanceof Traversable)
1570
		{
1571
			foreach($data as $priority=>$item)
1572
				$this->add($item);
1573
		}
1574
		else if($data!==null)
1575
			throw new TInvalidDataTypeException('map_data_not_iterable');
1576
	}
1577
	public function offsetExists($offset)
1578
	{
1579
		return ($offset>=0&&$offset<$this->getCount());
1580
	}
1581
	public function offsetGet($offset)
1582
	{
1583
		return $this->itemAt($offset);
1584
	}
1585
	public function offsetSet($offset,$item)
1586
	{
1587
		if($offset===null)
1588
			return $this->add($item);
1589
		if($offset===$this->getCount()) {
1590
			$priority=$this->priorityAt($offset-1,true);
1591
			$priority[1]++;
1592
		} else {
1593
			$priority=$this->priorityAt($offset,true);
1594
			$this->removeAtIndexInPriority($priority[1],$priority[0]);
1595
		}
1596
		$this->insertAtIndexInPriority($item,$priority[1],$priority[0]);
1597
	}
1598
	public function offsetUnset($offset)
1599
	{
1600
		$this->removeAt($offset);
1601
	}
1602
}
1603
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...
1604
{
1605
	private $_d=array();
1606
	private $_r=false;
1607
	public function __construct($data=null,$readOnly=false)
1608
	{
1609
		if($data!==null)
1610
			$this->copyFrom($data);
1611
		$this->setReadOnly($readOnly);
1612
	}
1613
	public function getReadOnly()
1614
	{
1615
		return $this->_r;
1616
	}
1617
	protected function setReadOnly($value)
1618
	{
1619
		$this->_r=TPropertyValue::ensureBoolean($value);
1620
	}
1621
	public function getIterator()
1622
	{
1623
		return new ArrayIterator( $this->_d );
1624
	}
1625
	public function count()
1626
	{
1627
		return $this->getCount();
1628
	}
1629
	public function getCount()
1630
	{
1631
		return count($this->_d);
1632
	}
1633
	public function getKeys()
1634
	{
1635
		return array_keys($this->_d);
1636
	}
1637
	public function itemAt($key)
1638
	{
1639
		return isset($this->_d[$key]) ? $this->_d[$key] : null;
1640
	}
1641
	public function add($key,$value)
1642
	{
1643
		if(!$this->_r)
1644
			$this->_d[$key]=$value;
1645
		else
1646
			throw new TInvalidOperationException('map_readonly',get_class($this));
1647
	}
1648
	public function remove($key)
1649
	{
1650
		if(!$this->_r)
1651
		{
1652
			if(isset($this->_d[$key]) || array_key_exists($key,$this->_d))
1653
			{
1654
				$value=$this->_d[$key];
1655
				unset($this->_d[$key]);
1656
				return $value;
1657
			}
1658
			else
1659
				return null;
1660
		}
1661
		else
1662
			throw new TInvalidOperationException('map_readonly',get_class($this));
1663
	}
1664
	public function clear()
1665
	{
1666
		foreach(array_keys($this->_d) as $key)
1667
			$this->remove($key);
1668
	}
1669
	public function contains($key)
1670
	{
1671
		return isset($this->_d[$key]) || array_key_exists($key,$this->_d);
1672
	}
1673
	public function toArray()
1674
	{
1675
		return $this->_d;
1676
	}
1677
	public function copyFrom($data)
1678
	{
1679
		if(is_array($data) || $data instanceof Traversable)
1680
		{
1681
			if($this->getCount()>0)
1682
				$this->clear();
1683
			foreach($data as $key=>$value)
1684
				$this->add($key,$value);
1685
		}
1686
		else if($data!==null)
1687
			throw new TInvalidDataTypeException('map_data_not_iterable');
1688
	}
1689
	public function mergeWith($data)
1690
	{
1691
		if(is_array($data) || $data instanceof Traversable)
1692
		{
1693
			foreach($data as $key=>$value)
1694
				$this->add($key,$value);
1695
		}
1696
		else if($data!==null)
1697
			throw new TInvalidDataTypeException('map_data_not_iterable');
1698
	}
1699
	public function offsetExists($offset)
1700
	{
1701
		return $this->contains($offset);
1702
	}
1703
	public function offsetGet($offset)
1704
	{
1705
		return $this->itemAt($offset);
1706
	}
1707
	public function offsetSet($offset,$item)
1708
	{
1709
		$this->add($offset,$item);
1710
	}
1711
	public function offsetUnset($offset)
1712
	{
1713
		$this->remove($offset);
1714
	}
1715
}
1716
class TMapIterator implements Iterator
1717
{
1718
	private $_d;
1719
	private $_keys;
1720
	private $_key;
1721
	public function __construct(&$data)
1722
	{
1723
		$this->_d=&$data;
1724
		$this->_keys=array_keys($data);
1725
	}
1726
	public function rewind()
1727
	{
1728
		$this->_key=reset($this->_keys);
1729
	}
1730
	public function key()
1731
	{
1732
		return $this->_key;
1733
	}
1734
	public function current()
1735
	{
1736
		return $this->_d[$this->_key];
1737
	}
1738
	public function next()
1739
	{
1740
		$this->_key=next($this->_keys);
1741
	}
1742
	public function valid()
1743
	{
1744
		return $this->_key!==false;
1745
	}
1746
}
1747
class TPriorityMap extends TMap
1748
{
1749
	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...
1750
	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...
1751
	private $_o=false;
1752
	private $_fd=null;
1753
	private $_c=0;
1754
	private $_dp=10;
1755
	private $_p=8;
1756
	public function __construct($data=null,$readOnly=false,$defaultPriority=10,$precision=8)
1757
	{
1758
		if($data!==null)
1759
			$this->copyFrom($data);
1760
		$this->setReadOnly($readOnly);
1761
		$this->setPrecision($precision);
1762
		$this->setDefaultPriority($defaultPriority);
1763
	}
1764
	public function getReadOnly()
1765
	{
1766
		return $this->_r;
1767
	}
1768
	protected function setReadOnly($value)
1769
	{
1770
		$this->_r=TPropertyValue::ensureBoolean($value);
1771
	}
1772
	public function getDefaultPriority()
1773
	{
1774
		return $this->_dp;
1775
	}
1776
	protected function setDefaultPriority($value)
1777
	{
1778
		$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...
1779
	}
1780
	public function getPrecision()
1781
	{
1782
		return $this->_p;
1783
	}
1784
	protected function setPrecision($value)
1785
	{
1786
		$this->_p=TPropertyValue::ensureInteger($value);
1787
	}
1788
	public function getIterator()
1789
	{
1790
		return new ArrayIterator($this->flattenPriorities());
1791
	}
1792
	protected function sortPriorities() {
1793
		if(!$this->_o) {
1794
			ksort($this->_d, SORT_NUMERIC);
1795
			$this->_o=true;
1796
		}
1797
	}
1798
	protected function flattenPriorities() {
1799
		if(is_array($this->_fd))
1800
			return $this->_fd;
1801
		$this->sortPriorities();
1802
		$this->_fd = array();
1803
		foreach($this->_d as $priority => $itemsatpriority)
1804
			$this->_fd = array_merge($this->_fd, $itemsatpriority);
1805
		return $this->_fd;
1806
	}
1807
	public function count()
1808
	{
1809
		return $this->getCount();
1810
	}
1811
	public function getCount()
1812
	{
1813
		return $this->_c;
1814
	}
1815
	public function getPriorityCount($priority=null)
1816
	{
1817
		if($priority===null)
1818
			$priority=$this->getDefaultPriority();
1819
		$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1820
		if(!isset($this->_d[$priority])||!is_array($this->_d[$priority]))
1821
			return false;
1822
		return count($this->_d[$priority]);
1823
	}
1824
	public function getPriorities()
1825
	{
1826
		$this->sortPriorities();
1827
		return array_keys($this->_d);
1828
	}
1829
	public function getKeys()
1830
	{
1831
		return array_keys($this->flattenPriorities());
1832
	}
1833
	public function itemAt($key,$priority=false)
1834
	{
1835
		if($priority===false){
1836
			$map=$this->flattenPriorities();
1837
			return isset($map[$key])?$map[$key]:null;
1838
		} else {
1839
			if($priority===null)
1840
				$priority=$this->getDefaultPriority();
1841
			$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1842
			return (isset($this->_d[$priority])&&isset($this->_d[$priority][$key]))?$this->_d[$priority][$key]:null;
1843
		}
1844
	}
1845
	public function setPriorityAt($key,$priority=null)
1846
	{
1847
		if($priority===null)
1848
			$priority=$this->getDefaultPriority();
1849
		$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1850
		$oldpriority=$this->priorityAt($key);
1851
		if($oldpriority!==false&&$oldpriority!=$priority) {
1852
			$value=$this->remove($key,$oldpriority);
1853
			$this->add($key,$value,$priority);
1854
		}
1855
		return $oldpriority;
1856
	}
1857
	public function itemsAtPriority($priority=null)
1858
	{
1859
		if($priority===null)
1860
			$priority=$this->getDefaultPriority();
1861
		$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1862
		return isset($this->_d[$priority])?$this->_d[$priority]:null;
1863
	}
1864
	public function priorityOf($item)
1865
	{
1866
		$this->sortPriorities();
1867
		foreach($this->_d as $priority=>$items)
1868
			if(($index=array_search($item,$items,true))!==false)
1869
				return $priority;
1870
		return false;
1871
	}
1872
	public function priorityAt($key)
1873
	{
1874
		$this->sortPriorities();
1875
		foreach($this->_d as $priority=>$items)
1876
			if(array_key_exists($key,$items))
1877
				return $priority;
1878
		return false;
1879
	}
1880
	public function add($key,$value,$priority=null)
1881
	{
1882
		if($priority===null)
1883
			$priority=$this->getDefaultPriority();
1884
		$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1885
		if(!$this->_r)
1886
		{
1887
			foreach($this->_d as $innerpriority=>$items)
1888
				if(array_key_exists($key,$items))
1889
				{
1890
					unset($this->_d[$innerpriority][$key]);
1891
					$this->_c--;
1892
					if(count($this->_d[$innerpriority])===0)
1893
						unset($this->_d[$innerpriority]);
1894
				}
1895
			if(!isset($this->_d[$priority])) {
1896
				$this->_d[$priority]=array($key=>$value);
1897
				$this->_o=false;
1898
			}
1899
			else
1900
				$this->_d[$priority][$key]=$value;
1901
			$this->_c++;
1902
			$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...
1903
		}
1904
		else
1905
			throw new TInvalidOperationException('map_readonly',get_class($this));
1906
		return $priority;
1907
	}
1908
	public function remove($key,$priority=false)
1909
	{
1910
		if(!$this->_r)
1911
		{
1912
			if($priority===null)
1913
				$priority=$this->getDefaultPriority();
1914
			if($priority===false)
1915
			{
1916
				$this->sortPriorities();
1917
				foreach($this->_d as $priority=>$items)
1918
					if(array_key_exists($key,$items))
1919
					{
1920
						$value=$this->_d[$priority][$key];
1921
						unset($this->_d[$priority][$key]);
1922
						$this->_c--;
1923
						if(count($this->_d[$priority])===0)
1924
						{
1925
							unset($this->_d[$priority]);
1926
							$this->_o=false;
1927
						}
1928
						$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...
1929
						return $value;
1930
					}
1931
				return null;
1932
			}
1933
			else
1934
			{
1935
				$priority=(string)round(TPropertyValue::ensureFloat($priority),$this->_p);
1936
				if(isset($this->_d[$priority])&&(isset($this->_d[$priority][$key])||array_key_exists($key,$this->_d[$priority])))
1937
				{
1938
					$value=$this->_d[$priority][$key];
1939
					unset($this->_d[$priority][$key]);
1940
					$this->_c--;
1941
					if(count($this->_d[$priority])===0) {
1942
						unset($this->_d[$priority]);
1943
						$this->_o=false;
1944
					}
1945
					$this->_fd=null;
1946
					return $value;
1947
				}
1948
				else
1949
					return null;
1950
			}
1951
		}
1952
		else
1953
			throw new TInvalidOperationException('map_readonly',get_class($this));
1954
	}
1955
	public function clear()
1956
	{
1957
		foreach($this->_d as $priority=>$items)
1958
			foreach(array_keys($items) as $key)
1959
				$this->remove($key);
1960
	}
1961
	public function contains($key)
1962
	{
1963
		$map=$this->flattenPriorities();
1964
		return isset($map[$key])||array_key_exists($key,$map);
1965
	}
1966
	public function toArray()
1967
	{
1968
		return $this->flattenPriorities();
1969
	}
1970
	public function toArrayBelowPriority($priority,$inclusive=false)
1971
	{
1972
		$this->sortPriorities();
1973
		$items=array();
1974
		foreach($this->_d as $itemspriority=>$itemsatpriority)
1975
		{
1976
			if((!$inclusive&&$itemspriority>=$priority)||$itemspriority>$priority)
1977
				break;
1978
			$items=array_merge($items,$itemsatpriority);
1979
		}
1980
		return $items;
1981
	}
1982
	public function toArrayAbovePriority($priority,$inclusive=true)
1983
	{
1984
		$this->sortPriorities();
1985
		$items=array();
1986
		foreach($this->_d as $itemspriority=>$itemsatpriority)
1987
		{
1988
			if((!$inclusive&&$itemspriority<=$priority)||$itemspriority<$priority)
1989
				continue;
1990
			$items=array_merge($items,$itemsatpriority);
1991
		}
1992
		return $items;
1993
	}
1994
	public function copyFrom($data)
1995
	{
1996
		if($data instanceof TPriorityMap)
1997
		{
1998
			if($this->getCount()>0)
1999
				$this->clear();
2000
			foreach($data->getPriorities() as $priority) {
2001
				foreach($data->itemsAtPriority($priority) as $key => $value) {
2002
					$this->add($key,$value,$priority);
2003
				}
2004
			}
2005
		}
2006
		else if(is_array($data)||$data instanceof Traversable)
2007
		{
2008
			if($this->getCount()>0)
2009
				$this->clear();
2010
			foreach($data as $key=>$value)
2011
				$this->add($key,$value);
2012
		}
2013
		else if($data!==null)
2014
			throw new TInvalidDataTypeException('map_data_not_iterable');
2015
	}
2016
	public function mergeWith($data)
2017
	{
2018
		if($data instanceof TPriorityMap)
2019
		{
2020
			foreach($data->getPriorities() as $priority)
2021
			{
2022
				foreach($data->itemsAtPriority($priority) as $key => $value)
2023
					$this->add($key,$value,$priority);
2024
			}
2025
		}
2026
		else if(is_array($data)||$data instanceof Traversable)
2027
		{
2028
			foreach($data as $key=>$value)
2029
				$this->add($key,$value);
2030
		}
2031
		else if($data!==null)
2032
			throw new TInvalidDataTypeException('map_data_not_iterable');
2033
	}
2034
	public function offsetExists($offset)
2035
	{
2036
		return $this->contains($offset);
2037
	}
2038
	public function offsetGet($offset)
2039
	{
2040
		return $this->itemAt($offset);
2041
	}
2042
	public function offsetSet($offset,$item)
2043
	{
2044
		$this->add($offset,$item);
2045
	}
2046
	public function offsetUnset($offset)
2047
	{
2048
		$this->remove($offset);
2049
	}
2050
}
2051
class TStack extends TComponent implements IteratorAggregate,Countable
0 ignored issues
show
Coding Style introduced by
Expected 1 space before "Countable"; 0 found
Loading history...
2052
{
2053
	private $_d=array();
2054
	private $_c=0;
2055
	public function __construct($data=null)
2056
	{
2057
		if($data!==null)
2058
			$this->copyFrom($data);
2059
	}
2060
	public function toArray()
2061
	{
2062
		return $this->_d;
2063
	}
2064
	public function copyFrom($data)
2065
	{
2066
		if(is_array($data) || ($data instanceof Traversable))
2067
		{
2068
			$this->clear();
2069
			foreach($data as $item)
2070
			{
2071
				$this->_d[]=$item;
2072
				++$this->_c;
2073
			}
2074
		}
2075
		else if($data!==null)
2076
			throw new TInvalidDataTypeException('stack_data_not_iterable');
2077
	}
2078
	public function clear()
2079
	{
2080
		$this->_c=0;
2081
		$this->_d=array();
2082
	}
2083
	public function contains($item)
2084
	{
2085
		return array_search($item,$this->_d,true)!==false;
2086
	}
2087
	public function peek()
2088
	{
2089
		if($this->_c===0)
2090
			throw new TInvalidOperationException('stack_empty');
2091
		else
2092
			return $this->_d[$this->_c-1];
2093
	}
2094
	public function pop()
2095
	{
2096
		if($this->_c===0)
2097
			throw new TInvalidOperationException('stack_empty');
2098
		else
2099
		{
2100
			--$this->_c;
2101
			return array_pop($this->_d);
2102
		}
2103
	}
2104
	public function push($item)
2105
	{
2106
		++$this->_c;
2107
		$this->_d[] = $item;
2108
	}
2109
	public function getIterator()
2110
	{
2111
		return new ArrayIterator( $this->_d );
2112
	}
2113
	public function getCount()
2114
	{
2115
		return $this->_c;
2116
	}
2117
	public function count()
2118
	{
2119
		return $this->getCount();
2120
	}
2121
}
2122
class TStackIterator implements Iterator
2123
{
2124
	private $_d;
2125
	private $_i;
2126
	private $_c;
2127
	public function __construct(&$data)
2128
	{
2129
		$this->_d=&$data;
2130
		$this->_i=0;
2131
		$this->_c=count($this->_d);
2132
	}
2133
	public function rewind()
2134
	{
2135
		$this->_i=0;
2136
	}
2137
	public function key()
2138
	{
2139
		return $this->_i;
2140
	}
2141
	public function current()
2142
	{
2143
		return $this->_d[$this->_i];
2144
	}
2145
	public function next()
2146
	{
2147
		$this->_i++;
2148
	}
2149
	public function valid()
2150
	{
2151
		return $this->_i<$this->_c;
2152
	}
2153
}
2154
class TXmlElement extends TComponent
2155
{
2156
	private $_parent=null;
2157
	private $_tagName='unknown';
2158
	private $_value='';
2159
	private $_elements=null;
2160
	private $_attributes=null;
2161
	public function __construct($tagName)
2162
	{
2163
		$this->setTagName($tagName);
2164
	}
2165
	public function getParent()
2166
	{
2167
		return $this->_parent;
2168
	}
2169
	public function setParent($parent)
2170
	{
2171
		$this->_parent=$parent;
2172
	}
2173
	public function getTagName()
2174
	{
2175
		return $this->_tagName;
2176
	}
2177
	public function setTagName($tagName)
2178
	{
2179
		$this->_tagName=$tagName;
2180
	}
2181
	public function getValue()
2182
	{
2183
		return $this->_value;
2184
	}
2185
	public function setValue($value)
2186
	{
2187
		$this->_value=TPropertyValue::ensureString($value);
2188
	}
2189
	public function getHasElement()
2190
	{
2191
		return $this->_elements!==null && $this->_elements->getCount()>0;
2192
	}
2193
	public function getHasAttribute()
2194
	{
2195
		return $this->_attributes!==null && $this->_attributes->getCount()>0;
2196
	}
2197
	public function getAttribute($name)
2198
	{
2199
		if($this->_attributes!==null)
2200
			return $this->_attributes->itemAt($name);
2201
		else
2202
			return null;
2203
	}
2204
	public function setAttribute($name,$value)
2205
	{
2206
		$this->getAttributes()->add($name,TPropertyValue::ensureString($value));
2207
	}
2208
	public function getElements()
2209
	{
2210
		if(!$this->_elements)
2211
			$this->_elements=new TXmlElementList($this);
2212
		return $this->_elements;
2213
	}
2214
	public function getAttributes()
2215
	{
2216
		if(!$this->_attributes)
2217
			$this->_attributes=new TMap;
2218
		return $this->_attributes;
2219
	}
2220
	public function getElementByTagName($tagName)
2221
	{
2222
		if($this->_elements)
2223
		{
2224
			foreach($this->_elements as $element)
2225
				if($element->_tagName===$tagName)
2226
					return $element;
2227
		}
2228
		return null;
2229
	}
2230
	public function getElementsByTagName($tagName)
2231
	{
2232
		$list=new TList;
2233
		if($this->_elements)
2234
		{
2235
			foreach($this->_elements as $element)
2236
				if($element->_tagName===$tagName)
2237
					$list->add($element);
2238
		}
2239
		return $list;
2240
	}
2241
	public function toString($indent=0)
2242
	{
2243
		$attr='';
2244
		if($this->_attributes!==null)
2245
		{
2246
			foreach($this->_attributes as $name=>$value)
2247
			{
2248
				$value=$this->xmlEncode($value);
2249
				$attr.=" $name=\"$value\"";
2250
			}
2251
		}
2252
		$prefix=str_repeat(' ',$indent*4);
2253
		if($this->getHasElement())
2254
		{
2255
			$str=$prefix."<{$this->_tagName}$attr>\n";
2256
			foreach($this->getElements() as $element)
2257
				$str.=$element->toString($indent+1)."\n";
2258
			$str.=$prefix."</{$this->_tagName}>";
2259
			return $str;
2260
		}
2261
		else if(($value=$this->getValue())!=='')
2262
		{
2263
			$value=$this->xmlEncode($value);
2264
			return $prefix."<{$this->_tagName}$attr>$value</{$this->_tagName}>";
2265
		}
2266
		else
2267
			return $prefix."<{$this->_tagName}$attr />";
2268
	}
2269
	public function __toString()
2270
	{
2271
		return $this->toString();
2272
	}
2273
	private function xmlEncode($str)
2274
	{
2275
		return strtr($str,array(
2276
			'>'=>'&gt;',
2277
			'<'=>'&lt;',
2278
			'&'=>'&amp;',
2279
			'"'=>'&quot;',
2280
			"\r"=>'&#xD;',
2281
			"\t"=>'&#x9;',
2282
			"\n"=>'&#xA;'));
2283
	}
2284
}
2285
class TXmlDocument extends TXmlElement
2286
{
2287
	private $_version;
2288
	private $_encoding;
2289
	public function __construct($version='1.0',$encoding='')
2290
	{
2291
		parent::__construct('');
2292
		$this->setVersion($version);
2293
		$this->setEncoding($encoding);
2294
	}
2295
	public function getVersion()
2296
	{
2297
		return $this->_version;
2298
	}
2299
	public function setVersion($version)
2300
	{
2301
		$this->_version=$version;
2302
	}
2303
	public function getEncoding()
2304
	{
2305
		return $this->_encoding;
2306
	}
2307
	public function setEncoding($encoding)
2308
	{
2309
		$this->_encoding=$encoding;
2310
	}
2311
	public function loadFromFile($file)
2312
	{
2313
		if(($str=@file_get_contents($file))!==false)
2314
			return $this->loadFromString($str);
2315
		else
2316
			throw new TIOException('xmldocument_file_read_failed',$file);
2317
	}
2318
	public function loadFromString($string)
2319
	{
2320
				$doc=new DOMDocument();
2321
		if($doc->loadXML($string)===false)
2322
			return false;
2323
		$this->setEncoding($doc->encoding);
2324
		$this->setVersion($doc->version);
0 ignored issues
show
Deprecated Code introduced by
The property DOMDocument::$version has been deprecated.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
2325
		$element=$doc->documentElement;
2326
		$this->setTagName($element->tagName);
2327
		$this->setValue($element->nodeValue);
2328
		$elements=$this->getElements();
2329
		$attributes=$this->getAttributes();
2330
		$elements->clear();
2331
		$attributes->clear();
2332
		static $bSimpleXml;
2333
		if($bSimpleXml === null)
2334
			$bSimpleXml = (boolean)function_exists('simplexml_load_string');
2335
		if($bSimpleXml)
2336
		{
2337
			$simpleDoc = simplexml_load_string($string);
2338
			$docNamespaces = $simpleDoc->getDocNamespaces(false);
2339
			$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...
2340
			foreach($docNamespaces as $prefix => $uri)
2341
			{
2342
 				if($prefix === '')
2343
   					$attributes->add('xmlns', $uri);
2344
   				else
2345
   					$attributes->add('xmlns:'.$prefix, $uri);
2346
			}
2347
		}
2348
		foreach($element->attributes as $name=>$attr)
2349
			$attributes->add(($attr->prefix === '' ? '' : $attr->prefix . ':') .$name,$attr->value);
2350
		foreach($element->childNodes as $child)
2351
		{
2352
			if($child instanceof DOMElement)
2353
				$elements->add($this->buildElement($child));
2354
		}
2355
		return true;
2356
	}
2357
	public function saveToFile($file)
2358
	{
2359
		if(($fw=fopen($file,'w'))!==false)
2360
		{
2361
			fwrite($fw,$this->saveToString());
2362
			fclose($fw);
2363
		}
2364
		else
2365
			throw new TIOException('xmldocument_file_write_failed',$file);
2366
	}
2367
	public function saveToString()
2368
	{
2369
		$version=empty($this->_version)?' version="1.0"':' version="'.$this->_version.'"';
2370
		$encoding=empty($this->_encoding)?'':' encoding="'.$this->_encoding.'"';
2371
		return "<?xml{$version}{$encoding}?>\n".$this->toString(0);
2372
	}
2373
	public function __toString()
2374
	{
2375
		return $this->saveToString();
2376
	}
2377
	protected function buildElement($node)
2378
	{
2379
		$element=new TXmlElement($node->tagName);
2380
		$element->setValue($node->nodeValue);
2381
		foreach($node->attributes as $name=>$attr)
2382
			$element->getAttributes()->add(($attr->prefix === '' ? '' : $attr->prefix . ':') . $name,$attr->value);
2383
		foreach($node->childNodes as $child)
2384
		{
2385
			if($child instanceof DOMElement)
2386
				$element->getElements()->add($this->buildElement($child));
2387
		}
2388
		return $element;
2389
	}
2390
}
2391
class TXmlElementList extends TList
2392
{
2393
	private $_o;
2394
	public function __construct(TXmlElement $owner)
2395
	{
2396
		$this->_o=$owner;
2397
	}
2398
	protected function getOwner()
2399
	{
2400
		return $this->_o;
2401
	}
2402
	public function insertAt($index,$item)
2403
	{
2404
		if($item instanceof TXmlElement)
2405
		{
2406
			parent::insertAt($index,$item);
2407
			if($item->getParent()!==null)
2408
				$item->getParent()->getElements()->remove($item);
2409
			$item->setParent($this->_o);
2410
		}
2411
		else
2412
			throw new TInvalidDataTypeException('xmlelementlist_xmlelement_required');
2413
	}
2414
	public function removeAt($index)
2415
	{
2416
		$item=parent::removeAt($index);
2417
		if($item instanceof TXmlElement)
2418
			$item->setParent(null);
2419
		return $item;
2420
	}
2421
}
2422
class TAuthorizationRule extends TComponent
2423
{
2424
	private $_action;
2425
	private $_users;
2426
	private $_roles;
2427
	private $_verb;
2428
	private $_ipRules;
2429
	private $_everyone;
2430
	private $_guest;
2431
	private $_authenticated;
2432
	public function __construct($action,$users,$roles,$verb='',$ipRules='')
2433
	{
2434
		$action=strtolower(trim($action));
2435
		if($action==='allow' || $action==='deny')
2436
			$this->_action=$action;
2437
		else
2438
			throw new TInvalidDataValueException('authorizationrule_action_invalid',$action);
2439
		$this->_users=array();
2440
		$this->_roles=array();
2441
		$this->_ipRules=array();
2442
		$this->_everyone=false;
2443
		$this->_guest=false;
2444
		$this->_authenticated=false;
2445
		if(trim($users)==='')
2446
			$users='*';
2447
		foreach(explode(',',$users) as $user)
2448
		{
2449
			if(($user=trim(strtolower($user)))!=='')
2450
			{
2451
				if($user==='*')
2452
				{
2453
					$this->_everyone=true;
2454
					break;
2455
				}
2456
				else if($user==='?')
2457
					$this->_guest=true;
2458
				else if($user==='@')
2459
					$this->_authenticated=true;
2460
				else
2461
					$this->_users[]=$user;
2462
			}
2463
		}
2464
		if(trim($roles)==='')
2465
			$roles='*';
2466
		foreach(explode(',',$roles) as $role)
2467
		{
2468
			if(($role=trim(strtolower($role)))!=='')
2469
				$this->_roles[]=$role;
2470
		}
2471
		if(($verb=trim(strtolower($verb)))==='')
2472
			$verb='*';
2473
		if($verb==='*' || $verb==='get' || $verb==='post')
2474
			$this->_verb=$verb;
2475
		else
2476
			throw new TInvalidDataValueException('authorizationrule_verb_invalid',$verb);
2477
		if(trim($ipRules)==='')
2478
			$ipRules='*';
2479
		foreach(explode(',',$ipRules) as $ipRule)
2480
		{
2481
			if(($ipRule=trim($ipRule))!=='')
2482
				$this->_ipRules[]=$ipRule;
2483
		}
2484
	}
2485
	public function getAction()
2486
	{
2487
		return $this->_action;
2488
	}
2489
	public function getUsers()
2490
	{
2491
		return $this->_users;
2492
	}
2493
	public function getRoles()
2494
	{
2495
		return $this->_roles;
2496
	}
2497
	public function getVerb()
2498
	{
2499
		return $this->_verb;
2500
	}
2501
	public function getIPRules()
2502
	{
2503
		return $this->_ipRules;
2504
	}
2505
	public function getGuestApplied()
2506
	{
2507
		return $this->_guest || $this->_everyone;
2508
	}
2509
	public function getEveryoneApplied()
2510
	{
2511
		return $this->_everyone;
2512
	}
2513
	public function getAuthenticatedApplied()
2514
	{
2515
		return $this->_authenticated || $this->_everyone;
2516
	}
2517
	public function isUserAllowed(IUser $user,$verb,$ip)
2518
	{
2519
		if($this->isVerbMatched($verb) && $this->isIpMatched($ip) && $this->isUserMatched($user) && $this->isRoleMatched($user))
2520
			return ($this->_action==='allow')?1:-1;
2521
		else
2522
			return 0;
2523
	}
2524
	private function isIpMatched($ip)
2525
	{
2526
		if(empty($this->_ipRules))
2527
			return 1;
2528
		foreach($this->_ipRules as $rule)
2529
		{
2530
			if($rule==='*' || $rule===$ip || (($pos=strpos($rule,'*'))!==false && strncmp($ip,$rule,$pos)===0))
2531
				return 1;
2532
		}
2533
		return 0;
2534
	}
2535
	private function isUserMatched($user)
2536
	{
2537
		return ($this->_everyone || ($this->_guest && $user->getIsGuest()) || ($this->_authenticated && !$user->getIsGuest()) || in_array(strtolower($user->getName()),$this->_users));
2538
	}
2539
	private function isRoleMatched($user)
2540
	{
2541
		foreach($this->_roles as $role)
2542
		{
2543
			if($role==='*' || $user->isInRole($role))
2544
				return true;
2545
		}
2546
		return false;
2547
	}
2548
	private function isVerbMatched($verb)
2549
	{
2550
		return ($this->_verb==='*' || strcasecmp($verb,$this->_verb)===0);
2551
	}
2552
}
2553
class TAuthorizationRuleCollection extends TList
2554
{
2555
	public function isUserAllowed($user,$verb,$ip)
2556
	{
2557
		if($user instanceof IUser)
2558
		{
2559
			$verb=strtolower(trim($verb));
2560
			foreach($this as $rule)
2561
			{
2562
				if(($decision=$rule->isUserAllowed($user,$verb,$ip))!==0)
2563
					return ($decision>0);
2564
			}
2565
			return true;
2566
		}
2567
		else
2568
			return false;
2569
	}
2570
	public function insertAt($index,$item)
2571
	{
2572
		if($item instanceof TAuthorizationRule)
2573
			parent::insertAt($index,$item);
2574
		else
2575
			throw new TInvalidDataTypeException('authorizationrulecollection_authorizationrule_required');
2576
	}
2577
}
2578
class TSecurityManager extends TModule
2579
{
2580
	const STATE_VALIDATION_KEY = 'prado:securitymanager:validationkey';
2581
	const STATE_ENCRYPTION_KEY = 'prado:securitymanager:encryptionkey';
2582
	private $_validationKey = null;
2583
	private $_encryptionKey = null;
2584
	private $_hashAlgorithm = 'sha1';
2585
	private $_cryptAlgorithm = 'rijndael-256';
2586
	private $_mbstring;
2587
	public function init($config)
2588
	{
2589
		$this->_mbstring=extension_loaded('mbstring');
2590
		$this->getApplication()->setSecurityManager($this);
2591
	}
2592
	protected function generateRandomKey()
2593
	{
2594
		return sprintf('%08x%08x%08x%08x',mt_rand(),mt_rand(),mt_rand(),mt_rand());
2595
	}
2596
	public function getValidationKey()
2597
	{
2598
		if(null === $this->_validationKey) {
2599
			if(null === ($this->_validationKey = $this->getApplication()->getGlobalState(self::STATE_VALIDATION_KEY))) {
2600
				$this->_validationKey = $this->generateRandomKey();
2601
				$this->getApplication()->setGlobalState(self::STATE_VALIDATION_KEY, $this->_validationKey, null, true);
2602
			}
2603
		}
2604
		return $this->_validationKey;
2605
	}
2606
	public function setValidationKey($value)
2607
	{
2608
		if('' === $value)
2609
			throw new TInvalidDataValueException('securitymanager_validationkey_invalid');
2610
		$this->_validationKey = $value;
2611
	}
2612
	public function getEncryptionKey()
2613
	{
2614
		if(null === $this->_encryptionKey) {
2615
			if(null === ($this->_encryptionKey = $this->getApplication()->getGlobalState(self::STATE_ENCRYPTION_KEY))) {
2616
				$this->_encryptionKey = $this->generateRandomKey();
2617
				$this->getApplication()->setGlobalState(self::STATE_ENCRYPTION_KEY, $this->_encryptionKey, null, true);
2618
			}
2619
		}
2620
		return $this->_encryptionKey;
2621
	}
2622
	public function setEncryptionKey($value)
2623
	{
2624
		if('' === $value)
2625
			throw new TInvalidDataValueException('securitymanager_encryptionkey_invalid');
2626
		$this->_encryptionKey = $value;
2627
	}
2628
	public function getValidation()
2629
	{
2630
		return $this->_hashAlgorithm;
2631
	}
2632
	public function getHashAlgorithm()
2633
	{
2634
		return $this->_hashAlgorithm;
2635
	}
2636
	public function setValidation($value)
2637
	{
2638
		$this->_hashAlgorithm = TPropertyValue::ensureEnum($value, 'TSecurityManagerValidationMode');
2639
	}
2640
	public function setHashAlgorithm($value)
2641
	{
2642
		$this->_hashAlgorithm = TPropertyValue::ensureString($value);
2643
	}
2644
	public function getEncryption()
2645
	{
2646
		if(is_string($this->_cryptAlgorithm))
2647
			return $this->_cryptAlgorithm;
2648
				return "3DES";
2649
	}
2650
	public function setEncryption($value)
2651
	{
2652
		$this->_cryptAlgorithm = $value;
2653
	}
2654
	public function getCryptAlgorithm()
2655
	{
2656
		return $this->_cryptAlgorithm;
2657
	}
2658
	public function setCryptAlgorithm($value)
2659
	{
2660
		$this->_cryptAlgorithm = $value;
2661
	}
2662
	public function encrypt($data)
2663
	{
2664
		$module=$this->openCryptModule();
2665
		$key = $this->substr(md5($this->getEncryptionKey()), 0, mcrypt_enc_get_key_size($module));
2666
		srand();
2667
		$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($module), MCRYPT_RAND);
2668
		mcrypt_generic_init($module, $key, $iv);
2669
		$encrypted = $iv.mcrypt_generic($module, $data);
2670
		mcrypt_generic_deinit($module);
2671
		mcrypt_module_close($module);
2672
		return $encrypted;
2673
	}
2674
	public function decrypt($data)
2675
	{
2676
		$module=$this->openCryptModule();
2677
		$key = $this->substr(md5($this->getEncryptionKey()), 0, mcrypt_enc_get_key_size($module));
2678
		$ivSize = mcrypt_enc_get_iv_size($module);
2679
		$iv = $this->substr($data, 0, $ivSize);
2680
		mcrypt_generic_init($module, $key, $iv);
2681
		$decrypted = mdecrypt_generic($module, $this->substr($data, $ivSize, $this->strlen($data)));
2682
		mcrypt_generic_deinit($module);
2683
		mcrypt_module_close($module);
2684
		return $decrypted;
2685
	}
2686
	protected function openCryptModule()
2687
	{
2688
		if(extension_loaded('mcrypt'))
2689
		{
2690
			if(is_array($this->_cryptAlgorithm))
2691
				$module=@call_user_func_array('mcrypt_module_open',$this->_cryptAlgorithm);
2692
			else
2693
				$module=@mcrypt_module_open($this->_cryptAlgorithm,'', MCRYPT_MODE_CBC,'');
2694
			if($module===false)
2695
				throw new TNotSupportedException('securitymanager_mcryptextension_initfailed');
2696
			return $module;
2697
		}
2698
		else
2699
			throw new TNotSupportedException('securitymanager_mcryptextension_required');
2700
	}
2701
	public function hashData($data)
2702
	{
2703
		$hmac = $this->computeHMAC($data);
2704
		return $hmac.$data;
2705
	}
2706
	public function validateData($data)
2707
	{
2708
		$len=$this->strlen($this->computeHMAC('test'));
2709
		if($this->strlen($data) < $len)
2710
			return false;
2711
		$hmac = $this->substr($data, 0, $len);
2712
		$data2=$this->substr($data, $len, $this->strlen($data));
2713
		return $hmac === $this->computeHMAC($data2) ? $data2 : false;
2714
	}
2715
	protected function computeHMAC($data)
2716
	{
2717
		$key = $this->getValidationKey();
2718
		if(function_exists('hash_hmac'))
2719
			return hash_hmac($this->_hashAlgorithm, $data, $key);
2720
		if(!strcasecmp($this->_hashAlgorithm,'sha1'))
2721
		{
2722
			$pack = 'H40';
2723
			$func = 'sha1';
2724
		} else {
2725
			$pack = 'H32';
2726
			$func = 'md5';
2727
		}
2728
		$key = str_pad($func($key), 64, chr(0));
2729
		return $func((str_repeat(chr(0x5C), 64) ^ substr($key, 0, 64)) . pack($pack, $func((str_repeat(chr(0x36), 64) ^ substr($key, 0, 64)) . $data)));
2730
	}
2731
	private function strlen($string)
2732
	{
2733
		return $this->_mbstring ? mb_strlen($string,'8bit') : strlen($string);
2734
	}
2735
	private function substr($string,$start,$length)
2736
	{
2737
		return $this->_mbstring ? mb_substr($string,$start,$length,'8bit') : substr($string,$start,$length);
2738
	}
2739
}
2740
class TSecurityManagerValidationMode extends TEnumerable
2741
{
2742
	const MD5 = 'MD5';
2743
	const SHA1 = 'SHA1';
2744
}
2745
class THttpUtility
2746
{
2747
	private static $_encodeTable=array('<'=>'&lt;','>'=>'&gt;','"'=>'&quot;');
2748
	private static $_decodeTable=array('&lt;'=>'<','&gt;'=>'>','&quot;'=>'"');
2749
	private static $_stripTable=array('&lt;'=>'','&gt;'=>'','&quot;'=>'');
2750
	public static function htmlEncode($s)
2751
	{
2752
		return strtr($s,self::$_encodeTable);
2753
	}
2754
	public static function htmlDecode($s)
2755
	{
2756
		return strtr($s,self::$_decodeTable);
2757
	}
2758
	public static function htmlStrip($s)
2759
	{
2760
		return strtr($s,self::$_stripTable);
2761
	}
2762
}
2763
class TJavaScript
2764
{
2765
	public static function renderScriptFiles($files)
2766
	{
2767
		$str='';
2768
		foreach($files as $file)
2769
			$str.= self::renderScriptFile($file);
2770
		return $str;
2771
	}
2772
	public static function renderScriptFile($file)
2773
	{
2774
		return '<script type="text/javascript" src="'.THttpUtility::htmlEncode($file)."\"></script>\n";
2775
	}
2776
	public static function renderScriptBlocks($scripts)
2777
	{
2778
		if(count($scripts))
2779
			return "<script type=\"text/javascript\">\n/*<![CDATA[*/\n".implode("\n",$scripts)."\n/*]]>*/\n</script>\n";
2780
		else
2781
			return '';
2782
	}
2783
	public static function renderScriptBlocksCallback($scripts)
2784
	{
2785
		if(count($scripts))
2786
			return implode("\n",$scripts)."\n";
2787
		else
2788
			return '';
2789
	}
2790
	public static function renderScriptBlock($script)
2791
	{
2792
		return "<script type=\"text/javascript\">\n/*<![CDATA[*/\n{$script}\n/*]]>*/\n</script>\n";
2793
	}
2794
	public static function quoteString($js)
2795
	{
2796
		return self::jsonEncode($js,JSON_HEX_QUOT | JSON_HEX_APOS | JSON_HEX_TAG);
2797
	}
2798
	public static function quoteJsLiteral($js)
2799
	{
2800
		if($js instanceof TJavaScriptLiteral)
2801
			return $js;
2802
		else
2803
			return new TJavaScriptLiteral($js);
2804
	}
2805
	public static function quoteFunction($js)
2806
	{
2807
		return self::quoteJsLiteral($js);
2808
	}
2809
	public static function isJsLiteral($js)
2810
	{
2811
		return ($js instanceof TJavaScriptLiteral);
2812
	}
2813
	public static function isFunction($js)
2814
	{
2815
		return self::isJsLiteral($js);
2816
	}
2817
	public static function encode($value,$toMap=true,$encodeEmptyStrings=false)
2818
	{
2819
		if(is_string($value))
2820
			return self::quoteString($value);
2821
		else if(is_bool($value))
2822
			return $value?'true':'false';
2823
		else if(is_array($value))
2824
		{
2825
			$results='';
2826
			if(($n=count($value))>0 && array_keys($value)!==range(0,$n-1))
2827
			{
2828
				foreach($value as $k=>$v)
2829
				{
2830
					if($v!=='' || $encodeEmptyStrings)
2831
					{
2832
						if($results!=='')
2833
							$results.=',';
2834
						$results.="'$k':".self::encode($v,$toMap,$encodeEmptyStrings);
2835
					}
2836
				}
2837
				return '{'.$results.'}';
2838
			}
2839
			else
2840
			{
2841
				foreach($value as $v)
2842
				{
2843
					if($v!=='' || $encodeEmptyStrings)
2844
					{
2845
						if($results!=='')
2846
							$results.=',';
2847
						$results.=self::encode($v,$toMap, $encodeEmptyStrings);
2848
					}
2849
				}
2850
				return '['.$results.']';
2851
			}
2852
		}
2853
		else if(is_integer($value))
2854
			return "$value";
2855
		else if(is_float($value))
2856
		{
2857
			switch($value)
2858
			{
2859
				case -INF:
2860
					return 'Number.NEGATIVE_INFINITY';
2861
					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...
2862
				case INF:
2863
					return 'Number.POSITIVE_INFINITY';
2864
					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...
2865
				default:
2866
					$locale=localeConv();
2867
					if($locale['decimal_point']=='.')
2868
						return "$value";
2869
					else
2870
						return str_replace($locale['decimal_point'], '.', "$value");
2871
					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...
2872
			}
2873
		}
2874
		else if(is_object($value))
2875
			if ($value instanceof TJavaScriptLiteral)
2876
				return $value->toJavaScriptLiteral();
2877
			else
2878
				return self::encode(get_object_vars($value),$toMap);
2879
		else if($value===null)
2880
			return 'null';
2881
		else
2882
			return '';
2883
	}
2884
	public static function jsonEncode($value, $options = 0)
2885
	{
2886
		if (($g=Prado::getApplication()->getGlobalization(false))!==null &&
2887
			strtoupper($enc=$g->getCharset())!='UTF-8') {
2888
			self::convertToUtf8($value, $enc);
2889
		}
2890
		$s = @json_encode($value,$options);
2891
		self::checkJsonError();
2892
		return $s;
2893
	}
2894
	private static function convertToUtf8(&$value, $sourceEncoding) {
2895
		if(is_string($value))
2896
			$value=iconv($sourceEncoding, 'UTF-8', $value);
2897
		else if (is_array($value))
2898
		{
2899
			foreach($value as &$element)
2900
				self::convertToUtf8($element, $sourceEncoding);
2901
		}
2902
	}
2903
	public static function jsonDecode($value, $assoc = false, $depth = 512)
2904
	{
2905
		$s= @json_decode($value, $assoc, $depth);
2906
		self::checkJsonError();
2907
		return $s;
2908
	}
2909
	private static function checkJsonError()
2910
	{
2911
		switch ($err = json_last_error())
2912
		{
2913
			case JSON_ERROR_NONE:
2914
				return;
2915
				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...
2916
			case JSON_ERROR_DEPTH:
2917
				$msg = 'Maximum stack depth exceeded';
2918
				break;
2919
			case JSON_ERROR_STATE_MISMATCH:
2920
				$msg = 'Underflow or the modes mismatch';
2921
				break;
2922
			case JSON_ERROR_CTRL_CHAR:
2923
				$msg = 'Unexpected control character found';
2924
				break;
2925
			case JSON_ERROR_SYNTAX:
2926
				$msg = 'Syntax error, malformed JSON';
2927
				break;
2928
			case JSON_ERROR_UTF8:
2929
				$msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
2930
				break;
2931
			default:
2932
				$msg = 'Unknown error';
2933
				break;
2934
		}
2935
		throw new Exception("JSON error ($err): $msg");
2936
	}
2937
	public static function JSMin($code)
2938
	{
2939
		Prado::using('System.Web.Javascripts.JSMin');
2940
		return JSMin::minify($code);
2941
	}
2942
}
2943
class TUrlManager extends TModule
2944
{
2945
	public function constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems)
2946
	{
2947
		$url=$serviceID.'='.urlencode($serviceParam);
2948
		$amp=$encodeAmpersand?'&amp;':'&';
2949
		$request=$this->getRequest();
2950
		if(is_array($getItems) || $getItems instanceof Traversable)
2951
		{
2952
			if($encodeGetItems)
2953
			{
2954
				foreach($getItems as $name=>$value)
2955
				{
2956
					if(is_array($value))
2957
					{
2958
						$name=urlencode($name.'[]');
2959
						foreach($value as $v)
2960
							$url.=$amp.$name.'='.urlencode($v);
2961
					}
2962
					else
2963
						$url.=$amp.urlencode($name).'='.urlencode($value);
2964
				}
2965
			}
2966
			else
2967
			{
2968
				foreach($getItems as $name=>$value)
2969
				{
2970
					if(is_array($value))
2971
					{
2972
						foreach($value as $v)
2973
							$url.=$amp.$name.'[]='.$v;
2974
					}
2975
					else
2976
						$url.=$amp.$name.'='.$value;
2977
				}
2978
			}
2979
		}
2980
		switch($request->getUrlFormat())
2981
		{
2982
			case THttpRequestUrlFormat::Path:
2983
				return $request->getApplicationUrl().'/'.strtr($url,array($amp=>'/','?'=>'/','='=>$request->getUrlParamSeparator()));
2984
			case THttpRequestUrlFormat::HiddenPath:
2985
				return rtrim(dirname($request->getApplicationUrl()), '/').'/'.strtr($url,array($amp=>'/','?'=>'/','='=>$request->getUrlParamSeparator()));
2986
			default:
2987
				return $request->getApplicationUrl().'?'.$url;
2988
		}
2989
	}
2990
	public function parseUrl()
2991
	{
2992
		$request=$this->getRequest();
2993
		$pathInfo=trim($request->getPathInfo(),'/');
2994
		if(($request->getUrlFormat()===THttpRequestUrlFormat::Path ||
2995
			$request->getUrlFormat()===THttpRequestUrlFormat::HiddenPath) &&
2996
			$pathInfo!=='')
2997
		{
2998
			$separator=$request->getUrlParamSeparator();
2999
			$paths=explode('/',$pathInfo);
3000
			$getVariables=array();
3001
			foreach($paths as $path)
3002
			{
3003
				if(($path=trim($path))!=='')
3004
				{
3005
					if(($pos=strpos($path,$separator))!==false)
3006
					{
3007
						$name=substr($path,0,$pos);
3008
						$value=substr($path,$pos+1);
3009
						if(($pos=strpos($name,'[]'))!==false)
3010
							$getVariables[substr($name,0,$pos)][]=$value;
3011
						else
3012
							$getVariables[$name]=$value;
3013
					}
3014
					else
3015
						$getVariables[$path]='';
3016
				}
3017
			}
3018
			return $getVariables;
3019
		}
3020
		else
3021
			return array();
3022
	}
3023
}
3024
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...
3025
{
3026
	const CGIFIX__PATH_INFO		= 1;
3027
	const CGIFIX__SCRIPT_NAME	= 2;
3028
	private $_urlManager=null;
3029
	private $_urlManagerID='';
3030
	private $_separator=',';
3031
	private $_serviceID=null;
3032
	private $_serviceParam=null;
3033
	private $_cookies=null;
3034
	private $_requestUri;
3035
	private $_pathInfo;
3036
	private $_cookieOnly=null;
3037
	private $_urlFormat=THttpRequestUrlFormat::Get;
3038
	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...
3039
	private $_requestResolved=false;
3040
	private $_enableCookieValidation=false;
3041
	private $_cgiFix=0;
3042
	private $_enableCache=false;
3043
	private $_url=null;
3044
	private $_id;
3045
	private $_items=array();
3046
	public function getID()
3047
	{
3048
		return $this->_id;
3049
	}
3050
	public function setID($value)
3051
	{
3052
		$this->_id=$value;
3053
	}
3054
	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...
3055
	{
3056
				if(php_sapi_name()==='cli')
3057
		{
3058
			$_SERVER['REMOTE_ADDR']='127.0.0.1';
3059
			$_SERVER['REQUEST_METHOD']='GET';
3060
			$_SERVER['SERVER_NAME']='localhost';
3061
			$_SERVER['SERVER_PORT']=80;
3062
			$_SERVER['HTTP_USER_AGENT']='';
3063
		}
3064
														if(isset($_SERVER['REQUEST_URI']))
3065
			$this->_requestUri=$_SERVER['REQUEST_URI'];
3066
		else  			$this->_requestUri=$_SERVER['SCRIPT_NAME'].(empty($_SERVER['QUERY_STRING'])?'':'?'.$_SERVER['QUERY_STRING']);
3067
		if($this->_cgiFix&self::CGIFIX__PATH_INFO && isset($_SERVER['ORIG_PATH_INFO']))
3068
			$this->_pathInfo=substr($_SERVER['ORIG_PATH_INFO'], strlen($_SERVER['SCRIPT_NAME']));
3069
		elseif(isset($_SERVER['PATH_INFO']))
3070
			$this->_pathInfo=$_SERVER['PATH_INFO'];
3071
		else if(strpos($_SERVER['PHP_SELF'],$_SERVER['SCRIPT_NAME'])===0 && $_SERVER['PHP_SELF']!==$_SERVER['SCRIPT_NAME'])
3072
			$this->_pathInfo=substr($_SERVER['PHP_SELF'],strlen($_SERVER['SCRIPT_NAME']));
3073
		else
3074
			$this->_pathInfo='';
3075
		if(get_magic_quotes_gpc())
3076
		{
3077
			if(isset($_GET))
3078
				$_GET=$this->stripSlashes($_GET);
3079
			if(isset($_POST))
3080
				$_POST=$this->stripSlashes($_POST);
3081
			if(isset($_REQUEST))
3082
				$_REQUEST=$this->stripSlashes($_REQUEST);
3083
			if(isset($_COOKIE))
3084
				$_COOKIE=$this->stripSlashes($_COOKIE);
3085
		}
3086
		$this->getApplication()->setRequest($this);
3087
	}
3088
	public function stripSlashes(&$data)
3089
	{
3090
		return is_array($data)?array_map(array($this,'stripSlashes'),$data):stripslashes($data);
3091
	}
3092
	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...
3093
	{
3094
		if($this->_url===null)
3095
		{
3096
			$secure=$this->getIsSecureConnection();
3097
			$url=$secure?'https://':'http://';
3098
			if(empty($_SERVER['HTTP_HOST']))
3099
			{
3100
				$url.=$_SERVER['SERVER_NAME'];
3101
				$port=$_SERVER['SERVER_PORT'];
3102
				if(($port!=80 && !$secure) || ($port!=443 && $secure))
3103
					$url.=':'.$port;
3104
			}
3105
			else
3106
				$url.=$_SERVER['HTTP_HOST'];
3107
			$url.=$this->getRequestUri();
3108
			$this->_url=new TUri($url);
3109
		}
3110
		return $this->_url;
3111
	}
3112
	public function setEnableCache($value)
3113
	{
3114
		$this->_enableCache = TPropertyValue::ensureBoolean($value);
3115
	}
3116
	public function getEnableCache()
3117
	{
3118
		return $this->_enableCache;
3119
	}
3120
	protected function getCacheKey()
3121
	{
3122
		return $this->getID();
3123
	}
3124
	protected function cacheUrlManager($manager)
3125
	{
3126
		if($this->getEnableCache())
3127
		{
3128
			$cache = $this->getApplication()->getCache();
3129
			if($cache !== null)
3130
			{
3131
				$dependencies = null;
3132
				if($this->getApplication()->getMode() !== TApplicationMode::Performance)
3133
					if ($manager instanceof TUrlMapping && $fn = $manager->getConfigFile())
3134
					{
3135
						$fn = Prado::getPathOfNamespace($fn,$this->getApplication()->getConfigurationFileExt());
3136
						$dependencies = new TFileCacheDependency($fn);
3137
					}
3138
				return $cache->set($this->getCacheKey(), $manager, 0, $dependencies);
3139
			}
3140
		}
3141
		return false;
3142
	}
3143
	protected function loadCachedUrlManager()
3144
	{
3145
		if($this->getEnableCache())
3146
		{
3147
			$cache = $this->getApplication()->getCache();
3148
			if($cache !== null)
3149
			{
3150
				$manager = $cache->get($this->getCacheKey());
3151
				if($manager instanceof TUrlManager)
3152
					return $manager;
3153
			}
3154
		}
3155
		return null;
3156
	}
3157
	public function getUrlManager()
3158
	{
3159
		return $this->_urlManagerID;
3160
	}
3161
	public function setUrlManager($value)
3162
	{
3163
		$this->_urlManagerID=$value;
3164
	}
3165
	public function getUrlManagerModule()
3166
	{
3167
		if($this->_urlManager===null)
3168
		{
3169
			if(($this->_urlManager = $this->loadCachedUrlManager())===null)
3170
			{
3171
				if(empty($this->_urlManagerID))
3172
				{
3173
					$this->_urlManager=new TUrlManager;
3174
					$this->_urlManager->init(null);
3175
				}
3176
				else
3177
				{
3178
					$this->_urlManager=$this->getApplication()->getModule($this->_urlManagerID);
3179
					if($this->_urlManager===null)
3180
						throw new TConfigurationException('httprequest_urlmanager_inexist',$this->_urlManagerID);
3181
					if(!($this->_urlManager instanceof TUrlManager))
3182
						throw new TConfigurationException('httprequest_urlmanager_invalid',$this->_urlManagerID);
3183
				}
3184
				$this->cacheUrlManager($this->_urlManager);
3185
			}
3186
		}
3187
		return $this->_urlManager;
3188
	}
3189
	public function getUrlFormat()
3190
	{
3191
		return $this->_urlFormat;
3192
	}
3193
	public function setUrlFormat($value)
3194
	{
3195
		$this->_urlFormat=TPropertyValue::ensureEnum($value,'THttpRequestUrlFormat');
3196
	}
3197
	public function getUrlParamSeparator()
3198
	{
3199
		return $this->_separator;
3200
	}
3201
	public function setUrlParamSeparator($value)
3202
	{
3203
		if(strlen($value)===1)
3204
			$this->_separator=$value;
3205
		else
3206
			throw new TInvalidDataValueException('httprequest_separator_invalid');
3207
	}
3208
	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...
3209
	{
3210
		return isset($_SERVER['REQUEST_METHOD'])?$_SERVER['REQUEST_METHOD']:null;
3211
	}
3212
	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...
3213
	{
3214
		if(!isset($_SERVER['CONTENT_TYPE']))
3215
			return null;
3216
		if($mimetypeOnly === true && ($_pos = strpos(';', $_SERVER['CONTENT_TYPE'])) !== false)
3217
			return substr($_SERVER['CONTENT_TYPE'], 0, $_pos);
3218
		return $_SERVER['CONTENT_TYPE'];
3219
	}
3220
	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...
3221
	{
3222
			return isset($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'],'off');
3223
	}
3224
	public function getPathInfo()
3225
	{
3226
		return $this->_pathInfo;
3227
	}
3228
	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...
3229
	{
3230
		return isset($_SERVER['QUERY_STRING'])?$_SERVER['QUERY_STRING']:null;
3231
	}
3232
	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...
3233
	{
3234
		return isset($_SERVER['SERVER_PROTOCOL'])?$_SERVER['SERVER_PROTOCOL']:null;
3235
	}
3236
	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...
3237
	{
3238
		static $result;
3239
		if($result === null && function_exists('apache_request_headers')) {
3240
			$result = apache_request_headers();
3241
		}
3242
		elseif($result === null) {
3243
			$result = array();
3244
			foreach($_SERVER as $key=>$value) {
3245
				if(strncasecmp($key, 'HTTP_', 5) !== 0) continue;
3246
					$key = str_replace(' ','-', ucwords(strtolower(str_replace('_',' ', substr($key, 5)))));
3247
					$result[$key] = $value;
3248
			}
3249
		}
3250
		if($case !== null)
3251
			return array_change_key_case($result, $case);
3252
		return $result;
3253
	}
3254
	public function getRequestUri()
3255
	{
3256
		return $this->_requestUri;
3257
	}
3258
	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...
3259
	{
3260
		$url=$this->getUrl();
3261
		$scheme=($forceSecureConnection)?"https": (($forceSecureConnection === null)?$url->getScheme():'http');
3262
		$host=$url->getHost();
3263
		if (($port=$url->getPort())) $host.=':'.$port;
3264
		return $scheme.'://'.$host;
3265
	}
3266
	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...
3267
	{
3268
		if($this->_cgiFix&self::CGIFIX__SCRIPT_NAME && isset($_SERVER['ORIG_SCRIPT_NAME']))
3269
			return $_SERVER['ORIG_SCRIPT_NAME'];
3270
		return isset($_SERVER['SCRIPT_NAME'])?$_SERVER['SCRIPT_NAME']:null;
3271
	}
3272
	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...
3273
	{
3274
		return $this->getBaseUrl($forceSecureConnection) . $this->getApplicationUrl();
3275
	}
3276
	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...
3277
	{
3278
		return realpath(isset($_SERVER['SCRIPT_FILENAME'])?$_SERVER['SCRIPT_FILENAME']:null);
3279
	}
3280
	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...
3281
	{
3282
		return isset($_SERVER['SERVER_NAME'])?$_SERVER['SERVER_NAME']:null;
3283
	}
3284
	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...
3285
	{
3286
		return isset($_SERVER['SERVER_PORT'])?$_SERVER['SERVER_PORT']:null;
3287
	}
3288
	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...
3289
	{
3290
		return isset($_SERVER['HTTP_REFERER'])?$_SERVER['HTTP_REFERER']:null;
3291
	}
3292
	public function getBrowser()
3293
	{
3294
		try
3295
		{
3296
			return get_browser();
3297
		}
3298
		catch(TPhpErrorException $e)
3299
		{
3300
			throw new TConfigurationException('httprequest_browscap_required');
3301
		}
3302
	}
3303
	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...
3304
	{
3305
		return isset($_SERVER['HTTP_USER_AGENT'])?$_SERVER['HTTP_USER_AGENT']:null;
3306
	}
3307
	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...
3308
	{
3309
		return isset($_SERVER['REMOTE_ADDR'])?$_SERVER['REMOTE_ADDR']:null;
3310
	}
3311
	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...
3312
	{
3313
		return isset($_SERVER['REMOTE_HOST'])?$_SERVER['REMOTE_HOST']:null;
3314
	}
3315
	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...
3316
	{
3317
				return isset($_SERVER['HTTP_ACCEPT'])?$_SERVER['HTTP_ACCEPT']:null;
3318
	}
3319
	public function getUserLanguages()
3320
	{
3321
		return Prado::getUserLanguages();
3322
	}
3323
	public function getEnableCookieValidation()
3324
	{
3325
		return $this->_enableCookieValidation;
3326
	}
3327
	public function setEnableCookieValidation($value)
3328
	{
3329
		$this->_enableCookieValidation=TPropertyValue::ensureBoolean($value);
3330
	}
3331
	public function getCgiFix()
3332
	{
3333
		return $this->_cgiFix;
3334
	}
3335
	public function setCgiFix($value)
3336
	{
3337
		$this->_cgiFix=TPropertyValue::ensureInteger($value);
3338
	}
3339
	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...
3340
	{
3341
		if($this->_cookies===null)
3342
		{
3343
			$this->_cookies=new THttpCookieCollection;
3344
			if($this->getEnableCookieValidation())
3345
			{
3346
				$sm=$this->getApplication()->getSecurityManager();
3347
				foreach($_COOKIE as $key=>$value)
3348
				{
3349
					if(($value=$sm->validateData($value))!==false)
3350
						$this->_cookies->add(new THttpCookie($key,$value));
3351
				}
3352
			}
3353
			else
3354
			{
3355
				foreach($_COOKIE as $key=>$value)
3356
					$this->_cookies->add(new THttpCookie($key,$value));
3357
			}
3358
		}
3359
		return $this->_cookies;
3360
	}
3361
	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...
3362
	{
3363
		return $_FILES;
3364
	}
3365
	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...
3366
	{
3367
		return $_SERVER;
3368
	}
3369
	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...
3370
	{
3371
		return $_ENV;
3372
	}
3373
	public function constructUrl($serviceID,$serviceParam,$getItems=null,$encodeAmpersand=true,$encodeGetItems=true)
3374
	{
3375
		if ($this->_cookieOnly===null)
3376
				$this->_cookieOnly=(int)ini_get('session.use_cookies') && (int)ini_get('session.use_only_cookies');
3377
		$url=$this->getUrlManagerModule()->constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems);
3378
		if(defined('SID') && SID != '' && !$this->_cookieOnly)
3379
			return $url . (strpos($url,'?')===false? '?' : ($encodeAmpersand?'&amp;':'&')) . SID;
3380
		else
3381
			return $url;
3382
	}
3383
	protected function parseUrl()
3384
	{
3385
		return $this->getUrlManagerModule()->parseUrl();
3386
	}
3387
	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...
3388
	{
3389
		$getParams=$this->parseUrl();
3390
		foreach($getParams as $name=>$value)
3391
			$_GET[$name]=$value;
3392
		$this->_items=array_merge($_GET,$_POST);
3393
		$this->_requestResolved=true;
3394
		foreach($serviceIDs as $serviceID)
3395
		{
3396
			if($this->contains($serviceID))
3397
			{
3398
				$this->setServiceID($serviceID);
3399
				$this->setServiceParameter($this->itemAt($serviceID));
3400
				return $serviceID;
3401
			}
3402
		}
3403
		return null;
3404
	}
3405
	public function getRequestResolved()
3406
	{
3407
		return $this->_requestResolved;
3408
	}
3409
	public function getServiceID()
3410
	{
3411
		return $this->_serviceID;
3412
	}
3413
	public function setServiceID($value)
3414
	{
3415
		$this->_serviceID=$value;
3416
	}
3417
	public function getServiceParameter()
3418
	{
3419
		return $this->_serviceParam;
3420
	}
3421
	public function setServiceParameter($value)
3422
	{
3423
		$this->_serviceParam=$value;
3424
	}
3425
	public function getIterator()
3426
	{
3427
		return new TMapIterator($this->_items);
0 ignored issues
show
Deprecated Code introduced by
The class TMapIterator has been deprecated with message: Issue 264 : ArrayIterator should be used instead

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
3428
	}
3429
	public function getCount()
3430
	{
3431
		return count($this->_items);
3432
	}
3433
	public function count()
3434
	{
3435
		return $this->getCount();
3436
	}
3437
	public function getKeys()
3438
	{
3439
		return array_keys($this->_items);
3440
	}
3441
	public function itemAt($key)
3442
	{
3443
		return isset($this->_items[$key]) ? $this->_items[$key] : null;
3444
	}
3445
	public function add($key,$value)
3446
	{
3447
		$this->_items[$key]=$value;
3448
	}
3449
	public function remove($key)
3450
	{
3451
		if(isset($this->_items[$key]) || array_key_exists($key,$this->_items))
3452
		{
3453
			$value=$this->_items[$key];
3454
			unset($this->_items[$key]);
3455
			return $value;
3456
		}
3457
		else
3458
			return null;
3459
	}
3460
	public function clear()
3461
	{
3462
		foreach(array_keys($this->_items) as $key)
3463
			$this->remove($key);
3464
	}
3465
	public function contains($key)
3466
	{
3467
		return isset($this->_items[$key]) || array_key_exists($key,$this->_items);
3468
	}
3469
	public function toArray()
3470
	{
3471
		return $this->_items;
3472
	}
3473
	public function offsetExists($offset)
3474
	{
3475
		return $this->contains($offset);
3476
	}
3477
	public function offsetGet($offset)
3478
	{
3479
		return $this->itemAt($offset);
3480
	}
3481
	public function offsetSet($offset,$item)
3482
	{
3483
		$this->add($offset,$item);
3484
	}
3485
	public function offsetUnset($offset)
3486
	{
3487
		$this->remove($offset);
3488
	}
3489
}
3490
class THttpCookieCollection extends TList
3491
{
3492
	private $_o;
3493
	public function __construct($owner=null)
3494
	{
3495
		$this->_o=$owner;
3496
	}
3497
	public function insertAt($index,$item)
3498
	{
3499
		if($item instanceof THttpCookie)
3500
		{
3501
			parent::insertAt($index,$item);
3502
			if($this->_o instanceof THttpResponse)
3503
				$this->_o->addCookie($item);
3504
		}
3505
		else
3506
			throw new TInvalidDataTypeException('httpcookiecollection_httpcookie_required');
3507
	}
3508
	public function removeAt($index)
3509
	{
3510
		$item=parent::removeAt($index);
3511
		if($this->_o instanceof THttpResponse)
3512
			$this->_o->removeCookie($item);
3513
		return $item;
3514
	}
3515
	public function itemAt($index)
3516
	{
3517
		if(is_integer($index))
3518
			return parent::itemAt($index);
3519
		else
3520
			return $this->findCookieByName($index);
3521
	}
3522
	public function findCookieByName($name)
3523
	{
3524
		foreach($this as $cookie)
3525
			if($cookie->getName()===$name)
3526
				return $cookie;
3527
		return null;
3528
	}
3529
}
3530
class THttpCookie extends TComponent
3531
{
3532
	private $_domain='';
3533
	private $_name;
3534
	private $_value='';
3535
	private $_expire=0;
3536
	private $_path='/';
3537
	private $_secure=false;
3538
	private $_httpOnly=false;
3539
	public function __construct($name,$value)
3540
	{
3541
		$this->_name=$name;
3542
		$this->_value=$value;
3543
	}
3544
	public function getDomain()
3545
	{
3546
		return $this->_domain;
3547
	}
3548
	public function setDomain($value)
3549
	{
3550
		$this->_domain=$value;
3551
	}
3552
	public function getExpire()
3553
	{
3554
		return $this->_expire;
3555
	}
3556
	public function setExpire($value)
3557
	{
3558
		$this->_expire=TPropertyValue::ensureInteger($value);
3559
	}
3560
	public function getHttpOnly()
3561
	{
3562
		return $this->_httpOnly;
3563
	}
3564
	public function setHttpOnly($value)
3565
	{
3566
		$this->_httpOnly = TPropertyValue::ensureBoolean($value);
3567
	}
3568
	public function getName()
3569
	{
3570
		return $this->_name;
3571
	}
3572
	public function setName($value)
3573
	{
3574
		$this->_name=$value;
3575
	}
3576
	public function getValue()
3577
	{
3578
		return $this->_value;
3579
	}
3580
	public function setValue($value)
3581
	{
3582
		$this->_value=$value;
3583
	}
3584
	public function getPath()
3585
	{
3586
		return $this->_path;
3587
	}
3588
	public function setPath($value)
3589
	{
3590
		$this->_path=$value;
3591
	}
3592
	public function getSecure()
3593
	{
3594
		return $this->_secure;
3595
	}
3596
	public function setSecure($value)
3597
	{
3598
		$this->_secure=TPropertyValue::ensureBoolean($value);
3599
	}
3600
}
3601
class TUri extends TComponent
3602
{
3603
	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...
3604
		'ftp'=>21,
3605
		'gopher'=>70,
3606
		'http'=>80,
3607
		'https'=>443,
3608
		'news'=>119,
3609
		'nntp'=>119,
3610
		'wais'=>210,
3611
		'telnet'=>23
3612
	);
3613
	private $_scheme;
3614
	private $_host;
3615
	private $_port;
3616
	private $_user;
3617
	private $_pass;
3618
	private $_path;
3619
	private $_query;
3620
	private $_fragment;
3621
	private $_uri;
3622
	public function __construct($uri)
3623
	{
3624
		if(($ret=@parse_url($uri))!==false)
3625
		{
3626
						$this->_scheme=isset($ret['scheme'])?$ret['scheme']:'';
3627
			$this->_host=isset($ret['host'])?$ret['host']:'';
3628
			$this->_port=isset($ret['port'])?$ret['port']:'';
3629
			$this->_user=isset($ret['user'])?$ret['user']:'';
3630
			$this->_pass=isset($ret['pass'])?$ret['pass']:'';
3631
			$this->_path=isset($ret['path'])?$ret['path']:'';
3632
			$this->_query=isset($ret['query'])?$ret['query']:'';
3633
			$this->_fragment=isset($ret['fragment'])?$ret['fragment']:'';
3634
			$this->_uri=$uri;
3635
		}
3636
		else
3637
		{
3638
			throw new TInvalidDataValueException('uri_format_invalid',$uri);
3639
		}
3640
	}
3641
	public function getUri()
3642
	{
3643
		return $this->_uri;
3644
	}
3645
	public function getScheme()
3646
	{
3647
		return $this->_scheme;
3648
	}
3649
	public function getHost()
3650
	{
3651
		return $this->_host;
3652
	}
3653
	public function getPort()
3654
	{
3655
		return $this->_port;
3656
	}
3657
	public function getUser()
3658
	{
3659
		return $this->_user;
3660
	}
3661
	public function getPassword()
3662
	{
3663
		return $this->_pass;
3664
	}
3665
	public function getPath()
3666
	{
3667
		return $this->_path;
3668
	}
3669
	public function getQuery()
3670
	{
3671
		return $this->_query;
3672
	}
3673
	public function getFragment()
3674
	{
3675
		return $this->_fragment;
3676
	}
3677
}
3678
class THttpRequestUrlFormat extends TEnumerable
3679
{
3680
	const Get='Get';
3681
	const Path='Path';
3682
	const HiddenPath='HiddenPath';
3683
}
3684
class THttpResponseAdapter extends TApplicationComponent
3685
{
3686
	private $_response;
3687
	public function __construct($response)
3688
	{
3689
		$this->_response=$response;
3690
	}
3691
	public function getResponse()
3692
	{
3693
		return $this->_response;
3694
	}
3695
	public function flushContent()
3696
	{
3697
		$this->_response->flushContent();
3698
	}
3699
	public function httpRedirect($url)
3700
	{
3701
		$this->_response->httpRedirect($url);
3702
	}
3703
	public function createNewHtmlWriter($type, $writer)
3704
	{
3705
		return $this->_response->createNewHtmlWriter($type,$writer);
3706
	}
3707
}
3708
class THttpResponse extends TModule implements ITextWriter
3709
{
3710
	const DEFAULT_CONTENTTYPE	= 'text/html';
3711
	const DEFAULT_CHARSET		= 'UTF-8';
3712
	private static $HTTP_STATUS_CODES = array(
3713
		100 => 'Continue', 101 => 'Switching Protocols',
3714
		200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content',
3715
		300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect',
3716
		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',
3717
		500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported'
3718
	);
3719
	private $_bufferOutput=true;
3720
	private $_initialized=false;
3721
	private $_cookies=null;
3722
	private $_status=200;
3723
	private $_reason='OK';
3724
	private $_htmlWriterType='System.Web.UI.THtmlWriter';
3725
	private $_contentType=null;
3726
	private $_charset='';
3727
	private $_adapter;
3728
	private $_httpHeaderSent;
3729
	private $_contentTypeHeaderSent;
3730
	public function __destruct()
3731
	{
3732
					}
3733
	public function setAdapter(THttpResponseAdapter $adapter)
3734
	{
3735
		$this->_adapter=$adapter;
3736
	}
3737
	public function getAdapter()
3738
	{
3739
		return $this->_adapter;
3740
	}
3741
	public function getHasAdapter()
3742
	{
3743
		return $this->_adapter!==null;
3744
	}
3745
	public function init($config)
3746
	{
3747
		if($this->_bufferOutput)
3748
			ob_start();
3749
		$this->_initialized=true;
3750
		$this->getApplication()->setResponse($this);
3751
	}
3752
	public function getCacheExpire()
3753
	{
3754
		return session_cache_expire();
3755
	}
3756
	public function setCacheExpire($value)
3757
	{
3758
		session_cache_expire(TPropertyValue::ensureInteger($value));
3759
	}
3760
	public function getCacheControl()
3761
	{
3762
		return session_cache_limiter();
3763
	}
3764
	public function setCacheControl($value)
3765
	{
3766
		session_cache_limiter(TPropertyValue::ensureEnum($value,array('none','nocache','private','private_no_expire','public')));
3767
	}
3768
	public function setContentType($type)
3769
	{
3770
		if ($this->_contentTypeHeaderSent)
3771
			throw new Exception('Unable to alter content-type as it has been already sent');
3772
		$this->_contentType = $type;
3773
	}
3774
	public function getContentType()
3775
	{
3776
		return $this->_contentType;
3777
	}
3778
	public function getCharset()
3779
	{
3780
		return $this->_charset;
3781
	}
3782
	public function setCharset($charset)
3783
	{
3784
		$this->_charset = (strToLower($charset) === 'false') ? false : (string)$charset;
3785
	}
3786
	public function getBufferOutput()
3787
	{
3788
		return $this->_bufferOutput;
3789
	}
3790
	public function setBufferOutput($value)
3791
	{
3792
		if($this->_initialized)
3793
			throw new TInvalidOperationException('httpresponse_bufferoutput_unchangeable');
3794
		else
3795
			$this->_bufferOutput=TPropertyValue::ensureBoolean($value);
3796
	}
3797
	public function getStatusCode()
3798
	{
3799
		return $this->_status;
3800
	}
3801
	public function setStatusCode($status, $reason=null)
3802
	{
3803
		if ($this->_httpHeaderSent)
3804
			throw new Exception('Unable to alter response as HTTP header already sent');
3805
		$status=TPropertyValue::ensureInteger($status);
3806
		if(isset(self::$HTTP_STATUS_CODES[$status])) {
3807
			$this->_reason=self::$HTTP_STATUS_CODES[$status];
3808
		}else{
3809
			if($reason===null || $reason==='') {
3810
				throw new TInvalidDataValueException("response_status_reason_missing");
3811
			}
3812
			$reason=TPropertyValue::ensureString($reason);
3813
			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...
3814
				throw new TInvalidDataValueException("response_status_reason_barchars");
3815
			}
3816
			$this->_reason=$reason;
3817
		}
3818
		$this->_status=$status;
3819
	}
3820
	public function getStatusReason() {
3821
		return $this->_reason;
3822
	}
3823
	public function getCookies()
3824
	{
3825
		if($this->_cookies===null)
3826
			$this->_cookies=new THttpCookieCollection($this);
3827
		return $this->_cookies;
3828
	}
3829
	public function write($str)
3830
	{
3831
				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...
3832
			$this->ensureHeadersSent();
3833
		echo $str;
3834
	}
3835
	public function writeFile($fileName,$content=null,$mimeType=null,$headers=null,$forceDownload=true,$clientFileName=null,$fileSize=null)
3836
	{
3837
		static $defaultMimeTypes=array(
3838
			'css'=>'text/css',
3839
			'gif'=>'image/gif',
3840
			'png'=>'image/png',
3841
			'jpg'=>'image/jpeg',
3842
			'jpeg'=>'image/jpeg',
3843
			'htm'=>'text/html',
3844
			'html'=>'text/html',
3845
			'js'=>'javascript/js',
3846
			'pdf'=>'application/pdf',
3847
			'xls'=>'application/vnd.ms-excel',
3848
		);
3849
		if($mimeType===null)
3850
		{
3851
			$mimeType='text/plain';
3852
			if(function_exists('mime_content_type'))
3853
				$mimeType=mime_content_type($fileName);
3854
			else if(($ext=strrchr($fileName,'.'))!==false)
3855
			{
3856
				$ext=substr($ext,1);
3857
				if(isset($defaultMimeTypes[$ext]))
3858
					$mimeType=$defaultMimeTypes[$ext];
3859
			}
3860
		}
3861
		if($clientFileName===null)
3862
			$clientFileName=basename($fileName);
3863
		else
3864
			$clientFileName=basename($clientFileName);
3865
		if($fileSize===null || $fileSize < 0)
3866
			$fileSize = ($content===null?filesize($fileName):strlen($content));
3867
		$this->sendHttpHeader();
3868
		if(is_array($headers))
3869
		{
3870
			foreach($headers as $h)
3871
				header($h);
3872
		}
3873
		else
3874
		{
3875
			header('Pragma: public');
3876
			header('Expires: 0');
3877
			header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
3878
			header("Content-Type: $mimeType");
3879
			$this->_contentTypeHeaderSent = true;
3880
		}
3881
		header('Content-Length: '.$fileSize);
3882
		header("Content-Disposition: " . ($forceDownload ? 'attachment' : 'inline') . "; filename=\"$clientFileName\"");
3883
		header('Content-Transfer-Encoding: binary');
3884
		if($content===null)
3885
			readfile($fileName);
3886
		else
3887
			echo $content;
3888
	}
3889
	public function redirect($url)
3890
	{
3891
		if($this->getHasAdapter())
3892
			$this->_adapter->httpRedirect($url);
3893
		else
3894
			$this->httpRedirect($url);
3895
	}
3896
	public function httpRedirect($url)
3897
	{
3898
		$this->ensureHeadersSent();
3899
		if($url[0]==='/')
3900
			$url=$this->getRequest()->getBaseUrl().$url;
3901
		if ($this->_status >= 300 && $this->_status < 400)
3902
						header('Location: '.str_replace('&amp;','&',$url), true, $this->_status);
3903
		else
3904
			header('Location: '.str_replace('&amp;','&',$url));
3905
		if(!$this->getApplication()->getRequestCompleted())
3906
			$this->getApplication()->onEndRequest();
3907
		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...
3908
	}
3909
	public function reload()
3910
	{
3911
		$this->redirect($this->getRequest()->getRequestUri());
3912
	}
3913
	public function flush($continueBuffering = true)
3914
	{
3915
		if($this->getHasAdapter())
3916
			$this->_adapter->flushContent($continueBuffering);
3917
		else
3918
			$this->flushContent($continueBuffering);
3919
	}
3920
	public function ensureHeadersSent()
3921
	{
3922
		$this->ensureHttpHeaderSent();
3923
		$this->ensureContentTypeHeaderSent();
3924
	}
3925
	public function flushContent($continueBuffering = true)
3926
	{
3927
		$this->ensureHeadersSent();
3928
		if($this->_bufferOutput)
3929
		{
3930
						if (ob_get_length()>0)
3931
			{
3932
				if (!$continueBuffering)
3933
				{
3934
					$this->_bufferOutput = false;
3935
					ob_end_flush();
3936
				}
3937
				else
3938
					ob_flush();
3939
				flush();
3940
			}
3941
		}
3942
		else
3943
			flush();
3944
	}
3945
	protected function ensureHttpHeaderSent()
3946
	{
3947
		if (!$this->_httpHeaderSent)
3948
			$this->sendHttpHeader();
3949
	}
3950
	protected function sendHttpHeader()
3951
	{
3952
		$protocol=$this->getRequest()->getHttpProtocolVersion();
3953
		if($this->getRequest()->getHttpProtocolVersion() === null)
3954
			$protocol='HTTP/1.1';
3955
		$phpSapiName = substr(php_sapi_name(), 0, 3);
3956
		$cgi = $phpSapiName == 'cgi' || $phpSapiName == 'fpm';
3957
		header(($cgi ? 'Status:' : $protocol).' '.$this->_status.' '.$this->_reason, true, TPropertyValue::ensureInteger($this->_status));
3958
		$this->_httpHeaderSent = true;
3959
	}
3960
	protected function ensureContentTypeHeaderSent()
3961
	{
3962
		if (!$this->_contentTypeHeaderSent)
3963
			$this->sendContentTypeHeader();
3964
	}
3965
	protected function sendContentTypeHeader()
3966
	{
3967
		$contentType=$this->_contentType===null?self::DEFAULT_CONTENTTYPE:$this->_contentType;
3968
		$charset=$this->getCharset();
3969
		if($charset === false) {
3970
			$this->appendHeader('Content-Type: '.$contentType);
3971
			return;
3972
		}
3973
		if($charset==='' && ($globalization=$this->getApplication()->getGlobalization(false))!==null)
3974
			$charset=$globalization->getCharset();
3975
		if($charset==='') $charset = self::DEFAULT_CHARSET;
3976
		$this->appendHeader('Content-Type: '.$contentType.';charset='.$charset);
3977
		$this->_contentTypeHeaderSent = true;
3978
	}
3979
	public function getContents()
3980
	{
3981
		return $this->_bufferOutput?ob_get_contents():'';
3982
	}
3983
	public function clear()
3984
	{
3985
		if($this->_bufferOutput)
3986
			ob_clean();
3987
	}
3988
	public function getHeaders($case=null)
3989
	{
3990
		$result = array();
3991
		$headers = headers_list();
3992
		foreach($headers as $header) {
3993
			$tmp = explode(':', $header);
3994
			$key = trim(array_shift($tmp));
3995
			$value = trim(implode(':', $tmp));
3996
			if(isset($result[$key]))
3997
				$result[$key] .= ', ' . $value;
3998
			else
3999
				$result[$key] = $value;
4000
		}
4001
		if($case !== null)
4002
			return array_change_key_case($result, $case);
4003
		return $result;
4004
	}
4005
	public function appendHeader($value, $replace=true)
4006
	{
4007
		header($value, $replace);
4008
	}
4009
	public function appendLog($message,$messageType=0,$destination='',$extraHeaders='')
4010
	{
4011
		error_log($message,$messageType,$destination,$extraHeaders);
4012
	}
4013
	public function addCookie($cookie)
4014
	{
4015
		$request=$this->getRequest();
4016
		if($request->getEnableCookieValidation())
4017
		{
4018
			$value=$this->getApplication()->getSecurityManager()->hashData($cookie->getValue());
4019
			setcookie(
4020
				$cookie->getName(),
4021
				$value,
4022
				$cookie->getExpire(),
4023
				$cookie->getPath(),
4024
				$cookie->getDomain(),
4025
				$cookie->getSecure(),
4026
				$cookie->getHttpOnly()
4027
			);
4028
		}
4029
		else {
4030
			setcookie(
4031
				$cookie->getName(),
4032
				$cookie->getValue(),
4033
				$cookie->getExpire(),
4034
				$cookie->getPath(),
4035
				$cookie->getDomain(),
4036
				$cookie->getSecure(),
4037
				$cookie->getHttpOnly()
4038
			);
4039
		}
4040
	}
4041
	public function removeCookie($cookie)
4042
	{
4043
		setcookie(
4044
			$cookie->getName(),
4045
			null,
4046
			0,
4047
			$cookie->getPath(),
4048
			$cookie->getDomain(),
4049
			$cookie->getSecure(),
4050
			$cookie->getHttpOnly()
4051
		);
4052
	}
4053
	public function getHtmlWriterType()
4054
	{
4055
		return $this->_htmlWriterType;
4056
	}
4057
	public function setHtmlWriterType($value)
4058
	{
4059
		$this->_htmlWriterType=$value;
4060
	}
4061
	public function createHtmlWriter($type=null)
4062
	{
4063
		if($type===null)
4064
			$type=$this->getHtmlWriterType();
4065
		if($this->getHasAdapter())
4066
			return $this->_adapter->createNewHtmlWriter($type, $this);
4067
		else
4068
			return $this->createNewHtmlWriter($type, $this);
4069
	}
4070
	public function createNewHtmlWriter($type, $writer)
4071
	{
4072
		return Prado::createComponent($type, $writer);
4073
	}
4074
}
4075
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...
4076
{
4077
	private $_initialized=false;
4078
	private $_started=false;
4079
	private $_autoStart=false;
4080
	private $_cookie=null;
4081
	private $_id;
4082
	private $_customStorage=false;
4083
	public function getID()
4084
	{
4085
		return $this->_id;
4086
	}
4087
	public function setID($value)
4088
	{
4089
		$this->_id=$value;
4090
	}
4091
	public function init($config)
4092
	{
4093
		if($this->_autoStart)
4094
			$this->open();
4095
		$this->_initialized=true;
4096
		$this->getApplication()->setSession($this);
4097
		register_shutdown_function(array($this, "close"));
4098
	}
4099
	public function open()
4100
	{
4101
		if(!$this->_started)
4102
		{
4103
			if($this->_customStorage)
4104
				session_set_save_handler(array($this,'_open'),array($this,'_close'),array($this,'_read'),array($this,'_write'),array($this,'_destroy'),array($this,'_gc'));
4105
			if($this->_cookie!==null)
4106
				session_set_cookie_params($this->_cookie->getExpire(),$this->_cookie->getPath(),$this->_cookie->getDomain(),$this->_cookie->getSecure(),$this->_cookie->getHttpOnly());
4107
			if(ini_get('session.auto_start')!=='1')
4108
				session_start();
4109
			$this->_started=true;
4110
		}
4111
	}
4112
	public function close()
4113
	{
4114
		if($this->_started)
4115
		{
4116
			session_write_close();
4117
			$this->_started=false;
4118
		}
4119
	}
4120
	public function destroy()
4121
	{
4122
		if($this->_started)
4123
		{
4124
			session_destroy();
4125
			$this->_started=false;
4126
		}
4127
	}
4128
	public function regenerate($deleteOld=false)
4129
	{
4130
		$old = $this->getSessionID();
4131
		session_regenerate_id($deleteOld);
4132
		return $old;
4133
	}
4134
	public function getIsStarted()
4135
	{
4136
		return $this->_started;
4137
	}
4138
	public function getSessionID()
4139
	{
4140
		return session_id();
4141
	}
4142
	public function setSessionID($value)
4143
	{
4144
		if($this->_started)
4145
			throw new TInvalidOperationException('httpsession_sessionid_unchangeable');
4146
		else
4147
			session_id($value);
4148
	}
4149
	public function getSessionName()
4150
	{
4151
		return session_name();
4152
	}
4153
	public function setSessionName($value)
4154
	{
4155
		if($this->_started)
4156
			throw new TInvalidOperationException('httpsession_sessionname_unchangeable');
4157
		else if(ctype_alnum($value))
4158
			session_name($value);
4159
		else
4160
			throw new TInvalidDataValueException('httpsession_sessionname_invalid',$value);
4161
	}
4162
	public function getSavePath()
4163
	{
4164
		return session_save_path();
4165
	}
4166
	public function setSavePath($value)
4167
	{
4168
		if($this->_started)
4169
			throw new TInvalidOperationException('httpsession_savepath_unchangeable');
4170
		else if(is_dir($value))
4171
			session_save_path($value);
4172
		else
4173
			throw new TInvalidDataValueException('httpsession_savepath_invalid',$value);
4174
	}
4175
	public function getUseCustomStorage()
4176
	{
4177
		return $this->_customStorage;
4178
	}
4179
	public function setUseCustomStorage($value)
4180
	{
4181
		$this->_customStorage=TPropertyValue::ensureBoolean($value);
4182
	}
4183
	public function getCookie()
4184
	{
4185
		if($this->_cookie===null)
4186
			$this->_cookie=new THttpCookie($this->getSessionName(),$this->getSessionID());
4187
		return $this->_cookie;
4188
	}
4189
	public function getCookieMode()
4190
	{
4191
		if(ini_get('session.use_cookies')==='0')
4192
			return THttpSessionCookieMode::None;
4193
		else if(ini_get('session.use_only_cookies')==='0')
4194
			return THttpSessionCookieMode::Allow;
4195
		else
4196
			return THttpSessionCookieMode::Only;
4197
	}
4198
	public function setCookieMode($value)
4199
	{
4200
		if($this->_started)
4201
			throw new TInvalidOperationException('httpsession_cookiemode_unchangeable');
4202
		else
4203
		{
4204
			$value=TPropertyValue::ensureEnum($value,'THttpSessionCookieMode');
4205
			if($value===THttpSessionCookieMode::None) 
4206
      {
4207
				ini_set('session.use_cookies','0');
4208
			  ini_set('session.use_only_cookies','0');
4209
      }
4210
			else if($value===THttpSessionCookieMode::Allow)
4211
			{
4212
				ini_set('session.use_cookies','1');
4213
				ini_set('session.use_only_cookies','0');
4214
			}
4215
			else
4216
			{
4217
				ini_set('session.use_cookies','1');
4218
				ini_set('session.use_only_cookies','1');
4219
				ini_set('session.use_trans_sid', 0);
4220
			}
4221
		}
4222
	}
4223
	public function getAutoStart()
4224
	{
4225
		return $this->_autoStart;
4226
	}
4227
	public function setAutoStart($value)
4228
	{
4229
		if($this->_initialized)
4230
			throw new TInvalidOperationException('httpsession_autostart_unchangeable');
4231
		else
4232
			$this->_autoStart=TPropertyValue::ensureBoolean($value);
4233
	}
4234
	public function getGCProbability()
4235
	{
4236
		return TPropertyValue::ensureInteger(ini_get('session.gc_probability'));
4237
	}
4238
	public function setGCProbability($value)
4239
	{
4240
		if($this->_started)
4241
			throw new TInvalidOperationException('httpsession_gcprobability_unchangeable');
4242
		else
4243
		{
4244
			$value=TPropertyValue::ensureInteger($value);
4245
			if($value>=0 && $value<=100)
4246
			{
4247
				ini_set('session.gc_probability',$value);
4248
				ini_set('session.gc_divisor','100');
4249
			}
4250
			else
4251
				throw new TInvalidDataValueException('httpsession_gcprobability_invalid',$value);
4252
		}
4253
	}
4254
	public function getUseTransparentSessionID()
4255
	{
4256
		return ini_get('session.use_trans_sid')==='1';
4257
	}
4258
	public function setUseTransparentSessionID($value)
4259
	{
4260
		if($this->_started)
4261
			throw new TInvalidOperationException('httpsession_transid_unchangeable');
4262
		else
4263
		{
4264
			$value=TPropertyValue::ensureBoolean($value);
4265
			if ($value && $this->getCookieMode()==THttpSessionCookieMode::Only)
4266
					throw new TInvalidOperationException('httpsession_transid_cookieonly');
4267
			ini_set('session.use_trans_sid',$value?'1':'0');
4268
		}
4269
	}
4270
	public function getTimeout()
4271
	{
4272
		return TPropertyValue::ensureInteger(ini_get('session.gc_maxlifetime'));
4273
	}
4274
	public function setTimeout($value)
4275
	{
4276
		if($this->_started)
4277
			throw new TInvalidOperationException('httpsession_maxlifetime_unchangeable');
4278
		else
4279
			ini_set('session.gc_maxlifetime',$value);
4280
	}
4281
	public function _open($savePath,$sessionName)
4282
	{
4283
		return true;
4284
	}
4285
	public function _close()
4286
	{
4287
		return true;
4288
	}
4289
	public function _read($id)
4290
	{
4291
		return '';
4292
	}
4293
	public function _write($id,$data)
4294
	{
4295
		return true;
4296
	}
4297
	public function _destroy($id)
4298
	{
4299
		return true;
4300
	}
4301
	public function _gc($maxLifetime)
4302
	{
4303
		return true;
4304
	}
4305
	public function getIterator()
4306
	{
4307
		return new TSessionIterator;
4308
	}
4309
	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...
4310
	{
4311
		return count($_SESSION);
4312
	}
4313
	public function count()
4314
	{
4315
		return $this->getCount();
4316
	}
4317
	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...
4318
	{
4319
		return array_keys($_SESSION);
4320
	}
4321
	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...
4322
	{
4323
		return isset($_SESSION[$key]) ? $_SESSION[$key] : null;
4324
	}
4325
	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...
4326
	{
4327
		$_SESSION[$key]=$value;
4328
	}
4329
	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...
4330
	{
4331
		if(isset($_SESSION[$key]))
4332
		{
4333
			$value=$_SESSION[$key];
4334
			unset($_SESSION[$key]);
4335
			return $value;
4336
		}
4337
		else
4338
			return null;
4339
	}
4340
	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...
4341
	{
4342
		foreach(array_keys($_SESSION) as $key)
4343
			unset($_SESSION[$key]);
4344
	}
4345
	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...
4346
	{
4347
		return isset($_SESSION[$key]);
4348
	}
4349
	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...
4350
	{
4351
		return $_SESSION;
4352
	}
4353
	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...
4354
	{
4355
		return isset($_SESSION[$offset]);
4356
	}
4357
	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...
4358
	{
4359
		return isset($_SESSION[$offset]) ? $_SESSION[$offset] : null;
4360
	}
4361
	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...
4362
	{
4363
		$_SESSION[$offset]=$item;
4364
	}
4365
	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...
4366
	{
4367
		unset($_SESSION[$offset]);
4368
	}
4369
}
4370
class TSessionIterator implements Iterator
4371
{
4372
	private $_keys;
4373
	private $_key;
4374
	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...
4375
	{
4376
		$this->_keys=array_keys($_SESSION);
4377
	}
4378
	public function rewind()
4379
	{
4380
		$this->_key=reset($this->_keys);
4381
	}
4382
	public function key()
4383
	{
4384
		return $this->_key;
4385
	}
4386
	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...
4387
	{
4388
		return isset($_SESSION[$this->_key])?$_SESSION[$this->_key]:null;
4389
	}
4390
	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...
4391
	{
4392
		do
4393
		{
4394
			$this->_key=next($this->_keys);
4395
		}
4396
		while(!isset($_SESSION[$this->_key]) && $this->_key!==false);
4397
	}
4398
	public function valid()
4399
	{
4400
		return $this->_key!==false;
4401
	}
4402
}
4403
class THttpSessionCookieMode extends TEnumerable
4404
{
4405
	const None='None';
4406
	const Allow='Allow';
4407
	const Only='Only';
4408
}
4409
Prado::using('System.Web.UI.WebControls.*');
4410
class TAttributeCollection extends TMap
4411
{
4412
	private $_caseSensitive=false;
4413
	public function __get($name)
4414
	{
4415
		return $this->contains($name)?$this->itemAt($name):parent::__get($name);
4416
	}
4417
	public function __set($name,$value)
4418
	{
4419
		$this->add($name,$value);
4420
	}
4421
	public function getCaseSensitive()
4422
	{
4423
		return $this->_caseSensitive;
4424
	}
4425
	public function setCaseSensitive($value)
4426
	{
4427
		$this->_caseSensitive=TPropertyValue::ensureBoolean($value);
4428
	}
4429
	public function itemAt($key)
4430
	{
4431
		return parent::itemAt($this->_caseSensitive?$key:strtolower($key));
4432
	}
4433
	public function add($key,$value)
4434
	{
4435
		parent::add($this->_caseSensitive?$key:strtolower($key),$value);
4436
	}
4437
	public function remove($key)
4438
	{
4439
		return parent::remove($this->_caseSensitive?$key:strtolower($key));
4440
	}
4441
	public function contains($key)
4442
	{
4443
		return parent::contains($this->_caseSensitive?$key:strtolower($key));
4444
	}
4445
	public function hasProperty($name)
4446
	{
4447
		return $this->contains($name) || parent::canGetProperty($name) || parent::canSetProperty($name);
2 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (canGetProperty() instead of hasProperty()). Are you sure this is correct? If so, you might want to change this to $this->canGetProperty().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
Comprehensibility Bug introduced by
It seems like you call parent on a different method (canSetProperty() instead of hasProperty()). Are you sure this is correct? If so, you might want to change this to $this->canSetProperty().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
4448
	}
4449
	public function canGetProperty($name)
4450
	{
4451
		return $this->contains($name) || parent::canGetProperty($name);
4452
	}
4453
	public function canSetProperty($name)
4454
	{
4455
		return true;
4456
	}
4457
}
4458
class TControlAdapter extends TApplicationComponent
4459
{
4460
	protected $_control;
4461
	public function __construct($control)
4462
	{
4463
		$this->_control=$control;
4464
	}
4465
	public function getControl()
4466
	{
4467
		return $this->_control;
4468
	}
4469
	public function getPage()
4470
	{
4471
		return $this->_control?$this->_control->getPage():null;
4472
	}
4473
	public function createChildControls()
4474
	{
4475
		$this->_control->createChildControls();
4476
	}
4477
	public function loadState()
4478
	{
4479
		$this->_control->loadState();
4480
	}
4481
	public function saveState()
4482
	{
4483
		$this->_control->saveState();
4484
	}
4485
	public function onInit($param)
4486
	{
4487
		$this->_control->onInit($param);
4488
	}
4489
	public function onLoad($param)
4490
	{
4491
		$this->_control->onLoad($param);
4492
	}
4493
	public function onPreRender($param)
4494
	{
4495
		$this->_control->onPreRender($param);
4496
	}
4497
	public function onUnload($param)
4498
	{
4499
		$this->_control->onUnload($param);
4500
	}
4501
	public function render($writer)
4502
	{
4503
		$this->_control->render($writer);
4504
	}
4505
	public function renderChildren($writer)
4506
	{
4507
		$this->_control->renderChildren($writer);
4508
	}
4509
}
4510
class TControl extends TApplicationComponent implements IRenderable, IBindable
4511
{
4512
	const ID_FORMAT='/^[a-zA-Z_]\\w*$/';
4513
	const ID_SEPARATOR='$';
4514
	const CLIENT_ID_SEPARATOR='_';
4515
	const AUTOMATIC_ID_PREFIX='ctl';
4516
	const CS_CONSTRUCTED=0;
4517
	const CS_CHILD_INITIALIZED=1;
4518
	const CS_INITIALIZED=2;
4519
	const CS_STATE_LOADED=3;
4520
	const CS_LOADED=4;
4521
	const CS_PRERENDERED=5;
4522
	const IS_ID_SET=0x01;
4523
	const IS_DISABLE_VIEWSTATE=0x02;
4524
	const IS_SKIN_APPLIED=0x04;
4525
	const IS_STYLESHEET_APPLIED=0x08;
4526
	const IS_DISABLE_THEMING=0x10;
4527
	const IS_CHILD_CREATED=0x20;
4528
	const IS_CREATING_CHILD=0x40;
4529
	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...
4530
	private $_id='';
4531
	private $_uid;
4532
	private $_parent;
4533
	private $_page;
4534
	private $_namingContainer;
4535
	private $_tplControl;
4536
	private $_viewState=array();
4537
	private $_tempState=array();
4538
	private $_trackViewState=true;
4539
	private $_stage=0;
4540
	private $_flags=0;
4541
	private $_rf=array();
4542
	public function __get($name)
4543
	{
4544
		if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
4545
			return $this->_rf[self::RF_NAMED_OBJECTS][$name];
4546
		else
4547
			return parent::__get($name);
4548
	}
4549
	public function getHasAdapter()
4550
	{
4551
		return isset($this->_rf[self::RF_ADAPTER]);
4552
	}
4553
	public function getAdapter()
4554
	{
4555
		return isset($this->_rf[self::RF_ADAPTER])?$this->_rf[self::RF_ADAPTER]:null;
4556
	}
4557
	public function setAdapter(TControlAdapter $adapter)
4558
	{
4559
		$this->_rf[self::RF_ADAPTER]=$adapter;
4560
	}
4561
	public function getParent()
4562
	{
4563
		return $this->_parent;
4564
	}
4565
	public function getNamingContainer()
4566
	{
4567
		if(!$this->_namingContainer && $this->_parent)
4568
		{
4569
			if($this->_parent instanceof INamingContainer)
4570
				$this->_namingContainer=$this->_parent;
4571
			else
4572
				$this->_namingContainer=$this->_parent->getNamingContainer();
4573
		}
4574
		return $this->_namingContainer;
4575
	}
4576
	public function getPage()
4577
	{
4578
		if(!$this->_page)
4579
		{
4580
			if($this->_parent)
4581
				$this->_page=$this->_parent->getPage();
4582
			else if($this->_tplControl)
4583
				$this->_page=$this->_tplControl->getPage();
4584
		}
4585
		return $this->_page;
4586
	}
4587
	public function setPage($page)
4588
	{
4589
		$this->_page=$page;
4590
	}
4591
	public function setTemplateControl($control)
4592
	{
4593
		$this->_tplControl=$control;
4594
	}
4595
	public function getTemplateControl()
4596
	{
4597
		if(!$this->_tplControl && $this->_parent)
4598
			$this->_tplControl=$this->_parent->getTemplateControl();
4599
		return $this->_tplControl;
4600
	}
4601
	public function getSourceTemplateControl()
4602
	{
4603
		$control=$this;
4604
		while(($control instanceof TControl) && ($control=$control->getTemplateControl())!==null)
4605
		{
4606
			if(($control instanceof TTemplateControl) && $control->getIsSourceTemplateControl())
4607
				return $control;
4608
		}
4609
		return $this->getPage();
4610
	}
4611
	protected function getControlStage()
4612
	{
4613
		return $this->_stage;
4614
	}
4615
	protected function setControlStage($value)
4616
	{
4617
		$this->_stage=$value;
4618
	}
4619
	public function getID($hideAutoID=true)
4620
	{
4621
		if($hideAutoID)
4622
			return ($this->_flags & self::IS_ID_SET) ? $this->_id : '';
4623
		else
4624
			return $this->_id;
4625
	}
4626
	public function setID($id)
4627
	{
4628
		if(!preg_match(self::ID_FORMAT,$id))
4629
			throw new TInvalidDataValueException('control_id_invalid',get_class($this),$id);
4630
		$this->_id=$id;
4631
		$this->_flags |= self::IS_ID_SET;
4632
		$this->clearCachedUniqueID($this instanceof INamingContainer);
4633
		if($this->_namingContainer)
4634
			$this->_namingContainer->clearNameTable();
4635
	}
4636
	public function getUniqueID()
4637
	{
4638
		if($this->_uid==='' || $this->_uid===null)			{
4639
			$this->_uid='';  			if($namingContainer=$this->getNamingContainer())
4640
			{
4641
				if($this->getPage()===$namingContainer)
4642
					return ($this->_uid=$this->_id);
4643
				else if(($prefix=$namingContainer->getUniqueID())==='')
4644
					return $this->_id;
4645
				else
4646
					return ($this->_uid=$prefix.self::ID_SEPARATOR.$this->_id);
4647
			}
4648
			else					return $this->_id;
4649
		}
4650
		else
4651
			return $this->_uid;
4652
	}
4653
	public function focus()
4654
	{
4655
		$this->getPage()->setFocus($this);
4656
	}
4657
	public function getClientID()
4658
	{
4659
		return strtr($this->getUniqueID(),self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
4660
	}
4661
	public static function convertUniqueIdToClientId($uniqueID)
4662
	{
4663
		return strtr($uniqueID,self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
4664
	}
4665
	public function getSkinID()
4666
	{
4667
		return isset($this->_rf[self::RF_SKIN_ID])?$this->_rf[self::RF_SKIN_ID]:'';
4668
	}
4669
	public function setSkinID($value)
4670
	{
4671
		if(($this->_flags & self::IS_SKIN_APPLIED) || $this->_stage>=self::CS_CHILD_INITIALIZED)
4672
			throw new TInvalidOperationException('control_skinid_unchangeable',get_class($this));
4673
		else
4674
			$this->_rf[self::RF_SKIN_ID]=$value;
4675
	}
4676
	public function getIsSkinApplied()
4677
	{
4678
		return ($this->_flags & self::IS_SKIN_APPLIED);
4679
	}
4680
	public function getEnableTheming()
4681
	{
4682
		if($this->_flags & self::IS_DISABLE_THEMING)
4683
			return false;
4684
		else
4685
			return $this->_parent?$this->_parent->getEnableTheming():true;
4686
	}
4687
	public function setEnableTheming($value)
4688
	{
4689
		if($this->_stage>=self::CS_CHILD_INITIALIZED)
4690
			throw new TInvalidOperationException('control_enabletheming_unchangeable',get_class($this),$this->getUniqueID());
4691
		else if(TPropertyValue::ensureBoolean($value))
4692
			$this->_flags &= ~self::IS_DISABLE_THEMING;
4693
		else
4694
			$this->_flags |= self::IS_DISABLE_THEMING;
4695
	}
4696
	public function getCustomData()
4697
	{
4698
		return $this->getViewState('CustomData',null);
4699
	}
4700
	public function setCustomData($value)
4701
	{
4702
		$this->setViewState('CustomData',$value,null);
4703
	}
4704
	public function getHasControls()
4705
	{
4706
		return isset($this->_rf[self::RF_CONTROLS]) && $this->_rf[self::RF_CONTROLS]->getCount()>0;
4707
	}
4708
	public function getControls()
4709
	{
4710
		if(!isset($this->_rf[self::RF_CONTROLS]))
4711
			$this->_rf[self::RF_CONTROLS]=$this->createControlCollection();
4712
		return $this->_rf[self::RF_CONTROLS];
4713
	}
4714
	protected function createControlCollection()
4715
	{
4716
		return $this->getAllowChildControls()?new TControlCollection($this):new TEmptyControlCollection($this);
4717
	}
4718
	public function getVisible($checkParents=true)
4719
	{
4720
		if($checkParents)
4721
		{
4722
			for($control=$this;$control;$control=$control->_parent)
4723
				if(!$control->getVisible(false))
4724
					return false;
4725
			return true;
4726
		}
4727
		else
4728
			return $this->getViewState('Visible',true);
4729
	}
4730
	public function setVisible($value)
4731
	{
4732
		$this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true);
4733
	}
4734
	public function getEnabled($checkParents=false)
4735
	{
4736
		if($checkParents)
4737
		{
4738
			for($control=$this;$control;$control=$control->_parent)
4739
				if(!$control->getViewState('Enabled',true))
4740
					return false;
4741
			return true;
4742
		}
4743
		else
4744
			return $this->getViewState('Enabled',true);
4745
	}
4746
	public function setEnabled($value)
4747
	{
4748
		$this->setViewState('Enabled',TPropertyValue::ensureBoolean($value),true);
4749
	}
4750
	public function getHasAttributes()
4751
	{
4752
		if($attributes=$this->getViewState('Attributes',null))
4753
			return $attributes->getCount()>0;
4754
		else
4755
			return false;
4756
	}
4757
	public function getAttributes()
4758
	{
4759
		if($attributes=$this->getViewState('Attributes',null))
4760
			return $attributes;
4761
		else
4762
		{
4763
			$attributes=new TAttributeCollection;
4764
			$this->setViewState('Attributes',$attributes,null);
4765
			return $attributes;
4766
		}
4767
	}
4768
	public function hasAttribute($name)
4769
	{
4770
		if($attributes=$this->getViewState('Attributes',null))
4771
			return $attributes->contains($name);
4772
		else
4773
			return false;
4774
	}
4775
	public function getAttribute($name)
4776
	{
4777
		if($attributes=$this->getViewState('Attributes',null))
4778
			return $attributes->itemAt($name);
4779
		else
4780
			return null;
4781
	}
4782
	public function setAttribute($name,$value)
4783
	{
4784
		$this->getAttributes()->add($name,$value);
4785
	}
4786
	public function removeAttribute($name)
4787
	{
4788
		if($attributes=$this->getViewState('Attributes',null))
4789
			return $attributes->remove($name);
4790
		else
4791
			return null;
4792
	}
4793
	public function getEnableViewState($checkParents=false)
4794
	{
4795
		if($checkParents)
4796
		{
4797
			for($control=$this;$control!==null;$control=$control->getParent())
4798
				if($control->_flags & self::IS_DISABLE_VIEWSTATE)
4799
					return false;
4800
			return true;
4801
		}
4802
		else
4803
			return !($this->_flags & self::IS_DISABLE_VIEWSTATE);
4804
	}
4805
	public function setEnableViewState($value)
4806
	{
4807
		if(TPropertyValue::ensureBoolean($value))
4808
			$this->_flags &= ~self::IS_DISABLE_VIEWSTATE;
4809
		else
4810
			$this->_flags |= self::IS_DISABLE_VIEWSTATE;
4811
	}
4812
	protected function getControlState($key,$defaultValue=null)
4813
	{
4814
		return isset($this->_rf[self::RF_CONTROLSTATE][$key])?$this->_rf[self::RF_CONTROLSTATE][$key]:$defaultValue;
4815
	}
4816
	protected function setControlState($key,$value,$defaultValue=null)
4817
	{
4818
		if($value===$defaultValue)
4819
			unset($this->_rf[self::RF_CONTROLSTATE][$key]);
4820
		else
4821
			$this->_rf[self::RF_CONTROLSTATE][$key]=$value;
4822
	}
4823
	protected function clearControlState($key)
4824
	{
4825
		unset($this->_rf[self::RF_CONTROLSTATE][$key]);
4826
	}
4827
	public function trackViewState($enabled)
4828
	{
4829
		$this->_trackViewState=TPropertyValue::ensureBoolean($enabled);
4830
	}
4831
	public function getViewState($key,$defaultValue=null)
4832
	{
4833
		if(isset($this->_viewState[$key]))
4834
			return $this->_viewState[$key]!==null?$this->_viewState[$key]:$defaultValue;
4835
		else if(isset($this->_tempState[$key]))
4836
		{
4837
			if(is_object($this->_tempState[$key]) && $this->_trackViewState)
4838
				$this->_viewState[$key]=$this->_tempState[$key];
4839
			return $this->_tempState[$key];
4840
		}
4841
		else
4842
			return $defaultValue;
4843
	}
4844
	public function setViewState($key,$value,$defaultValue=null)
4845
	{
4846
		if($this->_trackViewState)
4847
		{
4848
			$this->_viewState[$key]=$value;
4849
			unset($this->_tempState[$key]);
4850
		}
4851
		else
4852
		{
4853
			unset($this->_viewState[$key]);
4854
			$this->_tempState[$key]=$value;
4855
		}
4856
	}
4857
	public function clearViewState($key)
4858
	{
4859
		unset($this->_viewState[$key]);
4860
		unset($this->_tempState[$key]);
4861
	}
4862
	public function bindProperty($name,$expression)
4863
	{
4864
		$this->_rf[self::RF_DATA_BINDINGS][$name]=$expression;
4865
	}
4866
	public function unbindProperty($name)
4867
	{
4868
		unset($this->_rf[self::RF_DATA_BINDINGS][$name]);
4869
	}
4870
	public function autoBindProperty($name,$expression)
4871
	{
4872
		$this->_rf[self::RF_AUTO_BINDINGS][$name]=$expression;
4873
	}
4874
	public function dataBind()
4875
	{
4876
		$this->dataBindProperties();
4877
		$this->onDataBinding(null);
4878
		$this->dataBindChildren();
4879
	}
4880
	protected function dataBindProperties()
4881
	{
4882
		if(isset($this->_rf[self::RF_DATA_BINDINGS]))
4883
		{
4884
			if(($context=$this->getTemplateControl())===null)
4885
				$context=$this;
4886
			foreach($this->_rf[self::RF_DATA_BINDINGS] as $property=>$expression)
4887
				$this->setSubProperty($property,$context->evaluateExpression($expression));
4888
		}
4889
	}
4890
	protected function autoDataBindProperties()
4891
	{
4892
		if(isset($this->_rf[self::RF_AUTO_BINDINGS]))
4893
		{
4894
			if(($context=$this->getTemplateControl())===null)
4895
				$context=$this;
4896
			foreach($this->_rf[self::RF_AUTO_BINDINGS] as $property=>$expression)
4897
				$this->setSubProperty($property,$context->evaluateExpression($expression));
4898
		}
4899
	}
4900
	protected function dataBindChildren()
4901
	{
4902
		if(isset($this->_rf[self::RF_CONTROLS]))
4903
		{
4904
			foreach($this->_rf[self::RF_CONTROLS] as $control)
4905
				if($control instanceof IBindable)
4906
					$control->dataBind();
4907
		}
4908
	}
4909
	final protected function getChildControlsCreated()
4910
	{
4911
		return ($this->_flags & self::IS_CHILD_CREATED)!==0;
4912
	}
4913
	final protected function setChildControlsCreated($value)
4914
	{
4915
		if($value)
4916
			$this->_flags |= self::IS_CHILD_CREATED;
4917
		else
4918
		{
4919
			if($this->getHasControls() && ($this->_flags & self::IS_CHILD_CREATED))
4920
				$this->getControls()->clear();
4921
			$this->_flags &= ~self::IS_CHILD_CREATED;
4922
		}
4923
	}
4924
	public function ensureChildControls()
4925
	{
4926
		if(!($this->_flags & self::IS_CHILD_CREATED) && !($this->_flags & self::IS_CREATING_CHILD))
4927
		{
4928
			try
4929
			{
4930
				$this->_flags |= self::IS_CREATING_CHILD;
4931
				if(isset($this->_rf[self::RF_ADAPTER]))
4932
					$this->_rf[self::RF_ADAPTER]->createChildControls();
4933
				else
4934
					$this->createChildControls();
4935
				$this->_flags &= ~self::IS_CREATING_CHILD;
4936
				$this->_flags |= self::IS_CHILD_CREATED;
4937
			}
4938
			catch(Exception $e)
4939
			{
4940
				$this->_flags &= ~self::IS_CREATING_CHILD;
4941
				$this->_flags |= self::IS_CHILD_CREATED;
4942
				throw $e;
4943
			}
4944
		}
4945
	}
4946
	public function createChildControls()
4947
	{
4948
	}
4949
	public function findControl($id)
4950
	{
4951
		$id=strtr($id,'.',self::ID_SEPARATOR);
4952
		$container=($this instanceof INamingContainer)?$this:$this->getNamingContainer();
4953
		if(!$container || !$container->getHasControls())
4954
			return null;
4955
		if(!isset($container->_rf[self::RF_NAMED_CONTROLS]))
4956
		{
4957
			$container->_rf[self::RF_NAMED_CONTROLS]=array();
4958
			$container->fillNameTable($container,$container->_rf[self::RF_CONTROLS]);
4959
		}
4960
		if(($pos=strpos($id,self::ID_SEPARATOR))===false)
4961
			return isset($container->_rf[self::RF_NAMED_CONTROLS][$id])?$container->_rf[self::RF_NAMED_CONTROLS][$id]:null;
4962
		else
4963
		{
4964
			$cid=substr($id,0,$pos);
4965
			$sid=substr($id,$pos+1);
4966
			if(isset($container->_rf[self::RF_NAMED_CONTROLS][$cid]))
4967
				return $container->_rf[self::RF_NAMED_CONTROLS][$cid]->findControl($sid);
4968
			else
4969
				return null;
4970
		}
4971
	}
4972
	public function findControlsByType($type,$strict=true)
4973
	{
4974
		$controls=array();
4975
		if($this->getHasControls())
4976
		{
4977
			foreach($this->_rf[self::RF_CONTROLS] as $control)
4978
			{
4979
				if(is_object($control) && (get_class($control)===$type || (!$strict && ($control instanceof $type))))
4980
					$controls[]=$control;
4981
				if(($control instanceof TControl) && $control->getHasControls())
4982
					$controls=array_merge($controls,$control->findControlsByType($type,$strict));
4983
			}
4984
		}
4985
		return $controls;
4986
	}
4987
	public function findControlsByID($id)
4988
	{
4989
		$controls=array();
4990
		if($this->getHasControls())
4991
		{
4992
			foreach($this->_rf[self::RF_CONTROLS] as $control)
4993
			{
4994
				if($control instanceof TControl)
4995
				{
4996
					if($control->_id===$id)
4997
						$controls[]=$control;
4998
					$controls=array_merge($controls,$control->findControlsByID($id));
4999
				}
5000
			}
5001
		}
5002
		return $controls;
5003
	}
5004
	public function clearNamingContainer()
5005
	{
5006
		unset($this->_rf[self::RF_NAMED_CONTROLS_ID]);
5007
		$this->clearNameTable();
5008
	}
5009
	public function registerObject($name,$object)
5010
	{
5011
		if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
5012
			throw new TInvalidOperationException('control_object_reregistered',$name);
5013
		$this->_rf[self::RF_NAMED_OBJECTS][$name]=$object;
5014
	}
5015
	public function unregisterObject($name)
5016
	{
5017
		unset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
5018
	}
5019
	public function isObjectRegistered($name)
5020
	{
5021
		return isset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
5022
	}
5023
	public function getHasChildInitialized()
5024
	{
5025
		return $this->getControlStage() >= self::CS_CHILD_INITIALIZED;
5026
	}
5027
	public function getHasInitialized()
5028
	{
5029
		return $this->getControlStage() >= self::CS_INITIALIZED;
5030
	}
5031
	public function getHasLoadedPostData()
5032
	{
5033
		return $this->getControlStage() >= self::CS_STATE_LOADED;
5034
	}
5035
	public function getHasLoaded()
5036
	{
5037
		return $this->getControlStage() >= self::CS_LOADED;
5038
	}
5039
	public function getHasPreRendered()
5040
	{
5041
		return $this->getControlStage() >= self::CS_PRERENDERED;
5042
	}
5043
	public function getRegisteredObject($name)
5044
	{
5045
		return isset($this->_rf[self::RF_NAMED_OBJECTS][$name])?$this->_rf[self::RF_NAMED_OBJECTS][$name]:null;
5046
	}
5047
	public function getAllowChildControls()
5048
	{
5049
		return true;
5050
	}
5051
	public function addParsedObject($object)
5052
	{
5053
		$this->getControls()->add($object);
5054
	}
5055
	final protected function clearChildState()
5056
	{
5057
		unset($this->_rf[self::RF_CHILD_STATE]);
5058
	}
5059
	final protected function isDescendentOf($ancestor)
5060
	{
5061
		$control=$this;
5062
		while($control!==$ancestor && $control->_parent)
5063
			$control=$control->_parent;
5064
		return $control===$ancestor;
5065
	}
5066
	public function addedControl($control)
5067
	{
5068
		if($control->_parent)
5069
			$control->_parent->getControls()->remove($control);
5070
		$control->_parent=$this;
5071
		$control->_page=$this->getPage();
5072
		$namingContainer=($this instanceof INamingContainer)?$this:$this->_namingContainer;
5073
		if($namingContainer)
5074
		{
5075
			$control->_namingContainer=$namingContainer;
5076
			if($control->_id==='')
5077
				$control->generateAutomaticID();
5078
			else
5079
				$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...
5080
			$control->clearCachedUniqueID($control instanceof INamingContainer);
5081
		}
5082
		if($this->_stage>=self::CS_CHILD_INITIALIZED)
5083
		{
5084
			$control->initRecursive($namingContainer);
5085
			if($this->_stage>=self::CS_STATE_LOADED)
5086
			{
5087
				if(isset($this->_rf[self::RF_CHILD_STATE][$control->_id]))
5088
				{
5089
					$state=$this->_rf[self::RF_CHILD_STATE][$control->_id];
5090
					unset($this->_rf[self::RF_CHILD_STATE][$control->_id]);
5091
				}
5092
				else
5093
					$state=null;
5094
				$control->loadStateRecursive($state,!($this->_flags & self::IS_DISABLE_VIEWSTATE));
5095
				if($this->_stage>=self::CS_LOADED)
5096
				{
5097
					$control->loadRecursive();
5098
					if($this->_stage>=self::CS_PRERENDERED)
5099
						$control->preRenderRecursive();
5100
				}
5101
			}
5102
		}
5103
	}
5104
	public function removedControl($control)
5105
	{
5106
		if($this->_namingContainer)
5107
			$this->_namingContainer->clearNameTable();
5108
		$control->unloadRecursive();
5109
		$control->_parent=null;
5110
		$control->_page=null;
5111
		$control->_namingContainer=null;
5112
		$control->_tplControl=null;
5113
				if(!($control->_flags & self::IS_ID_SET))
5114
			$control->_id='';
5115
		else
5116
			unset($this->_rf[self::RF_NAMED_OBJECTS][$control->_id]);
5117
		$control->clearCachedUniqueID(true);
5118
	}
5119
	protected function initRecursive($namingContainer=null)
5120
	{
5121
		$this->ensureChildControls();
5122
		if($this->getHasControls())
5123
		{
5124
			if($this instanceof INamingContainer)
5125
				$namingContainer=$this;
5126
			$page=$this->getPage();
5127
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5128
			{
5129
				if($control instanceof TControl)
5130
				{
5131
					$control->_namingContainer=$namingContainer;
5132
					$control->_page=$page;
5133
					if($control->_id==='' && $namingContainer)
5134
						$control->generateAutomaticID();
5135
					$control->initRecursive($namingContainer);
5136
				}
5137
			}
5138
		}
5139
		if($this->_stage<self::CS_INITIALIZED)
5140
		{
5141
			$this->_stage=self::CS_CHILD_INITIALIZED;
5142
			if(($page=$this->getPage()) && $this->getEnableTheming() && !($this->_flags & self::IS_SKIN_APPLIED))
5143
			{
5144
				$page->applyControlSkin($this);
5145
				$this->_flags |= self::IS_SKIN_APPLIED;
5146
			}
5147
			if(isset($this->_rf[self::RF_ADAPTER]))
5148
				$this->_rf[self::RF_ADAPTER]->onInit(null);
5149
			else
5150
				$this->onInit(null);
5151
			$this->_stage=self::CS_INITIALIZED;
5152
		}
5153
	}
5154
	protected function loadRecursive()
5155
	{
5156
		if($this->_stage<self::CS_LOADED)
5157
		{
5158
			if(isset($this->_rf[self::RF_ADAPTER]))
5159
				$this->_rf[self::RF_ADAPTER]->onLoad(null);
5160
			else
5161
				$this->onLoad(null);
5162
		}
5163
		if($this->getHasControls())
5164
		{
5165
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5166
			{
5167
				if($control instanceof TControl)
5168
					$control->loadRecursive();
5169
			}
5170
		}
5171
		if($this->_stage<self::CS_LOADED)
5172
			$this->_stage=self::CS_LOADED;
5173
	}
5174
	protected function preRenderRecursive()
5175
	{
5176
		$this->autoDataBindProperties();
5177
		if($this->getVisible(false))
5178
		{
5179
			if(isset($this->_rf[self::RF_ADAPTER]))
5180
				$this->_rf[self::RF_ADAPTER]->onPreRender(null);
5181
			else
5182
				$this->onPreRender(null);
5183
			if($this->getHasControls())
5184
			{
5185
				foreach($this->_rf[self::RF_CONTROLS] as $control)
5186
				{
5187
					if($control instanceof TControl)
5188
						$control->preRenderRecursive();
5189
					else if($control instanceof TCompositeLiteral)
5190
						$control->evaluateDynamicContent();
5191
				}
5192
			}
5193
		}
5194
		$this->_stage=self::CS_PRERENDERED;
5195
	}
5196
	protected function unloadRecursive()
5197
	{
5198
		if(!($this->_flags & self::IS_ID_SET))
5199
			$this->_id='';
5200
		if($this->getHasControls())
5201
		{
5202
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5203
				if($control instanceof TControl)
5204
					$control->unloadRecursive();
5205
		}
5206
		if(isset($this->_rf[self::RF_ADAPTER]))
5207
			$this->_rf[self::RF_ADAPTER]->onUnload(null);
5208
		else
5209
			$this->onUnload(null);
5210
	}
5211
	public function onInit($param)
5212
	{
5213
		$this->raiseEvent('OnInit',$this,$param);
5214
	}
5215
	public function onLoad($param)
5216
	{
5217
		$this->raiseEvent('OnLoad',$this,$param);
5218
	}
5219
	public function onDataBinding($param)
5220
	{
5221
		$this->raiseEvent('OnDataBinding',$this,$param);
5222
	}
5223
	public function onUnload($param)
5224
	{
5225
		$this->raiseEvent('OnUnload',$this,$param);
5226
	}
5227
	public function onPreRender($param)
5228
	{
5229
		$this->raiseEvent('OnPreRender',$this,$param);
5230
	}
5231
	protected function raiseBubbleEvent($sender,$param)
5232
	{
5233
		$control=$this;
5234
		while($control=$control->_parent)
5235
		{
5236
			if($control->bubbleEvent($sender,$param))
5237
				break;
5238
		}
5239
	}
5240
	public function bubbleEvent($sender,$param)
5241
	{
5242
		return false;
5243
	}
5244
	public function broadcastEvent($name,$sender,$param)
5245
	{
5246
		$rootControl=(($page=$this->getPage())===null)?$this:$page;
5247
		$rootControl->broadcastEventInternal($name,$sender,new TBroadcastEventParameter($name,$param));
5248
	}
5249
	private function broadcastEventInternal($name,$sender,$param)
5250
	{
5251
		if($this->hasEvent($name))
5252
			$this->raiseEvent($name,$sender,$param->getParameter());
5253
		if($this instanceof IBroadcastEventReceiver)
5254
			$this->broadcastEventReceived($sender,$param);
5255
		if($this->getHasControls())
5256
		{
5257
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5258
			{
5259
				if($control instanceof TControl)
5260
					$control->broadcastEventInternal($name,$sender,$param);
5261
			}
5262
		}
5263
	}
5264
	protected function traverseChildControls($param,$preCallback=null,$postCallback=null)
5265
	{
5266
		if($preCallback!==null)
5267
			call_user_func($preCallback,$this,$param);
5268
		if($this->getHasControls())
5269
		{
5270
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5271
			{
5272
				if($control instanceof TControl)
5273
				{
5274
					$control->traverseChildControls($param,$preCallback,$postCallback);
5275
				}
5276
			}
5277
		}
5278
		if($postCallback!==null)
5279
			call_user_func($postCallback,$this,$param);
5280
	}
5281
	public function renderControl($writer)
5282
	{
5283
		if($this instanceof IActiveControl || $this->getVisible(false))
5284
		{
5285
			if(isset($this->_rf[self::RF_ADAPTER]))
5286
				$this->_rf[self::RF_ADAPTER]->render($writer);
5287
			else
5288
				$this->render($writer);
5289
		}
5290
	}
5291
	public function render($writer)
5292
	{
5293
		$this->renderChildren($writer);
5294
	}
5295
	public function renderChildren($writer)
5296
	{
5297
		if($this->getHasControls())
5298
		{
5299
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5300
			{
5301
				if(is_string($control))
5302
					$writer->write($control);
5303
				else if($control instanceof TControl)
5304
					$control->renderControl($writer);
5305
				else if($control instanceof IRenderable)
5306
					$control->render($writer);
5307
			}
5308
		}
5309
	}
5310
	public function saveState()
5311
	{
5312
	}
5313
	public function loadState()
5314
	{
5315
	}
5316
	protected function loadStateRecursive(&$state,$needViewState=true)
5317
	{
5318
		if(is_array($state))
5319
		{
5320
									$needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
5321
			if(isset($state[1]))
5322
			{
5323
				$this->_rf[self::RF_CONTROLSTATE]=&$state[1];
5324
				unset($state[1]);
5325
			}
5326
			else
5327
				unset($this->_rf[self::RF_CONTROLSTATE]);
5328
			if($needViewState)
5329
			{
5330
				if(isset($state[0]))
5331
					$this->_viewState=&$state[0];
5332
				else
5333
					$this->_viewState=array();
5334
			}
5335
			unset($state[0]);
5336
			if($this->getHasControls())
5337
			{
5338
				foreach($this->_rf[self::RF_CONTROLS] as $control)
5339
				{
5340
					if($control instanceof TControl)
5341
					{
5342
						if(isset($state[$control->_id]))
5343
						{
5344
							$control->loadStateRecursive($state[$control->_id],$needViewState);
5345
							unset($state[$control->_id]);
5346
						}
5347
					}
5348
				}
5349
			}
5350
			if(!empty($state))
5351
				$this->_rf[self::RF_CHILD_STATE]=&$state;
5352
		}
5353
		$this->_stage=self::CS_STATE_LOADED;
5354
		if(isset($this->_rf[self::RF_ADAPTER]))
5355
			$this->_rf[self::RF_ADAPTER]->loadState();
5356
		else
5357
			$this->loadState();
5358
	}
5359
	protected function &saveStateRecursive($needViewState=true)
5360
	{
5361
		if(isset($this->_rf[self::RF_ADAPTER]))
5362
			$this->_rf[self::RF_ADAPTER]->saveState();
5363
		else
5364
			$this->saveState();
5365
		$needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
5366
		$state=array();
5367
		if($this->getHasControls())
5368
		{
5369
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5370
			{
5371
				if($control instanceof TControl)
5372
					$state[$control->_id]=&$control->saveStateRecursive($needViewState);
5373
			}
5374
		}
5375
		if($needViewState && !empty($this->_viewState))
5376
			$state[0]=&$this->_viewState;
5377
		if(isset($this->_rf[self::RF_CONTROLSTATE]))
5378
			$state[1]=&$this->_rf[self::RF_CONTROLSTATE];
5379
		return $state;
5380
	}
5381
	public function applyStyleSheetSkin($page)
5382
	{
5383
		if($page && !($this->_flags & self::IS_STYLESHEET_APPLIED))
5384
		{
5385
			$page->applyControlStyleSheet($this);
5386
			$this->_flags |= self::IS_STYLESHEET_APPLIED;
5387
		}
5388
		else if($this->_flags & self::IS_STYLESHEET_APPLIED)
5389
			throw new TInvalidOperationException('control_stylesheet_applied',get_class($this));
5390
	}
5391
	private function clearCachedUniqueID($recursive)
5392
	{
5393
		if($recursive && $this->_uid!==null && isset($this->_rf[self::RF_CONTROLS]))
5394
		{
5395
			foreach($this->_rf[self::RF_CONTROLS] as $control)
5396
				if($control instanceof TControl)
5397
					$control->clearCachedUniqueID($recursive);
5398
		}
5399
		$this->_uid=null;
5400
	}
5401
	private function generateAutomaticID()
5402
	{
5403
		$this->_flags &= ~self::IS_ID_SET;
5404
		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...
5405
			$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...
5406
		$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...
5407
		$this->_id=self::AUTOMATIC_ID_PREFIX . $id;
5408
		$this->_namingContainer->clearNameTable();
5409
	}
5410
	private function clearNameTable()
5411
	{
5412
		unset($this->_rf[self::RF_NAMED_CONTROLS]);
5413
	}
5414
	private function fillNameTable($container,$controls)
5415
	{
5416
		foreach($controls as $control)
5417
		{
5418
			if($control instanceof TControl)
5419
			{
5420
				if($control->_id!=='')
5421
				{
5422
					if(isset($container->_rf[self::RF_NAMED_CONTROLS][$control->_id]))
5423
						throw new TInvalidDataValueException('control_id_nonunique',get_class($control),$control->_id);
5424
					else
5425
						$container->_rf[self::RF_NAMED_CONTROLS][$control->_id]=$control;
5426
				}
5427
				if(!($control instanceof INamingContainer) && $control->getHasControls())
5428
					$this->fillNameTable($container,$control->_rf[self::RF_CONTROLS]);
5429
			}
5430
		}
5431
	}
5432
}
5433
class TControlCollection extends TList
5434
{
5435
	private $_o;
5436
	public function __construct(TControl $owner,$readOnly=false)
5437
	{
5438
		$this->_o=$owner;
5439
		parent::__construct(null,$readOnly);
5440
	}
5441
	protected function getOwner()
5442
	{
5443
		return $this->_o;
5444
	}
5445
	public function insertAt($index,$item)
5446
	{
5447
		if($item instanceof TControl)
5448
		{
5449
			parent::insertAt($index,$item);
5450
			$this->_o->addedControl($item);
5451
		}
5452
		else if(is_string($item) || ($item instanceof IRenderable))
5453
			parent::insertAt($index,$item);
5454
		else
5455
			throw new TInvalidDataTypeException('controlcollection_control_required');
5456
	}
5457
	public function removeAt($index)
5458
	{
5459
		$item=parent::removeAt($index);
5460
		if($item instanceof TControl)
5461
			$this->_o->removedControl($item);
5462
		return $item;
5463
	}
5464
	public function clear()
5465
	{
5466
		parent::clear();
5467
		if($this->_o instanceof INamingContainer)
5468
			$this->_o->clearNamingContainer();
5469
	}
5470
}
5471
class TEmptyControlCollection extends TControlCollection
5472
{
5473
	public function __construct(TControl $owner)
5474
	{
5475
		parent::__construct($owner,true);
5476
	}
5477
	public function insertAt($index,$item)
5478
	{
5479
		if(!is_string($item))  			parent::insertAt($index,$item);  	}
5480
}
5481
interface INamingContainer
5482
{
5483
}
5484
interface IPostBackEventHandler
5485
{
5486
	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...
5487
}
5488
interface IPostBackDataHandler
5489
{
5490
	public function loadPostData($key,$values);
5491
	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...
5492
	public function getDataChanged();
5493
}
5494
interface IValidator
5495
{
5496
	public function validate();
5497
	public function getIsValid();
5498
	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...
5499
	public function getErrorMessage();
5500
	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...
5501
}
5502
interface IValidatable
5503
{
5504
	public function getValidationPropertyValue();
5505
	public function getIsValid();
5506
	public function setIsValid($value);
5507
}
5508
interface IBroadcastEventReceiver
5509
{
5510
	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...
5511
}
5512
interface ITheme
5513
{
5514
	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...
5515
}
5516
interface ITemplate
5517
{
5518
	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...
5519
}
5520
interface IButtonControl
5521
{
5522
	public function getText();
5523
	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...
5524
	public function getCausesValidation();
5525
	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...
5526
	public function getCommandName();
5527
	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...
5528
	public function getCommandParameter();
5529
	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...
5530
	public function getValidationGroup();
5531
	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...
5532
	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...
5533
	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...
5534
	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...
5535
	public function getIsDefaultButton();
5536
}
5537
interface ISurroundable
5538
{
5539
	public function getSurroundingTag();
5540
	public function getSurroundingTagID();
5541
}
5542
class TBroadcastEventParameter extends TEventParameter
5543
{
5544
	private $_name;
5545
	private $_param;
5546
	public function __construct($name='',$parameter=null)
5547
	{
5548
		$this->_name=$name;
5549
		$this->_param=$parameter;
5550
	}
5551
	public function getName()
5552
	{
5553
		return $this->_name;
5554
	}
5555
	public function setName($value)
5556
	{
5557
		$this->_name=$value;
5558
	}
5559
	public function getParameter()
5560
	{
5561
		return $this->_param;
5562
	}
5563
	public function setParameter($value)
5564
	{
5565
		$this->_param=$value;
5566
	}
5567
}
5568
class TCommandEventParameter extends TEventParameter
5569
{
5570
	private $_name;
5571
	private $_param;
5572
	public function __construct($name='',$parameter='')
5573
	{
5574
		$this->_name=$name;
5575
		$this->_param=$parameter;
5576
	}
5577
	public function getCommandName()
5578
	{
5579
		return $this->_name;
5580
	}
5581
	public function getCommandParameter()
5582
	{
5583
		return $this->_param;
5584
	}
5585
}
5586
class TCompositeLiteral extends TComponent implements IRenderable, IBindable
5587
{
5588
	const TYPE_EXPRESSION=0;
5589
	const TYPE_STATEMENTS=1;
5590
	const TYPE_DATABINDING=2;
5591
	private $_container=null;
5592
	private $_items=array();
5593
	private $_expressions=array();
5594
	private $_statements=array();
5595
	private $_bindings=array();
5596
	public function __construct($items)
5597
	{
5598
		$this->_items=array();
5599
		$this->_expressions=array();
5600
		$this->_statements=array();
5601
		foreach($items as $id=>$item)
5602
		{
5603
			if(is_array($item))
5604
			{
5605
				if($item[0]===self::TYPE_EXPRESSION)
5606
					$this->_expressions[$id]=$item[1];
5607
				else if($item[0]===self::TYPE_STATEMENTS)
5608
					$this->_statements[$id]=$item[1];
5609
				else if($item[0]===self::TYPE_DATABINDING)
5610
					$this->_bindings[$id]=$item[1];
5611
				$this->_items[$id]='';
5612
			}
5613
			else
5614
				$this->_items[$id]=$item;
5615
		}
5616
	}
5617
	public function getContainer()
5618
	{
5619
		return $this->_container;
5620
	}
5621
	public function setContainer(TComponent $value)
5622
	{
5623
		$this->_container=$value;
5624
	}
5625
	public function evaluateDynamicContent()
5626
	{
5627
		$context=$this->_container===null?$this:$this->_container;
5628
		foreach($this->_expressions as $id=>$expression)
5629
			$this->_items[$id]=$context->evaluateExpression($expression);
5630
		foreach($this->_statements as $id=>$statement)
5631
			$this->_items[$id]=$context->evaluateStatements($statement);
5632
	}
5633
	public function dataBind()
5634
	{
5635
		$context=$this->_container===null?$this:$this->_container;
5636
		foreach($this->_bindings as $id=>$binding)
5637
			$this->_items[$id]=$context->evaluateExpression($binding);
5638
	}
5639
	public function render($writer)
5640
	{
5641
		$writer->write(implode('',$this->_items));
5642
	}
5643
}
5644
class TFont extends TComponent
5645
{
5646
	const IS_BOLD=0x01;
5647
	const IS_ITALIC=0x02;
5648
	const IS_OVERLINE=0x04;
5649
	const IS_STRIKEOUT=0x08;
5650
	const IS_UNDERLINE=0x10;
5651
	const IS_SET_BOLD=0x01000;
5652
	const IS_SET_ITALIC=0x02000;
5653
	const IS_SET_OVERLINE=0x04000;
5654
	const IS_SET_STRIKEOUT=0x08000;
5655
	const IS_SET_UNDERLINE=0x10000;
5656
	const IS_SET_SIZE=0x20000;
5657
	const IS_SET_NAME=0x40000;
5658
	private $_flags=0;
5659
	private $_name='';
5660
	private $_size='';
5661
	public function getBold()
5662
	{
5663
		return ($this->_flags & self::IS_BOLD)!==0;
5664
	}
5665
	public function setBold($value)
5666
	{
5667
		$this->_flags |= self::IS_SET_BOLD;
5668
		if(TPropertyValue::ensureBoolean($value))
5669
			$this->_flags |= self::IS_BOLD;
5670
		else
5671
			$this->_flags &= ~self::IS_BOLD;
5672
	}
5673
	public function getItalic()
5674
	{
5675
		return ($this->_flags & self::IS_ITALIC)!==0;
5676
	}
5677
	public function setItalic($value)
5678
	{
5679
		$this->_flags |= self::IS_SET_ITALIC;
5680
		if(TPropertyValue::ensureBoolean($value))
5681
			$this->_flags |= self::IS_ITALIC;
5682
		else
5683
			$this->_flags &= ~self::IS_ITALIC;
5684
	}
5685
	public function getOverline()
5686
	{
5687
		return ($this->_flags & self::IS_OVERLINE)!==0;
5688
	}
5689
	public function setOverline($value)
5690
	{
5691
		$this->_flags |= self::IS_SET_OVERLINE;
5692
		if(TPropertyValue::ensureBoolean($value))
5693
			$this->_flags |= self::IS_OVERLINE;
5694
		else
5695
			$this->_flags &= ~self::IS_OVERLINE;
5696
	}
5697
	public function getSize()
5698
	{
5699
		return $this->_size;
5700
	}
5701
	public function setSize($value)
5702
	{
5703
		$this->_flags |= self::IS_SET_SIZE;
5704
		$this->_size=$value;
5705
	}
5706
	public function getStrikeout()
5707
	{
5708
		return ($this->_flags & self::IS_STRIKEOUT)!==0;
5709
	}
5710
	public function setStrikeout($value)
5711
	{
5712
		$this->_flags |= self::IS_SET_STRIKEOUT;
5713
		if(TPropertyValue::ensureBoolean($value))
5714
			$this->_flags |= self::IS_STRIKEOUT;
5715
		else
5716
			$this->_flags &= ~self::IS_STRIKEOUT;
5717
	}
5718
	public function getUnderline()
5719
	{
5720
		return ($this->_flags & self::IS_UNDERLINE)!==0;
5721
	}
5722
	public function setUnderline($value)
5723
	{
5724
		$this->_flags |= self::IS_SET_UNDERLINE;
5725
		if(TPropertyValue::ensureBoolean($value))
5726
			$this->_flags |= self::IS_UNDERLINE;
5727
		else
5728
			$this->_flags &= ~self::IS_UNDERLINE;
5729
	}
5730
	public function getName()
5731
	{
5732
		return $this->_name;
5733
	}
5734
	public function setName($value)
5735
	{
5736
		$this->_flags |= self::IS_SET_NAME;
5737
		$this->_name=$value;
5738
	}
5739
	public function getIsEmpty()
5740
	{
5741
		return !$this->_flags;
5742
	}
5743
	public function reset()
5744
	{
5745
		$this->_flags=0;
5746
		$this->_name='';
5747
		$this->_size='';
5748
	}
5749
	public function mergeWith($font)
5750
	{
5751
		if($font===null || $font->_flags===0)
5752
			return;
5753
		if(!($this->_flags & self::IS_SET_BOLD) && ($font->_flags & self::IS_SET_BOLD))
5754
			$this->setBold($font->getBold());
5755
		if(!($this->_flags & self::IS_SET_ITALIC) && ($font->_flags & self::IS_SET_ITALIC))
5756
			$this->setItalic($font->getItalic());
5757
		if(!($this->_flags & self::IS_SET_OVERLINE) && ($font->_flags & self::IS_SET_OVERLINE))
5758
			$this->setOverline($font->getOverline());
5759
		if(!($this->_flags & self::IS_SET_STRIKEOUT) && ($font->_flags & self::IS_SET_STRIKEOUT))
5760
			$this->setStrikeout($font->getStrikeout());
5761
		if(!($this->_flags & self::IS_SET_UNDERLINE) && ($font->_flags & self::IS_SET_UNDERLINE))
5762
			$this->setUnderline($font->getUnderline());
5763
		if(!($this->_flags & self::IS_SET_SIZE) && ($font->_flags & self::IS_SET_SIZE))
5764
			$this->setSize($font->getSize());
5765
		if(!($this->_flags & self::IS_SET_NAME) && ($font->_flags & self::IS_SET_NAME))
5766
			$this->setName($font->getName());
5767
	}
5768
	public function copyFrom($font)
5769
	{
5770
		if($font===null || $font->_flags===0)
5771
			return;
5772
		if($font->_flags & self::IS_SET_BOLD)
5773
			$this->setBold($font->getBold());
5774
		if($font->_flags & self::IS_SET_ITALIC)
5775
			$this->setItalic($font->getItalic());
5776
		if($font->_flags & self::IS_SET_OVERLINE)
5777
			$this->setOverline($font->getOverline());
5778
		if($font->_flags & self::IS_SET_STRIKEOUT)
5779
			$this->setStrikeout($font->getStrikeout());
5780
		if($font->_flags & self::IS_SET_UNDERLINE)
5781
			$this->setUnderline($font->getUnderline());
5782
		if($font->_flags & self::IS_SET_SIZE)
5783
			$this->setSize($font->getSize());
5784
		if($font->_flags & self::IS_SET_NAME)
5785
			$this->setName($font->getName());
5786
	}
5787
	public function toString()
5788
	{
5789
		if($this->_flags===0)
5790
			return '';
5791
		$str='';
5792
		if($this->_flags & self::IS_SET_BOLD)
5793
			$str.='font-weight:'.(($this->_flags & self::IS_BOLD)?'bold;':'normal;');
5794
		if($this->_flags & self::IS_SET_ITALIC)
5795
			$str.='font-style:'.(($this->_flags & self::IS_ITALIC)?'italic;':'normal;');
5796
		$textDec='';
5797
		if($this->_flags & self::IS_UNDERLINE)
5798
			$textDec.='underline';
5799
		if($this->_flags & self::IS_OVERLINE)
5800
			$textDec.=' overline';
5801
		if($this->_flags & self::IS_STRIKEOUT)
5802
			$textDec.=' line-through';
5803
		$textDec=ltrim($textDec);
5804
		if($textDec!=='')
5805
			$str.='text-decoration:'.$textDec.';';
5806
		if($this->_size!=='')
5807
			$str.='font-size:'.$this->_size.';';
5808
		if($this->_name!=='')
5809
			$str.='font-family:'.$this->_name.';';
5810
		return $str;
5811
	}
5812
	public function addAttributesToRender($writer)
5813
	{
5814
		if($this->_flags===0)
5815
			return;
5816
		if($this->_flags & self::IS_SET_BOLD)
5817
			$writer->addStyleAttribute('font-weight',(($this->_flags & self::IS_BOLD)?'bold':'normal'));
5818
		if($this->_flags & self::IS_SET_ITALIC)
5819
			$writer->addStyleAttribute('font-style',(($this->_flags & self::IS_ITALIC)?'italic':'normal'));
5820
		$textDec='';
5821
		if($this->_flags & self::IS_UNDERLINE)
5822
			$textDec.='underline';
5823
		if($this->_flags & self::IS_OVERLINE)
5824
			$textDec.=' overline';
5825
		if($this->_flags & self::IS_STRIKEOUT)
5826
			$textDec.=' line-through';
5827
		$textDec=ltrim($textDec);
5828
		if($textDec!=='')
5829
			$writer->addStyleAttribute('text-decoration',$textDec);
5830
		if($this->_size!=='')
5831
			$writer->addStyleAttribute('font-size',$this->_size);
5832
		if($this->_name!=='')
5833
			$writer->addStyleAttribute('font-family',$this->_name);
5834
	}
5835
}
5836
class TStyle extends TComponent
5837
{
5838
	private $_fields=array();
5839
	private $_font=null;
5840
	private $_class=null;
5841
	private $_customStyle=null;
5842
	private $_displayStyle='Fixed';
5843
	public function __construct($style=null)
5844
	{
5845
		if($style!==null)
5846
			$this->copyFrom($style);
5847
	}
5848
	public function __clone()
5849
	{
5850
		if($this->_font!==null)
5851
			$this->_font = clone($this->_font);
5852
	}
5853
	public function getBackColor()
5854
	{
5855
		return isset($this->_fields['background-color'])?$this->_fields['background-color']:'';
5856
	}
5857
	public function setBackColor($value)
5858
	{
5859
		if(trim($value)==='')
5860
			unset($this->_fields['background-color']);
5861
		else
5862
			$this->_fields['background-color']=$value;
5863
	}
5864
	public function getBorderColor()
5865
	{
5866
		return isset($this->_fields['border-color'])?$this->_fields['border-color']:'';
5867
	}
5868
	public function setBorderColor($value)
5869
	{
5870
		if(trim($value)==='')
5871
			unset($this->_fields['border-color']);
5872
		else
5873
			$this->_fields['border-color']=$value;
5874
	}
5875
	public function getBorderStyle()
5876
	{
5877
		return isset($this->_fields['border-style'])?$this->_fields['border-style']:'';
5878
	}
5879
	public function setBorderStyle($value)
5880
	{
5881
		if(trim($value)==='')
5882
			unset($this->_fields['border-style']);
5883
		else
5884
			$this->_fields['border-style']=$value;
5885
	}
5886
	public function getBorderWidth()
5887
	{
5888
		return isset($this->_fields['border-width'])?$this->_fields['border-width']:'';
5889
	}
5890
	public function setBorderWidth($value)
5891
	{
5892
		if(trim($value)==='')
5893
			unset($this->_fields['border-width']);
5894
		else
5895
			$this->_fields['border-width']=$value;
5896
	}
5897
	public function getCssClass()
5898
	{
5899
		return $this->_class===null?'':$this->_class;
5900
	}
5901
	public function hasCssClass()
5902
	{
5903
		return ($this->_class!==null);
5904
	}
5905
	public function setCssClass($value)
5906
	{
5907
		$this->_class=$value;
5908
	}
5909
	public function getFont()
5910
	{
5911
		if($this->_font===null)
5912
			$this->_font=new TFont;
5913
		return $this->_font;
5914
	}
5915
	public function hasFont()
5916
	{
5917
		return $this->_font !== null;
5918
	}
5919
	public function setDisplayStyle($value)
5920
	{
5921
		$this->_displayStyle = TPropertyValue::ensureEnum($value, 'TDisplayStyle');
5922
		switch($this->_displayStyle)
5923
		{
5924
			case TDisplayStyle::None:
5925
				$this->_fields['display'] = 'none';
5926
				break;
5927
			case TDisplayStyle::Dynamic:
5928
				$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...
5929
			case TDisplayStyle::Fixed:
5930
				$this->_fields['visibility'] = 'visible';
5931
				break;
5932
			case TDisplayStyle::Hidden:
5933
				$this->_fields['visibility'] = 'hidden';
5934
				break;
5935
		}
5936
	}
5937
	public function getDisplayStyle()
5938
	{
5939
		return $this->_displayStyle;
5940
	}
5941
	public function getForeColor()
5942
	{
5943
		return isset($this->_fields['color'])?$this->_fields['color']:'';
5944
	}
5945
	public function setForeColor($value)
5946
	{
5947
		if(trim($value)==='')
5948
			unset($this->_fields['color']);
5949
		else
5950
			$this->_fields['color']=$value;
5951
	}
5952
	public function getHeight()
5953
	{
5954
		return isset($this->_fields['height'])?$this->_fields['height']:'';
5955
	}
5956
	public function setHeight($value)
5957
	{
5958
		if(trim($value)==='')
5959
			unset($this->_fields['height']);
5960
		else
5961
			$this->_fields['height']=$value;
5962
	}
5963
	public function getCustomStyle()
5964
	{
5965
		return $this->_customStyle===null?'':$this->_customStyle;
5966
	}
5967
	public function setCustomStyle($value)
5968
	{
5969
		$this->_customStyle=$value;
5970
	}
5971
	public function getStyleField($name)
5972
	{
5973
		return isset($this->_fields[$name])?$this->_fields[$name]:'';
5974
	}
5975
	public function setStyleField($name,$value)
5976
	{
5977
		$this->_fields[$name]=$value;
5978
	}
5979
	public function clearStyleField($name)
5980
	{
5981
		unset($this->_fields[$name]);
5982
	}
5983
	public function hasStyleField($name)
5984
	{
5985
		return isset($this->_fields[$name]);
5986
	}
5987
	public function getWidth()
5988
	{
5989
		return isset($this->_fields['width'])?$this->_fields['width']:'';
5990
	}
5991
	public function setWidth($value)
5992
	{
5993
		$this->_fields['width']=$value;
5994
	}
5995
	public function reset()
5996
	{
5997
		$this->_fields=array();
5998
		$this->_font=null;
5999
		$this->_class=null;
6000
		$this->_customStyle=null;
6001
	}
6002
	public function copyFrom($style)
6003
	{
6004
		if($style instanceof TStyle)
6005
		{
6006
			$this->_fields=array_merge($this->_fields,$style->_fields);
6007
			if($style->_class!==null)
6008
				$this->_class=$style->_class;
6009
			if($style->_customStyle!==null)
6010
				$this->_customStyle=$style->_customStyle;
6011
			if($style->_font!==null)
6012
				$this->getFont()->copyFrom($style->_font);
6013
		}
6014
	}
6015
	public function mergeWith($style)
6016
	{
6017
		if($style instanceof TStyle)
6018
		{
6019
			$this->_fields=array_merge($style->_fields,$this->_fields);
6020
			if($this->_class===null)
6021
				$this->_class=$style->_class;
6022
			if($this->_customStyle===null)
6023
				$this->_customStyle=$style->_customStyle;
6024
			if($style->_font!==null)
6025
				$this->getFont()->mergeWith($style->_font);
6026
		}
6027
	}
6028
	public function addAttributesToRender($writer)
6029
	{
6030
		if($this->_customStyle!==null)
6031
		{
6032
			foreach(explode(';',$this->_customStyle) as $style)
6033
			{
6034
				$arr=explode(':',$style,2);
6035
				if(isset($arr[1]) && trim($arr[0])!=='')
6036
					$writer->addStyleAttribute(trim($arr[0]),trim($arr[1]));
6037
			}
6038
		}
6039
		$writer->addStyleAttributes($this->_fields);
6040
		if($this->_font!==null)
6041
			$this->_font->addAttributesToRender($writer);
6042
		if($this->_class!==null)
6043
			$writer->addAttribute('class',$this->_class);
6044
	}
6045
	public function getStyleFields()
6046
	{
6047
		return $this->_fields;
6048
	}
6049
}
6050
class TDisplayStyle extends TEnumerable
6051
{
6052
	const None='None';
6053
	const Dynamic='Dynamic';
6054
	const Fixed='Fixed';
6055
	const Hidden='Hidden';
6056
}
6057
class TTableStyle extends TStyle
6058
{
6059
	private $_backImageUrl=null;
6060
	private $_horizontalAlign=null;
6061
	private $_cellPadding=null;
6062
	private $_cellSpacing=null;
6063
	private $_gridLines=null;
6064
	private $_borderCollapse=null;
6065
	public function reset()
6066
	{
6067
		$this->_backImageUrl=null;
6068
		$this->_horizontalAlign=null;
6069
		$this->_cellPadding=null;
6070
		$this->_cellSpacing=null;
6071
		$this->_gridLines=null;
6072
		$this->_borderCollapse=null;
6073
	}
6074
	public function copyFrom($style)
6075
	{
6076
		parent::copyFrom($style);
6077
		if($style instanceof TTableStyle)
6078
		{
6079
			if($style->_backImageUrl!==null)
6080
				$this->_backImageUrl=$style->_backImageUrl;
6081
			if($style->_horizontalAlign!==null)
6082
				$this->_horizontalAlign=$style->_horizontalAlign;
6083
			if($style->_cellPadding!==null)
6084
				$this->_cellPadding=$style->_cellPadding;
6085
			if($style->_cellSpacing!==null)
6086
				$this->_cellSpacing=$style->_cellSpacing;
6087
			if($style->_gridLines!==null)
6088
				$this->_gridLines=$style->_gridLines;
6089
			if($style->_borderCollapse!==null)
6090
				$this->_borderCollapse=$style->_borderCollapse;
6091
		}
6092
	}
6093
	public function mergeWith($style)
6094
	{
6095
		parent::mergeWith($style);
6096
		if($style instanceof TTableStyle)
6097
		{
6098
			if($this->_backImageUrl===null && $style->_backImageUrl!==null)
6099
				$this->_backImageUrl=$style->_backImageUrl;
6100
			if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
6101
				$this->_horizontalAlign=$style->_horizontalAlign;
6102
			if($this->_cellPadding===null && $style->_cellPadding!==null)
6103
				$this->_cellPadding=$style->_cellPadding;
6104
			if($this->_cellSpacing===null && $style->_cellSpacing!==null)
6105
				$this->_cellSpacing=$style->_cellSpacing;
6106
			if($this->_gridLines===null && $style->_gridLines!==null)
6107
				$this->_gridLines=$style->_gridLines;
6108
			if($this->_borderCollapse===null && $style->_borderCollapse!==null)
6109
				$this->_borderCollapse=$style->_borderCollapse;
6110
		}
6111
	}
6112
	public function addAttributesToRender($writer)
6113
	{
6114
		if(($url=trim($this->getBackImageUrl()))!=='')
6115
			$writer->addStyleAttribute('background-image','url('.$url.')');
6116
		if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
6117
			$writer->addStyleAttribute('text-align',strtolower($horizontalAlign));
6118
		if(($cellPadding=$this->getCellPadding())>=0)
6119
			$writer->addAttribute('cellpadding',"$cellPadding");
6120
		if(($cellSpacing=$this->getCellSpacing())>=0)
6121
			$writer->addAttribute('cellspacing',"$cellSpacing");
6122
		if($this->getBorderCollapse())
6123
			$writer->addStyleAttribute('border-collapse','collapse');
6124
		switch($this->getGridLines())
6125
		{
6126
			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...
6127
			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...
6128
			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...
6129
		}
6130
		parent::addAttributesToRender($writer);
6131
	}
6132
	public function getBackImageUrl()
6133
	{
6134
		return $this->_backImageUrl===null?'':$this->_backImageUrl;
6135
	}
6136
	public function setBackImageUrl($value)
6137
	{
6138
		$this->_backImageUrl=$value;
6139
	}
6140
	public function getHorizontalAlign()
6141
	{
6142
		return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
6143
	}
6144
	public function setHorizontalAlign($value)
6145
	{
6146
		$this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
6147
	}
6148
	public function getCellPadding()
6149
	{
6150
		return $this->_cellPadding===null?-1:$this->_cellPadding;
6151
	}
6152
	public function setCellPadding($value)
6153
	{
6154
		if(($this->_cellPadding=TPropertyValue::ensureInteger($value))<-1)
6155
			throw new TInvalidDataValueException('tablestyle_cellpadding_invalid');
6156
	}
6157
	public function getCellSpacing()
6158
	{
6159
		return $this->_cellSpacing===null?-1:$this->_cellSpacing;
6160
	}
6161
	public function setCellSpacing($value)
6162
	{
6163
		if(($this->_cellSpacing=TPropertyValue::ensureInteger($value))<-1)
6164
			throw new TInvalidDataValueException('tablestyle_cellspacing_invalid');
6165
	}
6166
	public function getGridLines()
6167
	{
6168
		return $this->_gridLines===null?TTableGridLines::None:$this->_gridLines;
6169
	}
6170
	public function setGridLines($value)
6171
	{
6172
		$this->_gridLines=TPropertyValue::ensureEnum($value,'TTableGridLines');
6173
	}
6174
	public function getBorderCollapse()
6175
	{
6176
		return $this->_borderCollapse===null?false:$this->_borderCollapse;
6177
	}
6178
	public function setBorderCollapse($value)
6179
	{
6180
		$this->_borderCollapse=TPropertyValue::ensureBoolean($value);
6181
	}
6182
}
6183
class TTableItemStyle extends TStyle
6184
{
6185
	private $_horizontalAlign=null;
6186
	private $_verticalAlign=null;
6187
	private $_wrap=null;
6188
	public function reset()
6189
	{
6190
		parent::reset();
6191
		$this->_verticalAlign=null;
6192
		$this->_horizontalAlign=null;
6193
		$this->_wrap=null;
6194
	}
6195
	public function copyFrom($style)
6196
	{
6197
		parent::copyFrom($style);
6198
		if($style instanceof TTableItemStyle)
6199
		{
6200
			if($this->_verticalAlign===null && $style->_verticalAlign!==null)
6201
				$this->_verticalAlign=$style->_verticalAlign;
6202
			if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
6203
				$this->_horizontalAlign=$style->_horizontalAlign;
6204
			if($this->_wrap===null && $style->_wrap!==null)
6205
				$this->_wrap=$style->_wrap;
6206
		}
6207
	}
6208
	public function mergeWith($style)
6209
	{
6210
		parent::mergeWith($style);
6211
		if($style instanceof TTableItemStyle)
6212
		{
6213
			if($style->_verticalAlign!==null)
6214
				$this->_verticalAlign=$style->_verticalAlign;
6215
			if($style->_horizontalAlign!==null)
6216
				$this->_horizontalAlign=$style->_horizontalAlign;
6217
			if($style->_wrap!==null)
6218
				$this->_wrap=$style->_wrap;
6219
		}
6220
	}
6221
	public function addAttributesToRender($writer)
6222
	{
6223
		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...
6224
			$writer->addStyleAttribute('white-space','nowrap');
6225
		if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
6226
			$writer->addAttribute('align',strtolower($horizontalAlign));
6227
		if(($verticalAlign=$this->getVerticalAlign())!==TVerticalAlign::NotSet)
6228
			$writer->addAttribute('valign',strtolower($verticalAlign));
6229
		parent::addAttributesToRender($writer);
6230
	}
6231
	public function getHorizontalAlign()
6232
	{
6233
		return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
6234
	}
6235
	public function setHorizontalAlign($value)
6236
	{
6237
		$this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
6238
	}
6239
	public function getVerticalAlign()
6240
	{
6241
		return $this->_verticalAlign===null?TVerticalAlign::NotSet:$this->_verticalAlign;
6242
	}
6243
	public function setVerticalAlign($value)
6244
	{
6245
		$this->_verticalAlign=TPropertyValue::ensureEnum($value,'TVerticalAlign');
6246
	}
6247
	public function getWrap()
6248
	{
6249
		return $this->_wrap===null?true:$this->_wrap;
6250
	}
6251
	public function setWrap($value)
6252
	{
6253
		$this->_wrap=TPropertyValue::ensureBoolean($value);
6254
	}
6255
}
6256
class THorizontalAlign extends TEnumerable
6257
{
6258
	const NotSet='NotSet';
6259
	const Left='Left';
6260
	const Right='Right';
6261
	const Center='Center';
6262
	const Justify='Justify';
6263
}
6264
class TVerticalAlign extends TEnumerable
6265
{
6266
	const NotSet='NotSet';
6267
	const Top='Top';
6268
	const Bottom='Bottom';
6269
	const Middle='Middle';
6270
}
6271
class TTableGridLines extends TEnumerable
6272
{
6273
	const None='None';
6274
	const Horizontal='Horizontal';
6275
	const Vertical='Vertical';
6276
	const Both='Both';
6277
}
6278
class TWebControlAdapter extends TControlAdapter
6279
{
6280
	public function render($writer)
6281
	{
6282
		$this->renderBeginTag($writer);
6283
		$this->renderContents($writer);
6284
		$this->renderEndTag($writer);
6285
	}
6286
	public function renderBeginTag($writer)
6287
	{
6288
		$this->getControl()->renderBeginTag($writer);
6289
	}
6290
	public function renderContents($writer)
6291
	{
6292
		$this->getControl()->renderContents($writer);
6293
	}
6294
	public function renderEndTag($writer)
6295
	{
6296
		$this->getControl()->renderEndTag($writer);
6297
	}
6298
}
6299
class TWebControlDecorator extends TComponent {
6300
	private $_internalonly;
6301
	private $_usestate = false;
6302
	private $_control;
6303
	private $_outercontrol;
6304
	private $_addedTemplateDecoration=false;
6305
	private $_pretagtext = '';
6306
	private $_precontentstext = '';
6307
	private $_postcontentstext = '';
6308
	private $_posttagtext = '';
6309
	private $_pretagtemplate;
6310
	private $_precontentstemplate;
6311
	private $_postcontentstemplate;
6312
	private $_posttagtemplate;
6313
	public function __construct($control, $onlyinternal = false) {
6314
		$this->_control = $control;
6315
		$this->_internalonly = $onlyinternal;
6316
	}
6317
	public function getUseState()
6318
	{
6319
		return $this->_usestate;
6320
	}
6321
	public function setUseState($value)
6322
	{
6323
		$this->_usestate = TPropertyValue::ensureBoolean($value);
6324
	}
6325
	public function getPreTagText() {
6326
		return $this->_pretagtext;
6327
	}
6328
	public function setPreTagText($value) {
6329
		if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
6330
			$this->_pretagtext = TPropertyValue::ensureString($value);
6331
	}
6332
	public function getPreContentsText() {
6333
		return $this->_precontentstext;
6334
	}
6335
	public function setPreContentsText($value) {
6336
		if(!$this->_control->getIsSkinApplied())
6337
			$this->_precontentstext = TPropertyValue::ensureString($value);
6338
	}
6339
	public function getPostContentsText() {
6340
		return $this->_postcontentstext;
6341
	}
6342
	public function setPostContentsText($value) {
6343
		if(!$this->_control->getIsSkinApplied())
6344
			$this->_postcontentstext = TPropertyValue::ensureString($value);
6345
	}
6346
	public function getPostTagText() {
6347
		return $this->_posttagtext;
6348
	}
6349
	public function setPostTagText($value) {
6350
		if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
6351
			$this->_posttagtext = TPropertyValue::ensureString($value);
6352
	}
6353
	public function getPreTagTemplate() {
6354
		return $this->_pretagtemplate;
6355
	}
6356
	public function setPreTagTemplate($value) {
6357
		if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
6358
			$this->_pretagtemplate = $value;
6359
	}
6360
	public function getPreContentsTemplate() {
6361
		return $this->_precontentstemplate;
6362
	}
6363
	public function setPreContentsTemplate($value) {
6364
		if(!$this->_control->getIsSkinApplied())
6365
			$this->_precontentstemplate = $value;
6366
	}
6367
	public function getPostContentsTemplate() {
6368
		return $this->_postcontentstemplate;
6369
	}
6370
	public function setPostContentsTemplate($value) {
6371
		if(!$this->_control->getIsSkinApplied())
6372
			$this->_postcontentstemplate = $value;
6373
	}
6374
	public function getPostTagTemplate() {
6375
		return $this->_posttagtemplate;
6376
	}
6377
	public function setPostTagTemplate($value) {
6378
		if(!$this->_internalonly && !$this->_control->getIsSkinApplied())
6379
			$this->_posttagtemplate = $value;
6380
	}
6381
	public function instantiate($outercontrol = null) {
6382
		if($this->getPreTagTemplate() || $this->getPreContentsTemplate() ||
6383
			$this->getPostContentsTemplate() || $this->getPostTagTemplate()) {
6384
			$this->_outercontrol = $outercontrol;
6385
			if($this->getUseState())
6386
				$this->ensureTemplateDecoration();
6387
			else
6388
				$this->_control->getPage()->onSaveStateComplete[] = array($this, 'ensureTemplateDecoration');
6389
		}
6390
	}
6391
	public function ensureTemplateDecoration($sender=null, $param=null) {
6392
		$control = $this->_control;
6393
		$outercontrol = $this->_outercontrol;
6394
		if($outercontrol === null)
6395
			$outercontrol = $control;
6396
		if($this->_addedTemplateDecoration)
6397
			return $this->_addedTemplateDecoration;
6398
		$this->_addedTemplateDecoration = true;
6399
		if($this->getPreContentsTemplate())
6400
		{
6401
			$precontents = Prado::createComponent('TCompositeControl');
6402
			$this->getPreContentsTemplate()->instantiateIn($precontents);
6403
			$control->getControls()->insertAt(0, $precontents);
6404
		}
6405
		if($this->getPostContentsTemplate())
6406
		{
6407
			$postcontents = Prado::createComponent('TCompositeControl');
6408
			$this->getPostContentsTemplate()->instantiateIn($postcontents);
6409
			$control->getControls()->add($postcontents);
6410
		}
6411
		if(!$outercontrol->getParent())
6412
			return $this->_addedTemplateDecoration;
6413
		if($this->getPreTagTemplate())
6414
		{
6415
			$pretag = Prado::createComponent('TCompositeControl');
6416
			$this->getPreTagTemplate()->instantiateIn($pretag);
6417
			$outercontrol->getParent()->getControls()->insertBefore($outercontrol, $pretag);
6418
		}
6419
		if($this->getPostTagTemplate())
6420
		{
6421
			$posttag = Prado::createComponent('TCompositeControl');
6422
			$this->getPostTagTemplate()->instantiateIn($posttag);
6423
			$outercontrol->getParent()->getControls()->insertAfter($outercontrol, $posttag);
6424
		}
6425
		return true;
6426
	}
6427
	public function renderPreTagText($writer) {
6428
		$writer->write($this->getPreTagText());
6429
	}
6430
	public function renderPreContentsText($writer) {
6431
		$writer->write($this->getPreContentsText());
6432
	}
6433
	public function renderPostContentsText($writer) {
6434
		$writer->write($this->getPostContentsText());
6435
	}
6436
	public function renderPostTagText($writer) {
6437
		$writer->write($this->getPostTagText());
6438
	}
6439
}
6440
class TWebControl extends TControl implements IStyleable
6441
{
6442
	private $_ensureid=false;
6443
	protected $_decorator;
6444
	public function setEnsureId($value)
6445
	{
6446
		$this->_ensureid |= TPropertyValue::ensureBoolean($value);
6447
	}
6448
	public function getEnsureId()
6449
	{
6450
		return $this->_ensureid;
6451
	}
6452
	public function getDecorator($create=true)
6453
	{
6454
		if($create && !$this->_decorator)
6455
			$this->_decorator = Prado::createComponent('TWebControlDecorator', $this);
6456
		return $this->_decorator;
6457
	}
6458
	public function copyBaseAttributes(TWebControl $control)
6459
	{
6460
		$this->setAccessKey($control->getAccessKey());
6461
		$this->setToolTip($control->getToolTip());
6462
		$this->setTabIndex($control->getTabIndex());
6463
		if(!$control->getEnabled())
6464
			$this->setEnabled(false);
6465
		if($control->getHasAttributes())
6466
			$this->getAttributes()->copyFrom($control->getAttributes());
6467
	}
6468
	public function getAccessKey()
6469
	{
6470
		return $this->getViewState('AccessKey','');
6471
	}
6472
	public function setAccessKey($value)
6473
	{
6474
		if(strlen($value)>1)
6475
			throw new TInvalidDataValueException('webcontrol_accesskey_invalid',get_class($this),$value);
6476
		$this->setViewState('AccessKey',$value,'');
6477
	}
6478
	public function getBackColor()
6479
	{
6480
		if($style=$this->getViewState('Style',null))
6481
			return $style->getBackColor();
6482
		else
6483
			return '';
6484
	}
6485
	public function setBackColor($value)
6486
	{
6487
		$this->getStyle()->setBackColor($value);
6488
	}
6489
	public function getBorderColor()
6490
	{
6491
		if($style=$this->getViewState('Style',null))
6492
			return $style->getBorderColor();
6493
		else
6494
			return '';
6495
	}
6496
	public function setBorderColor($value)
6497
	{
6498
		$this->getStyle()->setBorderColor($value);
6499
	}
6500
	public function getBorderStyle()
6501
	{
6502
		if($style=$this->getViewState('Style',null))
6503
			return $style->getBorderStyle();
6504
		else
6505
			return '';
6506
	}
6507
	public function setBorderStyle($value)
6508
	{
6509
		$this->getStyle()->setBorderStyle($value);
6510
	}
6511
	public function getBorderWidth()
6512
	{
6513
		if($style=$this->getViewState('Style',null))
6514
			return $style->getBorderWidth();
6515
		else
6516
			return '';
6517
	}
6518
	public function setBorderWidth($value)
6519
	{
6520
		$this->getStyle()->setBorderWidth($value);
6521
	}
6522
	public function getFont()
6523
	{
6524
		return $this->getStyle()->getFont();
6525
	}
6526
	public function getForeColor()
6527
	{
6528
		if($style=$this->getViewState('Style',null))
6529
			return $style->getForeColor();
6530
		else
6531
			return '';
6532
	}
6533
	public function setForeColor($value)
6534
	{
6535
		$this->getStyle()->setForeColor($value);
6536
	}
6537
	public function getHeight()
6538
	{
6539
		if($style=$this->getViewState('Style',null))
6540
			return $style->getHeight();
6541
		else
6542
			return '';
6543
	}
6544
	public function setDisplay($value)
6545
	{
6546
		$this->getStyle()->setDisplayStyle($value);
6547
	}
6548
	public function getDisplay()
6549
	{
6550
		return $this->getStyle()->getDisplayStyle();
6551
	}
6552
	public function setCssClass($value)
6553
	{
6554
		$this->getStyle()->setCssClass($value);
6555
	}
6556
	public function getCssClass()
6557
	{
6558
		if($style=$this->getViewState('Style',null))
6559
			return $style->getCssClass();
6560
		else
6561
			return '';
6562
	}
6563
	public function setHeight($value)
6564
	{
6565
		$this->getStyle()->setHeight($value);
6566
	}
6567
	public function getHasStyle()
6568
	{
6569
		return $this->getViewState('Style',null)!==null;
6570
	}
6571
	protected function createStyle()
6572
	{
6573
		return new TStyle;
6574
	}
6575
	public function getStyle()
6576
	{
6577
		if($style=$this->getViewState('Style',null))
6578
			return $style;
6579
		else
6580
		{
6581
			$style=$this->createStyle();
6582
			$this->setViewState('Style',$style,null);
6583
			return $style;
6584
		}
6585
	}
6586
	public function setStyle($value)
6587
	{
6588
		if(is_string($value))
6589
			$this->getStyle()->setCustomStyle($value);
6590
		else
6591
			throw new TInvalidDataValueException('webcontrol_style_invalid',get_class($this));
6592
	}
6593
	public function clearStyle()
6594
	{
6595
		$this->clearViewState('Style');
6596
	}
6597
	public function getTabIndex()
6598
	{
6599
		return $this->getViewState('TabIndex',0);
6600
	}
6601
	public function setTabIndex($value)
6602
	{
6603
		$this->setViewState('TabIndex',TPropertyValue::ensureInteger($value),0);
6604
	}
6605
	protected function getTagName()
6606
	{
6607
		return 'span';
6608
	}
6609
	public function getToolTip()
6610
	{
6611
		return $this->getViewState('ToolTip','');
6612
	}
6613
	public function setToolTip($value)
6614
	{
6615
		$this->setViewState('ToolTip',$value,'');
6616
	}
6617
	public function getWidth()
6618
	{
6619
		if($style=$this->getViewState('Style',null))
6620
			return $style->getWidth();
6621
		else
6622
			return '';
6623
	}
6624
	public function setWidth($value)
6625
	{
6626
		$this->getStyle()->setWidth($value);
6627
	}
6628
	public function onPreRender($param) {
6629
		if($decorator = $this->getDecorator(false))
6630
			$decorator->instantiate();
6631
		parent::onPreRender($param);
6632
	}
6633
	protected function addAttributesToRender($writer)
6634
	{
6635
		if($this->getID()!=='' || $this->getEnsureId())
6636
			$writer->addAttribute('id',$this->getClientID());
6637
		if(($accessKey=$this->getAccessKey())!=='')
6638
			$writer->addAttribute('accesskey',$accessKey);
6639
		if(!$this->getEnabled())
6640
			$writer->addAttribute('disabled','disabled');
6641
		if(($tabIndex=$this->getTabIndex())>0)
6642
			$writer->addAttribute('tabindex',"$tabIndex");
6643
		if(($toolTip=$this->getToolTip())!=='')
6644
			$writer->addAttribute('title',$toolTip);
6645
		if($style=$this->getViewState('Style',null))
6646
			$style->addAttributesToRender($writer);
6647
		if($this->getHasAttributes())
6648
		{
6649
			foreach($this->getAttributes() as $name=>$value)
6650
				$writer->addAttribute($name,$value);
6651
		}
6652
	}
6653
	public function render($writer)
6654
	{
6655
		$this->renderBeginTag($writer);
6656
		$this->renderContents($writer);
6657
		$this->renderEndTag($writer);
6658
	}
6659
	public function renderBeginTag($writer)
6660
	{
6661
		if($decorator = $this->getDecorator(false)) {
6662
			$decorator->renderPreTagText($writer);
6663
			$this->addAttributesToRender($writer);
6664
			$writer->renderBeginTag($this->getTagName());
6665
			$decorator->renderPreContentsText($writer);
6666
		} else {
6667
			$this->addAttributesToRender($writer);
6668
			$writer->renderBeginTag($this->getTagName());
6669
		}
6670
	}
6671
	public function renderContents($writer)
6672
	{
6673
		parent::renderChildren($writer);
1 ignored issue
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (renderChildren() instead of renderContents()). Are you sure this is correct? If so, you might want to change this to $this->renderChildren().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
6674
	}
6675
	public function renderEndTag($writer)
6676
	{
6677
		if($decorator = $this->getDecorator(false)) {
6678
			$decorator->renderPostContentsText($writer);
6679
			$writer->renderEndTag();
6680
			$decorator->renderPostTagText($writer);
6681
		} else
6682
			$writer->renderEndTag($writer);
6683
	}
6684
}
6685
class TCompositeControl extends TControl implements INamingContainer
6686
{
6687
	protected function initRecursive($namingContainer=null)
6688
	{
6689
		$this->ensureChildControls();
6690
		parent::initRecursive($namingContainer);
6691
	}
6692
}
6693
class TTemplateControl extends TCompositeControl
6694
{
6695
	const EXT_TEMPLATE='.tpl';
6696
	private static $_template=array();
6697
	private $_localTemplate=null;
6698
	private $_master=null;
6699
	private $_masterClass='';
6700
	private $_contents=array();
6701
	private $_placeholders=array();
6702
	public function getTemplate()
6703
	{
6704
		if($this->_localTemplate===null)
6705
		{
6706
			$class=get_class($this);
6707
			if(!isset(self::$_template[$class]))
6708
				self::$_template[$class]=$this->loadTemplate();
6709
			return self::$_template[$class];
6710
		}
6711
		else
6712
			return $this->_localTemplate;
6713
	}
6714
	public function setTemplate($value)
6715
	{
6716
		$this->_localTemplate=$value;
6717
	}
6718
	public function getIsSourceTemplateControl()
6719
	{
6720
		if(($template=$this->getTemplate())!==null)
6721
			return $template->getIsSourceTemplate();
6722
		else
6723
			return false;
6724
	}
6725
	public function getTemplateDirectory()
6726
	{
6727
		if(($template=$this->getTemplate())!==null)
6728
			return $template->getContextPath();
6729
		else
6730
			return '';
6731
	}
6732
	protected function loadTemplate()
6733
	{
6734
		$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...
6735
		return $template;
6736
	}
6737
	public function createChildControls()
6738
	{
6739
		if($tpl=$this->getTemplate())
6740
		{
6741
			foreach($tpl->getDirective() as $name=>$value)
6742
			{
6743
				if(is_string($value))
6744
					$this->setSubProperty($name,$value);
6745
				else
6746
					throw new TConfigurationException('templatecontrol_directive_invalid',get_class($this),$name);
6747
			}
6748
			$tpl->instantiateIn($this);
6749
		}
6750
	}
6751
	public function registerContent($id,TContent $object)
6752
	{
6753
		if(isset($this->_contents[$id]))
6754
			throw new TConfigurationException('templatecontrol_contentid_duplicated',$id);
6755
		else
6756
			$this->_contents[$id]=$object;
6757
	}
6758
	public function registerContentPlaceHolder($id,TContentPlaceHolder $object)
6759
	{
6760
		if(isset($this->_placeholders[$id]))
6761
			throw new TConfigurationException('templatecontrol_placeholderid_duplicated',$id);
6762
		else
6763
			$this->_placeholders[$id]=$object;
6764
	}
6765
	public function getMasterClass()
6766
	{
6767
		return $this->_masterClass;
6768
	}
6769
	public function setMasterClass($value)
6770
	{
6771
		$this->_masterClass=$value;
6772
	}
6773
	public function getMaster()
6774
	{
6775
		return $this->_master;
6776
	}
6777
	public function injectContent($id,$content)
6778
	{
6779
		if(isset($this->_placeholders[$id]))
6780
		{
6781
			$placeholder=$this->_placeholders[$id];
6782
			$controls=$placeholder->getParent()->getControls();
6783
			$loc=$controls->remove($placeholder);
6784
			$controls->insertAt($loc,$content);
6785
		}
6786
		else
6787
			throw new TConfigurationException('templatecontrol_placeholder_inexistent',$id);
6788
	}
6789
	protected function initRecursive($namingContainer=null)
6790
	{
6791
		$this->ensureChildControls();
6792
		if($this->_masterClass!=='')
6793
		{
6794
			$master=Prado::createComponent($this->_masterClass);
6795
			if(!($master instanceof TTemplateControl))
6796
				throw new TInvalidDataValueException('templatecontrol_mastercontrol_invalid');
6797
			$this->_master=$master;
6798
			$this->getControls()->clear();
6799
			$this->getControls()->add($master);
6800
			$master->ensureChildControls();
6801
			foreach($this->_contents as $id=>$content)
6802
				$master->injectContent($id,$content);
6803
		}
6804
		else if(!empty($this->_contents))
6805
			throw new TConfigurationException('templatecontrol_mastercontrol_required',get_class($this));
6806
		parent::initRecursive($namingContainer);
6807
	}
6808
        public function tryToUpdateView($arObj, $throwExceptions = false)
6809
        {
6810
                $objAttrs = get_class_vars(get_class($arObj));
6811
                foreach (array_keys($objAttrs) as $key)
6812
                {
6813
                        try
6814
                        {
6815
                                if ($key != "RELATIONS")
6816
                                {
6817
                                        $control = $this->{$key};
6818
                                        if ($control instanceof TTextBox)
6819
                                                $control->Text = $arObj->{$key};
6820
                                        elseif ($control instanceof TCheckBox)
6821
                                                $control->Checked = (boolean) $arObj->{$key};
6822
                                        elseif ($control instanceof TDatePicker)
6823
                                                $control->Date = $arObj->{$key};
6824
                                }
6825
                                else
6826
                                {
6827
                                        foreach ($objAttrs["RELATIONS"] as $relKey => $relValues)
6828
                                        {
6829
                                                $relControl = $this->{$relKey};
6830
                                                switch ($relValues[0])
6831
                                                {
6832
                                                        case TActiveRecord::BELONGS_TO:
6833
                                                        case TActiveRecord::HAS_ONE:
6834
                                                                $relControl->Text = $arObj->{$relKey};
6835
                                                                break;
6836
                                                        case TActiveRecord::HAS_MANY:
6837
                                                                if ($relControl instanceof TListControl)
6838
                                                                {
6839
                                                                        $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...
6840
                                                                        $relControl->dataBind();
6841
                                                                }
6842
                                                                break;
6843
                                                }
6844
                                        }
6845
                                        break;
6846
                                }
6847
                        } 
6848
                        catch (Exception $ex)
6849
                        {
6850
                                if ($throwExceptions)
6851
                                        throw $ex;
6852
                        }
6853
                }
6854
        }
6855
        public function tryToUpdateAR($arObj, $throwExceptions = false)
6856
        {
6857
                $objAttrs = get_class_vars(get_class($arObj));
6858
                foreach (array_keys($objAttrs) as $key)
6859
                {
6860
                        try
6861
                        {
6862
                                if ($key == "RELATIONS")
6863
                                        break;
6864
                                $control = $this->{$key};
6865
                                if ($control instanceof TTextBox)
6866
                                        $arObj->{$key} = $control->Text;
6867
                                elseif ($control instanceof TCheckBox)
6868
                                        $arObj->{$key} = $control->Checked;
6869
                                elseif ($control instanceof TDatePicker)
6870
                                        $arObj->{$key} = $control->Date;
6871
                        } 
6872
                        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...
6873
                        {
6874
                                if ($throwExceptions)
0 ignored issues
show
Bug introduced by
The variable $throwExceptions seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

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

Let’s take a look at a simple example:

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

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

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

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

Loading history...
6875
                                        throw $ex;
6876
                        }
6877
                }
6878
        }
6879
}
6880
class TForm extends TControl
6881
{
6882
	public function onInit($param)
6883
	{
6884
		parent::onInit($param);
6885
		$this->getPage()->setForm($this);
6886
	}
6887
	protected function addAttributesToRender($writer)
6888
	{
6889
		$writer->addAttribute('id',$this->getClientID());
6890
		$writer->addAttribute('method',$this->getMethod());
6891
		$uri=$this->getRequest()->getRequestURI();
6892
		$writer->addAttribute('action',str_replace('&','&amp;',str_replace('&amp;','&',$uri)));
6893
		if(($enctype=$this->getEnctype())!=='')
6894
			$writer->addAttribute('enctype',$enctype);
6895
		$attributes=$this->getAttributes();
6896
		$attributes->remove('action');
6897
		$writer->addAttributes($attributes);
6898
		if(($butt=$this->getDefaultButton())!=='')
6899
		{
6900
			if(($button=$this->findControl($butt))!==null)
6901
				$this->getPage()->getClientScript()->registerDefaultButton($this, $button);
6902
			else
6903
				throw new TInvalidDataValueException('form_defaultbutton_invalid',$butt);
6904
		}
6905
	}
6906
	public function render($writer)
6907
	{
6908
		$page=$this->getPage();
6909
		$this->addAttributesToRender($writer);
6910
		$writer->renderBeginTag('form');
6911
		$cs=$page->getClientScript();
6912
		if($page->getClientSupportsJavaScript())
6913
		{
6914
			$cs->renderHiddenFieldsBegin($writer);
6915
			$cs->renderScriptFilesBegin($writer);
6916
			$cs->renderBeginScripts($writer);
6917
 			$page->beginFormRender($writer);
6918
 			$this->renderChildren($writer);
6919
			$cs->renderHiddenFieldsEnd($writer);
6920
 			$page->endFormRender($writer);
6921
			$cs->renderScriptFilesEnd($writer);
6922
			$cs->renderEndScripts($writer);
6923
		}
6924
		else
6925
		{
6926
			$cs->renderHiddenFieldsBegin($writer);
6927
			$page->beginFormRender($writer);
6928
			$this->renderChildren($writer);
6929
			$page->endFormRender($writer);
6930
			$cs->renderHiddenFieldsEnd($writer);
6931
		}
6932
		$writer->renderEndTag();
6933
	}
6934
	public function getDefaultButton()
6935
	{
6936
		return $this->getViewState('DefaultButton','');
6937
	}
6938
	public function setDefaultButton($value)
6939
	{
6940
		$this->setViewState('DefaultButton',$value,'');
6941
	}
6942
	public function getMethod()
6943
	{
6944
		return $this->getViewState('Method','post');
6945
	}
6946
	public function setMethod($value)
6947
	{
6948
		$this->setViewState('Method',TPropertyValue::ensureEnum($value,'post','get'),'post');
6949
	}
6950
	public function getEnctype()
6951
	{
6952
		return $this->getViewState('Enctype','');
6953
	}
6954
	public function setEnctype($value)
6955
	{
6956
		$this->setViewState('Enctype',$value,'');
6957
	}
6958
	public function getName()
6959
	{
6960
		return $this->getUniqueID();
6961
	}
6962
}
6963
class TClientScriptManager extends TApplicationComponent
6964
{
6965
	const SCRIPT_PATH='Web/Javascripts/source';
6966
	const PACKAGES_FILE='Web/Javascripts/packages.php';
6967
	private $_page;
6968
	private $_hiddenFields=array();
6969
	private $_beginScripts=array();
6970
	private $_endScripts=array();
6971
	private $_scriptFiles=array();
6972
	private $_headScriptFiles=array();
6973
	private $_headScripts=array();
6974
	private $_styleSheetFiles=array();
6975
	private $_styleSheets=array();
6976
	private $_registeredPradoScripts=array();
6977
	private static $_pradoScripts;
6978
	private static $_pradoPackages;
6979
	private $_renderedHiddenFields;
6980
	private $_renderedScriptFiles=array();
6981
	private $_expandedPradoScripts;
6982
	public function __construct(TPage $owner)
6983
	{
6984
		$this->_page=$owner;
6985
	}
6986
	public function getRequiresHead()
6987
	{
6988
		return count($this->_styleSheetFiles) || count($this->_styleSheets)
6989
			|| count($this->_headScriptFiles) || count($this->_headScripts);
6990
	}
6991
	public static function getPradoPackages()
6992
	{
6993
		return self::$_pradoPackages;
6994
	}
6995
	public static function getPradoScripts()
6996
	{
6997
		return self::$_pradoScripts;
6998
	}
6999
	public function registerPradoScript($name)
7000
	{
7001
		$this->registerPradoScriptInternal($name);
7002
		$params=func_get_args();
7003
		$this->_page->registerCachingAction('Page.ClientScript','registerPradoScript',$params);
7004
	}
7005
	protected function registerPradoScriptInternal($name)
7006
	{
7007
				if(!isset($this->_registeredPradoScripts[$name]))
7008
		{
7009
			if(self::$_pradoScripts === null)
7010
			{
7011
				$packageFile = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::PACKAGES_FILE;
7012
				list($packages,$deps)= include($packageFile);
7013
				self::$_pradoScripts = $deps;
7014
				self::$_pradoPackages = $packages;
7015
			}
7016
			if (isset(self::$_pradoScripts[$name]))
7017
				$this->_registeredPradoScripts[$name]=true;
7018
			else
7019
				throw new TInvalidOperationException('csmanager_pradoscript_invalid',$name);
7020
			if(($packages=array_keys($this->_registeredPradoScripts))!==array())
7021
			{
7022
				$base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
7023
				list($path,$baseUrl)=$this->getPackagePathUrl($base);
7024
				$packagesUrl=array();
7025
				$isDebug=$this->getApplication()->getMode()===TApplicationMode::Debug;
7026
				foreach ($packages as $p)
7027
				{
7028
					foreach (self::$_pradoScripts[$p] as $dep)
7029
					{
7030
						foreach (self::$_pradoPackages[$dep] as $script)
7031
						if (!isset($this->_expandedPradoScripts[$script]))
7032
						{
7033
							$this->_expandedPradoScripts[$script] = true;
7034
							if($isDebug)
7035
							{
7036
								if (!in_array($url=$baseUrl.'/'.$script,$packagesUrl))
7037
									$packagesUrl[]=$url;
7038
							} else {
7039
								if (!in_array($url=$baseUrl.'/min/'.$script,$packagesUrl))
7040
								{
7041
									if(!is_file($filePath=$path.'/min/'.$script))
7042
									{
7043
										$dirPath=dirname($filePath);
7044
										if(!is_dir($dirPath))
7045
											mkdir($dirPath, PRADO_CHMOD, true);
7046
										file_put_contents($filePath, TJavaScript::JSMin(file_get_contents($base.'/'.$script)));
7047
										chmod($filePath, PRADO_CHMOD);
7048
									}
7049
									$packagesUrl[]=$url;
7050
								}
7051
							}
7052
						}
7053
					}
7054
				}
7055
				foreach($packagesUrl as $url)
7056
					$this->registerScriptFile($url,$url);
7057
			}
7058
		}
7059
	}
7060
	public function getPradoScriptAssetUrl()
7061
	{
7062
		$base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH;
7063
		$assets = Prado::getApplication()->getAssetManager();
7064
		return $assets->getPublishedUrl($base);
7065
	}
7066
	public function getScriptUrls()
7067
	{
7068
		$scripts = array_values($this->_headScriptFiles);
7069
		$scripts = array_merge($scripts, array_values($this->_scriptFiles));
7070
		$scripts = array_unique($scripts);
7071
		return $scripts;
7072
	}
7073
	protected function getPackagePathUrl($base)
7074
	{
7075
		$assets = Prado::getApplication()->getAssetManager();
7076
		if(strpos($base, $assets->getBaseUrl())===false)
7077
		{
7078
			if(($dir = Prado::getPathOfNameSpace($base)) !== null) {
7079
				$base = $dir;
7080
			}
7081
			return array($assets->getPublishedPath($base), $assets->publishFilePath($base));
7082
		}
7083
		else
7084
		{
7085
			return array($assets->getBasePath().str_replace($assets->getBaseUrl(),'',$base), $base);
7086
		}
7087
	}
7088
	public function getCallbackReference(ICallbackEventHandler $callbackHandler, $options=null)
7089
	{
7090
		$options = !is_array($options) ? array() : $options;
7091
		$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...
7092
		$clientSide = $callbackHandler->getActiveControl()->getClientSide();
7093
		$options = array_merge($options, $clientSide->getOptions()->toArray());
7094
		$optionString = TJavaScript::encode($options);
7095
		$this->registerPradoScriptInternal('ajax');
7096
		$id = $callbackHandler->getUniqueID();
7097
		return "new Prado.CallbackRequest('{$id}',{$optionString})";
7098
	}
7099
	public function registerCallbackControl($class, $options)
7100
	{
7101
		$optionString=TJavaScript::encode($options);
7102
		$code="new {$class}({$optionString});";
7103
		$this->_endScripts[sprintf('%08X', crc32($code))]=$code;
7104
		$this->registerPradoScriptInternal('ajax');
7105
		$params=func_get_args();
7106
		$this->_page->registerCachingAction('Page.ClientScript','registerCallbackControl',$params);
7107
	}
7108
	public function registerPostBackControl($class,$options)
7109
	{
7110
		if($class === null) {
7111
			return;
7112
		}
7113
		if(!isset($options['FormID']) && ($form=$this->_page->getForm())!==null)
7114
			$options['FormID']=$form->getClientID();
7115
		$optionString=TJavaScript::encode($options);
7116
		$code="new {$class}({$optionString});";
7117
		$this->_endScripts[sprintf('%08X', crc32($code))]=$code;
7118
		$this->registerPradoScriptInternal('prado');
7119
		$params=func_get_args();
7120
		$this->_page->registerCachingAction('Page.ClientScript','registerPostBackControl',$params);
7121
	}
7122
	public function registerDefaultButton($panel, $button)
7123
	{
7124
		$panelID=is_string($panel)?$panel:$panel->getUniqueID();
7125
		if(is_string($button))
7126
			$buttonID=$button;
7127
		else
7128
		{
7129
			$button->setIsDefaultButton(true);
7130
			$buttonID=$button->getUniqueID();
7131
		}
7132
		$options = TJavaScript::encode($this->getDefaultButtonOptions($panelID, $buttonID));
7133
		$code = "new Prado.WebUI.DefaultButton($options);";
7134
		$this->_endScripts['prado:'.$panelID]=$code;
7135
		$this->registerPradoScriptInternal('prado');
7136
		$params=array($panelID,$buttonID);
7137
		$this->_page->registerCachingAction('Page.ClientScript','registerDefaultButton',$params);
7138
	}
7139
	protected function getDefaultButtonOptions($panelID, $buttonID)
7140
	{
7141
		$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...
7142
		$options['Panel'] = TControl::convertUniqueIdToClientId($panelID);
7143
		$options['Target'] = TControl::convertUniqueIdToClientId($buttonID);
7144
		$options['EventTarget'] = $buttonID;
7145
		$options['Event'] = 'click';
7146
		return $options;
7147
	}
7148
	public function registerFocusControl($target)
7149
	{
7150
		$this->registerPradoScriptInternal('jquery');
7151
		if($target instanceof TControl)
7152
			$target=$target->getClientID();
7153
		$this->_endScripts['prado:focus'] = 'jQuery(\'#'.$target.'\').focus();';
7154
		$params=func_get_args();
7155
		$this->_page->registerCachingAction('Page.ClientScript','registerFocusControl',$params);
7156
	}
7157
	public function registerStyleSheetFile($key,$url,$media='')
7158
	{
7159
		if($media==='')
7160
			$this->_styleSheetFiles[$key]=$url;
7161
		else
7162
			$this->_styleSheetFiles[$key]=array($url,$media);
7163
		$params=func_get_args();
7164
		$this->_page->registerCachingAction('Page.ClientScript','registerStyleSheetFile',$params);
7165
	}
7166
	public function registerStyleSheet($key,$css,$media='')
7167
	{
7168
		$this->_styleSheets[$key]=$css;
7169
		$params=func_get_args();
7170
		$this->_page->registerCachingAction('Page.ClientScript','registerStyleSheet',$params);
7171
	}
7172
	public function getStyleSheetUrls()
7173
	{
7174
		$stylesheets = array_values(
7175
			array_map(
7176
				create_function('$e', 'return is_array($e) ? $e[0] : $e;'),
0 ignored issues
show
Security Best Practice introduced by
The use of create_function is highly discouraged, better use a closure.

create_function can pose a great security vulnerability as it is similar to eval, and could be used for arbitrary code execution. We highly recommend to use a closure instead.

// Instead of
$function = create_function('$a, $b', 'return $a + $b');

// Better use
$function = function($a, $b) { return $a + $b; }
Loading history...
7177
				$this->_styleSheetFiles)
7178
		);
7179
		foreach(Prado::getApplication()->getAssetManager()->getPublished() as $path=>$url)
7180
			if (substr($url,strlen($url)-4)=='.css')
7181
				$stylesheets[] = $url;
7182
		$stylesheets = array_unique($stylesheets);
7183
		return $stylesheets;
7184
	}
7185
	public function getStyleSheetCodes()
7186
	{
7187
		return array_unique(array_values($this->_styleSheets));
7188
	}
7189
	public function registerHeadScriptFile($key,$url)
7190
	{
7191
		$this->checkIfNotInRender();
7192
		$this->_headScriptFiles[$key]=$url;
7193
		$params=func_get_args();
7194
		$this->_page->registerCachingAction('Page.ClientScript','registerHeadScriptFile',$params);
7195
	}
7196
	public function registerHeadScript($key,$script)
7197
	{
7198
		$this->checkIfNotInRender();
7199
		$this->_headScripts[$key]=$script;
7200
		$params=func_get_args();
7201
		$this->_page->registerCachingAction('Page.ClientScript','registerHeadScript',$params);
7202
	}
7203
	public function registerScriptFile($key, $url)
7204
	{
7205
		$this->_scriptFiles[$key]=$url;
7206
		$params=func_get_args();
7207
		$this->_page->registerCachingAction('Page.ClientScript','registerScriptFile',$params);
7208
	}
7209
	public function registerBeginScript($key,$script)
7210
	{
7211
		$this->checkIfNotInRender();
7212
		$this->_beginScripts[$key]=$script;
7213
		$params=func_get_args();
7214
		$this->_page->registerCachingAction('Page.ClientScript','registerBeginScript',$params);
7215
	}
7216
	public function registerEndScript($key,$script)
7217
	{
7218
		$this->_endScripts[$key]=$script;
7219
		$params=func_get_args();
7220
		$this->_page->registerCachingAction('Page.ClientScript','registerEndScript',$params);
7221
	}
7222
	public function registerHiddenField($name,$value)
7223
	{
7224
		$this->_hiddenFields[$name]=$value;
7225
		$params=func_get_args();
7226
		$this->_page->registerCachingAction('Page.ClientScript','registerHiddenField',$params);
7227
	}
7228
	public function isStyleSheetFileRegistered($key)
7229
	{
7230
		return isset($this->_styleSheetFiles[$key]);
7231
	}
7232
	public function isStyleSheetRegistered($key)
7233
	{
7234
		return isset($this->_styleSheets[$key]);
7235
	}
7236
	public function isHeadScriptFileRegistered($key)
7237
	{
7238
		return isset($this->_headScriptFiles[$key]);
7239
	}
7240
	public function isHeadScriptRegistered($key)
7241
	{
7242
		return isset($this->_headScripts[$key]);
7243
	}
7244
	public function isScriptFileRegistered($key)
7245
	{
7246
		return isset($this->_scriptFiles[$key]);
7247
	}
7248
	public function isBeginScriptRegistered($key)
7249
	{
7250
		return isset($this->_beginScripts[$key]);
7251
	}
7252
	public function isEndScriptRegistered($key)
7253
	{
7254
		return isset($this->_endScripts[$key]);
7255
	}
7256
	public function hasEndScripts()
7257
	{
7258
		return count($this->_endScripts) > 0;
7259
	}
7260
	public function hasBeginScripts()
7261
	{
7262
		return count($this->_beginScripts) > 0;
7263
	}
7264
	public function isHiddenFieldRegistered($key)
7265
	{
7266
		return isset($this->_hiddenFields[$key]);
7267
	}
7268
	public function renderStyleSheetFiles($writer)
7269
	{
7270
		$str='';
7271
		foreach($this->_styleSheetFiles as $url)
7272
		{
7273
			if(is_array($url))
7274
				$str.="<link rel=\"stylesheet\" type=\"text/css\" media=\"{$url[1]}\" href=\"".THttpUtility::htmlEncode($url[0])."\" />\n";
7275
			else
7276
				$str.="<link rel=\"stylesheet\" type=\"text/css\" href=\"".THttpUtility::htmlEncode($url)."\" />\n";
7277
		}
7278
		$writer->write($str);
7279
	}
7280
	public function renderStyleSheets($writer)
7281
	{
7282
		if(count($this->_styleSheets))
7283
			$writer->write("<style type=\"text/css\">\n/*<![CDATA[*/\n".implode("\n",$this->_styleSheets)."\n/*]]>*/\n</style>\n");
7284
	}
7285
	public function renderHeadScriptFiles($writer)
7286
	{
7287
		$this->renderScriptFiles($writer,$this->_headScriptFiles);
7288
	}
7289
	public function renderHeadScripts($writer)
7290
	{
7291
		$writer->write(TJavaScript::renderScriptBlocks($this->_headScripts));
7292
	}
7293
	public function renderScriptFilesBegin($writer)
7294
	{
7295
		$this->renderAllPendingScriptFiles($writer);
7296
	}
7297
	public function renderScriptFilesEnd($writer)
7298
	{
7299
		$this->renderAllPendingScriptFiles($writer);
7300
	}
7301
	public function markScriptFileAsRendered($url)
7302
	{
7303
		$this->_renderedScriptFiles[$url] = $url;
7304
		$params=func_get_args();
7305
		$this->_page->registerCachingAction('Page.ClientScript','markScriptFileAsRendered',$params);
7306
	}
7307
	protected function renderScriptFiles($writer, Array $scripts)
7308
	{
7309
		foreach($scripts as $script)
7310
		{
7311
			$writer->write(TJavaScript::renderScriptFile($script));
7312
			$this->markScriptFileAsRendered($script);
7313
		}
7314
	}
7315
	protected function getRenderedScriptFiles()
7316
	{
7317
		return $this->_renderedScriptFiles;
7318
	}
7319
	public function renderAllPendingScriptFiles($writer)
7320
	{
7321
		if(!empty($this->_scriptFiles))
7322
		{
7323
			$addedScripts = array_diff($this->_scriptFiles,$this->getRenderedScriptFiles());
7324
			$this->renderScriptFiles($writer,$addedScripts);
7325
		}
7326
	}
7327
	public function renderBeginScripts($writer)
7328
	{
7329
		$writer->write(TJavaScript::renderScriptBlocks($this->_beginScripts));
7330
	}
7331
	public function renderEndScripts($writer)
7332
	{
7333
		$writer->write(TJavaScript::renderScriptBlocks($this->_endScripts));
7334
	}
7335
	public function renderBeginScriptsCallback($writer)
7336
	{
7337
		$writer->write(TJavaScript::renderScriptBlocksCallback($this->_beginScripts));
7338
	}
7339
	public function renderEndScriptsCallback($writer)
7340
	{
7341
		$writer->write(TJavaScript::renderScriptBlocksCallback($this->_endScripts));
7342
	}
7343
	public function renderHiddenFieldsBegin($writer)
7344
	{
7345
		$this->renderHiddenFieldsInt($writer,true);
7346
	}
7347
	public function renderHiddenFieldsEnd($writer)
7348
	{
7349
		$this->renderHiddenFieldsInt($writer,false);
7350
	}
7351
	public function flushScriptFiles($writer, $control=null)
7352
	{
7353
		if(!$this->_page->getIsCallback())
7354
		{
7355
			$this->_page->ensureRenderInForm($control);
7356
			$this->renderAllPendingScriptFiles($writer);
7357
		}
7358
	}
7359
	protected function renderHiddenFieldsInt($writer, $initial)
7360
 	{
7361
		if ($initial) $this->_renderedHiddenFields = array();
7362
		$str='';
7363
		foreach($this->_hiddenFields as $name=>$value)
7364
		{
7365
			if (in_array($name,$this->_renderedHiddenFields)) continue;
7366
			$id=strtr($name,':','_');
7367
			if(is_array($value))
7368
			{
7369
				foreach($value as $v)
7370
					$str.='<input type="hidden" name="'.$name.'[]" id="'.$id.'" value="'.THttpUtility::htmlEncode($value)."\" />\n";
7371
			}
7372
			else
7373
			{
7374
				$str.='<input type="hidden" name="'.$name.'" id="'.$id.'" value="'.THttpUtility::htmlEncode($value)."\" />\n";
7375
			}
7376
			$this->_renderedHiddenFields[] = $name;
7377
		}
7378
		if($str!=='')
7379
			$writer->write("<div style=\"visibility:hidden;\">\n".$str."</div>\n");
7380
	}
7381
	public function getHiddenFields()
7382
	{
7383
		return $this->_hiddenFields;
7384
	}
7385
	protected function checkIfNotInRender()
7386
	{
7387
		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...
7388
			throw new Exception('Operation invalid when page is already rendering');
7389
	}
7390
}
7391
abstract class TClientSideOptions extends TComponent
7392
{
7393
	private $_options;
7394
	protected function setFunction($name, $code)
7395
	{
7396
		if(!TJavaScript::isJsLiteral($code))
7397
			$code = TJavaScript::quoteJsLiteral($this->ensureFunction($code));
7398
		$this->setOption($name, $code);
7399
	}
7400
	protected function getOption($name)
7401
	{
7402
		if ($this->_options)
7403
			return $this->_options->itemAt($name);
7404
		else
7405
			return null;
7406
	}
7407
	protected function setOption($name, $value)
7408
	{
7409
		$this->getOptions()->add($name, $value);
7410
	}
7411
	public function getOptions()
7412
	{
7413
		if (!$this->_options)
7414
			$this->_options = Prado::createComponent('System.Collections.TMap');
7415
		return $this->_options;
7416
	}
7417
	protected function ensureFunction($javascript)
7418
	{
7419
		return "function(sender, parameter){ {$javascript} }";
7420
	}
7421
}
7422
class TPage extends TTemplateControl
7423
{
7424
	const FIELD_POSTBACK_TARGET='PRADO_POSTBACK_TARGET';
7425
	const FIELD_POSTBACK_PARAMETER='PRADO_POSTBACK_PARAMETER';
7426
	const FIELD_LASTFOCUS='PRADO_LASTFOCUS';
7427
	const FIELD_PAGESTATE='PRADO_PAGESTATE';
7428
	const FIELD_CALLBACK_TARGET='PRADO_CALLBACK_TARGET';
7429
	const FIELD_CALLBACK_PARAMETER='PRADO_CALLBACK_PARAMETER';
7430
	private static $_systemPostFields=array(
7431
		'PRADO_POSTBACK_TARGET'=>true,
7432
		'PRADO_POSTBACK_PARAMETER'=>true,
7433
		'PRADO_LASTFOCUS'=>true,
7434
		'PRADO_PAGESTATE'=>true,
7435
		'PRADO_CALLBACK_TARGET'=>true,
7436
		'PRADO_CALLBACK_PARAMETER'=>true
7437
	);
7438
	private $_form;
7439
	private $_head;
7440
	private $_validators=array();
7441
	private $_validated=false;
7442
	private $_theme;
7443
	private $_title;
7444
	private $_styleSheet;
7445
	private $_clientScript;
7446
	protected $_postData;
7447
	protected $_restPostData;
7448
	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...
7449
	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...
7450
	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...
7451
	private $_postBackEventTarget;
7452
	private $_postBackEventParameter;
7453
	protected $_formRendered=false;
7454
	protected $_inFormRender=false;
7455
	private $_focus;
7456
	private $_pagePath='';
7457
	private $_enableStateValidation=true;
7458
	private $_enableStateEncryption=false;
7459
	private $_enableStateCompression=true;
7460
	private $_statePersisterClass='System.Web.UI.TPageStatePersister';
7461
	private $_statePersister;
7462
	private $_cachingStack;
7463
	private $_clientState='';
7464
	protected $_isLoadingPostData=false;
7465
	private $_enableJavaScript=true;
7466
	private $_writer;
7467
	public function __construct()
7468
	{
7469
		$this->setPage($this);
7470
	}
7471
	public function run($writer)
7472
	{
7473
		$this->_writer = $writer;
7474
		$this->determinePostBackMode();
7475
		if($this->getIsPostBack())
7476
		{
7477
			if($this->getIsCallback())
7478
				$this->processCallbackRequest($writer);
7479
			else
7480
				$this->processPostBackRequest($writer);
7481
		}
7482
		else
7483
			$this->processNormalRequest($writer);
7484
		$this->_writer = null;
7485
	}
7486
	protected function processNormalRequest($writer)
7487
	{
7488
		$this->onPreInit(null);
7489
		$this->initRecursive();
7490
		$this->onInitComplete(null);
7491
		$this->onPreLoad(null);
7492
		$this->loadRecursive();
7493
		$this->onLoadComplete(null);
7494
		$this->preRenderRecursive();
7495
		$this->onPreRenderComplete(null);
7496
		$this->savePageState();
7497
		$this->onSaveStateComplete(null);
7498
		$this->renderControl($writer);
7499
		$this->unloadRecursive();
7500
	}
7501
	protected function processPostBackRequest($writer)
7502
	{
7503
		$this->onPreInit(null);
7504
		$this->initRecursive();
7505
		$this->onInitComplete(null);
7506
		$this->_restPostData=new TMap;
7507
		$this->loadPageState();
7508
		$this->processPostData($this->_postData,true);
7509
		$this->onPreLoad(null);
7510
		$this->loadRecursive();
7511
		$this->processPostData($this->_restPostData,false);
7512
		$this->raiseChangedEvents();
7513
		$this->raisePostBackEvent();
7514
		$this->onLoadComplete(null);
7515
		$this->preRenderRecursive();
7516
		$this->onPreRenderComplete(null);
7517
		$this->savePageState();
7518
		$this->onSaveStateComplete(null);
7519
		$this->renderControl($writer);
7520
		$this->unloadRecursive();
7521
	}
7522
	protected static function decodeUTF8($data, $enc)
7523
	{
7524
		if(is_array($data))
7525
		{
7526
			foreach($data as $k=>$v)
7527
				$data[$k]=self::decodeUTF8($v, $enc);
7528
			return $data;
7529
		} elseif(is_string($data)) {
7530
			return iconv('UTF-8',$enc.'//IGNORE',$data);
7531
		} else {
7532
			return $data;
7533
		}
7534
	}
7535
	protected function processCallbackRequest($writer)
7536
	{
7537
		Prado::using('System.Web.UI.ActiveControls.TActivePageAdapter');
7538
		$this->setAdapter(new TActivePageAdapter($this));
7539
        $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...
7540
        if(strlen($callbackEventParameter) > 0)
7541
            $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...
7542
                if (($g=$this->getApplication()->getGlobalization(false))!==null &&
7543
            strtoupper($enc=$g->getCharset())!='UTF-8')
7544
                foreach ($this->_postData as $k=>$v)
7545
                	$this->_postData[$k]=self::decodeUTF8($v, $enc);
7546
		$this->onPreInit(null);
7547
		$this->initRecursive();
7548
		$this->onInitComplete(null);
7549
		$this->_restPostData=new TMap;
7550
		$this->loadPageState();
7551
		$this->processPostData($this->_postData,true);
7552
		$this->onPreLoad(null);
7553
		$this->loadRecursive();
7554
		$this->processPostData($this->_restPostData,false);
7555
		$this->raiseChangedEvents();
7556
		$this->getAdapter()->processCallbackEvent($writer);
7557
		$this->onLoadComplete(null);
7558
		$this->preRenderRecursive();
7559
		$this->onPreRenderComplete(null);
7560
		$this->savePageState();
7561
		$this->onSaveStateComplete(null);
7562
		$this->getAdapter()->renderCallbackResponse($writer);
7563
		$this->unloadRecursive();
7564
	}
7565
	public function getCallbackClient()
7566
	{
7567
		if($this->getAdapter() !== null)
7568
			return $this->getAdapter()->getCallbackClientHandler();
7569
		else
7570
			return new TCallbackClientScript();
7571
	}
7572
	public function setCallbackClient($client)
7573
	{
7574
		$this->getAdapter()->setCallbackClientHandler($client);
7575
	}
7576
	public function getCallbackEventTarget()
7577
	{
7578
		return $this->getAdapter()->getCallbackEventTarget();
7579
	}
7580
	public function setCallbackEventTarget(TControl $control)
7581
	{
7582
		$this->getAdapter()->setCallbackEventTarget($control);
7583
	}
7584
	public function getCallbackEventParameter()
7585
	{
7586
		return $this->getAdapter()->getCallbackEventParameter();
7587
	}
7588
	public function setCallbackEventParameter($value)
7589
	{
7590
		$this->getAdapter()->setCallbackEventParameter($value);
7591
	}
7592
	public function getForm()
7593
	{
7594
		return $this->_form;
7595
	}
7596
	public function setForm(TForm $form)
7597
	{
7598
		if($this->_form===null)
7599
			$this->_form=$form;
7600
		else
7601
			throw new TInvalidOperationException('page_form_duplicated');
7602
	}
7603
	public function getValidators($validationGroup=null)
7604
	{
7605
		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...
7606
			$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...
7607
		if(empty($validationGroup) === true)
7608
			return $this->_validators;
7609
		else
7610
		{
7611
			$list=new TList;
7612
			foreach($this->_validators as $validator)
7613
				if($validator->getValidationGroup()===$validationGroup)
7614
					$list->add($validator);
7615
			return $list;
7616
		}
7617
	}
7618
	public function validate($validationGroup=null)
7619
	{
7620
		$this->_validated=true;
7621
		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...
7622
		{
7623
			if($validationGroup===null)
7624
			{
7625
				foreach($this->_validators as $validator)
7626
					$validator->validate();
7627
			}
7628
			else
7629
			{
7630
				foreach($this->_validators as $validator)
7631
				{
7632
					if($validator->getValidationGroup()===$validationGroup)
7633
						$validator->validate();
7634
				}
7635
			}
7636
		}
7637
	}
7638
	public function getIsValid()
7639
	{
7640
		if($this->_validated)
7641
		{
7642
			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...
7643
			{
7644
				foreach($this->_validators as $validator)
7645
					if(!$validator->getIsValid())
7646
						return false;
7647
			}
7648
			return true;
7649
		}
7650
		else
7651
			throw new TInvalidOperationException('page_isvalid_unknown');
7652
	}
7653
	public function getTheme()
7654
	{
7655
		if(is_string($this->_theme))
7656
			$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...
7657
		return $this->_theme;
7658
	}
7659
	public function setTheme($value)
7660
	{
7661
		$this->_theme=empty($value)?null:$value;
7662
	}
7663
	public function getStyleSheetTheme()
7664
	{
7665
		if(is_string($this->_styleSheet))
7666
			$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...
7667
		return $this->_styleSheet;
7668
	}
7669
	public function setStyleSheetTheme($value)
7670
	{
7671
		$this->_styleSheet=empty($value)?null:$value;
7672
	}
7673
	public function applyControlSkin($control)
7674
	{
7675
		if(($theme=$this->getTheme())!==null)
7676
			$theme->applySkin($control);
7677
	}
7678
	public function applyControlStyleSheet($control)
7679
	{
7680
		if(($theme=$this->getStyleSheetTheme())!==null)
7681
			$theme->applySkin($control);
7682
	}
7683
	public function getClientScript()
7684
	{
7685
		if(!$this->_clientScript) {
7686
			$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...
7687
			Prado::using($className);
7688
			if(($pos=strrpos($className,'.'))!==false)
7689
				$className=substr($className,$pos+1);
7690
 			if(!class_exists($className,false) || ($className!=='TClientScriptManager' && !is_subclass_of($className,'TClientScriptManager')))
7691
				throw new THttpException(404,'page_csmanagerclass_invalid',$classPath);
7692
			$this->_clientScript=new $className($this);
7693
		}
7694
		return $this->_clientScript;
7695
	}
7696
	public function onPreInit($param)
7697
	{
7698
		$this->raiseEvent('OnPreInit',$this,$param);
7699
	}
7700
	public function onInitComplete($param)
7701
	{
7702
		$this->raiseEvent('OnInitComplete',$this,$param);
7703
	}
7704
	public function onPreLoad($param)
7705
	{
7706
		$this->raiseEvent('OnPreLoad',$this,$param);
7707
	}
7708
	public function onLoadComplete($param)
7709
	{
7710
		$this->raiseEvent('OnLoadComplete',$this,$param);
7711
	}
7712
	public function onPreRenderComplete($param)
7713
	{
7714
		$this->raiseEvent('OnPreRenderComplete',$this,$param);
7715
		$cs=$this->getClientScript();
7716
		$theme=$this->getTheme();
7717
		if($theme instanceof ITheme)
7718
		{
7719
			foreach($theme->getStyleSheetFiles() as $url)
7720
				$cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
7721
			foreach($theme->getJavaScriptFiles() as $url)
7722
				$cs->registerHeadScriptFile($url,$url);
7723
		}
7724
		$styleSheet=$this->getStyleSheetTheme();
7725
		if($styleSheet instanceof ITheme)
7726
		{
7727
			foreach($styleSheet->getStyleSheetFiles() as $url)
7728
				$cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
7729
			foreach($styleSheet->getJavaScriptFiles() as $url)
7730
				$cs->registerHeadScriptFile($url,$url);
7731
		}
7732
		if($cs->getRequiresHead() && $this->getHead()===null)
7733
			throw new TConfigurationException('page_head_required');
7734
	}
7735
	private function getCssMediaType($url)
7736
	{
7737
		$segs=explode('.',basename($url));
7738
		if(isset($segs[2]))
7739
			return $segs[count($segs)-2];
7740
		else
7741
			return '';
7742
	}
7743
	public function onSaveStateComplete($param)
7744
	{
7745
		$this->raiseEvent('OnSaveStateComplete',$this,$param);
7746
	}
7747
	private function determinePostBackMode()
7748
	{
7749
		$postData=$this->getRequest();
7750
		if($postData->contains(self::FIELD_PAGESTATE) || $postData->contains(self::FIELD_POSTBACK_TARGET))
7751
			$this->_postData=$postData;
7752
	}
7753
	public function getIsPostBack()
7754
	{
7755
		return $this->_postData!==null;
7756
	}
7757
	public function getIsCallback()
7758
	{
7759
		return $this->getIsPostBack() && $this->getRequest()->contains(self::FIELD_CALLBACK_TARGET);
7760
	}
7761
	public function saveState()
7762
	{
7763
		parent::saveState();
7764
		$this->setViewState('ControlsRequiringPostBack',$this->_controlsRegisteredForPostData,array());
7765
	}
7766
	public function loadState()
7767
	{
7768
		parent::loadState();
7769
		$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...
7770
	}
7771
	protected function loadPageState()
7772
	{
7773
		$state=$this->getStatePersister()->load();
7774
		$this->loadStateRecursive($state,$this->getEnableViewState());
7775
	}
7776
	protected function savePageState()
7777
	{
7778
		$state=&$this->saveStateRecursive($this->getEnableViewState());
7779
		$this->getStatePersister()->save($state);
7780
	}
7781
	protected function isSystemPostField($field)
7782
	{
7783
		return isset(self::$_systemPostFields[$field]);
7784
	}
7785
	public function registerRequiresPostData($control)
7786
	{
7787
		$id=is_string($control)?$control:$control->getUniqueID();
7788
		$this->_controlsRegisteredForPostData[$id]=true;
7789
		$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...
7790
		foreach($this->getCachingStack() as $item)
7791
			$item->registerAction('Page','registerRequiresPostData',array($id));
7792
	}
7793
	public function getPostBackEventTarget()
7794
	{
7795
		if($this->_postBackEventTarget===null && $this->_postData!==null)
7796
		{
7797
			$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...
7798
			if(!empty($eventTarget))
7799
				$this->_postBackEventTarget=$this->findControl($eventTarget);
7800
		}
7801
		return $this->_postBackEventTarget;
7802
	}
7803
	public function setPostBackEventTarget(TControl $control)
7804
	{
7805
		$this->_postBackEventTarget=$control;
7806
	}
7807
	public function getPostBackEventParameter()
7808
	{
7809
		if($this->_postBackEventParameter===null && $this->_postData!==null)
7810
		{
7811
			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...
7812
				$this->_postBackEventParameter='';
7813
		}
7814
		return $this->_postBackEventParameter;
7815
	}
7816
	public function setPostBackEventParameter($value)
7817
	{
7818
		$this->_postBackEventParameter=$value;
7819
	}
7820
	protected function processPostData($postData,$beforeLoad)
7821
	{
7822
		$this->_isLoadingPostData=true;
7823
		if($beforeLoad)
7824
			$this->_restPostData=new TMap;
7825
		foreach($postData as $key=>$value)
7826
		{
7827
			if($this->isSystemPostField($key))
7828
				continue;
7829
			else if($control=$this->findControl($key))
7830
			{
7831
				if($control instanceof IPostBackDataHandler)
7832
				{
7833
					if($control->loadPostData($key,$postData))
7834
						$this->_controlsPostDataChanged[]=$control;
7835
				}
7836
				else if($control instanceof IPostBackEventHandler &&
7837
					empty($this->_postData[self::FIELD_POSTBACK_TARGET]))
7838
				{
7839
					$this->_postData->add(self::FIELD_POSTBACK_TARGET,$key);  				}
7840
				unset($this->_controlsRequiringPostData[$key]);
7841
			}
7842
			else if($beforeLoad)
7843
				$this->_restPostData->add($key,$value);
7844
		}
7845
		foreach($this->_controlsRequiringPostData as $key=>$value)
7846
		{
7847
			if($control=$this->findControl($key))
7848
			{
7849
				if($control instanceof IPostBackDataHandler)
7850
				{
7851
					if($control->loadPostData($key,$this->_postData))
7852
						$this->_controlsPostDataChanged[]=$control;
7853
				}
7854
				else
7855
					throw new TInvalidDataValueException('page_postbackcontrol_invalid',$key);
7856
				unset($this->_controlsRequiringPostData[$key]);
7857
			}
7858
		}
7859
		$this->_isLoadingPostData=false;
7860
	}
7861
	public function getIsLoadingPostData()
7862
	{
7863
		return $this->_isLoadingPostData;
7864
	}
7865
	protected function raiseChangedEvents()
7866
	{
7867
		foreach($this->_controlsPostDataChanged as $control)
7868
			$control->raisePostDataChangedEvent();
7869
	}
7870
	protected function raisePostBackEvent()
7871
	{
7872
		if(($postBackHandler=$this->getPostBackEventTarget())===null)
7873
			$this->validate();
7874
		else if($postBackHandler instanceof IPostBackEventHandler)
7875
			$postBackHandler->raisePostBackEvent($this->getPostBackEventParameter());
7876
	}
7877
	public function getInFormRender()
7878
	{
7879
		return $this->_inFormRender;
7880
	}
7881
	public function ensureRenderInForm($control)
7882
	{
7883
		if(!$this->getIsCallback() && !$this->_inFormRender)
7884
			throw new TConfigurationException('page_control_outofform',get_class($control), $control ? $control->getUniqueID() : null);
7885
	}
7886
	public function beginFormRender($writer)
7887
	{
7888
		if($this->_formRendered)
7889
			throw new TConfigurationException('page_form_duplicated');
7890
		$this->_formRendered=true;
7891
		$this->getClientScript()->registerHiddenField(self::FIELD_PAGESTATE,$this->getClientState());
7892
		$this->_inFormRender=true;
7893
	}
7894
	public function endFormRender($writer)
7895
	{
7896
		if($this->_focus)
7897
		{
7898
			if(($this->_focus instanceof TControl) && $this->_focus->getVisible(true))
7899
				$focus=$this->_focus->getClientID();
7900
			else
7901
				$focus=$this->_focus;
7902
			$this->getClientScript()->registerFocusControl($focus);
7903
		}
7904
		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...
7905
			$this->getClientScript()->registerFocusControl($lastFocus);
7906
		$this->_inFormRender=false;
7907
	}
7908
	public function setFocus($value)
7909
	{
7910
		$this->_focus=$value;
7911
	}
7912
	public function getClientSupportsJavaScript()
7913
	{
7914
		return $this->_enableJavaScript;
7915
	}
7916
	public function setClientSupportsJavaScript($value)
7917
	{
7918
		$this->_enableJavaScript=TPropertyValue::ensureBoolean($value);
7919
	}
7920
	public function getHead()
7921
	{
7922
		return $this->_head;
7923
	}
7924
	public function setHead(THead $value)
7925
	{
7926
		if($this->_head)
7927
			throw new TInvalidOperationException('page_head_duplicated');
7928
		$this->_head=$value;
7929
		if($this->_title!==null)
7930
		{
7931
			$this->_head->setTitle($this->_title);
7932
			$this->_title=null;
7933
		}
7934
	}
7935
	public function getTitle()
7936
	{
7937
		if($this->_head)
7938
			return $this->_head->getTitle();
7939
		else
7940
			return $this->_title===null ? '' : $this->_title;
7941
	}
7942
	public function setTitle($value)
7943
	{
7944
		if($this->_head)
7945
			$this->_head->setTitle($value);
7946
		else
7947
			$this->_title=$value;
7948
	}
7949
	public function getClientState()
7950
	{
7951
		return $this->_clientState;
7952
	}
7953
	public function setClientState($state)
7954
	{
7955
		$this->_clientState=$state;
7956
	}
7957
	public function getRequestClientState()
7958
	{
7959
		return $this->getRequest()->itemAt(self::FIELD_PAGESTATE);
7960
	}
7961
	public function getStatePersisterClass()
7962
	{
7963
		return $this->_statePersisterClass;
7964
	}
7965
	public function setStatePersisterClass($value)
7966
	{
7967
		$this->_statePersisterClass=$value;
7968
	}
7969
	public function getStatePersister()
7970
	{
7971
		if($this->_statePersister===null)
7972
		{
7973
			$this->_statePersister=Prado::createComponent($this->_statePersisterClass);
7974
			if(!($this->_statePersister instanceof IPageStatePersister))
7975
				throw new TInvalidDataTypeException('page_statepersister_invalid');
7976
			$this->_statePersister->setPage($this);
7977
		}
7978
		return $this->_statePersister;
7979
	}
7980
	public function getEnableStateValidation()
7981
	{
7982
		return $this->_enableStateValidation;
7983
	}
7984
	public function setEnableStateValidation($value)
7985
	{
7986
		$this->_enableStateValidation=TPropertyValue::ensureBoolean($value);
7987
	}
7988
	public function getEnableStateEncryption()
7989
	{
7990
		return $this->_enableStateEncryption;
7991
	}
7992
	public function setEnableStateEncryption($value)
7993
	{
7994
		$this->_enableStateEncryption=TPropertyValue::ensureBoolean($value);
7995
	}
7996
	public function getEnableStateCompression()
7997
	{
7998
		return $this->_enableStateCompression;
7999
	}
8000
	public function setEnableStateCompression($value)
8001
	{
8002
		$this->_enableStateCompression=TPropertyValue::ensureBoolean($value);
8003
	}
8004
	public function getPagePath()
8005
	{
8006
		return $this->_pagePath;
8007
	}
8008
	public function setPagePath($value)
8009
	{
8010
		$this->_pagePath=$value;
8011
	}
8012
	public function registerCachingAction($context,$funcName,$funcParams)
8013
	{
8014
		if($this->_cachingStack)
8015
		{
8016
			foreach($this->_cachingStack as $cache)
8017
				$cache->registerAction($context,$funcName,$funcParams);
8018
		}
8019
	}
8020
	public function getCachingStack()
8021
	{
8022
		if(!$this->_cachingStack)
8023
			$this->_cachingStack=new TStack;
8024
		return $this->_cachingStack;
8025
	}
8026
	public function flushWriter()
8027
	{
8028
		if ($this->_writer)
8029
			$this->Response->write($this->_writer->flush());
8030
	}
8031
}
8032
interface IPageStatePersister
8033
{
8034
	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...
8035
	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...
8036
	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...
8037
	public function load();
8038
}
8039
class TPageStateFormatter
8040
{
8041
	public static function serialize($page,$data)
8042
	{
8043
		$sm=$page->getApplication()->getSecurityManager();
8044
		if($page->getEnableStateValidation())
8045
			$str=$sm->hashData(serialize($data));
8046
		else
8047
			$str=serialize($data);
8048
		if($page->getEnableStateCompression() && extension_loaded('zlib'))
8049
			$str=gzcompress($str);
8050
		if($page->getEnableStateEncryption())
8051
			$str=$sm->encrypt($str);
8052
		return base64_encode($str);
8053
	}
8054
	public static function unserialize($page,$data)
8055
	{
8056
		$str=base64_decode($data);
8057
		if($str==='')
8058
			return null;
8059
		if($str!==false)
8060
		{
8061
			$sm=$page->getApplication()->getSecurityManager();
8062
			if($page->getEnableStateEncryption())
8063
				$str=$sm->decrypt($str);
8064
			if($page->getEnableStateCompression() && extension_loaded('zlib'))
8065
				$str=@gzuncompress($str);
8066
			if($page->getEnableStateValidation())
8067
			{
8068
				if(($str=$sm->validateData($str))!==false)
8069
					return unserialize($str);
8070
			}
8071
			else
8072
				return unserialize($str);
8073
		}
8074
		return null;
8075
	}
8076
}
8077
class TOutputCache extends TControl implements INamingContainer
8078
{
8079
	const CACHE_ID_PREFIX='prado:outputcache';
8080
	private $_cacheModuleID='';
8081
	private $_dataCached=false;
8082
	private $_cacheAvailable=false;
8083
	private $_cacheChecked=false;
8084
	private $_cacheKey=null;
8085
	private $_duration=60;
8086
	private $_cache=null;
8087
	private $_contents;
8088
	private $_state;
8089
	private $_actions=array();
8090
	private $_varyByParam='';
8091
	private $_keyPrefix='';
8092
	private $_varyBySession=false;
8093
	private $_cachePostBack=false;
8094
	private $_cacheTime=0;
8095
	public function getAllowChildControls()
8096
	{
8097
		$this->determineCacheability();
8098
		return !$this->_dataCached;
8099
	}
8100
	private function determineCacheability()
8101
	{
8102
		if(!$this->_cacheChecked)
8103
		{
8104
			$this->_cacheChecked=true;
8105
			if($this->_duration>0 && ($this->_cachePostBack || !$this->getPage()->getIsPostBack()))
8106
			{
8107
				if($this->_cacheModuleID!=='')
8108
				{
8109
					$this->_cache=$this->getApplication()->getModule($this->_cacheModuleID);
8110
					if(!($this->_cache instanceof ICache))
8111
						throw new TConfigurationException('outputcache_cachemoduleid_invalid',$this->_cacheModuleID);
8112
				}
8113
				else
8114
					$this->_cache=$this->getApplication()->getCache();
8115
				if($this->_cache!==null)
8116
				{
8117
					$this->_cacheAvailable=true;
8118
					$data=$this->_cache->get($this->getCacheKey());
8119
					if(is_array($data))
8120
					{
8121
						$param=new TOutputCacheCheckDependencyEventParameter;
8122
						$param->setCacheTime(isset($data[3])?$data[3]:0);
8123
						$this->onCheckDependency($param);
8124
						$this->_dataCached=$param->getIsValid();
8125
					}
8126
					else
8127
						$this->_dataCached=false;
8128
					if($this->_dataCached)
8129
						list($this->_contents,$this->_state,$this->_actions,$this->_cacheTime)=$data;
8130
				}
8131
			}
8132
		}
8133
	}
8134
	protected function initRecursive($namingContainer=null)
8135
	{
8136
		if($this->_cacheAvailable && !$this->_dataCached)
8137
		{
8138
			$stack=$this->getPage()->getCachingStack();
8139
			$stack->push($this);
8140
			parent::initRecursive($namingContainer);
8141
			$stack->pop();
8142
		}
8143
		else
8144
			parent::initRecursive($namingContainer);
8145
	}
8146
	protected function loadRecursive()
8147
	{
8148
		if($this->_cacheAvailable && !$this->_dataCached)
8149
		{
8150
			$stack=$this->getPage()->getCachingStack();
8151
			$stack->push($this);
8152
			parent::loadRecursive();
8153
			$stack->pop();
8154
		}
8155
		else
8156
		{
8157
			if($this->_dataCached)
8158
				$this->performActions();
8159
			parent::loadRecursive();
8160
		}
8161
	}
8162
	private function performActions()
8163
	{
8164
		$page=$this->getPage();
8165
		$cs=$page->getClientScript();
8166
		foreach($this->_actions as $action)
8167
		{
8168
			if($action[0]==='Page.ClientScript')
8169
				call_user_func_array(array($cs,$action[1]),$action[2]);
8170
			else if($action[0]==='Page')
8171
				call_user_func_array(array($page,$action[1]),$action[2]);
8172
			else
8173
				call_user_func_array(array($this->getSubProperty($action[0]),$action[1]),$action[2]);
8174
		}
8175
	}
8176
	protected function preRenderRecursive()
8177
	{
8178
		if($this->_cacheAvailable && !$this->_dataCached)
8179
		{
8180
			$stack=$this->getPage()->getCachingStack();
8181
			$stack->push($this);
8182
			parent::preRenderRecursive();
8183
			$stack->pop();
8184
		}
8185
		else
8186
			parent::preRenderRecursive();
8187
	}
8188
	protected function loadStateRecursive(&$state,$needViewState=true)
8189
	{
8190
		$st=unserialize($state);
8191
		parent::loadStateRecursive($st,$needViewState);
8192
	}
8193
	protected function &saveStateRecursive($needViewState=true)
8194
	{
8195
		if($this->_dataCached)
8196
			return $this->_state;
8197
		else
8198
		{
8199
			$st=parent::saveStateRecursive($needViewState);
8200
						$this->_state=serialize($st);
8201
			return $this->_state;
8202
		}
8203
	}
8204
	public function registerAction($context,$funcName,$funcParams)
8205
	{
8206
		$this->_actions[]=array($context,$funcName,$funcParams);
8207
	}
8208
	public function getCacheKey()
8209
	{
8210
		if($this->_cacheKey===null)
8211
			$this->_cacheKey=$this->calculateCacheKey();
8212
		return $this->_cacheKey;
8213
	}
8214
	protected function calculateCacheKey()
8215
	{
8216
		$key=$this->getBaseCacheKey();
8217
		if($this->_varyBySession)
8218
			$key.=$this->getSession()->getSessionID();
8219
		if($this->_varyByParam!=='')
8220
		{
8221
			$params=array();
8222
			$request=$this->getRequest();
8223
			foreach(explode(',',$this->_varyByParam) as $name)
8224
			{
8225
				$name=trim($name);
8226
				$params[$name]=$request->itemAt($name);
8227
			}
8228
			$key.=serialize($params);
8229
		}
8230
		$param=new TOutputCacheCalculateKeyEventParameter;
8231
		$this->onCalculateKey($param);
8232
		$key.=$param->getCacheKey();
8233
		return $key;
8234
	}
8235
	protected function getBaseCacheKey()
8236
	{
8237
		return self::CACHE_ID_PREFIX.$this->_keyPrefix.$this->getPage()->getPagePath().$this->getUniqueID();
8238
	}
8239
	public function getCacheModuleID()
8240
	{
8241
		return $this->_cacheModuleID;
8242
	}
8243
	public function setCacheModuleID($value)
8244
	{
8245
		$this->_cacheModuleID=$value;
8246
	}
8247
	public function setCacheKeyPrefix($value)
8248
	{
8249
		$this->_keyPrefix=$value;
8250
	}
8251
	public function getCacheTime()
8252
	{
8253
		return $this->_cacheTime;
8254
	}
8255
	protected function getCacheDependency()
8256
	{
8257
		return null;
8258
	}
8259
	public function getContentCached()
8260
	{
8261
		return $this->_dataCached;
8262
	}
8263
	public function getDuration()
8264
	{
8265
		return $this->_duration;
8266
	}
8267
	public function setDuration($value)
8268
	{
8269
		if(($value=TPropertyValue::ensureInteger($value))<0)
8270
			throw new TInvalidDataValueException('outputcache_duration_invalid',get_class($this));
8271
		$this->_duration=$value;
8272
	}
8273
	public function getVaryByParam()
8274
	{
8275
		return $this->_varyByParam;
8276
	}
8277
	public function setVaryByParam($value)
8278
	{
8279
		$this->_varyByParam=trim($value);
8280
	}
8281
	public function getVaryBySession()
8282
	{
8283
		return $this->_varyBySession;
8284
	}
8285
	public function setVaryBySession($value)
8286
	{
8287
		$this->_varyBySession=TPropertyValue::ensureBoolean($value);
8288
	}
8289
	public function getCachingPostBack()
8290
	{
8291
		return $this->_cachePostBack;
8292
	}
8293
	public function setCachingPostBack($value)
8294
	{
8295
		$this->_cachePostBack=TPropertyValue::ensureBoolean($value);
8296
	}
8297
	public function onCheckDependency($param)
8298
	{
8299
		$this->raiseEvent('OnCheckDependency',$this,$param);
8300
	}
8301
	public function onCalculateKey($param)
8302
	{
8303
		$this->raiseEvent('OnCalculateKey',$this,$param);
8304
	}
8305
	public function render($writer)
8306
	{
8307
		if($this->_dataCached)
8308
			$writer->write($this->_contents);
8309
		else if($this->_cacheAvailable)
8310
		{
8311
			$textwriter = new TTextWriter();
8312
			$multiwriter = new TOutputCacheTextWriterMulti(array($writer->getWriter(),$textwriter));
8313
			$htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), $multiwriter);
8314
			$stack=$this->getPage()->getCachingStack();
8315
			$stack->push($this);
8316
			parent::render($htmlWriter);
8317
			$stack->pop();
8318
			$content=$textwriter->flush();
8319
			$data=array($content,$this->_state,$this->_actions,time());
8320
			$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...
8321
		}
8322
		else
8323
			parent::render($writer);
8324
	}
8325
}
8326
class TOutputCacheCheckDependencyEventParameter extends TEventParameter
8327
{
8328
	private $_isValid=true;
8329
	private $_cacheTime=0;
8330
	public function getIsValid()
8331
	{
8332
		return $this->_isValid;
8333
	}
8334
	public function setIsValid($value)
8335
	{
8336
		$this->_isValid=TPropertyValue::ensureBoolean($value);
8337
	}
8338
	public function getCacheTime()
8339
	{
8340
		return $this->_cacheTime;
8341
	}
8342
	public function setCacheTime($value)
8343
	{
8344
		$this->_cacheTime=TPropertyValue::ensureInteger($value);
8345
	}
8346
}
8347
class TOutputCacheCalculateKeyEventParameter extends TEventParameter
8348
{
8349
	private $_cacheKey='';
8350
	public function getCacheKey()
8351
	{
8352
		return $this->_cacheKey;
8353
	}
8354
	public function setCacheKey($value)
8355
	{
8356
		$this->_cacheKey=TPropertyValue::ensureString($value);
8357
	}
8358
}
8359
class TOutputCacheTextWriterMulti extends TTextWriter
8360
{
8361
	protected $_writers;
8362
	public function __construct(Array $writers)
8363
	{
8364
				$this->_writers = $writers;
8365
	}
8366
	public function write($s)
8367
	{
8368
		foreach($this->_writers as $writer)
8369
			$writer->write($s);
8370
	}
8371
	public function flush()
8372
	{
8373
		foreach($this->_writers as $writer)
8374
			$s = $writer->flush();
8375
		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...
8376
	}
8377
}
8378
class TTemplateManager extends TModule
8379
{
8380
	const TEMPLATE_FILE_EXT='.tpl';
8381
	const TEMPLATE_CACHE_PREFIX='prado:template:';
8382
	public function init($config)
8383
	{
8384
		$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...
8385
	}
8386
	public function getTemplateByClassName($className)
8387
	{
8388
		$class=new ReflectionClass($className);
8389
		$tplFile=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$className.self::TEMPLATE_FILE_EXT;
8390
		return $this->getTemplateByFileName($tplFile);
8391
	}
8392
	public function getTemplateByFileName($fileName)
8393
	{
8394
		if(($fileName=$this->getLocalizedTemplate($fileName))!==null)
8395
		{
8396
			if(($cache=$this->getApplication()->getCache())===null)
8397
				return new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
8398
			else
8399
			{
8400
				$array=$cache->get(self::TEMPLATE_CACHE_PREFIX.$fileName);
8401
				if(is_array($array))
8402
				{
8403
					list($template,$timestamps)=$array;
8404
					if($this->getApplication()->getMode()===TApplicationMode::Performance)
8405
						return $template;
8406
					$cacheValid=true;
8407
					foreach($timestamps as $tplFile=>$timestamp)
8408
					{
8409
						if(!is_file($tplFile) || filemtime($tplFile)>$timestamp)
8410
						{
8411
							$cacheValid=false;
8412
							break;
8413
						}
8414
					}
8415
					if($cacheValid)
8416
						return $template;
8417
				}
8418
				$template=new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
8419
				$includedFiles=$template->getIncludedFiles();
8420
				$timestamps=array();
8421
				$timestamps[$fileName]=filemtime($fileName);
8422
				foreach($includedFiles as $includedFile)
8423
					$timestamps[$includedFile]=filemtime($includedFile);
8424
				$cache->set(self::TEMPLATE_CACHE_PREFIX.$fileName,array($template,$timestamps));
8425
				return $template;
8426
			}
8427
		}
8428
		else
8429
			return null;
8430
	}
8431
	protected function getLocalizedTemplate($filename)
8432
	{
8433
		if(($app=$this->getApplication()->getGlobalization(false))===null)
8434
			return is_file($filename)?$filename:null;
8435
		foreach($app->getLocalizedResource($filename) as $file)
8436
		{
8437
			if(($file=realpath($file))!==false && is_file($file))
8438
				return $file;
8439
		}
8440
		return null;
8441
	}
8442
}
8443
class TTemplate extends TApplicationComponent implements ITemplate
8444
{
8445
	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';
8446
	const CONFIG_DATABIND=0;
8447
	const CONFIG_EXPRESSION=1;
8448
	const CONFIG_ASSET=2;
8449
	const CONFIG_PARAMETER=3;
8450
	const CONFIG_LOCALIZATION=4;
8451
	const CONFIG_TEMPLATE=5;
8452
	private $_tpl=array();
8453
	private $_directive=array();
8454
	private $_contextPath;
8455
	private $_tplFile=null;
8456
	private $_startingLine=0;
8457
	private $_content;
8458
	private $_sourceTemplate=true;
8459
	private $_hashCode='';
8460
	private $_tplControl=null;
8461
	private $_includedFiles=array();
8462
	private $_includeAtLine=array();
8463
	private $_includeLines=array();
8464
	public function __construct($template,$contextPath,$tplFile=null,$startingLine=0,$sourceTemplate=true)
8465
	{
8466
		$this->_sourceTemplate=$sourceTemplate;
8467
		$this->_contextPath=$contextPath;
8468
		$this->_tplFile=$tplFile;
8469
		$this->_startingLine=$startingLine;
8470
		$this->_content=$template;
8471
		$this->_hashCode=md5($template);
8472
		$this->parse($template);
8473
		$this->_content=null; 	}
8474
	public function getTemplateFile()
8475
	{
8476
		return $this->_tplFile;
8477
	}
8478
	public function getIsSourceTemplate()
8479
	{
8480
		return $this->_sourceTemplate;
8481
	}
8482
	public function getContextPath()
8483
	{
8484
		return $this->_contextPath;
8485
	}
8486
	public function getDirective()
8487
	{
8488
		return $this->_directive;
8489
	}
8490
	public function getHashCode()
8491
	{
8492
		return $this->_hashCode;
8493
	}
8494
	public function &getItems()
8495
	{
8496
		return $this->_tpl;
8497
	}
8498
	public function instantiateIn($tplControl,$parentControl=null)
8499
	{
8500
		$this->_tplControl=$tplControl;
8501
		if($parentControl===null)
8502
			$parentControl=$tplControl;
8503
		if(($page=$tplControl->getPage())===null)
8504
			$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...
8505
		$controls=array();
8506
		$directChildren=array();
8507
		foreach($this->_tpl as $key=>$object)
8508
		{
8509
			if($object[0]===-1)
8510
				$parent=$parentControl;
8511
			else if(isset($controls[$object[0]]))
8512
				$parent=$controls[$object[0]];
8513
			else
8514
				continue;
8515
			if(isset($object[2]))				{
8516
				$component=Prado::createComponent($object[1]);
8517
				$properties=&$object[2];
8518
				if($component instanceof TControl)
8519
				{
8520
					if($component instanceof TOutputCache)
8521
						$component->setCacheKeyPrefix($this->_hashCode.$key);
8522
					$component->setTemplateControl($tplControl);
8523
					if(isset($properties['id']))
8524
					{
8525
						if(is_array($properties['id']))
8526
							$properties['id']=$component->evaluateExpression($properties['id'][1]);
8527
						$tplControl->registerObject($properties['id'],$component);
8528
					}
8529
					if(isset($properties['skinid']))
8530
					{
8531
						if(is_array($properties['skinid']))
8532
							$component->setSkinID($component->evaluateExpression($properties['skinid'][1]));
8533
						else
8534
							$component->setSkinID($properties['skinid']);
8535
						unset($properties['skinid']);
8536
					}
8537
					$component->trackViewState(false);
8538
					$component->applyStyleSheetSkin($page);
8539
					foreach($properties as $name=>$value)
8540
						$this->configureControl($component,$name,$value);
8541
					$component->trackViewState(true);
8542
					if($parent===$parentControl)
8543
						$directChildren[]=$component;
8544
					else
8545
						$component->createdOnTemplate($parent);
8546
					if($component->getAllowChildControls())
8547
						$controls[$key]=$component;
8548
				}
8549
				else if($component instanceof TComponent)
8550
				{
8551
					$controls[$key]=$component;
8552
					if(isset($properties['id']))
8553
					{
8554
						if(is_array($properties['id']))
8555
							$properties['id']=$component->evaluateExpression($properties['id'][1]);
8556
						$tplControl->registerObject($properties['id'],$component);
8557
						if(!$component->hasProperty('id'))
8558
							unset($properties['id']);
8559
					}
8560
					foreach($properties as $name=>$value)
8561
						$this->configureComponent($component,$name,$value);
8562
					if($parent===$parentControl)
8563
						$directChildren[]=$component;
8564
					else
8565
						$component->createdOnTemplate($parent);
8566
				}
8567
			}
8568
			else
8569
			{
8570
				if($object[1] instanceof TCompositeLiteral)
8571
				{
8572
										$o=clone $object[1];
8573
					$o->setContainer($tplControl);
8574
					if($parent===$parentControl)
8575
						$directChildren[]=$o;
8576
					else
8577
						$parent->addParsedObject($o);
8578
				}
8579
				else
8580
				{
8581
					if($parent===$parentControl)
8582
						$directChildren[]=$object[1];
8583
					else
8584
						$parent->addParsedObject($object[1]);
8585
				}
8586
			}
8587
		}
8588
								foreach($directChildren as $control)
8589
		{
8590
			if($control instanceof TComponent)
8591
				$control->createdOnTemplate($parentControl);
8592
			else
8593
				$parentControl->addParsedObject($control);
8594
		}
8595
	}
8596
	protected function configureControl($control,$name,$value)
8597
	{
8598
		if(strncasecmp($name,'on',2)===0)					$this->configureEvent($control,$name,$value,$control);
8599
		else if(($pos=strrpos($name,'.'))===false)				$this->configureProperty($control,$name,$value);
8600
		else				$this->configureSubProperty($control,$name,$value);
8601
	}
8602
	protected function configureComponent($component,$name,$value)
8603
	{
8604
		if(strpos($name,'.')===false)				$this->configureProperty($component,$name,$value);
8605
		else				$this->configureSubProperty($component,$name,$value);
8606
	}
8607
	protected function configureEvent($control,$name,$value,$contextControl)
8608
	{
8609
		if(strpos($value,'.')===false)
8610
			$control->attachEventHandler($name,array($contextControl,'TemplateControl.'.$value));
8611
		else
8612
			$control->attachEventHandler($name,array($contextControl,$value));
8613
	}
8614
	protected function configureProperty($component,$name,$value)
8615
	{
8616
		if(is_array($value))
8617
		{
8618
			switch($value[0])
8619
			{
8620
				case self::CONFIG_DATABIND:
8621
					$component->bindProperty($name,$value[1]);
8622
					break;
8623
				case self::CONFIG_EXPRESSION:
8624
					if($component instanceof TControl)
8625
						$component->autoBindProperty($name,$value[1]);
8626
					else
8627
					{
8628
						$setter='set'.$name;
8629
						$component->$setter($this->_tplControl->evaluateExpression($value[1]));
8630
					}
8631
					break;
8632
				case self::CONFIG_TEMPLATE:
8633
					$setter='set'.$name;
8634
					$component->$setter($value[1]);
8635
					break;
8636
				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...
8637
					$url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
8638
					$component->$setter($url);
8639
					break;
8640
				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...
8641
					$component->$setter($this->getApplication()->getParameters()->itemAt($value[1]));
8642
					break;
8643
				case self::CONFIG_LOCALIZATION:
8644
					$setter='set'.$name;
8645
					$component->$setter(Prado::localize($value[1]));
8646
					break;
8647
				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...
8648
					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...
8649
			}
8650
		}
8651
		else
8652
		{
8653
			if (substr($name,0,2)=='js')
8654
				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...
8655
					$value = new TJavaScriptLiteral($value);
8656
			$setter='set'.$name;
8657
			$component->$setter($value);
8658
		}
8659
	}
8660
	protected function configureSubProperty($component,$name,$value)
8661
	{
8662
		if(is_array($value))
8663
		{
8664
			switch($value[0])
8665
			{
8666
				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...
8667
					break;
8668
				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...
8669
						$component->autoBindProperty($name,$value[1]);
8670
					else
8671
						$component->setSubProperty($name,$this->_tplControl->evaluateExpression($value[1]));
8672
					break;
8673
				case self::CONFIG_TEMPLATE:
8674
					$component->setSubProperty($name,$value[1]);
8675
					break;
8676
				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...
8677
					$component->setSubProperty($name,$url);
8678
					break;
8679
				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...
8680
					break;
8681
				case self::CONFIG_LOCALIZATION:
8682
					$component->setSubProperty($name,Prado::localize($value[1]));
8683
					break;
8684
				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...
8685
					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...
8686
			}
8687
		}
8688
		else
8689
			$component->setSubProperty($name,$value);
8690
	}
8691
	protected function parse($input)
8692
	{
8693
		$input=$this->preprocess($input);
8694
		$tpl=&$this->_tpl;
8695
		$n=preg_match_all(self::REGEX_RULES,$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
8696
		$expectPropEnd=false;
8697
		$textStart=0;
8698
				$stack=array();
8699
		$container=-1;
8700
		$matchEnd=0;
8701
		$c=0;
8702
		$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...
8703
		try
8704
		{
8705
			for($i=0;$i<$n;++$i)
8706
			{
8707
				$match=&$matches[$i];
8708
				$str=$match[0][0];
8709
				$matchStart=$match[0][1];
8710
				$matchEnd=$matchStart+strlen($str)-1;
8711
				if(strpos($str,'<com:')===0)					{
8712
					if($expectPropEnd)
8713
						continue;
8714
					if($matchStart>$textStart)
8715
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8716
					$textStart=$matchEnd+1;
8717
					$type=$match[1][0];
8718
					$attributes=$this->parseAttributes($match[2][0],$match[2][1]);
8719
					$this->validateAttributes($type,$attributes);
8720
					$tpl[$c++]=array($container,$type,$attributes);
8721
					if($str[strlen($str)-2]!=='/')  					{
8722
						$stack[] = $type;
8723
						$container=$c-1;
8724
					}
8725
				}
8726
				else if(strpos($str,'</com:')===0)					{
8727
					if($expectPropEnd)
8728
						continue;
8729
					if($matchStart>$textStart)
8730
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8731
					$textStart=$matchEnd+1;
8732
					$type=$match[1][0];
8733
					if(empty($stack))
8734
						throw new TConfigurationException('template_closingtag_unexpected',"</com:$type>");
8735
					$name=array_pop($stack);
8736
					if($name!==$type)
8737
					{
8738
						$tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
8739
						throw new TConfigurationException('template_closingtag_expected',$tag);
8740
					}
8741
					$container=$tpl[$container][0];
8742
				}
8743
				else if(strpos($str,'<%@')===0)					{
8744
					if($expectPropEnd)
8745
						continue;
8746
					if($matchStart>$textStart)
8747
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8748
					$textStart=$matchEnd+1;
8749
					if(isset($tpl[0]) || $this->_directive!==null)
8750
						throw new TConfigurationException('template_directive_nonunique');
8751
					$this->_directive=$this->parseAttributes($match[4][0],$match[4][1]);
8752
				}
8753
				else if(strpos($str,'<%')===0)					{
8754
					if($expectPropEnd)
8755
						continue;
8756
					if($matchStart>$textStart)
8757
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8758
					$textStart=$matchEnd+1;
8759
					$literal=trim($match[5][0]);
8760
					if($str[2]==='=')							$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,$literal));
8761
					else if($str[2]==='%')  						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_STATEMENTS,$literal));
8762
					else if($str[2]==='#')
8763
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_DATABINDING,$literal));
8764
					else if($str[2]==='$')
8765
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->getApplication()->getParameters()->itemAt('$literal')"));
8766
					else if($str[2]==='~')
8767
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->publishFilePath('$this->_contextPath/$literal')"));
8768
					else if($str[2]==='/')
8769
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"rtrim(dirname(\$this->getApplication()->getRequest()->getApplicationUrl()), '/').'/$literal'"));
8770
					else if($str[2]==='[')
8771
					{
8772
						$literal=strtr(trim(substr($literal,0,strlen($literal)-1)),array("'"=>"\'","\\"=>"\\\\"));
8773
						$tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"Prado::localize('$literal')"));
8774
					}
8775
				}
8776
				else if(strpos($str,'<prop:')===0)					{
8777
					if(strrpos($str,'/>')===strlen($str)-2)  					{
8778
						if($expectPropEnd)
8779
							continue;
8780
						if($matchStart>$textStart)
8781
							$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8782
						$textStart=$matchEnd+1;
8783
						$prop=strtolower($match[6][0]);
8784
						$attrs=$this->parseAttributes($match[7][0],$match[7][1]);
8785
						$attributes=array();
8786
						foreach($attrs as $name=>$value)
8787
							$attributes[$prop.'.'.$name]=$value;
8788
						$type=$tpl[$container][1];
8789
						$this->validateAttributes($type,$attributes);
8790
						foreach($attributes as $name=>$value)
8791
						{
8792
							if(isset($tpl[$container][2][$name]))
8793
								throw new TConfigurationException('template_property_duplicated',$name);
8794
							$tpl[$container][2][$name]=$value;
8795
						}
8796
					}
8797
					else  					{
8798
						$prop=strtolower($match[3][0]);
8799
						$stack[] = '@'.$prop;
8800
						if(!$expectPropEnd)
8801
						{
8802
							if($matchStart>$textStart)
8803
								$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8804
							$textStart=$matchEnd+1;
8805
							$expectPropEnd=true;
8806
						}
8807
					}
8808
				}
8809
				else if(strpos($str,'</prop:')===0)					{
8810
					$prop=strtolower($match[3][0]);
8811
					if(empty($stack))
8812
						throw new TConfigurationException('template_closingtag_unexpected',"</prop:$prop>");
8813
					$name=array_pop($stack);
8814
					if($name!=='@'.$prop)
8815
					{
8816
						$tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
8817
						throw new TConfigurationException('template_closingtag_expected',$tag);
8818
					}
8819
					if(($last=count($stack))<1 || $stack[$last-1][0]!=='@')
8820
					{
8821
						if($matchStart>$textStart)
8822
						{
8823
							$value=substr($input,$textStart,$matchStart-$textStart);
8824
							if(substr($prop,-8,8)==='template')
8825
								$value=$this->parseTemplateProperty($value,$textStart);
8826
							else
8827
								$value=$this->parseAttribute($value);
8828
							if($container>=0)
8829
							{
8830
								$type=$tpl[$container][1];
8831
								$this->validateAttributes($type,array($prop=>$value));
8832
								if(isset($tpl[$container][2][$prop]))
8833
									throw new TConfigurationException('template_property_duplicated',$prop);
8834
								$tpl[$container][2][$prop]=$value;
8835
							}
8836
							else									$this->_directive[$prop]=$value;
8837
							$textStart=$matchEnd+1;
8838
						}
8839
						$expectPropEnd=false;
8840
					}
8841
				}
8842
				else if(strpos($str,'<!--')===0)					{
8843
					if($expectPropEnd)
8844
						throw new TConfigurationException('template_comments_forbidden');
8845
					if($matchStart>$textStart)
8846
						$tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
8847
					$textStart=$matchEnd+1;
8848
				}
8849
				else
8850
					throw new TConfigurationException('template_matching_unexpected',$match);
8851
			}
8852
			if(!empty($stack))
8853
			{
8854
				$name=array_pop($stack);
8855
				$tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
8856
				throw new TConfigurationException('template_closingtag_expected',$tag);
8857
			}
8858
			if($textStart<strlen($input))
8859
				$tpl[$c++]=array($container,substr($input,$textStart));
8860
		}
8861
		catch(Exception $e)
8862
		{
8863
			if(($e instanceof TException) && ($e instanceof TTemplateException))
8864
				throw $e;
8865
			if($matchEnd===0)
8866
				$line=$this->_startingLine+1;
8867
			else
8868
				$line=$this->_startingLine+count(explode("\n",substr($input,0,$matchEnd+1)));
8869
			$this->handleException($e,$line,$input);
8870
		}
8871
		if($this->_directive===null)
8872
			$this->_directive=array();
8873
				$objects=array();
8874
		$parent=null;
8875
		$merged=array();
8876
		foreach($tpl as $id=>$object)
8877
		{
8878
			if(isset($object[2]) || $object[0]!==$parent)
8879
			{
8880
				if($parent!==null)
8881
				{
8882
					if(count($merged[1])===1 && is_string($merged[1][0]))
8883
						$objects[$id-1]=array($merged[0],$merged[1][0]);
8884
					else
8885
						$objects[$id-1]=array($merged[0],new TCompositeLiteral($merged[1]));
8886
				}
8887
				if(isset($object[2]))
8888
				{
8889
					$parent=null;
8890
					$objects[$id]=$object;
8891
				}
8892
				else
8893
				{
8894
					$parent=$object[0];
8895
					$merged=array($parent,array($object[1]));
8896
				}
8897
			}
8898
			else
8899
				$merged[1][]=$object[1];
8900
		}
8901
		if($parent!==null)
8902
		{
8903
			if(count($merged[1])===1 && is_string($merged[1][0]))
8904
				$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 8876. 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...
8905
			else
8906
				$objects[$id]=array($merged[0],new TCompositeLiteral($merged[1]));
8907
		}
8908
		$tpl=$objects;
8909
		return $objects;
8910
	}
8911
	protected function parseAttributes($str,$offset)
8912
	{
8913
		if($str==='')
8914
			return array();
8915
		$pattern='/([\w\.\-]+)\s*=\s*(\'.*?\'|".*?"|<%.*?%>)/msS';
8916
		$attributes=array();
8917
		$n=preg_match_all($pattern,$str,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
8918
		for($i=0;$i<$n;++$i)
8919
		{
8920
			$match=&$matches[$i];
8921
			$name=strtolower($match[1][0]);
8922
			if(isset($attributes[$name]))
8923
				throw new TConfigurationException('template_property_duplicated',$name);
8924
			$value=$match[2][0];
8925
			if(substr($name,-8,8)==='template')
8926
			{
8927
				if($value[0]==='\'' || $value[0]==='"')
8928
					$attributes[$name]=$this->parseTemplateProperty(substr($value,1,strlen($value)-2),$match[2][1]+1);
8929
				else
8930
					$attributes[$name]=$this->parseTemplateProperty($value,$match[2][1]);
8931
			}
8932
			else
8933
			{
8934
				if($value[0]==='\'' || $value[0]==='"')
8935
					$attributes[$name]=$this->parseAttribute(substr($value,1,strlen($value)-2));
8936
				else
8937
					$attributes[$name]=$this->parseAttribute($value);
8938
			}
8939
		}
8940
		return $attributes;
8941
	}
8942
	protected function parseTemplateProperty($content,$offset)
8943
	{
8944
		$line=$this->_startingLine+count(explode("\n",substr($this->_content,0,$offset)))-1;
8945
		return array(self::CONFIG_TEMPLATE,new TTemplate($content,$this->_contextPath,$this->_tplFile,$line,false));
8946
	}
8947
	protected function parseAttribute($value)
8948
	{
8949
		if(($n=preg_match_all('/<%[#=].*?%>/msS',$value,$matches,PREG_OFFSET_CAPTURE))>0)
8950
		{
8951
			$isDataBind=false;
8952
			$textStart=0;
8953
			$expr='';
8954
			for($i=0;$i<$n;++$i)
8955
			{
8956
				$match=$matches[0][$i];
8957
				$token=$match[0];
8958
				$offset=$match[1];
8959
				$length=strlen($token);
8960
				if($token[2]==='#')
8961
					$isDataBind=true;
8962
				if($offset>$textStart)
8963
					$expr.=".'".strtr(substr($value,$textStart,$offset-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
8964
				$expr.='.('.substr($token,3,$length-5).')';
8965
				$textStart=$offset+$length;
8966
			}
8967
			$length=strlen($value);
8968
			if($length>$textStart)
8969
				$expr.=".'".strtr(substr($value,$textStart,$length-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
8970
			if($isDataBind)
8971
				return array(self::CONFIG_DATABIND,ltrim($expr,'.'));
8972
			else
8973
				return array(self::CONFIG_EXPRESSION,ltrim($expr,'.'));
8974
		}
8975
		else if(preg_match('/\\s*(<%~.*?%>|<%\\$.*?%>|<%\\[.*?\\]%>|<%\/.*?%>)\\s*/msS',$value,$matches) && $matches[0]===$value)
8976
		{
8977
			$value=$matches[1];
8978
			if($value[2]==='~')
8979
				return array(self::CONFIG_ASSET,trim(substr($value,3,strlen($value)-5)));
8980
			elseif($value[2]==='[')
8981
				return array(self::CONFIG_LOCALIZATION,trim(substr($value,3,strlen($value)-6)));
8982
			elseif($value[2]==='$')
8983
				return array(self::CONFIG_PARAMETER,trim(substr($value,3,strlen($value)-5)));
8984
			elseif($value[2]==='/') {
8985
				$literal = trim(substr($value,3,strlen($value)-5));
8986
				return array(self::CONFIG_EXPRESSION,"rtrim(dirname(\$this->getApplication()->getRequest()->getApplicationUrl()), '/').'/$literal'");
8987
			}
8988
		}
8989
		else
8990
			return $value;
8991
	}
8992
	protected function validateAttributes($type,$attributes)
8993
	{
8994
		Prado::using($type);
8995
		if(($pos=strrpos($type,'.'))!==false)
8996
			$className=substr($type,$pos+1);
8997
		else
8998
			$className=$type;
8999
		$class=new ReflectionClass($className);
9000
		if(is_subclass_of($className,'TControl') || $className==='TControl')
9001
		{
9002
			foreach($attributes as $name=>$att)
9003
			{
9004
				if(($pos=strpos($name,'.'))!==false)
9005
				{
9006
										$subname=substr($name,0,$pos);
9007
					if(!$class->hasMethod('get'.$subname))
9008
						throw new TConfigurationException('template_property_unknown',$type,$subname);
9009
				}
9010
				else if(strncasecmp($name,'on',2)===0)
9011
				{
9012
										if(!$class->hasMethod($name))
9013
						throw new TConfigurationException('template_event_unknown',$type,$name);
9014
					else if(!is_string($att))
9015
						throw new TConfigurationException('template_eventhandler_invalid',$type,$name);
9016
				}
9017
				else
9018
				{
9019
										if (! ($class->hasMethod('set'.$name) || $class->hasMethod('setjs'.$name) || $this->isClassBehaviorMethod($class,'set'.$name)) )
9020
					{
9021
						if ($class->hasMethod('get'.$name) || $class->hasMethod('getjs'.$name))
9022
							throw new TConfigurationException('template_property_readonly',$type,$name);
9023
						else
9024
							throw new TConfigurationException('template_property_unknown',$type,$name);
9025
					}
9026
					else if(is_array($att) && $att[0]!==self::CONFIG_EXPRESSION)
9027
					{
9028
						if(strcasecmp($name,'id')===0)
9029
							throw new TConfigurationException('template_controlid_invalid',$type);
9030
						else if(strcasecmp($name,'skinid')===0)
9031
							throw new TConfigurationException('template_controlskinid_invalid',$type);
9032
					}
9033
				}
9034
			}
9035
		}
9036
		else if(is_subclass_of($className,'TComponent') || $className==='TComponent')
9037
		{
9038
			foreach($attributes as $name=>$att)
9039
			{
9040
				if(is_array($att) && ($att[0]===self::CONFIG_DATABIND))
9041
					throw new TConfigurationException('template_databind_forbidden',$type,$name);
9042
				if(($pos=strpos($name,'.'))!==false)
9043
				{
9044
										$subname=substr($name,0,$pos);
9045
					if(!$class->hasMethod('get'.$subname))
9046
						throw new TConfigurationException('template_property_unknown',$type,$subname);
9047
				}
9048
				else if(strncasecmp($name,'on',2)===0)
9049
					throw new TConfigurationException('template_event_forbidden',$type,$name);
9050
				else
9051
				{
9052
										if(strcasecmp($name,'id')!==0 && !($class->hasMethod('set'.$name) || $this->isClassBehaviorMethod($class,'set'.$name)))
9053
					{
9054
						if($class->hasMethod('get'.$name))
9055
							throw new TConfigurationException('template_property_readonly',$type,$name);
9056
						else
9057
							throw new TConfigurationException('template_property_unknown',$type,$name);
9058
					}
9059
				}
9060
			}
9061
		}
9062
		else
9063
			throw new TConfigurationException('template_component_required',$type);
9064
	}
9065
	public function getIncludedFiles()
9066
	{
9067
		return $this->_includedFiles;
9068
	}
9069
	protected function handleException($e,$line,$input=null)
9070
	{
9071
		$srcFile=$this->_tplFile;
9072
		if(($n=count($this->_includedFiles))>0) 		{
9073
			for($i=$n-1;$i>=0;--$i)
9074
			{
9075
				if($this->_includeAtLine[$i]<=$line)
9076
				{
9077
					if($line<$this->_includeAtLine[$i]+$this->_includeLines[$i])
9078
					{
9079
						$line=$line-$this->_includeAtLine[$i]+1;
9080
						$srcFile=$this->_includedFiles[$i];
9081
						break;
9082
					}
9083
					else
9084
						$line=$line-$this->_includeLines[$i]+1;
9085
				}
9086
			}
9087
		}
9088
		$exception=new TTemplateException('template_format_invalid',$e->getMessage());
9089
		$exception->setLineNumber($line);
9090
		if(!empty($srcFile))
9091
			$exception->setTemplateFile($srcFile);
9092
		else
9093
			$exception->setTemplateSource($input);
9094
		throw $exception;
9095
	}
9096
	protected function preprocess($input)
9097
	{
9098
		if($n=preg_match_all('/<%include(.*?)%>/',$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE))
9099
		{
9100
			for($i=0;$i<$n;++$i)
9101
			{
9102
				$filePath=Prado::getPathOfNamespace(trim($matches[$i][1][0]),TTemplateManager::TEMPLATE_FILE_EXT);
9103
				if($filePath!==null && is_file($filePath))
9104
					$this->_includedFiles[]=$filePath;
9105
				else
9106
				{
9107
					$errorLine=count(explode("\n",substr($input,0,$matches[$i][0][1]+1)));
9108
					$this->handleException(new TConfigurationException('template_include_invalid',trim($matches[$i][1][0])),$errorLine,$input);
9109
				}
9110
			}
9111
			$base=0;
9112
			for($i=0;$i<$n;++$i)
9113
			{
9114
				$ext=file_get_contents($this->_includedFiles[$i]);
9115
				$length=strlen($matches[$i][0][0]);
9116
				$offset=$base+$matches[$i][0][1];
9117
				$this->_includeAtLine[$i]=count(explode("\n",substr($input,0,$offset)));
9118
				$this->_includeLines[$i]=count(explode("\n",$ext));
9119
				$input=substr_replace($input,$ext,$offset,$length);
9120
				$base+=strlen($ext)-$length;
9121
			}
9122
		}
9123
		return $input;
9124
	}
9125
	protected function isClassBehaviorMethod(ReflectionClass $class,$method)
9126
	{
9127
	  $component=new ReflectionClass('TComponent');
9128
	  $behaviors=$component->getStaticProperties();
9129
	  if(!isset($behaviors['_um']))
9130
	    return false;
9131
	  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...
9132
	  {
9133
	    if(strtolower($class->getShortName())!==$name && !$class->isSubclassOf($name)) continue;
9134
	    foreach($list as $param)
9135
	    {
9136
	      if(method_exists($param->getBehavior(),$method))
9137
	        return true;
9138
	    }
9139
	  }
9140
	  return false;
9141
	}
9142
}
9143
class TThemeManager extends TModule
9144
{
9145
	const DEFAULT_BASEPATH='themes';
9146
	const DEFAULT_THEMECLASS = 'TTheme';
9147
	private $_themeClass=self::DEFAULT_THEMECLASS;
9148
	private $_initialized=false;
9149
	private $_basePath=null;
9150
	private $_baseUrl=null;
9151
	public function init($config)
9152
	{
9153
		$this->_initialized=true;
9154
		$service=$this->getService();
9155
		if($service instanceof TPageService)
9156
			$service->setThemeManager($this);
9157
		else
9158
			throw new TConfigurationException('thememanager_service_unavailable');
9159
	}
9160
	public function getTheme($name)
9161
	{
9162
		$themePath=$this->getBasePath().DIRECTORY_SEPARATOR.$name;
9163
		$themeUrl=rtrim($this->getBaseUrl(),'/').'/'.$name;
9164
		return Prado::createComponent($this->getThemeClass(), $themePath, $themeUrl);
9165
	}
9166
	public function setThemeClass($class) {
9167
		$this->_themeClass = $class===null ? self::DEFAULT_THEMECLASS : (string)$class;
9168
	}
9169
	public function getThemeClass() {
9170
		return $this->_themeClass;
9171
	}
9172
	public function getAvailableThemes()
9173
	{
9174
		$themes=array();
9175
		$basePath=$this->getBasePath();
9176
		$folder=@opendir($basePath);
9177
		while($file=@readdir($folder))
9178
		{
9179
			if($file!=='.' && $file!=='..' && $file!=='.svn' && is_dir($basePath.DIRECTORY_SEPARATOR.$file))
9180
				$themes[]=$file;
9181
		}
9182
		closedir($folder);
9183
		return $themes;
9184
	}
9185
	public function getBasePath()
9186
	{
9187
		if($this->_basePath===null)
9188
		{
9189
			$this->_basePath=dirname($this->getRequest()->getApplicationFilePath()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
9190
			if(($basePath=realpath($this->_basePath))===false || !is_dir($basePath))
9191
				throw new TConfigurationException('thememanager_basepath_invalid2',$this->_basePath);
9192
			$this->_basePath=$basePath;
9193
		}
9194
		return $this->_basePath;
9195
	}
9196
	public function setBasePath($value)
9197
	{
9198
		if($this->_initialized)
9199
			throw new TInvalidOperationException('thememanager_basepath_unchangeable');
9200
		else
9201
		{
9202
			$this->_basePath=Prado::getPathOfNamespace($value);
9203
			if($this->_basePath===null || !is_dir($this->_basePath))
9204
				throw new TInvalidDataValueException('thememanager_basepath_invalid',$value);
9205
		}
9206
	}
9207
	public function getBaseUrl()
9208
	{
9209
		if($this->_baseUrl===null)
9210
		{
9211
			$appPath=dirname($this->getRequest()->getApplicationFilePath());
9212
			$basePath=$this->getBasePath();
9213
			if(strpos($basePath,$appPath)===false)
9214
				throw new TConfigurationException('thememanager_baseurl_required');
9215
			$appUrl=rtrim(dirname($this->getRequest()->getApplicationUrl()),'/\\');
9216
			$this->_baseUrl=$appUrl.strtr(substr($basePath,strlen($appPath)),'\\','/');
9217
		}
9218
		return $this->_baseUrl;
9219
	}
9220
	public function setBaseUrl($value)
9221
	{
9222
		$this->_baseUrl=rtrim($value,'/');
9223
	}
9224
}
9225
class TTheme extends TApplicationComponent implements ITheme
9226
{
9227
	const THEME_CACHE_PREFIX='prado:theme:';
9228
	const SKIN_FILE_EXT='.skin';
9229
	private $_themePath;
9230
	private $_themeUrl;
9231
	private $_skins=null;
9232
	private $_name='';
9233
	private $_cssFiles=array();
9234
	private $_jsFiles=array();
9235
	public function __construct($themePath,$themeUrl)
9236
	{
9237
		$this->_themeUrl=$themeUrl;
9238
		$this->_themePath=realpath($themePath);
9239
		$this->_name=basename($themePath);
9240
		$cacheValid=false;
9241
				if(($cache=$this->getApplication()->getCache())!==null)
9242
		{
9243
			$array=$cache->get(self::THEME_CACHE_PREFIX.$themePath);
9244
			if(is_array($array))
9245
			{
9246
				list($skins,$cssFiles,$jsFiles,$timestamp)=$array;
9247
				if($this->getApplication()->getMode()!==TApplicationMode::Performance)
9248
				{
9249
					if(($dir=opendir($themePath))===false)
9250
						throw new TIOException('theme_path_inexistent',$themePath);
9251
					$cacheValid=true;
9252
					while(($file=readdir($dir))!==false)
9253
					{
9254
						if($file==='.' || $file==='..')
9255
							continue;
9256
						else if(basename($file,'.css')!==$file)
9257
							$this->_cssFiles[]=$themeUrl.'/'.$file;
9258
						else if(basename($file,'.js')!==$file)
9259
							$this->_jsFiles[]=$themeUrl.'/'.$file;
9260
						else if(basename($file,self::SKIN_FILE_EXT)!==$file && filemtime($themePath.DIRECTORY_SEPARATOR.$file)>$timestamp)
9261
						{
9262
							$cacheValid=false;
9263
							break;
9264
						}
9265
					}
9266
					closedir($dir);
9267
					if($cacheValid)
9268
						$this->_skins=$skins;
9269
				}
9270
				else
9271
				{
9272
					$cacheValid=true;
9273
					$this->_cssFiles=$cssFiles;
9274
					$this->_jsFiles=$jsFiles;
9275
					$this->_skins=$skins;
9276
				}
9277
			}
9278
		}
9279
		if(!$cacheValid)
9280
		{
9281
			$this->_cssFiles=array();
9282
			$this->_jsFiles=array();
9283
			$this->_skins=array();
9284
			if(($dir=opendir($themePath))===false)
9285
				throw new TIOException('theme_path_inexistent',$themePath);
9286
			while(($file=readdir($dir))!==false)
9287
			{
9288
				if($file==='.' || $file==='..')
9289
					continue;
9290
				else if(basename($file,'.css')!==$file)
9291
					$this->_cssFiles[]=$themeUrl.'/'.$file;
9292
				else if(basename($file,'.js')!==$file)
9293
					$this->_jsFiles[]=$themeUrl.'/'.$file;
9294
				else if(basename($file,self::SKIN_FILE_EXT)!==$file)
9295
				{
9296
					$template=new TTemplate(file_get_contents($themePath.'/'.$file),$themePath,$themePath.'/'.$file);
9297
					foreach($template->getItems() as $skin)
9298
					{
9299
						if(!isset($skin[2]))  							continue;
9300
						else if($skin[0]!==-1)
9301
							throw new TConfigurationException('theme_control_nested',$skin[1],dirname($themePath));
9302
						$type=$skin[1];
9303
						$id=isset($skin[2]['skinid'])?$skin[2]['skinid']:0;
9304
						unset($skin[2]['skinid']);
9305
						if(isset($this->_skins[$type][$id]))
9306
							throw new TConfigurationException('theme_skinid_duplicated',$type,$id,dirname($themePath));
9307
						$this->_skins[$type][$id]=$skin[2];
9308
					}
9309
				}
9310
			}
9311
			closedir($dir);
9312
			sort($this->_cssFiles);
9313
			sort($this->_jsFiles);
9314
			if($cache!==null)
9315
				$cache->set(self::THEME_CACHE_PREFIX.$themePath,array($this->_skins,$this->_cssFiles,$this->_jsFiles,time()));
9316
		}
9317
	}
9318
	public function getName()
9319
	{
9320
		return $this->_name;
9321
	}
9322
	protected function setName($value)
9323
	{
9324
		$this->_name = $value;
9325
	}
9326
	public function getBaseUrl()
9327
	{
9328
		return $this->_themeUrl;
9329
	}
9330
	protected function setBaseUrl($value)
9331
	{
9332
		$this->_themeUrl=rtrim($value,'/');
9333
	}
9334
	public function getBasePath()
9335
	{
9336
		return $this->_themePath;
9337
	}
9338
	protected function setBasePath($value)
9339
	{
9340
		$this->_themePath=$value;
9341
	}
9342
	public function getSkins()
9343
	{
9344
		return $this->_skins;
9345
	}
9346
	protected function setSkins($value)
9347
	{
9348
		$this->_skins = $value;
9349
	}
9350
	public function applySkin($control)
9351
	{
9352
		$type=get_class($control);
9353
		if(($id=$control->getSkinID())==='')
9354
			$id=0;
9355
		if(isset($this->_skins[$type][$id]))
9356
		{
9357
			foreach($this->_skins[$type][$id] as $name=>$value)
9358
			{
9359
				if(is_array($value))
9360
				{
9361
					switch($value[0])
9362
					{
9363
						case TTemplate::CONFIG_EXPRESSION:
9364
							$value=$this->evaluateExpression($value[1]);
9365
							break;
9366
						case TTemplate::CONFIG_ASSET:
9367
							$value=$this->_themeUrl.'/'.ltrim($value[1],'/');
9368
							break;
9369
						case TTemplate::CONFIG_DATABIND:
9370
							$control->bindProperty($name,$value[1]);
9371
							break;
9372
						case TTemplate::CONFIG_PARAMETER:
9373
							$control->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
9374
							break;
9375
						case TTemplate::CONFIG_TEMPLATE:
9376
							$control->setSubProperty($name,$value[1]);
9377
							break;
9378
						case TTemplate::CONFIG_LOCALIZATION:
9379
							$control->setSubProperty($name,Prado::localize($value[1]));
9380
							break;
9381
						default:
9382
							throw new TConfigurationException('theme_tag_unexpected',$name,$value[0]);
9383
							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...
9384
					}
9385
				}
9386
				if(!is_array($value))
9387
				{
9388
					if(strpos($name,'.')===false)						{
9389
						if($control->hasProperty($name))
9390
						{
9391
							if($control->canSetProperty($name))
9392
							{
9393
								$setter='set'.$name;
9394
								$control->$setter($value);
9395
							}
9396
							else
9397
								throw new TConfigurationException('theme_property_readonly',$type,$name);
9398
						}
9399
						else
9400
							throw new TConfigurationException('theme_property_undefined',$type,$name);
9401
					}
9402
					else							$control->setSubProperty($name,$value);
9403
				}
9404
			}
9405
			return true;
9406
		}
9407
		else
9408
			return false;
9409
	}
9410
	public function getStyleSheetFiles()
9411
	{
9412
		return $this->_cssFiles;
9413
	}
9414
	protected function setStyleSheetFiles($value)
9415
	{
9416
		$this->_cssFiles=$value;
9417
	}
9418
	public function getJavaScriptFiles()
9419
	{
9420
		return $this->_jsFiles;
9421
	}
9422
	protected function setJavaScriptFiles($value)
9423
	{
9424
		$this->_jsFiles=$value;
9425
	}
9426
}
9427
class TPageService extends TService
9428
{
9429
	const CONFIG_FILE_XML='config.xml';
9430
	const CONFIG_FILE_PHP='config.php';
9431
	const DEFAULT_BASEPATH='Pages';
9432
	const FALLBACK_BASEPATH='pages';
9433
	const CONFIG_CACHE_PREFIX='prado:pageservice:';
9434
	const PAGE_FILE_EXT='.page';
9435
	private $_basePath=null;
9436
	private $_basePageClass='TPage';
9437
	private $_clientScriptManagerClass='System.Web.UI.TClientScriptManager';
9438
	private $_defaultPage='Home';
9439
	private $_pagePath=null;
9440
	private $_page=null;
9441
	private $_properties=array();
9442
	private $_initialized=false;
9443
	private $_themeManager=null;
9444
	private $_templateManager=null;
9445
	public function init($config)
9446
	{
9447
		$pageConfig=$this->loadPageConfig($config);
9448
		$this->initPageContext($pageConfig);
9449
		$this->_initialized=true;
9450
	}
9451
	protected function initPageContext($pageConfig)
9452
	{
9453
		$application=$this->getApplication();
9454
		foreach($pageConfig->getApplicationConfigurations() as $appConfig)
9455
			$application->applyConfiguration($appConfig);
9456
		$this->applyConfiguration($pageConfig);
9457
	}
9458
	protected function applyConfiguration($config)
9459
	{
9460
				$this->_properties=array_merge($this->_properties, $config->getProperties());
9461
		$this->getApplication()->getAuthorizationRules()->mergeWith($config->getRules());
9462
		$pagePath=$this->getRequestedPagePath();
9463
				foreach($config->getExternalConfigurations() as $filePath=>$params)
9464
		{
9465
			list($configPagePath,$condition)=$params;
9466
			if($condition!==true)
9467
				$condition=$this->evaluateExpression($condition);
9468
			if($condition)
9469
			{
9470
				if(($path=Prado::getPathOfNamespace($filePath,Prado::getApplication()->getConfigurationFileExt()))===null || !is_file($path))
9471
					throw new TConfigurationException('pageservice_includefile_invalid',$filePath);
9472
				$c=new TPageConfiguration($pagePath);
9473
				$c->loadFromFile($path,$configPagePath);
9474
				$this->applyConfiguration($c);
9475
			}
9476
		}
9477
	}
9478
	protected function determineRequestedPagePath()
9479
	{
9480
		$pagePath=$this->getRequest()->getServiceParameter();
9481
		if(empty($pagePath))
9482
			$pagePath=$this->getDefaultPage();
9483
		return $pagePath;
9484
	}
9485
	protected function loadPageConfig($config)
9486
	{
9487
		$application=$this->getApplication();
9488
		$pagePath=$this->getRequestedPagePath();
9489
		if(($cache=$application->getCache())===null)
9490
		{
9491
			$pageConfig=new TPageConfiguration($pagePath);
9492
			if($config!==null)
9493
			{
9494
				if($application->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
9495
					$pageConfig->loadPageConfigurationFromPhp($config,$application->getBasePath(),'');
9496
				else
9497
					$pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),'');
9498
			}
9499
			$pageConfig->loadFromFiles($this->getBasePath());
9500
		}
9501
		else
9502
		{
9503
			$configCached=true;
9504
			$currentTimestamp=array();
9505
			$arr=$cache->get(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath);
9506
			if(is_array($arr))
9507
			{
9508
				list($pageConfig,$timestamps)=$arr;
9509
				if($application->getMode()!==TApplicationMode::Performance)
9510
				{
9511
					foreach($timestamps as $fileName=>$timestamp)
9512
					{
9513
						if($fileName===0) 						{
9514
							$appConfigFile=$application->getConfigurationFile();
9515
							$currentTimestamp[0]=$appConfigFile===null?0:@filemtime($appConfigFile);
9516
							if($currentTimestamp[0]>$timestamp || ($timestamp>0 && !$currentTimestamp[0]))
9517
								$configCached=false;
9518
						}
9519
						else
9520
						{
9521
							$currentTimestamp[$fileName]=@filemtime($fileName);
9522
							if($currentTimestamp[$fileName]>$timestamp || ($timestamp>0 && !$currentTimestamp[$fileName]))
9523
								$configCached=false;
9524
						}
9525
					}
9526
				}
9527
			}
9528
			else
9529
			{
9530
				$configCached=false;
9531
				$paths=explode('.',$pagePath);
9532
				$configPath=$this->getBasePath();
9533
				$fileName = $this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP
9534
					? self::CONFIG_FILE_PHP
9535
					: self::CONFIG_FILE_XML;
9536
				foreach($paths as $path)
9537
				{
9538
					$configFile=$configPath.DIRECTORY_SEPARATOR.$fileName;
9539
					$currentTimestamp[$configFile]=@filemtime($configFile);
9540
					$configPath.=DIRECTORY_SEPARATOR.$path;
9541
				}
9542
				$appConfigFile=$application->getConfigurationFile();
9543
				$currentTimestamp[0]=$appConfigFile===null?0:@filemtime($appConfigFile);
9544
			}
9545
			if(!$configCached)
9546
			{
9547
				$pageConfig=new TPageConfiguration($pagePath);
9548
				if($config!==null)
9549
				{
9550
					if($application->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
9551
						$pageConfig->loadPageConfigurationFromPhp($config,$application->getBasePath(),'');
9552
					else
9553
						$pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),'');
9554
				}
9555
				$pageConfig->loadFromFiles($this->getBasePath());
9556
				$cache->set(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath,array($pageConfig,$currentTimestamp));
9557
			}
9558
		}
9559
		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...
9560
	}
9561
	public function getTemplateManager()
9562
	{
9563
		if(!$this->_templateManager)
9564
		{
9565
			$this->_templateManager=new TTemplateManager;
9566
			$this->_templateManager->init(null);
9567
		}
9568
		return $this->_templateManager;
9569
	}
9570
	public function setTemplateManager(TTemplateManager $value)
9571
	{
9572
		$this->_templateManager=$value;
9573
	}
9574
	public function getThemeManager()
9575
	{
9576
		if(!$this->_themeManager)
9577
		{
9578
			$this->_themeManager=new TThemeManager;
9579
			$this->_themeManager->init(null);
9580
		}
9581
		return $this->_themeManager;
9582
	}
9583
	public function setThemeManager(TThemeManager $value)
9584
	{
9585
		$this->_themeManager=$value;
9586
	}
9587
	public function getRequestedPagePath()
9588
	{
9589
		if($this->_pagePath===null)
9590
		{
9591
			$this->_pagePath=strtr($this->determineRequestedPagePath(),'/\\','..');
9592
			if(empty($this->_pagePath))
9593
				throw new THttpException(404,'pageservice_page_required');
9594
		}
9595
		return $this->_pagePath;
9596
	}
9597
	public function getRequestedPage()
9598
	{
9599
		return $this->_page;
9600
	}
9601
	public function getDefaultPage()
9602
	{
9603
		return $this->_defaultPage;
9604
	}
9605
	public function setDefaultPage($value)
9606
	{
9607
		if($this->_initialized)
9608
			throw new TInvalidOperationException('pageservice_defaultpage_unchangeable');
9609
		else
9610
			$this->_defaultPage=$value;
9611
	}
9612
	public function getDefaultPageUrl()
9613
	{
9614
		return $this->constructUrl($this->getDefaultPage());
9615
	}
9616
	public function getBasePath()
9617
	{
9618
		if($this->_basePath===null)
9619
		{
9620
			$basePath=$this->getApplication()->getBasePath().DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
9621
			if(($this->_basePath=realpath($basePath))===false || !is_dir($this->_basePath))
9622
			{
9623
				$basePath=$this->getApplication()->getBasePath().DIRECTORY_SEPARATOR.self::FALLBACK_BASEPATH;
9624
				if(($this->_basePath=realpath($basePath))===false || !is_dir($this->_basePath))
9625
					throw new TConfigurationException('pageservice_basepath_invalid',$basePath);
9626
			}
9627
		}
9628
		return $this->_basePath;
9629
	}
9630
	public function setBasePath($value)
9631
	{
9632
		if($this->_initialized)
9633
			throw new TInvalidOperationException('pageservice_basepath_unchangeable');
9634
		else if(($path=Prado::getPathOfNamespace($value))===null || !is_dir($path))
9635
			throw new TConfigurationException('pageservice_basepath_invalid',$value);
9636
		$this->_basePath=realpath($path);
9637
	}
9638
	public function setBasePageClass($value)
9639
	{
9640
		$this->_basePageClass=$value;
9641
	}
9642
	public function getBasePageClass()
9643
	{
9644
		return $this->_basePageClass;
9645
	}
9646
	public function setClientScriptManagerClass($value)
9647
	{
9648
		$this->_clientScriptManagerClass=$value;
9649
	}
9650
	public function getClientScriptManagerClass()
9651
	{
9652
		return $this->_clientScriptManagerClass;
9653
	}
9654
	public function run()
9655
	{
9656
		$this->_page=$this->createPage($this->getRequestedPagePath());
9657
		$this->runPage($this->_page,$this->_properties);
9658
	}
9659
	protected function createPage($pagePath)
9660
	{
9661
		$path=$this->getBasePath().DIRECTORY_SEPARATOR.strtr($pagePath,'.',DIRECTORY_SEPARATOR);
9662
		$hasTemplateFile=is_file($path.self::PAGE_FILE_EXT);
9663
		$hasClassFile=is_file($path.Prado::CLASS_FILE_EXT);
9664
		if(!$hasTemplateFile && !$hasClassFile)
9665
			throw new THttpException(404,'pageservice_page_unknown',$pagePath);
9666
		if($hasClassFile)
9667
		{
9668
			$className=basename($path);
9669
			if(!class_exists($className,false))
9670
				include_once($path.Prado::CLASS_FILE_EXT);
9671
		}
9672
		else
9673
		{
9674
			$className=$this->getBasePageClass();
9675
			Prado::using($className);
9676
			if(($pos=strrpos($className,'.'))!==false)
9677
				$className=substr($className,$pos+1);
9678
		}
9679
 		if(!class_exists($className,false) || ($className!=='TPage' && !is_subclass_of($className,'TPage')))
9680
			throw new THttpException(404,'pageservice_page_unknown',$pagePath);
9681
		$page=Prado::createComponent($className);
9682
		$page->setPagePath($pagePath);
9683
		if($hasTemplateFile)
9684
			$page->setTemplate($this->getTemplateManager()->getTemplateByFileName($path.self::PAGE_FILE_EXT));
9685
		return $page;
9686
	}
9687
	protected function runPage($page,$properties)
9688
	{
9689
		foreach($properties as $name=>$value)
9690
			$page->setSubProperty($name,$value);
9691
		$page->run($this->getResponse()->createHtmlWriter());
9692
	}
9693
	public function constructUrl($pagePath,$getParams=null,$encodeAmpersand=true,$encodeGetItems=true)
9694
	{
9695
		return $this->getRequest()->constructUrl($this->getID(),$pagePath,$getParams,$encodeAmpersand,$encodeGetItems);
9696
	}
9697
}
9698
class TPageConfiguration extends TComponent
9699
{
9700
	private $_appConfigs=array();
9701
	private $_properties=array();
9702
	private $_rules=array();
9703
	private $_includes=array();
9704
	private $_pagePath='';
9705
	public function __construct($pagePath)
9706
	{
9707
		$this->_pagePath=$pagePath;
9708
	}
9709
	public function getExternalConfigurations()
9710
	{
9711
		return $this->_includes;
9712
	}
9713
	public function getProperties()
9714
	{
9715
		return $this->_properties;
9716
	}
9717
	public function getRules()
9718
	{
9719
		return $this->_rules;
9720
	}
9721
	public function getApplicationConfigurations()
9722
	{
9723
		return $this->_appConfigs;
9724
	}
9725
	public function loadFromFiles($basePath)
9726
	{
9727
		$paths=explode('.',$this->_pagePath);
9728
		$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...
9729
		$path=$basePath;
9730
		$configPagePath='';
9731
		$fileName = Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP
9732
			? TPageService::CONFIG_FILE_PHP
9733
			: TPageService::CONFIG_FILE_XML;
9734
		foreach($paths as $p)
9735
		{
9736
			$this->loadFromFile($path.DIRECTORY_SEPARATOR.$fileName,$configPagePath);
9737
			$path.=DIRECTORY_SEPARATOR.$p;
9738
			if($configPagePath==='')
9739
				$configPagePath=$p;
9740
			else
9741
				$configPagePath.='.'.$p;
9742
		}
9743
		$this->loadFromFile($path.DIRECTORY_SEPARATOR.$fileName,$configPagePath);
9744
		$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...
9745
	}
9746
	public function loadFromFile($fname,$configPagePath)
9747
	{
9748
		if(empty($fname) || !is_file($fname))
9749
			return;
9750
		if(Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
9751
		{
9752
			$fcontent = include $fname;
9753
			$this->loadFromPhp($fcontent,dirname($fname),$configPagePath);
9754
		}
9755
		else
9756
		{
9757
			$dom=new TXmlDocument;
9758
			if($dom->loadFromFile($fname))
9759
				$this->loadFromXml($dom,dirname($fname),$configPagePath);
9760
			else
9761
				throw new TConfigurationException('pageserviceconf_file_invalid',$fname);
9762
		}
9763
	}
9764
	public function loadFromPhp($config,$configPath,$configPagePath)
9765
	{
9766
		$this->loadApplicationConfigurationFromPhp($config,$configPath);
9767
		$this->loadPageConfigurationFromPhp($config,$configPath,$configPagePath);
9768
	}
9769
	public function loadFromXml($dom,$configPath,$configPagePath)
9770
	{
9771
		$this->loadApplicationConfigurationFromXml($dom,$configPath);
9772
		$this->loadPageConfigurationFromXml($dom,$configPath,$configPagePath);
9773
	}
9774
	public function loadApplicationConfigurationFromPhp($config,$configPath)
9775
	{
9776
		$appConfig=new TApplicationConfiguration;
9777
		$appConfig->loadFromPhp($config,$configPath);
9778
		$this->_appConfigs[]=$appConfig;
9779
	}
9780
	public function loadApplicationConfigurationFromXml($dom,$configPath)
9781
	{
9782
		$appConfig=new TApplicationConfiguration;
9783
		$appConfig->loadFromXml($dom,$configPath);
9784
		$this->_appConfigs[]=$appConfig;
9785
	}
9786
	public function loadPageConfigurationFromPhp($config, $configPath, $configPagePath)
9787
	{
9788
				if(isset($config['authorization']) && is_array($config['authorization']))
9789
		{
9790
			$rules = array();
9791
			foreach($config['authorization'] as $authorization)
9792
			{
9793
				$patterns=isset($authorization['pages'])?$authorization['pages']:'';
9794
				$ruleApplies=false;
9795
				if(empty($patterns) || trim($patterns)==='*') 					$ruleApplies=true;
9796
				else
9797
				{
9798
					foreach(explode(',',$patterns) as $pattern)
9799
					{
9800
						if(($pattern=trim($pattern))!=='')
9801
						{
9802
														if($configPagePath!=='')  								$pattern=$configPagePath.'.'.$pattern;
9803
							if(strcasecmp($pattern,$this->_pagePath)===0)
9804
							{
9805
								$ruleApplies=true;
9806
								break;
9807
							}
9808
							if($pattern[strlen($pattern)-1]==='*') 							{
9809
								if(strncasecmp($this->_pagePath,$pattern,strlen($pattern)-1)===0)
9810
								{
9811
									$ruleApplies=true;
9812
									break;
9813
								}
9814
							}
9815
						}
9816
					}
9817
				}
9818
				if($ruleApplies)
9819
				{
9820
					$action = isset($authorization['action'])?$authorization['action']:'';
9821
					$users = isset($authorization['users'])?$authorization['users']:'';
9822
					$roles = isset($authorization['roles'])?$authorization['roles']:'';
9823
					$verb = isset($authorization['verb'])?$authorization['verb']:'';
9824
					$ips = isset($authorization['ips'])?$authorization['ips']:'';
9825
					$rules[]=new TAuthorizationRule($action,$users,$roles,$verb,$ips);
9826
				}
9827
			}
9828
			$this->_rules=array_merge($rules,$this->_rules);
9829
		}
9830
				if(isset($config['pages']) && is_array($config['pages']))
9831
		{
9832
			if(isset($config['pages']['properties']))
9833
			{
9834
				$this->_properties = array_merge($this->_properties, $config['pages']['properties']);
9835
				unset($config['pages']['properties']);
9836
			}
9837
			foreach($config['pages'] as $id => $page)
9838
			{
9839
				$properties = array();
9840
				if(isset($page['properties']))
9841
				{
9842
					$properties=$page['properties'];
9843
					unset($page['properties']);
9844
				}
9845
				$matching=false;
9846
				$id=($configPagePath==='')?$id:$configPagePath.'.'.$id;
9847
				if(strcasecmp($id,$this->_pagePath)===0)
9848
					$matching=true;
9849
				else if($id[strlen($id)-1]==='*') 					$matching=strncasecmp($this->_pagePath,$id,strlen($id)-1)===0;
9850
				if($matching)
9851
					$this->_properties=array_merge($this->_properties,$properties);
9852
			}
9853
		}
9854
				if(isset($config['includes']) && is_array($config['includes']))
9855
		{
9856
			foreach($config['includes'] as $include)
9857
			{
9858
				$when = isset($include['when'])?true:false;
9859
				if(!isset($include['file']))
9860
					throw new TConfigurationException('pageserviceconf_includefile_required');
9861
				$filePath = $include['file'];
9862
				if(isset($this->_includes[$filePath]))
9863
					$this->_includes[$filePath]=array($configPagePath,'('.$this->_includes[$filePath][1].') || ('.$when.')');
9864
				else
9865
					$this->_includes[$filePath]=array($configPagePath,$when);
9866
			}
9867
		}
9868
	}
9869
	public function loadPageConfigurationFromXml($dom,$configPath,$configPagePath)
9870
	{
9871
				if(($authorizationNode=$dom->getElementByTagName('authorization'))!==null)
9872
		{
9873
			$rules=array();
9874
			foreach($authorizationNode->getElements() as $node)
9875
			{
9876
				$patterns=$node->getAttribute('pages');
9877
				$ruleApplies=false;
9878
				if(empty($patterns) || trim($patterns)==='*') 					$ruleApplies=true;
9879
				else
9880
				{
9881
					foreach(explode(',',$patterns) as $pattern)
9882
					{
9883
						if(($pattern=trim($pattern))!=='')
9884
						{
9885
														if($configPagePath!=='')  								$pattern=$configPagePath.'.'.$pattern;
9886
							if(strcasecmp($pattern,$this->_pagePath)===0)
9887
							{
9888
								$ruleApplies=true;
9889
								break;
9890
							}
9891
							if($pattern[strlen($pattern)-1]==='*') 							{
9892
								if(strncasecmp($this->_pagePath,$pattern,strlen($pattern)-1)===0)
9893
								{
9894
									$ruleApplies=true;
9895
									break;
9896
								}
9897
							}
9898
						}
9899
					}
9900
				}
9901
				if($ruleApplies)
9902
					$rules[]=new TAuthorizationRule($node->getTagName(),$node->getAttribute('users'),$node->getAttribute('roles'),$node->getAttribute('verb'),$node->getAttribute('ips'));
9903
			}
9904
			$this->_rules=array_merge($rules,$this->_rules);
9905
		}
9906
				if(($pagesNode=$dom->getElementByTagName('pages'))!==null)
9907
		{
9908
			$this->_properties=array_merge($this->_properties,$pagesNode->getAttributes()->toArray());
9909
						foreach($pagesNode->getElementsByTagName('page') as $node)
9910
			{
9911
				$properties=$node->getAttributes();
9912
				$id=$properties->remove('id');
9913
				if(empty($id))
9914
					throw new TConfigurationException('pageserviceconf_page_invalid',$configPath);
9915
				$matching=false;
9916
				$id=($configPagePath==='')?$id:$configPagePath.'.'.$id;
9917
				if(strcasecmp($id,$this->_pagePath)===0)
9918
					$matching=true;
9919
				else if($id[strlen($id)-1]==='*') 					$matching=strncasecmp($this->_pagePath,$id,strlen($id)-1)===0;
9920
				if($matching)
9921
					$this->_properties=array_merge($this->_properties,$properties->toArray());
9922
			}
9923
		}
9924
				foreach($dom->getElementsByTagName('include') as $node)
9925
		{
9926
			if(($when=$node->getAttribute('when'))===null)
9927
				$when=true;
9928
			if(($filePath=$node->getAttribute('file'))===null)
9929
				throw new TConfigurationException('pageserviceconf_includefile_required');
9930
			if(isset($this->_includes[$filePath]))
9931
				$this->_includes[$filePath]=array($configPagePath,'('.$this->_includes[$filePath][1].') || ('.$when.')');
9932
			else
9933
				$this->_includes[$filePath]=array($configPagePath,$when);
9934
		}
9935
	}
9936
}
9937
class TAssetManager extends TModule
9938
{
9939
	const DEFAULT_BASEPATH='assets';
9940
	private $_basePath=null;
9941
	private $_baseUrl=null;
9942
	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...
9943
	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...
9944
	private $_published=array();
9945
	private $_initialized=false;
9946
	public function init($config)
9947
	{
9948
		$application=$this->getApplication();
9949
		if($this->_basePath===null)
9950
			$this->_basePath=dirname($application->getRequest()->getApplicationFilePath()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
9951
		if(!is_writable($this->_basePath) || !is_dir($this->_basePath))
9952
			throw new TConfigurationException('assetmanager_basepath_invalid',$this->_basePath);
9953
		if($this->_baseUrl===null)
9954
			$this->_baseUrl=rtrim(dirname($application->getRequest()->getApplicationUrl()),'/\\').'/'.self::DEFAULT_BASEPATH;
9955
		$application->setAssetManager($this);
9956
		$this->_initialized=true;
9957
	}
9958
	public function getBasePath()
9959
	{
9960
		return $this->_basePath;
9961
	}
9962
	public function setBasePath($value)
9963
	{
9964
		if($this->_initialized)
9965
			throw new TInvalidOperationException('assetmanager_basepath_unchangeable');
9966
		else
9967
		{
9968
			$this->_basePath=Prado::getPathOfNamespace($value);
9969
			if($this->_basePath===null || !is_dir($this->_basePath) || !is_writable($this->_basePath))
9970
				throw new TInvalidDataValueException('assetmanager_basepath_invalid',$value);
9971
		}
9972
	}
9973
	public function getBaseUrl()
9974
	{
9975
		return $this->_baseUrl;
9976
	}
9977
	public function setBaseUrl($value)
9978
	{
9979
		if($this->_initialized)
9980
			throw new TInvalidOperationException('assetmanager_baseurl_unchangeable');
9981
		else
9982
			$this->_baseUrl=rtrim($value,'/');
9983
	}
9984
	public function publishFilePath($path,$checkTimestamp=false)
9985
	{
9986
		if(isset($this->_published[$path]))
9987
			return $this->_published[$path];
9988
		else if(empty($path) || ($fullpath=realpath($path))===false)
9989
			throw new TInvalidDataValueException('assetmanager_filepath_invalid',$path);
9990
		else if(is_file($fullpath))
9991
		{
9992
			$dir=$this->hash(dirname($fullpath));
9993
			$fileName=basename($fullpath);
9994
			$dst=$this->_basePath.DIRECTORY_SEPARATOR.$dir;
9995
			if(!is_file($dst.DIRECTORY_SEPARATOR.$fileName) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
9996
				$this->copyFile($fullpath,$dst);
9997
			return $this->_published[$path]=$this->_baseUrl.'/'.$dir.'/'.$fileName;
9998
		}
9999
		else
10000
		{
10001
			$dir=$this->hash($fullpath);
10002
			if(!is_dir($this->_basePath.DIRECTORY_SEPARATOR.$dir) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
10003
			{
10004
				$this->copyDirectory($fullpath,$this->_basePath.DIRECTORY_SEPARATOR.$dir);
10005
			}
10006
			return $this->_published[$path]=$this->_baseUrl.'/'.$dir;
10007
		}
10008
	}
10009
	public function getPublished()
10010
	{
10011
		return $this->_published;
10012
	}
10013
	protected function setPublished($values=array())
10014
	{
10015
		$this->_published = $values;
10016
	}
10017
	public function getPublishedPath($path)
10018
	{
10019
		$path=realpath($path);
10020
		if(is_file($path))
10021
			return $this->_basePath.DIRECTORY_SEPARATOR.$this->hash(dirname($path)).DIRECTORY_SEPARATOR.basename($path);
10022
		else
10023
			return $this->_basePath.DIRECTORY_SEPARATOR.$this->hash($path);
10024
	}
10025
	public function getPublishedUrl($path)
10026
	{
10027
		$path=realpath($path);
10028
		if(is_file($path))
10029
			return $this->_baseUrl.'/'.$this->hash(dirname($path)).'/'.basename($path);
10030
		else
10031
			return $this->_baseUrl.'/'.$this->hash($path);
10032
	}
10033
	protected function hash($dir)
10034
	{
10035
		return sprintf('%x',crc32($dir.Prado::getVersion()));
10036
	}
10037
	protected function copyFile($src,$dst)
10038
	{
10039
		if(!is_dir($dst))
10040
		{
10041
			@mkdir($dst);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
10042
			@chmod($dst, PRADO_CHMOD);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
10043
		}
10044
		$dstFile=$dst.DIRECTORY_SEPARATOR.basename($src);
10045
		if(@filemtime($dstFile)<@filemtime($src))
10046
		{
10047
			@copy($src,$dstFile);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
10048
		}
10049
	}
10050
	public function copyDirectory($src,$dst)
10051
	{
10052
		if(!is_dir($dst))
10053
		{
10054
			@mkdir($dst);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
10055
			@chmod($dst, PRADO_CHMOD);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
10056
		}
10057
		if($folder=@opendir($src))
10058
		{
10059
			while($file=@readdir($folder))
10060
			{
10061
				if($file==='.' || $file==='..' || $file==='.svn')
10062
					continue;
10063
				else if(is_file($src.DIRECTORY_SEPARATOR.$file))
10064
				{
10065
					if(@filemtime($dst.DIRECTORY_SEPARATOR.$file)<@filemtime($src.DIRECTORY_SEPARATOR.$file))
10066
					{
10067
						@copy($src.DIRECTORY_SEPARATOR.$file,$dst.DIRECTORY_SEPARATOR.$file);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
10068
						@chmod($dst.DIRECTORY_SEPARATOR.$file, PRADO_CHMOD);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
10069
					}
10070
				}
10071
				else
10072
					$this->copyDirectory($src.DIRECTORY_SEPARATOR.$file,$dst.DIRECTORY_SEPARATOR.$file);
10073
			}
10074
			closedir($folder);
10075
		} else {
10076
			throw new TInvalidDataValueException('assetmanager_source_directory_invalid', $src);
10077
		}
10078
	}
10079
	public function publishTarFile($tarfile, $md5sum, $checkTimestamp=false)
10080
	{
10081
		if(isset($this->_published[$md5sum]))
10082
			return $this->_published[$md5sum];
10083
		else if(($fullpath=realpath($md5sum))===false || !is_file($fullpath))
10084
			throw new TInvalidDataValueException('assetmanager_tarchecksum_invalid',$md5sum);
10085
		else
10086
		{
10087
			$dir=$this->hash(dirname($fullpath));
10088
			$fileName=basename($fullpath);
10089
			$dst=$this->_basePath.DIRECTORY_SEPARATOR.$dir;
10090
			if(!is_file($dst.DIRECTORY_SEPARATOR.$fileName) || $checkTimestamp || $this->getApplication()->getMode()!==TApplicationMode::Performance)
10091
			{
10092
				if(@filemtime($dst.DIRECTORY_SEPARATOR.$fileName)<@filemtime($fullpath))
10093
				{
10094
					$this->copyFile($fullpath,$dst);
10095
					$this->deployTarFile($tarfile,$dst);
10096
				}
10097
			}
10098
			return $this->_published[$md5sum]=$this->_baseUrl.'/'.$dir;
10099
		}
10100
	}
10101
	protected function deployTarFile($path,$destination)
10102
	{
10103
		if(($fullpath=realpath($path))===false || !is_file($fullpath))
10104
			throw new TIOException('assetmanager_tarfile_invalid',$path);
10105
		else
10106
		{
10107
			Prado::using('System.IO.TTarFileExtractor');
10108
			$tar = new TTarFileExtractor($fullpath);
10109
			return $tar->extract($destination);
10110
		}
10111
	}
10112
}
10113
class TGlobalization extends TModule
10114
{
10115
	private $_defaultCharset = 'UTF-8';
10116
	private $_defaultCulture = 'en';
10117
	private $_charset=null;
10118
	private $_culture=null;
10119
	private $_translation;
10120
	private $_translateDefaultCulture=true;
10121
	public function init($config)
10122
	{
10123
		if($this->_charset===null)
10124
			$this->_charset=$this->getDefaultCharset();
10125
		if($this->_culture===null)
10126
			$this->_culture=$this->getDefaultCulture();
10127
		if($config!==null)
10128
		{
10129
			if($this->getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
10130
				$translation = isset($config['translate'])?$config['translate']:null;
10131
			else
10132
			{
10133
				$t = $config->getElementByTagName('translation');
10134
				$translation = ($t)?$t->getAttributes():null;
10135
			}
10136
			if($translation)
10137
				$this->setTranslationConfiguration($translation);
10138
		}
10139
		$this->getApplication()->setGlobalization($this);
10140
	}
10141
	public function getTranslateDefaultCulture()
10142
	{
10143
		return $this->_translateDefaultCulture;
10144
	}
10145
	public function setTranslateDefaultCulture($value)
10146
	{
10147
		$this->_translateDefaultCulture = TPropertyValue::ensureBoolean($value);
10148
	}
10149
	public function getDefaultCulture()
10150
	{
10151
		return $this->_defaultCulture;
10152
	}
10153
	public function setDefaultCulture($culture)
10154
	{
10155
		$this->_defaultCulture = str_replace('-','_',$culture);
10156
	}
10157
	public function getDefaultCharset()
10158
	{
10159
		return $this->_defaultCharset;
10160
	}
10161
	public function setDefaultCharset($charset)
10162
	{
10163
		$this->_defaultCharset = $charset;
10164
	}
10165
	public function getCulture()
10166
	{
10167
		return $this->_culture;
10168
	}
10169
	public function setCulture($culture)
10170
	{
10171
		$this->_culture = str_replace('-','_',$culture);
10172
	}
10173
	public function getCharset()
10174
	{
10175
		return $this->_charset;
10176
	}
10177
	public function setCharset($charset)
10178
	{
10179
		$this->_charset = $charset;
10180
	}
10181
	public function getTranslationConfiguration()
10182
	{
10183
		return (!$this->_translateDefaultCulture && ($this->getDefaultCulture() == $this->getCulture()))
10184
			? null
10185
			: $this->_translation;
10186
	}
10187
	protected function setTranslationConfiguration($config)
10188
	{
10189
		if($config['type'] == 'XLIFF' || $config['type'] == 'gettext')
10190
		{
10191
			if($config['source'])
10192
			{
10193
				$config['source'] = Prado::getPathOfNamespace($config['source']);
10194
				if(!is_dir($config['source']))
10195
				{
10196
					if(@mkdir($config['source'])===false)
10197
					throw new TConfigurationException('globalization_source_path_failed',
10198
						$config['source']);
10199
					chmod($config['source'], PRADO_CHMOD); 				}
10200
			}
10201
			else
10202
			{
10203
				throw new TConfigurationException("invalid source dir '{$config['source']}'");
10204
			}
10205
		}
10206
		if($config['cache'])
10207
		{
10208
			$config['cache'] = $this->getApplication()->getRunTimePath().'/i18n';
10209
			if(!is_dir($config['cache']))
10210
			{
10211
				if(@mkdir($config['cache'])===false)
10212
					throw new TConfigurationException('globalization_cache_path_failed',
10213
						$config['cache']);
10214
				chmod($config['cache'], PRADO_CHMOD); 			}
10215
		}
10216
		$this->_translation = $config;
10217
	}
10218
	public function getTranslationCatalogue()
10219
	{
10220
		return $this->_translation['catalogue'];
10221
	}
10222
	public function setTranslationCatalogue($value)
10223
	{
10224
		$this->_translation['catalogue'] = $value;
10225
	}
10226
	public function getCultureVariants($culture=null)
10227
	{
10228
		if($culture===null) $culture = $this->getCulture();
10229
		$variants = explode('_', $culture);
10230
		$result = array();
10231
		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...
10232
			$result[] = implode('_', $variants);
10233
		return $result;
10234
	}
10235
	public function getLocalizedResource($file,$culture=null)
10236
	{
10237
		$files = array();
10238
		$variants = $this->getCultureVariants($culture);
10239
		$path = pathinfo($file);
10240
		foreach($variants as $variant)
10241
			$files[] = $path['dirname'].DIRECTORY_SEPARATOR.$variant.DIRECTORY_SEPARATOR.$path['basename'];
10242
		$filename = substr($path['basename'],0,strrpos($path['basename'],'.'));
10243
		foreach($variants as $variant)
10244
			$files[] = $path['dirname'].DIRECTORY_SEPARATOR.$filename.'.'.$variant.'.'.$path['extension'];
10245
		$files[] = $file;
10246
		return $files;
10247
	}
10248
}
10249
class TApplication extends TComponent
10250
{
10251
	const STATE_OFF='Off';
10252
	const STATE_DEBUG='Debug';
10253
	const STATE_NORMAL='Normal';
10254
	const STATE_PERFORMANCE='Performance';
10255
	const PAGE_SERVICE_ID='page';
10256
	const CONFIG_FILE_XML='application.xml';
10257
	const CONFIG_FILE_EXT_XML='.xml';
10258
	const CONFIG_TYPE_XML = 'xml';
10259
	const CONFIG_FILE_PHP='application.php';
10260
	const CONFIG_FILE_EXT_PHP='.php';
10261
	const CONFIG_TYPE_PHP = 'php';
10262
	const RUNTIME_PATH='runtime';
10263
	const CONFIGCACHE_FILE='config.cache';
10264
	const GLOBAL_FILE='global.cache';
10265
	private static $_steps=array(
10266
		'onBeginRequest',
10267
		'onLoadState',
10268
		'onLoadStateComplete',
10269
		'onAuthentication',
10270
		'onAuthenticationComplete',
10271
		'onAuthorization',
10272
		'onAuthorizationComplete',
10273
		'onPreRunService',
10274
		'runService',
10275
		'onSaveState',
10276
		'onSaveStateComplete',
10277
		'onPreFlushOutput',
10278
		'flushOutput'
10279
	);
10280
	private $_id;
10281
	private $_uniqueID;
10282
	private $_requestCompleted=false;
10283
	private $_step;
10284
	private $_services;
10285
	private $_service;
10286
	private $_modules=array();
10287
	private $_lazyModules=array();
10288
	private $_parameters;
10289
	private $_configFile;
10290
	private $_configFileExt;
10291
	private $_configType;
10292
	private $_basePath;
10293
	private $_runtimePath;
10294
	private $_stateChanged=false;
10295
	private $_globals=array();
10296
	private $_cacheFile;
10297
	private $_errorHandler;
10298
	private $_request;
10299
	private $_response;
10300
	private $_session;
10301
	private $_cache;
10302
	private $_statePersister;
10303
	private $_user;
10304
	private $_globalization;
10305
	private $_security;
10306
	private $_assetManager;
10307
	private $_authRules;
10308
	private $_mode=TApplicationMode::Debug;
10309
	private $_pageServiceID = self::PAGE_SERVICE_ID;
10310
	public function __construct($basePath='protected',$cacheConfig=true, $configType=self::CONFIG_TYPE_XML)
10311
	{
10312
				Prado::setApplication($this);
10313
		$this->setConfigurationType($configType);
10314
		$this->resolvePaths($basePath);
10315
		if($cacheConfig)
10316
			$this->_cacheFile=$this->_runtimePath.DIRECTORY_SEPARATOR.self::CONFIGCACHE_FILE;
10317
				$this->_uniqueID=md5($this->_runtimePath);
10318
		$this->_parameters=new TMap;
10319
		$this->_services=array($this->getPageServiceID()=>array('TPageService',array(),null));
10320
		Prado::setPathOfAlias('Application',$this->_basePath);
10321
	}
10322
	protected function resolvePaths($basePath)
10323
	{
10324
				if(empty($basePath) || ($basePath=realpath($basePath))===false)
10325
			throw new TConfigurationException('application_basepath_invalid',$basePath);
10326
		if(is_dir($basePath) && is_file($basePath.DIRECTORY_SEPARATOR.$this->getConfigurationFileName()))
10327
			$configFile=$basePath.DIRECTORY_SEPARATOR.$this->getConfigurationFileName();
10328
		else if(is_file($basePath))
10329
		{
10330
			$configFile=$basePath;
10331
			$basePath=dirname($configFile);
10332
		}
10333
		else
10334
			$configFile=null;
10335
				$runtimePath=$basePath.DIRECTORY_SEPARATOR.self::RUNTIME_PATH;
10336
		if(is_writable($runtimePath))
10337
		{
10338
			if($configFile!==null)
10339
			{
10340
				$runtimePath.=DIRECTORY_SEPARATOR.basename($configFile).'-'.Prado::getVersion();
10341
				if(!is_dir($runtimePath))
10342
				{
10343
					if(@mkdir($runtimePath)===false)
10344
						throw new TConfigurationException('application_runtimepath_failed',$runtimePath);
10345
					@chmod($runtimePath, PRADO_CHMOD); 				}
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
10346
				$this->setConfigurationFile($configFile);
10347
			}
10348
			$this->setBasePath($basePath);
10349
			$this->setRuntimePath($runtimePath);
10350
		}
10351
		else
10352
			throw new TConfigurationException('application_runtimepath_invalid',$runtimePath);
10353
	}
10354
	public function run()
10355
	{
10356
		try
10357
		{
10358
			$this->initApplication();
10359
			$n=count(self::$_steps);
10360
			$this->_step=0;
10361
			$this->_requestCompleted=false;
10362
			while($this->_step<$n)
10363
			{
10364
				if($this->_mode===self::STATE_OFF)
10365
					throw new THttpException(503,'application_unavailable');
10366
				if($this->_requestCompleted)
10367
					break;
10368
				$method=self::$_steps[$this->_step];
10369
				$this->$method();
10370
				$this->_step++;
10371
			}
10372
		}
10373
		catch(Exception $e)
10374
		{
10375
			$this->onError($e);
10376
		}
10377
		$this->onEndRequest();
10378
	}
10379
	public function completeRequest()
10380
	{
10381
		$this->_requestCompleted=true;
10382
	}
10383
	public function getRequestCompleted()
10384
	{
10385
		return $this->_requestCompleted;
10386
	}
10387
	public function getGlobalState($key,$defaultValue=null)
10388
	{
10389
		return isset($this->_globals[$key])?$this->_globals[$key]:$defaultValue;
10390
	}
10391
	public function setGlobalState($key,$value,$defaultValue=null,$forceSave=false)
10392
	{
10393
		$this->_stateChanged=true;
10394
		if($value===$defaultValue)
10395
			unset($this->_globals[$key]);
10396
		else
10397
			$this->_globals[$key]=$value;
10398
		if($forceSave)
10399
			$this->saveGlobals();
10400
	}
10401
	public function clearGlobalState($key)
10402
	{
10403
		$this->_stateChanged=true;
10404
		unset($this->_globals[$key]);
10405
	}
10406
	protected function loadGlobals()
10407
	{
10408
		$this->_globals=$this->getApplicationStatePersister()->load();
10409
	}
10410
	protected function saveGlobals()
10411
	{
10412
		if($this->_stateChanged)
10413
		{
10414
			$this->_stateChanged=false;
10415
			$this->getApplicationStatePersister()->save($this->_globals);
10416
		}
10417
	}
10418
	public function getID()
10419
	{
10420
		return $this->_id;
10421
	}
10422
	public function setID($value)
10423
	{
10424
		$this->_id=$value;
10425
	}
10426
	public function getPageServiceID()
10427
	{
10428
		return $this->_pageServiceID;
10429
	}
10430
	public function setPageServiceID($value)
10431
	{
10432
		$this->_pageServiceID=$value;
10433
	}
10434
	public function getUniqueID()
10435
	{
10436
		return $this->_uniqueID;
10437
	}
10438
	public function getMode()
10439
	{
10440
		return $this->_mode;
10441
	}
10442
	public function setMode($value)
10443
	{
10444
		$this->_mode=TPropertyValue::ensureEnum($value,'TApplicationMode');
10445
	}
10446
	public function getBasePath()
10447
	{
10448
		return $this->_basePath;
10449
	}
10450
	public function setBasePath($value)
10451
	{
10452
		$this->_basePath=$value;
10453
	}
10454
	public function getConfigurationFile()
10455
	{
10456
		return $this->_configFile;
10457
	}
10458
	public function setConfigurationFile($value)
10459
	{
10460
		$this->_configFile=$value;
10461
	}
10462
	public function getConfigurationType()
10463
	{
10464
		return $this->_configType;
10465
	}
10466
	public function setConfigurationType($value)
10467
	{
10468
		$this->_configType = $value;
10469
	}
10470
	public function getConfigurationFileExt()
10471
	{
10472
		if($this->_configFileExt===null)
10473
		{
10474
			switch($this->_configType)
10475
			{
10476
				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...
10477
					$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...
10478
					break;
10479
				default:
10480
					$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...
10481
			}
10482
		}
10483
		return $this->_configFileExt;
10484
	}
10485
	public function getConfigurationFileName()
10486
	{
10487
		static $fileName;
10488
		if($fileName == null)
10489
		{
10490
			switch($this->_configType)
10491
			{
10492
				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...
10493
					$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...
10494
					break;
10495
				default:
10496
					$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...
10497
			}
10498
		}
10499
		return $fileName;
10500
	}
10501
	public function getRuntimePath()
10502
	{
10503
		return $this->_runtimePath;
10504
	}
10505
	public function setRuntimePath($value)
10506
	{
10507
		$this->_runtimePath=$value;
10508
		if($this->_cacheFile)
10509
			$this->_cacheFile=$this->_runtimePath.DIRECTORY_SEPARATOR.self::CONFIGCACHE_FILE;
10510
				$this->_uniqueID=md5($this->_runtimePath);
10511
	}
10512
	public function getService()
10513
	{
10514
		return $this->_service;
10515
	}
10516
	public function setService($value)
10517
	{
10518
		$this->_service=$value;
10519
	}
10520
	public function setModule($id,IModule $module=null)
10521
	{
10522
		if(isset($this->_modules[$id]))
10523
			throw new TConfigurationException('application_moduleid_duplicated',$id);
10524
		else
10525
			$this->_modules[$id]=$module;
10526
	}
10527
	public function getModule($id)
10528
	{
10529
		if(!array_key_exists($id, $this->_modules))
10530
			return null;
10531
				if($this->_modules[$id]===null)
10532
		{
10533
			$module = $this->internalLoadModule($id, true);
10534
			$module[0]->init($module[1]);
10535
		}
10536
		return $this->_modules[$id];
10537
	}
10538
	public function getModules()
10539
	{
10540
		return $this->_modules;
10541
	}
10542
	public function getParameters()
10543
	{
10544
		return $this->_parameters;
10545
	}
10546
	public function getRequest()
10547
	{
10548
		if(!$this->_request)
10549
		{
10550
			$this->_request=new THttpRequest;
10551
			$this->_request->init(null);
10552
		}
10553
		return $this->_request;
10554
	}
10555
	public function setRequest(THttpRequest $request)
10556
	{
10557
		$this->_request=$request;
10558
	}
10559
	public function getResponse()
10560
	{
10561
		if(!$this->_response)
10562
		{
10563
			$this->_response=new THttpResponse;
10564
			$this->_response->init(null);
10565
		}
10566
		return $this->_response;
10567
	}
10568
	public function setResponse(THttpResponse $response)
10569
	{
10570
		$this->_response=$response;
10571
	}
10572
	public function getSession()
10573
	{
10574
		if(!$this->_session)
10575
		{
10576
			$this->_session=new THttpSession;
10577
			$this->_session->init(null);
10578
		}
10579
		return $this->_session;
10580
	}
10581
	public function setSession(THttpSession $session)
10582
	{
10583
		$this->_session=$session;
10584
	}
10585
	public function getErrorHandler()
10586
	{
10587
		if(!$this->_errorHandler)
10588
		{
10589
			$this->_errorHandler=new TErrorHandler;
10590
			$this->_errorHandler->init(null);
10591
		}
10592
		return $this->_errorHandler;
10593
	}
10594
	public function setErrorHandler(TErrorHandler $handler)
10595
	{
10596
		$this->_errorHandler=$handler;
10597
	}
10598
	public function getSecurityManager()
10599
	{
10600
		if(!$this->_security)
10601
		{
10602
			$this->_security=new TSecurityManager;
10603
			$this->_security->init(null);
10604
		}
10605
		return $this->_security;
10606
	}
10607
	public function setSecurityManager(TSecurityManager $sm)
10608
	{
10609
		$this->_security=$sm;
10610
	}
10611
	public function getAssetManager()
10612
	{
10613
		if(!$this->_assetManager)
10614
		{
10615
			$this->_assetManager=new TAssetManager;
10616
			$this->_assetManager->init(null);
10617
		}
10618
		return $this->_assetManager;
10619
	}
10620
	public function setAssetManager(TAssetManager $value)
10621
	{
10622
		$this->_assetManager=$value;
10623
	}
10624
	public function getApplicationStatePersister()
10625
	{
10626
		if(!$this->_statePersister)
10627
		{
10628
			$this->_statePersister=new TApplicationStatePersister;
10629
			$this->_statePersister->init(null);
10630
		}
10631
		return $this->_statePersister;
10632
	}
10633
	public function setApplicationStatePersister(IStatePersister $persister)
10634
	{
10635
		$this->_statePersister=$persister;
10636
	}
10637
	public function getCache()
10638
	{
10639
		return $this->_cache;
10640
	}
10641
	public function setCache(ICache $cache)
10642
	{
10643
		$this->_cache=$cache;
10644
	}
10645
	public function getUser()
10646
	{
10647
		return $this->_user;
10648
	}
10649
	public function setUser(IUser $user)
10650
	{
10651
		$this->_user=$user;
10652
	}
10653
	public function getGlobalization($createIfNotExists=true)
10654
	{
10655
		if($this->_globalization===null && $createIfNotExists)
10656
		{
10657
			$this->_globalization=new TGlobalization;
10658
			$this->_globalization->init(null);
10659
		}
10660
		return $this->_globalization;
10661
	}
10662
	public function setGlobalization(TGlobalization $glob)
10663
	{
10664
		$this->_globalization=$glob;
10665
	}
10666
	public function getAuthorizationRules()
10667
	{
10668
		if($this->_authRules===null)
10669
			$this->_authRules=new TAuthorizationRuleCollection;
10670
		return $this->_authRules;
10671
	}
10672
	protected function getApplicationConfigurationClass()
10673
	{
10674
		return 'TApplicationConfiguration';
10675
	}
10676
	protected function internalLoadModule($id, $force=false)
10677
	{
10678
		list($moduleClass, $initProperties, $configElement)=$this->_lazyModules[$id];
10679
		if(isset($initProperties['lazy']) && $initProperties['lazy'] && !$force)
10680
		{
10681
			$this->setModule($id, null);
10682
			return null;
10683
		}
10684
		$module=Prado::createComponent($moduleClass);
10685
		foreach($initProperties as $name=>$value)
10686
		{
10687
			if($name==='lazy') continue;
10688
			$module->setSubProperty($name,$value);
10689
		}
10690
		$this->setModule($id,$module);
10691
				$this->_lazyModules[$id]=null;
10692
		return array($module,$configElement);
10693
	}
10694
	public function applyConfiguration($config,$withinService=false)
10695
	{
10696
		if($config->getIsEmpty())
10697
			return;
10698
				foreach($config->getAliases() as $alias=>$path)
10699
			Prado::setPathOfAlias($alias,$path);
10700
		foreach($config->getUsings() as $using)
10701
			Prado::using($using);
10702
				if(!$withinService)
10703
		{
10704
			foreach($config->getProperties() as $name=>$value)
10705
				$this->setSubProperty($name,$value);
10706
		}
10707
		if(empty($this->_services))
10708
			$this->_services=array($this->getPageServiceID()=>array('TPageService',array(),null));
10709
				foreach($config->getParameters() as $id=>$parameter)
10710
		{
10711
			if(is_array($parameter))
10712
			{
10713
				$component=Prado::createComponent($parameter[0]);
10714
				foreach($parameter[1] as $name=>$value)
10715
					$component->setSubProperty($name,$value);
10716
				$this->_parameters->add($id,$component);
10717
			}
10718
			else
10719
				$this->_parameters->add($id,$parameter);
10720
		}
10721
				$modules=array();
10722
		foreach($config->getModules() as $id=>$moduleConfig)
10723
		{
10724
			if(!is_string($id))
10725
				$id='_module'.count($this->_lazyModules);
10726
			$this->_lazyModules[$id]=$moduleConfig;
10727
			if($module = $this->internalLoadModule($id))
10728
				$modules[]=$module;
10729
		}
10730
		foreach($modules as $module)
10731
			$module[0]->init($module[1]);
10732
				foreach($config->getServices() as $serviceID=>$serviceConfig)
10733
			$this->_services[$serviceID]=$serviceConfig;
10734
				foreach($config->getExternalConfigurations() as $filePath=>$condition)
10735
		{
10736
			if($condition!==true)
10737
				$condition=$this->evaluateExpression($condition);
10738
			if($condition)
10739
			{
10740
				if(($path=Prado::getPathOfNamespace($filePath,$this->getConfigurationFileExt()))===null || !is_file($path))
10741
					throw new TConfigurationException('application_includefile_invalid',$filePath);
10742
				$cn=$this->getApplicationConfigurationClass();
10743
				$c=new $cn;
10744
				$c->loadFromFile($path);
10745
				$this->applyConfiguration($c,$withinService);
10746
			}
10747
		}
10748
	}
10749
	protected function initApplication()
10750
	{
10751
		if($this->_configFile!==null)
10752
		{
10753
			if($this->_cacheFile===null || @filemtime($this->_cacheFile)<filemtime($this->_configFile))
10754
			{
10755
				$config=new TApplicationConfiguration;
10756
				$config->loadFromFile($this->_configFile);
10757
				if($this->_cacheFile!==null)
10758
					file_put_contents($this->_cacheFile,serialize($config),LOCK_EX);
10759
			}
10760
			else
10761
				$config=unserialize(file_get_contents($this->_cacheFile));
10762
			$this->applyConfiguration($config,false);
10763
		}
10764
		if(($serviceID=$this->getRequest()->resolveRequest(array_keys($this->_services)))===null)
10765
			$serviceID=$this->getPageServiceID();
10766
		$this->startService($serviceID);
10767
	}
10768
	public function startService($serviceID)
10769
	{
10770
		if(isset($this->_services[$serviceID]))
10771
		{
10772
			list($serviceClass,$initProperties,$configElement)=$this->_services[$serviceID];
10773
			$service=Prado::createComponent($serviceClass);
10774
			if(!($service instanceof IService))
10775
				throw new THttpException(500,'application_service_invalid',$serviceClass);
10776
			if(!$service->getEnabled())
10777
				throw new THttpException(500,'application_service_unavailable',$serviceClass);
10778
			$service->setID($serviceID);
10779
			$this->setService($service);
10780
			foreach($initProperties as $name=>$value)
10781
				$service->setSubProperty($name,$value);
10782
			if($configElement!==null)
10783
			{
10784
				$config=new TApplicationConfiguration;
10785
				if($this->getConfigurationType()==self::CONFIG_TYPE_PHP)
10786
					$config->loadFromPhp($configElement,$this->getBasePath());
10787
				else
10788
					$config->loadFromXml($configElement,$this->getBasePath());
10789
				$this->applyConfiguration($config,true);
10790
			}
10791
			$service->init($configElement);
10792
		}
10793
		else
10794
			throw new THttpException(500,'application_service_unknown',$serviceID);
10795
	}
10796
	public function onError($param)
10797
	{
10798
		Prado::log($param->getMessage(),TLogger::ERROR,'System.TApplication');
10799
		$this->raiseEvent('OnError',$this,$param);
10800
		$this->getErrorHandler()->handleError($this,$param);
10801
	}
10802
	public function onBeginRequest()
10803
	{
10804
		$this->raiseEvent('OnBeginRequest',$this,null);
10805
	}
10806
	public function onAuthentication()
10807
	{
10808
		$this->raiseEvent('OnAuthentication',$this,null);
10809
	}
10810
	public function onAuthenticationComplete()
10811
	{
10812
		$this->raiseEvent('OnAuthenticationComplete',$this,null);
10813
	}
10814
	public function onAuthorization()
10815
	{
10816
		$this->raiseEvent('OnAuthorization',$this,null);
10817
	}
10818
	public function onAuthorizationComplete()
10819
	{
10820
		$this->raiseEvent('OnAuthorizationComplete',$this,null);
10821
	}
10822
	public function onLoadState()
10823
	{
10824
		$this->loadGlobals();
10825
		$this->raiseEvent('OnLoadState',$this,null);
10826
	}
10827
	public function onLoadStateComplete()
10828
	{
10829
		$this->raiseEvent('OnLoadStateComplete',$this,null);
10830
	}
10831
	public function onPreRunService()
10832
	{
10833
		$this->raiseEvent('OnPreRunService',$this,null);
10834
	}
10835
	public function runService()
10836
	{
10837
		if($this->_service)
10838
			$this->_service->run();
10839
	}
10840
	public function onSaveState()
10841
	{
10842
		$this->raiseEvent('OnSaveState',$this,null);
10843
		$this->saveGlobals();
10844
	}
10845
	public function onSaveStateComplete()
10846
	{
10847
		$this->raiseEvent('OnSaveStateComplete',$this,null);
10848
	}
10849
	public function onPreFlushOutput()
10850
	{
10851
		$this->raiseEvent('OnPreFlushOutput',$this,null);
10852
	}
10853
	public function flushOutput($continueBuffering = true)
10854
	{
10855
		$this->getResponse()->flush($continueBuffering);
10856
	}
10857
	public function onEndRequest()
10858
	{
10859
		$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...
10860
	}
10861
}
10862
class TApplicationMode extends TEnumerable
10863
{
10864
	const Off='Off';
10865
	const Debug='Debug';
10866
	const Normal='Normal';
10867
	const Performance='Performance';
10868
}
10869
class TApplicationConfiguration extends TComponent
10870
{
10871
	private $_properties=array();
10872
	private $_usings=array();
10873
	private $_aliases=array();
10874
	private $_modules=array();
10875
	private $_services=array();
10876
	private $_parameters=array();
10877
	private $_includes=array();
10878
	private $_empty=true;
10879
	public function loadFromFile($fname)
10880
	{
10881
		if(Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
10882
		{
10883
			$fcontent = include $fname;
10884
			$this->loadFromPhp($fcontent,dirname($fname));
10885
		}
10886
		else
10887
		{
10888
			$dom=new TXmlDocument;
10889
			$dom->loadFromFile($fname);
10890
			$this->loadFromXml($dom,dirname($fname));
10891
		}
10892
	}
10893
	public function getIsEmpty()
10894
	{
10895
		return $this->_empty;
10896
	}
10897
	public function loadFromPhp($config, $configPath)
10898
	{
10899
				if(isset($config['application']))
10900
		{
10901
			foreach($config['application'] as $name=>$value)
10902
			{
10903
				$this->_properties[$name]=$value;
10904
			}
10905
			$this->_empty = false;
10906
		}
10907
		if(isset($config['paths']) && is_array($config['paths']))
10908
			$this->loadPathsPhp($config['paths'],$configPath);
10909
		if(isset($config['modules']) && is_array($config['modules']))
10910
			$this->loadModulesPhp($config['modules'],$configPath);
10911
		if(isset($config['services']) && is_array($config['services']))
10912
			$this->loadServicesPhp($config['services'],$configPath);
10913
		if(isset($config['parameters']) && is_array($config['parameters']))
10914
			$this->loadParametersPhp($config['parameters'], $configPath);
10915
		if(isset($config['includes']) && is_array($config['includes']))
10916
			$this->loadExternalXml($config['includes'],$configPath);
10917
	}
10918
	public function loadFromXml($dom,$configPath)
10919
	{
10920
				foreach($dom->getAttributes() as $name=>$value)
10921
		{
10922
			$this->_properties[$name]=$value;
10923
			$this->_empty=false;
10924
		}
10925
		foreach($dom->getElements() as $element)
10926
		{
10927
			switch($element->getTagName())
10928
			{
10929
				case 'paths':
10930
					$this->loadPathsXml($element,$configPath);
10931
					break;
10932
				case 'modules':
10933
					$this->loadModulesXml($element,$configPath);
10934
					break;
10935
				case 'services':
10936
					$this->loadServicesXml($element,$configPath);
10937
					break;
10938
				case 'parameters':
10939
					$this->loadParametersXml($element,$configPath);
10940
					break;
10941
				case 'include':
10942
					$this->loadExternalXml($element,$configPath);
10943
					break;
10944
				default:
10945
										break;
10946
			}
10947
		}
10948
	}
10949
	protected function loadPathsPhp($pathsNode, $configPath)
10950
	{
10951
		if(isset($pathsNode['aliases']) && is_array($pathsNode['aliases']))
10952
		{
10953
			foreach($pathsNode['aliases'] as $id=>$path)
10954
			{
10955
				$path=str_replace('\\','/',$path);
10956
				if(preg_match('/^\\/|.:\\/|.:\\\\/',$path))						$p=realpath($path);
10957
				else
10958
					$p=realpath($configPath.DIRECTORY_SEPARATOR.$path);
10959
				if($p===false || !is_dir($p))
10960
					throw new TConfigurationException('appconfig_aliaspath_invalid',$id,$path);
10961
				if(isset($this->_aliases[$id]))
10962
					throw new TConfigurationException('appconfig_alias_redefined',$id);
10963
				$this->_aliases[$id]=$p;
10964
			}
10965
		}
10966
		if(isset($pathsNode['using']) && is_array($pathsNode['using']))
10967
		{
10968
			foreach($pathsNode['using'] as $namespace)
10969
			{
10970
				$this->_usings[] = $namespace;
10971
			}
10972
		}
10973
	}
10974
	protected function loadPathsXml($pathsNode,$configPath)
10975
	{
10976
		foreach($pathsNode->getElements() as $element)
10977
		{
10978
			switch($element->getTagName())
10979
			{
10980
				case 'alias':
0 ignored issues
show
Coding Style introduced by
CASE statements must be defined using a colon

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

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

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

Loading history...
10981
				{
10982
					if(($id=$element->getAttribute('id'))!==null && ($path=$element->getAttribute('path'))!==null)
10983
					{
10984
						$path=str_replace('\\','/',$path);
10985
						if(preg_match('/^\\/|.:\\/|.:\\\\/',$path))								$p=realpath($path);
10986
						else
10987
							$p=realpath($configPath.DIRECTORY_SEPARATOR.$path);
10988
						if($p===false || !is_dir($p))
10989
							throw new TConfigurationException('appconfig_aliaspath_invalid',$id,$path);
10990
						if(isset($this->_aliases[$id]))
10991
							throw new TConfigurationException('appconfig_alias_redefined',$id);
10992
						$this->_aliases[$id]=$p;
10993
					}
10994
					else
10995
						throw new TConfigurationException('appconfig_alias_invalid');
10996
					$this->_empty=false;
10997
					break;
10998
				}
10999
				case 'using':
0 ignored issues
show
Coding Style introduced by
CASE statements must be defined using a colon

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

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

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

Loading history...
11000
				{
11001
					if(($namespace=$element->getAttribute('namespace'))!==null)
11002
						$this->_usings[]=$namespace;
11003
					else
11004
						throw new TConfigurationException('appconfig_using_invalid');
11005
					$this->_empty=false;
11006
					break;
11007
				}
11008
				default:
11009
					throw new TConfigurationException('appconfig_paths_invalid',$element->getTagName());
11010
			}
11011
		}
11012
	}
11013
	protected function loadModulesPhp($modulesNode, $configPath)
11014
	{
11015
		foreach($modulesNode as $id=>$module)
11016
		{
11017
			if(!isset($module['class']))
11018
				throw new TConfigurationException('appconfig_moduletype_required',$id);
11019
			$type = $module['class'];
11020
			unset($module['class']);
11021
			$properties = array();
11022
			if(isset($module['properties']))
11023
			{
11024
				$properties = $module['properties'];
11025
				unset($module['properties']);
11026
			}
11027
			$properties['id'] = $id;
11028
			$this->_modules[$id]=array($type,$properties,$module);
11029
			$this->_empty=false;
11030
		}
11031
	}
11032
	protected function loadModulesXml($modulesNode,$configPath)
11033
	{
11034
		foreach($modulesNode->getElements() as $element)
11035
		{
11036
			if($element->getTagName()==='module')
11037
			{
11038
				$properties=$element->getAttributes();
11039
				$id=$properties->itemAt('id');
11040
				$type=$properties->remove('class');
11041
				if($type===null)
11042
					throw new TConfigurationException('appconfig_moduletype_required',$id);
11043
				$element->setParent(null);
11044
				if($id===null)
11045
					$this->_modules[]=array($type,$properties->toArray(),$element);
11046
				else
11047
					$this->_modules[$id]=array($type,$properties->toArray(),$element);
11048
				$this->_empty=false;
11049
			}
11050
			else
11051
				throw new TConfigurationException('appconfig_modules_invalid',$element->getTagName());
11052
		}
11053
	}
11054
	protected function loadServicesPhp($servicesNode,$configPath)
11055
	{
11056
		foreach($servicesNode as $id => $service)
11057
		{
11058
			if(!isset($service['class']))
11059
				throw new TConfigurationException('appconfig_servicetype_required');
11060
			$type = $service['class'];
11061
			$properties = isset($service['properties']) ? $service['properties'] : array();
11062
			unset($service['properties']);
11063
			$properties['id'] = $id;
11064
			$this->_services[$id] = array($type,$properties,$service);
11065
			$this->_empty = false;
11066
		}
11067
	}
11068
	protected function loadServicesXml($servicesNode,$configPath)
11069
	{
11070
		foreach($servicesNode->getElements() as $element)
11071
		{
11072
			if($element->getTagName()==='service')
11073
			{
11074
				$properties=$element->getAttributes();
11075
				if(($id=$properties->itemAt('id'))===null)
11076
					throw new TConfigurationException('appconfig_serviceid_required');
11077
				if(($type=$properties->remove('class'))===null)
11078
					throw new TConfigurationException('appconfig_servicetype_required',$id);
11079
				$element->setParent(null);
11080
				$this->_services[$id]=array($type,$properties->toArray(),$element);
11081
				$this->_empty=false;
11082
			}
11083
			else
11084
				throw new TConfigurationException('appconfig_services_invalid',$element->getTagName());
11085
		}
11086
	}
11087
	protected function loadParametersPhp($parametersNode,$configPath)
11088
	{
11089
		foreach($parametersNode as $id => $parameter)
11090
		{
11091
			if(is_array($parameter))
11092
			{
11093
				if(isset($parameter['class']))
11094
				{
11095
					$type = $parameter['class'];
11096
					unset($parameter['class']);
11097
					$properties = isset($service['properties']) ? $service['properties'] : array();
11098
					$properties['id'] = $id;
11099
					$this->_parameters[$id] = array($type,$properties);
11100
				}
11101
			}
11102
			else
11103
			{
11104
				$this->_parameters[$id] = $parameter;
11105
			}
11106
		}
11107
	}
11108
	protected function loadParametersXml($parametersNode,$configPath)
11109
	{
11110
		foreach($parametersNode->getElements() as $element)
11111
		{
11112
			if($element->getTagName()==='parameter')
11113
			{
11114
				$properties=$element->getAttributes();
11115
				if(($id=$properties->remove('id'))===null)
11116
					throw new TConfigurationException('appconfig_parameterid_required');
11117
				if(($type=$properties->remove('class'))===null)
11118
				{
11119
					if(($value=$properties->remove('value'))===null)
11120
						$this->_parameters[$id]=$element;
11121
					else
11122
						$this->_parameters[$id]=$value;
11123
				}
11124
				else
11125
					$this->_parameters[$id]=array($type,$properties->toArray());
11126
				$this->_empty=false;
11127
			}
11128
			else
11129
				throw new TConfigurationException('appconfig_parameters_invalid',$element->getTagName());
11130
		}
11131
	}
11132
	protected function loadExternalPhp($includeNode,$configPath)
11133
	{
11134
		foreach($includeNode as $include)
11135
		{
11136
			$when = isset($include['when'])?true:false;
11137
			if(!isset($include['file']))
11138
				throw new TConfigurationException('appconfig_includefile_required');
11139
			$filePath = $include['file'];
11140
			if(isset($this->_includes[$filePath]))
11141
				$this->_includes[$filePath]='('.$this->_includes[$filePath].') || ('.$when.')';
11142
			else
11143
				$$this->_includes[$filePath]=$when;
11144
			$this->_empty=false;
11145
		}
11146
	}
11147
	protected function loadExternalXml($includeNode,$configPath)
11148
	{
11149
		if(($when=$includeNode->getAttribute('when'))===null)
11150
			$when=true;
11151
		if(($filePath=$includeNode->getAttribute('file'))===null)
11152
			throw new TConfigurationException('appconfig_includefile_required');
11153
		if(isset($this->_includes[$filePath]))
11154
			$this->_includes[$filePath]='('.$this->_includes[$filePath].') || ('.$when.')';
11155
		else
11156
			$this->_includes[$filePath]=$when;
11157
		$this->_empty=false;
11158
	}
11159
	public function getProperties()
11160
	{
11161
		return $this->_properties;
11162
	}
11163
	public function getAliases()
11164
	{
11165
		return $this->_aliases;
11166
	}
11167
	public function getUsings()
11168
	{
11169
		return $this->_usings;
11170
	}
11171
	public function getModules()
11172
	{
11173
		return $this->_modules;
11174
	}
11175
	public function getServices()
11176
	{
11177
		return $this->_services;
11178
	}
11179
	public function getParameters()
11180
	{
11181
		return $this->_parameters;
11182
	}
11183
	public function getExternalConfigurations()
11184
	{
11185
		return $this->_includes;
11186
	}
11187
}
11188
class TApplicationStatePersister extends TModule implements IStatePersister
11189
{
11190
	const CACHE_NAME='prado:appstate';
11191
	public function init($config)
11192
	{
11193
		$this->getApplication()->setApplicationStatePersister($this);
11194
	}
11195
	protected function getStateFilePath()
11196
	{
11197
		return $this->getApplication()->getRuntimePath().'/global.cache';
11198
	}
11199
	public function load()
11200
	{
11201
		if(($cache=$this->getApplication()->getCache())!==null && ($value=$cache->get(self::CACHE_NAME))!==false)
11202
			return unserialize($value);
11203
		else
11204
		{
11205
			if(($content=@file_get_contents($this->getStateFilePath()))!==false)
11206
				return unserialize($content);
11207
			else
11208
				return null;
11209
		}
11210
	}
11211
	public function save($state)
11212
	{
11213
		$content=serialize($state);
11214
		$saveFile=true;
11215
		if(($cache=$this->getApplication()->getCache())!==null)
11216
		{
11217
			if($cache->get(self::CACHE_NAME)===$content)
11218
				$saveFile=false;
11219
			else
11220
				$cache->set(self::CACHE_NAME,$content);
11221
		}
11222
		if($saveFile)
11223
		{
11224
			$fileName=$this->getStateFilePath();
11225
			file_put_contents($fileName,$content,LOCK_EX);
11226
		}
11227
	}
11228
}
11229
class TShellApplication extends TApplication
11230
{
11231
	public function run()
11232
	{
11233
		$this->initApplication();
11234
	}
11235
}
11236
?>
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...