From 80adbe3fff117025d66d21e32166d40166c68d4a Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 8 Feb 2020 13:29:38 +0200 Subject: [PATCH 01/45] ~ test deploy --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6bd08ef..ffa5500 100644 --- a/README.md +++ b/README.md @@ -96,4 +96,4 @@ Please visit the project website for tutorials, class reference and join discuss - [Official Website](http://www.apphpframework.com) - [Website](https://www.apphp.com/php-framework/) -- [GitHub Repository](https://github.com/apphp/php-mvc-framework) \ No newline at end of file +- [GitHub Repository](https://github.com/apphp/php-mvc-framework) From 31f19cdeff65251fc0bdba7490ab137cebbf41ac Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sun, 9 Feb 2020 23:20:53 +0200 Subject: [PATCH 02/45] ~ fixed wrong assignment of _isRendered in CView --- CHANGELOG | 5 +++++ framework/core/CView.php | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 232ebf6..ecd6ef9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,8 @@ +Version 1.4.x - +---------------------------- +- Bug: fixed wrong assignment of _isRendered in CView + + Version 1.3.2 - 24 Jan, 2020 ---------------------------- - New: added CRecordEntity to ORM model diff --git a/framework/core/CView.php b/framework/core/CView.php index a160bb6..4c8afc3 100644 --- a/framework/core/CView.php +++ b/framework/core/CView.php @@ -339,11 +339,10 @@ public function render($params, $isPartial = false, $return = false) } } - $this->_isRendered = true; - if ($return) { return $output; } else { + $this->_isRendered = true; echo $output; } From e4094444cbbed3047f99871bdbc061b71329300f Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 15 Feb 2020 11:56:12 +0200 Subject: [PATCH 03/45] ~ changes in README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ffa5500..b42ed90 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,8 @@

Build Status License LGPL -Stable Version +Stable Version +Total Downloads

## About ApPHP Framework From ac26d54236a7578b45105194bdeb518e29e1cc6b Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 22 Feb 2020 11:41:36 +0200 Subject: [PATCH 04/45] ~ changes in README --- CHANGELOG | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ecd6ef9..073e195 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,7 +6,7 @@ Version 1.4.x - Version 1.3.2 - 24 Jan, 2020 ---------------------------- - New: added CRecordEntity to ORM model -- New: added phpunit tests +- New: added PHPUnit tests - Enh: added possibility to use create() and update() methods in CActiveRecord - Enh: changes in components CHttpRequest - Enh: minor changes in database migrations @@ -18,7 +18,7 @@ Version 1.3.2 - 24 Jan, 2020 - Enh: added possibility for lazy loading of core components via config - Enh: fixed wrong path of log file in CLogger component - Bug: fixed PHP7 syntax requirements in TCPDF vendor, CValidator helper -- Bug: fixed overwriting existing vars in View rendeting +- Bug: fixed overwriting existing vars in View rendering Version 1.2.2 - 01 Jan, 2019 From 284c22a58b4b3fa8c177b73d2af8f77fd7f04d7c Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 7 Mar 2020 13:26:52 +0200 Subject: [PATCH 05/45] Added command line files: bin/aii --- bin/aii | 15 ++++ bin/aii.bat | 23 +++++++ bin/aii.php | 87 ++++++++++++++++++++++++ framework/console/CCacheClearCommand.php | 5 ++ framework/console/CHelpCommand.php | 1 + 5 files changed, 131 insertions(+) create mode 100644 bin/aii create mode 100644 bin/aii.bat create mode 100644 bin/aii.php create mode 100644 framework/console/CCacheClearCommand.php create mode 100644 framework/console/CHelpCommand.php diff --git a/bin/aii b/bin/aii new file mode 100644 index 0000000..d9509a0 --- /dev/null +++ b/bin/aii @@ -0,0 +1,15 @@ +#!/usr/bin/env php + + * @link http://www.apphpframework.com/ + * @copyright Copyright (c) 2012 - 2020 ApPHP Framework + * @license http://www.apphpframework.com/license/ + */ + +require_once(dirname(__FILE__).'/aii.php'); diff --git a/bin/aii.bat b/bin/aii.bat new file mode 100644 index 0000000..0627de6 --- /dev/null +++ b/bin/aii.bat @@ -0,0 +1,23 @@ +@echo off + +rem ------------------------------------------------------------- +rem Aii command line script for Windows. +rem +rem This is the bootstrap script for running aii on Windows. +rem +rem @project ApPHP Framework +rem @author ApPHP +rem @link http://www.apphpframework.com/ +rem @copyright Copyright (c) 2012 - 2020 ApPHP Framework +rem @license http://www.apphpframework.com/license/ +rem ------------------------------------------------------------- + +@setlocal + +set APPHP_PATH=%~dp0 + +if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe + +"%PHP_COMMAND%" "%APPHP_PATH%aii" %* + +@endlocal \ No newline at end of file diff --git a/bin/aii.php b/bin/aii.php new file mode 100644 index 0000000..fe52dcc --- /dev/null +++ b/bin/aii.php @@ -0,0 +1,87 @@ +run(); + +function green($string = '') +{ + return "\e[0;32m".$string."\e[0m"; +} +function yellow($string = '') +{ + return "\e[0;33m".$string."\e[0m"; +} +function redbg($string = '') +{ + return "\e[0;41m".$string."\e[0m"; +} + +/** + * Commands + * --help + * --version + */ + +$output = ''; + +if (!empty($argv)) { + + $command = !empty($argv[1]) ? $argv[1] : ''; + $param = !empty($argv[2]) ? $argv[2] : ''; + + switch ($command) { + + case '': + case '-h': + case '--help': + + $output .= 'ApPHP Framework ' . green(A::version()) . PHP_EOL; + $output .= PHP_EOL; + + $output .= yellow("Usage:") . PHP_EOL; + $output .= " command [options] [arguments]" . PHP_EOL . PHP_EOL; + + $output .= yellow("Options:") . PHP_EOL; + $output .= " ".green("-h, --help")."\t\tDisplay this help message". PHP_EOL; + $output .= " ".green("-V, --version")."\t\tDisplay this application version". PHP_EOL; + + //-q, --quiet Do not output any message + //-n, --no-interaction Do not ask any interactive question + $output .= PHP_EOL; + + $output .= yellow("Available commands:") . PHP_EOL; + $output .= " ".green("cache:clear")."\t\tFlush specific application cache". PHP_EOL; + $output .= " ".green("cache:clearall")."\tFlush all application cache". PHP_EOL; + + break; + + case '-V': + case '-version': + + $output .= 'ApPHP Framework ' . green(A::version()); + + break; + + default: + + $output .= PHP_EOL; + $output .= redbg("Command '".$command."' is not defined.") . PHP_EOL; + $output .= 'Type "bin/aii --help" to check all commands and options.'; + break; + } + + $output .= PHP_EOL; +} + +echo $output; \ No newline at end of file diff --git a/framework/console/CCacheClearCommand.php b/framework/console/CCacheClearCommand.php new file mode 100644 index 0000000..b9e54f1 --- /dev/null +++ b/framework/console/CCacheClearCommand.php @@ -0,0 +1,5 @@ + Date: Sat, 7 Mar 2020 13:31:10 +0200 Subject: [PATCH 06/45] Version number fix --- framework/Apphp.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/Apphp.php b/framework/Apphp.php index e1ec219..dcb4e86 100644 --- a/framework/Apphp.php +++ b/framework/Apphp.php @@ -68,7 +68,7 @@ class A /** @var string */ - private static $_frameworkVersion = '1.2.2'; + private static $_frameworkVersion = '1.3.2'; /** @var string */ private static $_phpVersion; /** @var object */ From 93d77665a5238dcbc01298779af82247bce8ff48 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 14 Mar 2020 14:22:18 +0200 Subject: [PATCH 07/45] Added console cache:clear and cache:clear-all command --- bin/aii.php | 52 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/bin/aii.php b/bin/aii.php index fe52dcc..c1f2376 100644 --- a/bin/aii.php +++ b/bin/aii.php @@ -33,6 +33,9 @@ function redbg($string = '') * --version */ +//print_r($_SERVER['argc']); +//print_r($_SERVER['argv']); + $output = ''; if (!empty($argv)) { @@ -54,7 +57,7 @@ function redbg($string = '') $output .= yellow("Options:") . PHP_EOL; $output .= " ".green("-h, --help")."\t\tDisplay this help message". PHP_EOL; - $output .= " ".green("-V, --version")."\t\tDisplay this application version". PHP_EOL; + $output .= " ".green("-v, --version")."\t\tDisplay this application version". PHP_EOL; //-q, --quiet Do not output any message //-n, --no-interaction Do not ask any interactive question @@ -62,17 +65,60 @@ function redbg($string = '') $output .= yellow("Available commands:") . PHP_EOL; $output .= " ".green("cache:clear")."\t\tFlush specific application cache". PHP_EOL; - $output .= " ".green("cache:clearall")."\tFlush all application cache". PHP_EOL; + $output .= " ".green("cache:clear-all")."\tFlush all application cache". PHP_EOL; break; - case '-V': + case '-v': case '-version': $output .= 'ApPHP Framework ' . green(A::version()); break; + case 'cache:clear': + case 'cache:clear-all': + + if ($command === 'cache:clear-all') { + $param = 'all'; + } + + if (empty($param)) { + $output .= redbg("No cache type for deleting is defined. Type cache:clear -help") . PHP_EOL; + } elseif ($param === '-h' || $param === '-help') { + $output .= yellow("Usage:") . PHP_EOL; + $output .= " cache:clear-all\tFlush all application cache". PHP_EOL; + $output .= " cache:clear [type]\tFlush specific application cache". PHP_EOL; + $output .= " \t\t\t[type] - the type of cache to be removed: 'db', 'css', 'js' or 'all'". PHP_EOL; + } elseif (in_array($param, array('db', 'css', 'js', 'all'))) { + if($param == 'db' || $param == 'all'){ + if (CConfig::get('cache.db.path') == '') { + $output .= redbg("Config value 'cache.db.path' is not defined. Check your configuration file.") . PHP_EOL; + }else{ + $result = CFile::emptyDirectory(CConfig::get('cache.db.path'), array('index.html')); + $output .= 'DB cache ' . ($result ? 'successfully cleaned' : 'error'); + } + } + if($param == 'css' || $param == 'all'){ + if (CConfig::get('compression.css.path') == '') { + $output .= redbg("Config value 'compression.css.path' is not defined. Check your configuration file.") . PHP_EOL; + }else{ + $result = CFile::emptyDirectory(CConfig::get('compression.css.path'), array('index.html')); + $output .= 'CSS cache ' . ($result ? 'successfully cleaned' : 'error'); + } + } + if($param == 'js' || $param == 'all'){ + if (CConfig::get('compression.js.path') == '') { + $output .= redbg("Config value 'compression.js.path' is not defined. Check your configuration file.") . PHP_EOL; + }else{ + $result = CFile::emptyDirectory(CConfig::get('compression.js.path'), array('index.html')); + $output .= 'JS cache ' . ($result ? 'successfully cleaned' : 'error'); + } + } + } + + break; + default: $output .= PHP_EOL; From b8dad21579f85ba47d6df83038a0958b3acc4cea Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 14 Mar 2020 14:23:07 +0200 Subject: [PATCH 08/45] Added CDebug:dd() alias for CDebug:dump() method --- framework/core/CDebug.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/framework/core/CDebug.php b/framework/core/CDebug.php index 8933168..78a8274 100644 --- a/framework/core/CDebug.php +++ b/framework/core/CDebug.php @@ -11,7 +11,7 @@ * PUBLIC (static): PROTECTED: PRIVATE (static): * --------------- --------------- --------------- * init - * dump / d + * dump / d / dd * console / c * write * prepareBacktrace @@ -77,7 +77,18 @@ public static function d($param, $terminate = false, $useDbug = true) { self::dump($param, $terminate, $useDbug); } - + + /** + * Alias to method 'dump' with $terminate=true param + * @param mixed $param + * @param bool $useDbug + * @return HTML dump + */ + public static function dd($param, $useDbug = true) + { + self::dump($param, true, $useDbug); + } + /** * Displays parameter on the screen * @param mixed $param From ede015e01b166d9ea611487a47dcd0831c93c866 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 21 Mar 2020 15:09:03 +0200 Subject: [PATCH 09/45] Changes in console commands --- bin/aii.php | 128 ++---------------------- framework/Apphp.php | 5 +- framework/console/CConsole.php | 85 ++++++++++++++++ framework/console/CConsoleCommand.php | 139 ++++++++++++++++++++++++++ framework/core/CModel.php | 11 +- 5 files changed, 243 insertions(+), 125 deletions(-) create mode 100644 framework/console/CConsole.php create mode 100644 framework/console/CConsoleCommand.php diff --git a/bin/aii.php b/bin/aii.php index c1f2376..5f6c6f1 100644 --- a/bin/aii.php +++ b/bin/aii.php @@ -1,10 +1,10 @@ run(); -function green($string = '') -{ - return "\e[0;32m".$string."\e[0m"; -} -function yellow($string = '') -{ - return "\e[0;33m".$string."\e[0m"; -} -function redbg($string = '') -{ - return "\e[0;41m".$string."\e[0m"; -} -/** - * Commands - * --help - * --version - */ - -//print_r($_SERVER['argc']); -//print_r($_SERVER['argv']); - -$output = ''; - -if (!empty($argv)) { - - $command = !empty($argv[1]) ? $argv[1] : ''; - $param = !empty($argv[2]) ? $argv[2] : ''; - - switch ($command) { - - case '': - case '-h': - case '--help': - - $output .= 'ApPHP Framework ' . green(A::version()) . PHP_EOL; - $output .= PHP_EOL; - - $output .= yellow("Usage:") . PHP_EOL; - $output .= " command [options] [arguments]" . PHP_EOL . PHP_EOL; - - $output .= yellow("Options:") . PHP_EOL; - $output .= " ".green("-h, --help")."\t\tDisplay this help message". PHP_EOL; - $output .= " ".green("-v, --version")."\t\tDisplay this application version". PHP_EOL; - - //-q, --quiet Do not output any message - //-n, --no-interaction Do not ask any interactive question - $output .= PHP_EOL; - - $output .= yellow("Available commands:") . PHP_EOL; - $output .= " ".green("cache:clear")."\t\tFlush specific application cache". PHP_EOL; - $output .= " ".green("cache:clear-all")."\tFlush all application cache". PHP_EOL; - - break; - - case '-v': - case '-version': - - $output .= 'ApPHP Framework ' . green(A::version()); - - break; - - case 'cache:clear': - case 'cache:clear-all': - - if ($command === 'cache:clear-all') { - $param = 'all'; - } - - if (empty($param)) { - $output .= redbg("No cache type for deleting is defined. Type cache:clear -help") . PHP_EOL; - } elseif ($param === '-h' || $param === '-help') { - $output .= yellow("Usage:") . PHP_EOL; - $output .= " cache:clear-all\tFlush all application cache". PHP_EOL; - $output .= " cache:clear [type]\tFlush specific application cache". PHP_EOL; - $output .= " \t\t\t[type] - the type of cache to be removed: 'db', 'css', 'js' or 'all'". PHP_EOL; - } elseif (in_array($param, array('db', 'css', 'js', 'all'))) { - if($param == 'db' || $param == 'all'){ - if (CConfig::get('cache.db.path') == '') { - $output .= redbg("Config value 'cache.db.path' is not defined. Check your configuration file.") . PHP_EOL; - }else{ - $result = CFile::emptyDirectory(CConfig::get('cache.db.path'), array('index.html')); - $output .= 'DB cache ' . ($result ? 'successfully cleaned' : 'error'); - } - } - if($param == 'css' || $param == 'all'){ - if (CConfig::get('compression.css.path') == '') { - $output .= redbg("Config value 'compression.css.path' is not defined. Check your configuration file.") . PHP_EOL; - }else{ - $result = CFile::emptyDirectory(CConfig::get('compression.css.path'), array('index.html')); - $output .= 'CSS cache ' . ($result ? 'successfully cleaned' : 'error'); - } - } - if($param == 'js' || $param == 'all'){ - if (CConfig::get('compression.js.path') == '') { - $output .= redbg("Config value 'compression.js.path' is not defined. Check your configuration file.") . PHP_EOL; - }else{ - $result = CFile::emptyDirectory(CConfig::get('compression.js.path'), array('index.html')); - $output .= 'JS cache ' . ($result ? 'successfully cleaned' : 'error'); - } - } - } - - break; - - default: - - $output .= PHP_EOL; - $output .= redbg("Command '".$command."' is not defined.") . PHP_EOL; - $output .= 'Type "bin/aii --help" to check all commands and options.'; - break; - } - - $output .= PHP_EOL; -} - -echo $output; \ No newline at end of file +$console = new CConsole($argv); +$consoleCommand = new CConsoleCommand( + $console->getCommand(), + $console->getParams() +); +$consoleCommand->run(); diff --git a/framework/Apphp.php b/framework/Apphp.php index dcb4e86..4ade9aa 100644 --- a/framework/Apphp.php +++ b/framework/Apphp.php @@ -83,7 +83,10 @@ class A /** @var array */ private static $_coreClasses = array( 'CConfig' => 'collections/CConfig.php', - + + 'CConsole' => 'console/CConsole.php', + 'CConsoleCommand' => 'console/CConsoleCommand.php', + 'CController' => 'core/CController.php', 'CDebug' => 'core/CDebug.php', 'CModel' => 'core/CModel.php', diff --git a/framework/console/CConsole.php b/framework/console/CConsole.php new file mode 100644 index 0000000..4d6961b --- /dev/null +++ b/framework/console/CConsole.php @@ -0,0 +1,85 @@ + + * @link http://www.apphpframework.com/ + * @copyright Copyright (c) 2012 - 2020 ApPHP Framework + * @license http://www.apphpframework.com/license/ + * + * PUBLIC (static): PROTECTED: PRIVATE (static): + * --------------- --------------- --------------- + * __construct + * getCommand + * getParams + * green (static) + * yellow (static) + * redbg (static) + */ + +class CConsole +{ + /** + * @var array + */ + private $argv; + + /** + * Class constructor + */ + public function __construct($argv = array()) + { + $this->argv = $argv; + } + + /** + * Get command + * @return mixed|string + */ + public function getCommand() + { + return !empty($this->argv[1]) ? $this->argv[1] : ''; + } + + /** + * Get parameters + * @return mixed|string + */ + public function getParams() + { + return !empty($this->argv[2]) ? $this->argv[2] : ''; + } + + /** + * Draw green line + * @param string $string + * @return string + */ + public static function green($string = '') + { + return "\e[0;32m".$string."\e[0m"; + } + + /** + * Draw yellow line + * @param string $string + * @return string + */ + public static function yellow($string = '') + { + return "\e[0;33m".$string."\e[0m"; + } + + /** + * Draw line with red background + * @param string $string + * @return string + */ + public static function redbg($string = '') + { + return "\e[0;41m".$string."\e[0m"; + } + + +} \ No newline at end of file diff --git a/framework/console/CConsoleCommand.php b/framework/console/CConsoleCommand.php new file mode 100644 index 0000000..fdd0462 --- /dev/null +++ b/framework/console/CConsoleCommand.php @@ -0,0 +1,139 @@ + + * @link http://www.apphpframework.com/ + * @copyright Copyright (c) 2012 - 2020 ApPHP Framework + * @license http://www.apphpframework.com/license/ + * + * PUBLIC (static): PROTECTED: PRIVATE (static): + * --------------- --------------- --------------- + * __construct + * run + * + */ + +class CConsoleCommand +{ + /** + * @var string + */ + private $param; + private $command; + + /** + * Class constructor + * + * @param string $command + * @param string $param + */ + public function __construct($command = '', $param = '') + { + $this->command = $command; + $this->param = $param; + } + + /** + * Run command + * @param bool $return + * @return string + */ + public function run($return = false) + { + $output = ''; + + switch ($this->command) { + + case '': + case '-h': + case '--help': + + $output .= 'ApPHP Framework ' . CConsole::green(A::version()) . PHP_EOL; + $output .= PHP_EOL; + + $output .= CConsole::yellow("Usage:") . PHP_EOL; + $output .= " command [options] [arguments]" . PHP_EOL . PHP_EOL; + + $output .= CConsole::yellow("Options:") . PHP_EOL; + $output .= " ".CConsole::green("-h, --help")."\t\tDisplay this help message". PHP_EOL; + $output .= " ".CConsole::green("-v, --version")."\t\tDisplay this application version". PHP_EOL; + + //-q, --quiet Do not output any message + //-n, --no-interaction Do not ask any interactive question + $output .= PHP_EOL; + + $output .= CConsole::yellow("Available commands:") . PHP_EOL; + $output .= " ".CConsole::green("cache:clear")."\t\tFlush specific application cache". PHP_EOL; + $output .= " ".CConsole::green("cache:clear-all")."\tFlush all application cache". PHP_EOL; + + break; + + case '-v': + case '-version': + + $output .= 'ApPHP Framework ' . CConsole::green(A::version()); + + break; + + case 'cache:clear': + case 'cache:clear-all': + + if ($this->command === 'cache:clear-all') { + $this->param = 'all'; + } + + if (empty($this->param)) { + $output .= CConsole::redbg("No cache type for deleting is defined. Type cache:clear -help") . PHP_EOL; + } elseif ($this->param === '-h' || $this->param === '-help') { + $output .= CConsole::yellow("Usage:") . PHP_EOL; + $output .= " cache:clear-all\tFlush all application cache". PHP_EOL; + $output .= " cache:clear [type]\tFlush specific application cache". PHP_EOL; + $output .= " \t\t\t[type] - the type of cache to be removed: 'db', 'css', 'js' or 'all'". PHP_EOL; + } elseif (in_array($this->param, array('db', 'css', 'js', 'all'))) { + if($this->param == 'db' || $this->param == 'all'){ + if (CConfig::get('cache.db.path') == '') { + $output .= CConsole::redbg("Config value 'cache.db.path' is not defined. Check your configuration file.") . PHP_EOL; + }else{ + $result = CFile::emptyDirectory(CConfig::get('cache.db.path'), array('index.html')); + $output .= 'DB cache ' . ($result ? 'successfully cleaned' : 'error'); + } + } + if($this->param == 'css' || $this->param == 'all'){ + if (CConfig::get('compression.css.path') == '') { + $output .= CConsole::redbg("Config value 'compression.css.path' is not defined. Check your configuration file.") . PHP_EOL; + }else{ + $result = CFile::emptyDirectory(CConfig::get('compression.css.path'), array('index.html')); + $output .= 'CSS cache ' . ($result ? 'successfully cleaned' : 'error'); + } + } + if($this->param == 'js' || $this->param == 'all'){ + if (CConfig::get('compression.js.path') == '') { + $output .= CConsole::redbg("Config value 'compression.js.path' is not defined. Check your configuration file.") . PHP_EOL; + }else{ + $result = CFile::emptyDirectory(CConfig::get('compression.js.path'), array('index.html')); + $output .= 'JS cache ' . ($result ? 'successfully cleaned' : 'error'); + } + } + } + + break; + + default: + + $output .= PHP_EOL; + $output .= CConsole::redbg("Command '".$this->command."' is not defined.") . PHP_EOL; + $output .= 'Type "bin/aii --help" to check all commands and options.'; + break; + } + + $output .= PHP_EOL; + + if ($return) { + return $output; + } else { + echo $output; + } + } +} \ No newline at end of file diff --git a/framework/core/CModel.php b/framework/core/CModel.php index 6ad0afe..1d7ab20 100644 --- a/framework/core/CModel.php +++ b/framework/core/CModel.php @@ -41,11 +41,12 @@ public function __construct($params = array()) $this->_error = CDatabase::getError(); $this->_errorMessage = CDatabase::getErrorMessage(); } - - /** - * Initializes the database class - * @param array $params - */ + + /** + * Initializes the database class + * @param array $params + * @return CModel|object + */ public static function init($params = array()) { if (self::$_instance == null) self::$_instance = new self($params); From cf6ac9465b8b7a671576f237af46c59f06939cc6 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 21 Mar 2020 16:41:14 +0200 Subject: [PATCH 10/45] Added ddd() --- demos/static-site/protected/views/page/info.php | 2 +- framework/core/CDebug.php | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/demos/static-site/protected/views/page/info.php b/demos/static-site/protected/views/page/info.php index 21cec27..94fb50f 100644 --- a/demos/static-site/protected/views/page/info.php +++ b/demos/static-site/protected/views/page/info.php @@ -27,4 +27,4 @@

Article Title

- \ No newline at end of file + diff --git a/framework/core/CDebug.php b/framework/core/CDebug.php index 78a8274..cee56ff 100644 --- a/framework/core/CDebug.php +++ b/framework/core/CDebug.php @@ -11,7 +11,7 @@ * PUBLIC (static): PROTECTED: PRIVATE (static): * --------------- --------------- --------------- * init - * dump / d / dd + * dump / d / dd / ddd * console / c * write * prepareBacktrace @@ -89,6 +89,17 @@ public static function dd($param, $useDbug = true) self::dump($param, true, $useDbug); } + /** + * Alias to method 'dump' with $terminate=true param and showing debug panel + * @param mixed $param + * @return HTML dump + */ + public static function ddd($param) + { + CDebug::displayInfo(); + self::dump($param, true, true); + } + /** * Displays parameter on the screen * @param mixed $param @@ -102,7 +113,7 @@ public static function dump($param, $terminate = false, $useDbug = true) @header('content-type: text/html; charset=utf-8'); echo ''; } - + if ($useDbug) { include_once(dirname(__FILE__) . DS . '..' . DS . 'vendors' . DS . 'dbug' . DS . 'dbug.php'); new dBug($param); From 27b74335d777653d18f0a37c066669de5878712d Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 28 Mar 2020 16:25:08 +0300 Subject: [PATCH 11/45] Changed in doc about test class path --- docs/pages/unit-tests.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/pages/unit-tests.html b/docs/pages/unit-tests.html index 8a8aa8f..32b677f 100644 --- a/docs/pages/unit-tests.html +++ b/docs/pages/unit-tests.html @@ -93,8 +93,12 @@

Running tests:

composer test AbcTest
  • - To run specific test from the specific test file use following command: + To run specific test from the specific test file use following command (if it's placed in default directory):
    composer test AbcTest::testXyz
    + + or +
    composer test AbcTest Tests\\Unit\\Entity\\User\\AbcTest.php
    + where 2nd parameter is a path to test class
  • \ No newline at end of file From ebce27128a63c7849bfbed801102d020d0527f44 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 28 Mar 2020 16:43:47 +0300 Subject: [PATCH 12/45] Added console commands and defined APP_MODE = console --- bin/aii.php | 4 +- bin/protected/tmp/logs/error.log | 8 ++ framework/Apphp.php | 155 +++++++++++++++----------- framework/console/CConsoleCommand.php | 24 +--- framework/console/CHelpCommand.php | 43 +++++++ framework/console/CVersionCommand.php | 27 +++++ 6 files changed, 173 insertions(+), 88 deletions(-) create mode 100644 bin/protected/tmp/logs/error.log create mode 100644 framework/console/CVersionCommand.php diff --git a/bin/aii.php b/bin/aii.php index 5f6c6f1..8e211a6 100644 --- a/bin/aii.php +++ b/bin/aii.php @@ -4,8 +4,8 @@ defined('APPHP_PATH') || define('APPHP_PATH', dirname(__FILE__)); // Directory separator defined('DS') || define('DS', DIRECTORY_SEPARATOR); -// Hidden mode only -defined('APPHP_MODE') or define('APPHP_MODE', 'hidden'); +// Console mode only +defined('APPHP_MODE') or define('APPHP_MODE', 'console'); $apphp = dirname(__FILE__) . '/../framework/Apphp.php'; diff --git a/bin/protected/tmp/logs/error.log b/bin/protected/tmp/logs/error.log new file mode 100644 index 0000000..98bf975 --- /dev/null +++ b/bin/protected/tmp/logs/error.log @@ -0,0 +1,8 @@ +[28-Mar-2020 13:28:18 UTC] PHP Fatal error: Uncaught Error: Class 'Modules\Setup\Controllers\SetupController' not found in C:\xampp\htdocs\git\php-mvc-framework\framework\core\CRouter.php:203 +Stack trace: +#0 C:\xampp\htdocs\git\php-mvc-framework\framework\Apphp.php(548): CRouter->route() +#1 C:\xampp\htdocs\git\php-mvc-framework\framework\Apphp.php(321): A->_runApp() +#2 C:\xampp\htdocs\git\php-mvc-framework\bin\aii.php(15): A->run() +#3 C:\xampp\htdocs\git\php-mvc-framework\bin\aii(15): require_once('C:\\xampp\\htdocs...') +#4 {main} + thrown in C:\xampp\htdocs\git\php-mvc-framework\framework\core\CRouter.php on line 203 diff --git a/framework/Apphp.php b/framework/Apphp.php index 4ade9aa..1f2e1a1 100644 --- a/framework/Apphp.php +++ b/framework/Apphp.php @@ -82,68 +82,72 @@ class A ); /** @var array */ private static $_coreClasses = array( - 'CConfig' => 'collections/CConfig.php', + 'CConfig' => 'collections/CConfig.php', - 'CConsole' => 'console/CConsole.php', - 'CConsoleCommand' => 'console/CConsoleCommand.php', + 'CController' => 'core/CController.php', + 'CDebug' => 'core/CDebug.php', + 'CModel' => 'core/CModel.php', + 'CRouter' => 'core/CRouter.php', + 'CView' => 'core/CView.php', - 'CController' => 'core/CController.php', - 'CDebug' => 'core/CDebug.php', - 'CModel' => 'core/CModel.php', - 'CRouter' => 'core/CRouter.php', - 'CView' => 'core/CView.php', - - 'CActiveRecord' => array('5.4.0' => 'db/CActiveRecord.php'), - 'CRecordEntity' => 'db/CRecordEntity.php', - 'CDatabase' => 'db/CDatabase.php', - 'CDbCommand' => 'db/CDbCommand.php', + 'CActiveRecord' => array('5.4.0' => 'db/CActiveRecord.php'), + 'CRecordEntity' => 'db/CRecordEntity.php', + 'CDatabase' => 'db/CDatabase.php', + 'CDbCommand' => 'db/CDbCommand.php', ); + /** @var array */ + private static $_coreConsoleClasses = array( + 'CConsole' => 'console/CConsole.php', + 'CConsoleCommand' => 'console/CConsoleCommand.php', + 'CHelpCommand' => 'console/CHelpCommand.php', + 'CVersionCommand' => 'console/CVersionCommand.php', + ); /** @var array */ private static $_coreComponents = array( - //'component' => array('class' => 'CComponent', 'path' => array('5.4.0' => 'components/CComponent.php')), - 'component' => array('class' => 'CComponent', 'path' => 'components/CComponent.php'), - 'clientScript' => array('class' => 'CClientScript', 'path' => 'components/CClientScript.php'), - 'dbSession' => array('class' => 'CDbHttpSession', 'path' => 'components/CDbHttpSession.php'), - 'request' => array('class' => 'CHttpRequest', 'path' => 'components/CHttpRequest.php'), - 'session' => array('class' => 'CHttpSession', 'path' => 'components/CHttpSession.php'), - 'cookie' => array('class' => 'CHttpCookie', 'path' => 'components/CHttpCookie.php'), - 'localTime' => array('class' => 'CLocalTime', 'path' => 'components/CLocalTime.php'), - 'logger' => array('class' => 'CLogger', 'path' => 'components/CLogger.php'), - 'coreMessages' => array('class' => 'CMessageSource', 'path' => 'components/CMessageSource.php', 'language' => 'en'), - 'messages' => array('class' => 'CMessageSource', 'path' => 'components/CMessageSource.php'), - 'mobileDetect' => array('class' => 'CMobileDetect', 'path' => 'components/CMobileDetect.php'), - 'shoppingCart' => array('class' => 'CShoppingCart', 'path' => 'components/CShoppingCart.php'), - 'uri' => array('class' => 'CUri', 'path' => 'components/CUri.php'), + //'component' => array('class' => 'CComponent', 'path' => array('5.4.0' => 'components/CComponent.php')), + 'component' => array('class' => 'CComponent', 'path' => 'components/CComponent.php'), + 'clientScript' => array('class' => 'CClientScript', 'path' => 'components/CClientScript.php'), + 'dbSession' => array('class' => 'CDbHttpSession', 'path' => 'components/CDbHttpSession.php'), + 'request' => array('class' => 'CHttpRequest', 'path' => 'components/CHttpRequest.php'), + 'session' => array('class' => 'CHttpSession', 'path' => 'components/CHttpSession.php'), + 'cookie' => array('class' => 'CHttpCookie', 'path' => 'components/CHttpCookie.php'), + 'localTime' => array('class' => 'CLocalTime', 'path' => 'components/CLocalTime.php'), + 'logger' => array('class' => 'CLogger', 'path' => 'components/CLogger.php'), + 'coreMessages' => array('class' => 'CMessageSource', 'path' => 'components/CMessageSource.php', 'language' => 'en'), + 'messages' => array('class' => 'CMessageSource', 'path' => 'components/CMessageSource.php'), + 'mobileDetect' => array('class' => 'CMobileDetect', 'path' => 'components/CMobileDetect.php'), + 'shoppingCart' => array('class' => 'CShoppingCart', 'path' => 'components/CShoppingCart.php'), + 'uri' => array('class' => 'CUri', 'path' => 'components/CUri.php'), ); /** @var array */ private static $_coreHelpers = array( - 'CArray' => 'helpers/CArray.php', - 'CAuth' => 'helpers/CAuth.php', - 'CCache' => 'helpers/CCache.php', - 'CClass' => 'helpers/CClass.php', - 'CConvert' => 'helpers/CConvert.php', - 'CCurrency' => 'helpers/CCurrency.php', - 'CFile' => 'helpers/CFile.php', - 'CFilter' => 'helpers/CFilter.php', - 'CGeoLocation' => 'helpers/CGeoLocation.php', - 'CHash' => 'helpers/CHash.php', - 'CHtml' => 'helpers/CHtml.php', - 'CImage' => 'helpers/CImage.php', - 'CLoader' => 'helpers/CLoader.php', - 'CLocale' => 'helpers/CLocale.php', - 'CLog' => 'helpers/CLog.php', - 'CMailer' => 'helpers/CMailer.php', - 'CMinify' => 'helpers/CMinify.php', - 'CNumber' => 'helpers/CNumber.php', - 'COauth' => 'helpers/COauth.php', - 'CPdf' => 'helpers/CPdf.php', - 'CRss' => 'helpers/CRss.php', - 'CSessionCache' => 'helpers/CSessionCache.php', - 'CSoap' => 'helpers/CSoap.php', - 'CString' => 'helpers/CString.php', - 'CTime' => 'helpers/CTime.php', - 'CValidator' => 'helpers/CValidator.php', - 'CWidget' => 'helpers/CWidget.php', + 'CArray' => 'helpers/CArray.php', + 'CAuth' => 'helpers/CAuth.php', + 'CCache' => 'helpers/CCache.php', + 'CClass' => 'helpers/CClass.php', + 'CConvert' => 'helpers/CConvert.php', + 'CCurrency' => 'helpers/CCurrency.php', + 'CFile' => 'helpers/CFile.php', + 'CFilter' => 'helpers/CFilter.php', + 'CGeoLocation' => 'helpers/CGeoLocation.php', + 'CHash' => 'helpers/CHash.php', + 'CHtml' => 'helpers/CHtml.php', + 'CImage' => 'helpers/CImage.php', + 'CLoader' => 'helpers/CLoader.php', + 'CLocale' => 'helpers/CLocale.php', + 'CLog' => 'helpers/CLog.php', + 'CMailer' => 'helpers/CMailer.php', + 'CMinify' => 'helpers/CMinify.php', + 'CNumber' => 'helpers/CNumber.php', + 'COauth' => 'helpers/COauth.php', + 'CPdf' => 'helpers/CPdf.php', + 'CRss' => 'helpers/CRss.php', + 'CSessionCache' => 'helpers/CSessionCache.php', + 'CSoap' => 'helpers/CSoap.php', + 'CString' => 'helpers/CString.php', + 'CTime' => 'helpers/CTime.php', + 'CValidator' => 'helpers/CValidator.php', + 'CWidget' => 'helpers/CWidget.php', ); /** @var array */ private static $_coreModules = array( @@ -195,7 +199,7 @@ public function __construct($configDir) require(dirname(__FILE__) . DS . 'core' . DS . 'interfaces.php'); self::$_phpVersion = phpversion(); - + $configMain = $configDir . 'main.php'; $configDb = $configDir . 'db.php'; @@ -269,7 +273,7 @@ public function __construct($configDir) } // Set components loading type - if (APPHP_MODE == 'hidden' || (CConfig::exists('coreComponentsLazyLoading') && CConfig::get('coreComponentsLazyLoading') === false)) { + if (APPHP_MODE == 'hidden' || APPHP_MODE == 'console' || (CConfig::exists('coreComponentsLazyLoading') && CConfig::get('coreComponentsLazyLoading') === false)) { $this->_coreComponentsLazyLoading = false; } @@ -284,8 +288,8 @@ public function __construct($configDir) */ public function run() { - if (APPHP_MODE != 'hidden') { - // Specify error settings + if ( ! in_array(APPHP_MODE, array('hidden', 'console')) ) { + // Specify error settings if (APPHP_MODE == 'debug' || APPHP_MODE == 'test') { error_reporting(E_ALL); ini_set('display_errors', 'On'); @@ -419,6 +423,22 @@ public static function te($category = 'app', $message = '', $params = array(), $ */ private function _autoload($className) { + // Framework: CONSOLE CORE CLASSES + if (APPHP_MODE === 'console' && isset(self::$_coreConsoleClasses[$className])) { + $classPath = ''; + // Check if we need PHP version compatible class + if (is_array(self::$_coreConsoleClasses[$className])) { + foreach (self::$_coreConsoleClasses[$className] as $key => $val) { + if (self::$_phpVersion >= $key) { + $classPath = $val; + } + } + } else { + $classPath = self::$_coreConsoleClasses[$className]; + } + + include(dirname(__FILE__) . DS . $classPath); + } // Framework: CORE CLASSES if (isset(self::$_coreClasses[$className])) { $classPath = ''; @@ -434,7 +454,8 @@ private function _autoload($className) } include(dirname(__FILE__) . DS . $classPath); - } // Framework: HELPER CLASSES or HELPER EXTENSIONS + } + // Framework: HELPER CLASSES or HELPER EXTENSIONS elseif (isset(self::$_coreHelpers[$className])) { $coreHelper = dirname(__FILE__) . DS . self::$_coreHelpers[$className]; $extCoreHelper = APPHP_PATH . DS . 'protected' . DS . self::$_coreHelpers[$className]; @@ -444,16 +465,20 @@ private function _autoload($className) } else { include($coreHelper); } - } // Framework: COMPONENT CLASSES + } + // Framework: COMPONENT CLASSES elseif ($coreComponent = $this->mapCoreComponent($className)) { include(dirname(__FILE__) . DS . $coreComponent); - } // Application: COMPONENT CLASSES + } + // Application: COMPONENT CLASSES elseif (isset(self::$_appClasses[$className])) { include(APPHP_PATH . DS . 'protected' . DS . self::$_appClasses[$className]); - } // Application: HELPER CLASSES + } + // Application: HELPER CLASSES elseif (isset(self::$_coreHelpers[$className])) { include(APPHP_PATH . DS . 'protected' . DS . self::$_appHelpers[$className]); - } // Check if required class is Controller, Model or Entity (in application or modules) + } + // Check if required class is Controller, Model or Entity (in application or modules) else { $classNameItems = preg_split('/(?=[A-Z])/', $className); $itemsCount = count($classNameItems); @@ -542,8 +567,8 @@ private function _runApp() // Run begin events if ($this->_hasEventHandler('_onBeginRequest')) $this->_onBeginRequest(); - - if (APPHP_MODE != 'hidden') { + + if ( ! in_array(APPHP_MODE, array('hidden', 'console')) ) { $this->router = new CRouter(); $this->router->route(); // Run finish events diff --git a/framework/console/CConsoleCommand.php b/framework/console/CConsoleCommand.php index fdd0462..99f7168 100644 --- a/framework/console/CConsoleCommand.php +++ b/framework/console/CConsoleCommand.php @@ -50,31 +50,13 @@ public function run($return = false) case '-h': case '--help': - $output .= 'ApPHP Framework ' . CConsole::green(A::version()) . PHP_EOL; - $output .= PHP_EOL; - - $output .= CConsole::yellow("Usage:") . PHP_EOL; - $output .= " command [options] [arguments]" . PHP_EOL . PHP_EOL; - - $output .= CConsole::yellow("Options:") . PHP_EOL; - $output .= " ".CConsole::green("-h, --help")."\t\tDisplay this help message". PHP_EOL; - $output .= " ".CConsole::green("-v, --version")."\t\tDisplay this application version". PHP_EOL; - - //-q, --quiet Do not output any message - //-n, --no-interaction Do not ask any interactive question - $output .= PHP_EOL; - - $output .= CConsole::yellow("Available commands:") . PHP_EOL; - $output .= " ".CConsole::green("cache:clear")."\t\tFlush specific application cache". PHP_EOL; - $output .= " ".CConsole::green("cache:clear-all")."\tFlush all application cache". PHP_EOL; - + $output .= CHelpCommand::handle(); break; case '-v': - case '-version': - - $output .= 'ApPHP Framework ' . CConsole::green(A::version()); + case '--version': + $output .= CVersionCommand::handle(); break; case 'cache:clear': diff --git a/framework/console/CHelpCommand.php b/framework/console/CHelpCommand.php index b3d9bbc..9351237 100644 --- a/framework/console/CHelpCommand.php +++ b/framework/console/CHelpCommand.php @@ -1 +1,44 @@ + * @link http://www.apphpframework.com/ + * @copyright Copyright (c) 2012 - 2020 ApPHP Framework + * @license http://www.apphpframework.com/license/ + * + * PUBLIC (static): PROTECTED: PRIVATE (static): + * --------------- --------------- --------------- + * handle (static) + */ + +class CHelpCommand +{ + + public static function handle() + { + $output = ''; + $output .= 'ApPHP Framework ' . CConsole::green(A::version()) . PHP_EOL; + $output .= PHP_EOL; + + $output .= CConsole::yellow("Usage:") . PHP_EOL; + $output .= " command [options] [arguments]" . PHP_EOL . PHP_EOL; + + $output .= CConsole::yellow("Options:") . PHP_EOL; + $output .= " ".CConsole::green("-h, --help")."\t\tDisplay this help message". PHP_EOL; + $output .= " ".CConsole::green("-v, --version")."\t\tDisplay this application version". PHP_EOL; + + //-q, --quiet Do not output any message + //-n, --no-interaction Do not ask any interactive question + $output .= PHP_EOL; + + $output .= CConsole::yellow("Available commands:") . PHP_EOL; + $output .= " ".CConsole::green("cache:clear")."\t\tFlush specific application cache". PHP_EOL; + $output .= " ".CConsole::green("cache:clear-all")."\tFlush all application cache". PHP_EOL; + + return $output; + } + +} diff --git a/framework/console/CVersionCommand.php b/framework/console/CVersionCommand.php new file mode 100644 index 0000000..5004ed7 --- /dev/null +++ b/framework/console/CVersionCommand.php @@ -0,0 +1,27 @@ + + * @link http://www.apphpframework.com/ + * @copyright Copyright (c) 2012 - 2020 ApPHP Framework + * @license http://www.apphpframework.com/license/ + * + * PUBLIC (static): PROTECTED: PRIVATE (static): + * --------------- --------------- --------------- + * handle (static) + */ + +class CVersionCommand +{ + + public static function handle() + { + $output = 'ApPHP Framework ' . CConsole::green(A::version()); + + return $output; + } + +} From e12c5d9fdd2591ec2968d6418ad4dd1d1040acdc Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 28 Mar 2020 16:48:52 +0300 Subject: [PATCH 13/45] Changes in docs about partial view --- docs/pages/views.html | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/docs/pages/views.html b/docs/pages/views.html index 58b08ba..715ef62 100644 --- a/docs/pages/views.html +++ b/docs/pages/views.html @@ -17,7 +17,7 @@

    General Info

    protected/views/{controller-lowercase-name}/ directory. There is only one exclusion for view files, that related to script components and they must be placed in directory protected/views/components/.

    -
    Remeber, that view file name must be in lowercase! Example: views/posts/edit.php
    +
    Remeber, that view file name must be in lowercase! Example: views/posts/edit.php

    @@ -60,11 +60,18 @@

    Rendering Data - passing data to the View (template engine) _view->renderView('statistics', $data); + /* Sample 6 - call of one view from another view */ $this->_view->renderView('tabs/emails'); $this->_view->renderView('tabs/emails', array('email'=>$email)); From b5c9e72f0e9dbcd387f523f13fd6e945bad43e37 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 28 Mar 2020 17:30:14 +0300 Subject: [PATCH 14/45] Added logo icon in debug panel, action buttons moved to the right --- framework/core/CDebug.php | 55 +++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/framework/core/CDebug.php b/framework/core/CDebug.php index cee56ff..81cfad2 100644 --- a/framework/core/CDebug.php +++ b/framework/core/CDebug.php @@ -363,25 +363,33 @@ public static function displayInfo() $totalWarnings = count(self::$_arrWarnings); $totalErrors = count(self::$_arrErrors); $totalQueries = count(self::$_arrQueries); - - // Debug bar status + + $totalRunningTime = round((float)self::$_endTime - (float)self::$_startTime, 5); + $totalRunningTimeQueriesSql = round((float)self::$_sqlTotalTime, 5); + $totalRunningTimeConnectionSql = round((float)self::$_sqlConnectionTime, 5); + $totalRunningTimeScript = round($totalRunningTime - $totalRunningTimeConnectionSql - $totalRunningTimeQueriesSql, 5); + $totalMemoryUsage = CConvert::fileSize((float)self::$_endMemoryUsage - (float)self::$_startMemoryUsage); + $htmlCompressionRate = !empty(self::$_arrData['html-compression-rate']) ? self::$_arrData['html-compression-rate'] : A::t('core', 'Unknown'); + + // Debug bar status $debugBarState = isset($_COOKIE['debugBarState']) ? $_COOKIE['debugBarState'] : 'min'; $onDblClick = 'appTabsMinimize()'; $panelAlign = A::app()->getLanguage('direction') == 'rtl' ? 'left' : 'right'; $panelTextAlign = A::app()->getLanguage('direction') == 'rtl' ? 'right' : 'left'; + $output = $nl . ' - + '; -
    + $output .= $nl . '
    @@ -467,13 +485,6 @@ function appExpandTabs(act, key){ $output .= A::t('core', 'PHP version') . ': ' . phpversion() . '
    '; $output .= (CConfig::get('db.driver') != '' ? ucfirst(CConfig::get('db.driver')) . ' ' . A::t('core', 'version') . ': ' . CDatabase::init()->getVersion() : 'DB: ' . A::te('core', 'no')) . '

    '; - $totalRunningTime = round((float)self::$_endTime - (float)self::$_startTime, 5); - $totalRunningTimeQueriesSql = round((float)self::$_sqlTotalTime, 5); - $totalRunningTimeConnectionSql = round((float)self::$_sqlConnectionTime, 5); - $totalRunningTimeScript = round($totalRunningTime - $totalRunningTimeConnectionSql - $totalRunningTimeQueriesSql, 5); - $totalMemoryUsage = CConvert::fileSize((float)self::$_endMemoryUsage - (float)self::$_startMemoryUsage); - $htmlCompressionRate = !empty(self::$_arrData['html-compression-rate']) ? self::$_arrData['html-compression-rate'] : A::t('core', 'Unknown'); - $output .= A::t('core', 'Total running time') . ': ' . $totalRunningTime . ' ' . A::t('core', 'sec') . '.
    '; $output .= A::t('core', 'SQL connection running time') . ': ' . $totalRunningTimeConnectionSql . ' ' . A::t('core', 'sec') . '.
    '; $output .= A::t('core', 'SQL queries running time') . ': ' . $totalRunningTimeQueriesSql . ' ' . A::t('core', 'sec') . '.
    '; From 23a89d20477d3b8ccdb31be187ee764a6afa4753 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Fri, 1 May 2020 23:23:55 +0300 Subject: [PATCH 15/45] Fix for european float number format validation --- framework/helpers/widgets/CDataForm.php | 15 ++++++++++----- framework/helpers/widgets/CFormValidation.php | 4 ++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/framework/helpers/widgets/CDataForm.php b/framework/helpers/widgets/CDataForm.php index d213652..d5a4a17 100644 --- a/framework/helpers/widgets/CDataForm.php +++ b/framework/helpers/widgets/CDataForm.php @@ -978,11 +978,16 @@ private static function _setValidationAttributes(&$htmlOptions, $validationRules $htmlOptions['data-validation-error-msg'] = A::t('core', 'The field {title} must be a valid HTML element size value (ex.: 100px, pt, em or %)! Please re-enter.', array('{title}' => $title)); break; case 'float': - $format_sample = ($validationFormat == 'european') ? '1234,00' : '1234.00'; - $htmlOptions['data-validation'] = 'number'; - $htmlOptions['data-validation-allowing'] = 'float,negative'; - $htmlOptions['data-validation-error-msg'] = A::t('core', 'The field {title} must be a valid float value in format: {format}! Please re-enter.', array('{title}' => $title, '{format}' => $format_sample)); - break; + if ($validationFormat == 'european') { + $formatSample = '1234,00'; + $htmlOptions['data-validation-decimal-separator'] = ','; + }else{ + $formatSample = '1234.00'; + } + $htmlOptions['data-validation'] = 'number'; + $htmlOptions['data-validation-allowing'] = 'float,negative'; + $htmlOptions['data-validation-error-msg'] = A::t('core', 'The field {title} must be a valid float value in format: {format}! Please re-enter.', array('{title}' => $title, '{format}' => $formatSample)); + break; case 'url': //$htmlOptions['data-validation-regexp'] = '^(http:\/\/|https:\/\/|ftp:\/\/)$'; $htmlOptions['data-validation'] = 'url'; diff --git a/framework/helpers/widgets/CFormValidation.php b/framework/helpers/widgets/CFormValidation.php index 05ee12a..a53afc7 100644 --- a/framework/helpers/widgets/CFormValidation.php +++ b/framework/helpers/widgets/CFormValidation.php @@ -407,8 +407,8 @@ private static function _handleField($field, $fieldInfo, $isMultiArray = false, break; case 'float': $valid = CValidator::isFloat($fieldValue, $format); - $format_sample = ($format == 'european') ? '1234,00' : '1234.00'; - $errorMessage = A::t($msgSource, 'The field {title} must be a valid float value in format: {format}! Please re-enter.', array('{title}' => $title, '{format}' => $format_sample)); + $formatSample = ($format == 'european') ? '1234,00' : '1234.00'; + $errorMessage = A::t($msgSource, 'The field {title} must be a valid float value in format: {format}! Please re-enter.', array('{title}' => $title, '{format}' => $formatSample)); if ($valid && $minValue != '') { $valid = CValidator::validateMin($fieldValue, $minValue, $format); $errorMessage = A::t($msgSource, 'The field {title} must be greater than or equal to {min}! Please re-enter.', array('{title}' => $title, '{min}' => $minValue)); From a729ce4426948de1845ef8ea6aca40487cfe0db3 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 16 May 2020 18:22:44 +0300 Subject: [PATCH 16/45] Added possibility to hide system queries in debug panel --- CHANGELOG | 1 + framework/core/CDebug.php | 11 +++++++++-- framework/db/CDatabase.php | 18 +++++++++--------- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 073e195..f08bb95 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,6 @@ Version 1.4.x - ---------------------------- +- Enh: added possibility to hide system queries in debug panel - Bug: fixed wrong assignment of _isRendered in CView diff --git a/framework/core/CDebug.php b/framework/core/CDebug.php index 81cfad2..8d2ffe7 100644 --- a/framework/core/CDebug.php +++ b/framework/core/CDebug.php @@ -409,6 +409,8 @@ public static function displayInfo() var arrDebugTabs = ["General","Params","Console","Warnings","Errors","Queries"]; var debugTabsHeight = "200px"; var cssText = keyTab = ""; + + function toggleSystemQueries(){var x, i; x = document.getElementsByClassName("dbugQuery");for(i = 0; i < x.length; i++){if(x[i].style.display === "none"){x[i].style.display = "";}else {x[i].style.display = "none";}}} function appSetCookie(state, tab){ document.cookie = "debugBarState="+state+"; path=/"; if(tab !== null) document.cookie = "debugBarTab="+tab+"; path=/"; } function appGetCookie(name){ if(document.cookie.length > 0){ start_c = document.cookie.indexOf(name + "="); if(start_c != -1){ start_c += (name.length + 1); end_c = document.cookie.indexOf(";", start_c); if(end_c == -1) end_c = document.cookie.length; return unescape(document.cookie.substring(start_c,end_c)); }} return ""; } function appTabsMiddle(){ appExpandTabs("middle", appGetCookie("debugBarTab")); } @@ -663,11 +665,16 @@ function appExpandTabs(act, key){ diff --git a/framework/db/CDatabase.php b/framework/db/CDatabase.php index 2f32096..367a310 100644 --- a/framework/db/CDatabase.php +++ b/framework/db/CDatabase.php @@ -236,7 +236,7 @@ public function select($sql, $params = array(), $method = 'fetchAll', $fetchMode $finishTime = CTime::getMicrotime(); $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); CDebug::addSqlTime($sqlTotalTime); - CDebug::addMessage('queries', ++self::$count . '. select | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ' . A::t('core', 'total') . ': ' . (($result) ? count($result) : '0 (' . ($error ? 'error' : 'empty') . ')') . ($cacheContent ? ' [cached]' : '') . '', $this->_query); + CDebug::addMessage('queries', ''.++self::$count . '. select | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ' . A::t('core', 'total') . ': ' . (($result) ? count($result) : '0 (' . ($error ? 'error' : 'empty') . ')') . ($cacheContent ? ' [cached]' : '') . '', $this->_query); } return $result; @@ -301,7 +301,7 @@ public function insert($table, $data, $forceUpdate = false) $finishTime = CTime::getMicrotime(); $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); CDebug::addSqlTime($sqlTotalTime); - CDebug::addMessage('queries', ++self::$count . '. insert | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ID: ' . (($result) ? $result : '0 (error)') . '', $this->_query); + CDebug::addMessage('queries', '' . ++self::$count . '. insert | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ID: ' . (($result) ? $result : '0 (error)') . '', $this->_query); } return $result; @@ -385,7 +385,7 @@ public function update($table, $data, $where = '1', $params = array(), $forceUpd $finishTime = CTime::getMicrotime(); $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); CDebug::addSqlTime($sqlTotalTime); - CDebug::addMessage('queries', ++self::$count . '. update | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ' . A::t('core', 'total') . ': ' . (($result) ? $sth->rowCount() : '0 (error)') . '', $this->_query); + CDebug::addMessage('queries', ''.++self::$count . '. update | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ' . A::t('core', 'total') . ': ' . (($result) ? $sth->rowCount() : '0 (error)') . '', $this->_query); } return $result; @@ -436,7 +436,7 @@ public function delete($table, $where = '', $params = array()) $finishTime = CTime::getMicrotime(); $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); CDebug::addSqlTime($sqlTotalTime); - CDebug::addMessage('queries', ++self::$count . '. delete | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ' . A::t('core', 'total') . ': ' . (($result) ? $result : '0 (warning)') . '', $this->_query); + CDebug::addMessage('queries', ''.++self::$count . '. delete | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ' . A::t('core', 'total') . ': ' . (($result) ? $result : '0 (warning)') . '', $this->_query); } return $result; @@ -478,7 +478,7 @@ public function truncate($table) $finishTime = CTime::getMicrotime(); $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); CDebug::addSqlTime($sqlTotalTime); - CDebug::addMessage('queries', ++self::$count . '. truncate | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ' . A::t('core', 'total') . ': ' . (($result) ? $result : '0 (warning)') . '', $this->_query); + CDebug::addMessage('queries', ''.++self::$count . '. truncate | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ' . A::t('core', 'total') . ': ' . (($result) ? $result : '0 (warning)') . '', $this->_query); } return $result; @@ -545,7 +545,7 @@ public function customQuery($sql, $params = array(), $fetchMode = PDO::FETCH_ASS $finishTime = CTime::getMicrotime(); $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); CDebug::addSqlTime($sqlTotalTime); - CDebug::addMessage('queries', ++self::$count . '. query | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ' . A::t('core', 'total') . ': ' . (($result) ? count($result) : '0 (error)') . '', $this->_query); + CDebug::addMessage('queries', ''.++self::$count . '. query | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ' . A::t('core', 'total') . ': ' . (($result) ? count($result) : '0 (error)') . '', $this->_query); } return $result; @@ -594,7 +594,7 @@ public function customExec($sql, $params = array(), $forceUpdate = false) $finishTime = CTime::getMicrotime(); $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); CDebug::addSqlTime($sqlTotalTime); - CDebug::addMessage('queries', ++self::$count . '. query | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ' . A::t('core', 'total') . ': ' . (($result) ? $result : '0 (error)') . '', $this->_query); + CDebug::addMessage('queries', ''.++self::$count . '. query | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ' . A::t('core', 'total') . ': ' . (($result) ? $result : '0 (error)') . '', $this->_query); } return $result; @@ -659,7 +659,7 @@ public function showTables() $finishTime = CTime::getMicrotime(); $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); CDebug::addSqlTime($sqlTotalTime); - CDebug::addMessage('queries', ++self::$count . '. query | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ' . A::t('core', 'total') . ': ' . (($result) ? count($result) : '0 (error)') . '', $this->_query); + CDebug::addMessage('queries', ''.++self::$count . '. query | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ' . A::t('core', 'total') . ': ' . (($result) ? count($result) : '0 (error)') . '', $this->_query); } return $result; @@ -722,7 +722,7 @@ public function showColumns($table = '') $finishTime = CTime::getMicrotime(); $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); CDebug::addSqlTime($sqlTotalTime); - CDebug::addMessage('queries', ++self::$count . '. query | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ' . A::t('core', 'total') . ': ' . (($result) ? count($result) : '0 (error)') . ($cacheContent ? ' [cached]' : '') . '', $this->_query); + CDebug::addMessage('queries', ''.++self::$count . ' show | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ' . A::t('core', 'total') . ': ' . (($result) ? count($result) : '0 (error)') . ($cacheContent ? ' [cached]' : '') . '', $this->_query); } return $result; From dc0721a44917b74fb9d2daf35e80893b3be59c7e Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Fri, 29 May 2020 12:14:58 +0300 Subject: [PATCH 17/45] Fixed curly braces in array to [] --- framework/vendors/tcpdf/include/tcpdf_filters.php | 4 ++-- framework/vendors/tcpdf/include/tcpdf_images.php | 2 +- framework/vendors/tcpdf/tcpdf_parser.php | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/framework/vendors/tcpdf/include/tcpdf_filters.php b/framework/vendors/tcpdf/include/tcpdf_filters.php index dfb80c5..63c9316 100644 --- a/framework/vendors/tcpdf/include/tcpdf_filters.php +++ b/framework/vendors/tcpdf/include/tcpdf_filters.php @@ -279,7 +279,7 @@ public static function decodeFilterLZWDecode($data) { // convert string to binary string $bitstring = ''; for ($i = 0; $i < $data_length; ++$i) { - $bitstring .= sprintf('%08b', ord($data{$i})); + $bitstring .= sprintf('%08b', ord($data[$i])); } // get the number of bits $data_length = strlen($bitstring); @@ -376,7 +376,7 @@ public static function decodeFilterRunLengthDecode($data) { $i = 0; while($i < $data_length) { // get current byte value - $byte = ord($data{$i}); + $byte = ord($data[$i]); if ($byte == 128) { // a length value of 128 denote EOD break; diff --git a/framework/vendors/tcpdf/include/tcpdf_images.php b/framework/vendors/tcpdf/include/tcpdf_images.php index c2e3c36..018f243 100644 --- a/framework/vendors/tcpdf/include/tcpdf_images.php +++ b/framework/vendors/tcpdf/include/tcpdf_images.php @@ -315,7 +315,7 @@ public static function _parsepng($file) { if ($n > 0) { $trns = array(); for ($i = 0; $i < $n; ++ $i) { - $trns[] = ord($t{$i}); + $trns[] = ord($t[$i]); } } } diff --git a/framework/vendors/tcpdf/tcpdf_parser.php b/framework/vendors/tcpdf/tcpdf_parser.php index 780ec21..05a0588 100644 --- a/framework/vendors/tcpdf/tcpdf_parser.php +++ b/framework/vendors/tcpdf/tcpdf_parser.php @@ -531,10 +531,10 @@ protected function getRawObject($offset=0) { if ($char == '(') { $open_bracket = 1; while ($open_bracket > 0) { - if (!isset($this->pdfdata{$strpos})) { + if (!isset($this->pdfdata[$strpos])) { break; } - $ch = $this->pdfdata{$strpos}; + $ch = $this->pdfdata[$strpos]; switch ($ch) { case '\\': { // REVERSE SOLIDUS (5Ch) (Backslash) // skip next character From 3f47e275e8c0a23a5d03808703aae77262e06def Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 30 May 2020 02:20:31 +0300 Subject: [PATCH 18/45] Fixed curly braces in array to [] --- framework/helpers/CImage.php | 4 ++++ framework/helpers/widgets/CDataForm.php | 2 +- framework/helpers/widgets/CFormValidation.php | 2 +- framework/helpers/widgets/CFormView.php | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/framework/helpers/CImage.php b/framework/helpers/CImage.php index ac562b6..f6d3dec 100644 --- a/framework/helpers/CImage.php +++ b/framework/helpers/CImage.php @@ -87,6 +87,10 @@ public static function resizeImage($imagePath, $imageName, $resizeWidth = '', $r $imagePathNameNew = $imagePath . $imageName; if ($case != '') { + // Prevent using of size like 150px or something else + $resizeWidth = intval($resizeWidth); + $resizeHeight = intval($resizeHeight); + if ($resizeWidth != '' && $resizeHeight == '') { $newWidth = $resizeWidth; $newHeight = ($height / $width) * $newWidth; diff --git a/framework/helpers/widgets/CDataForm.php b/framework/helpers/widgets/CDataForm.php index d5a4a17..463c82a 100644 --- a/framework/helpers/widgets/CDataForm.php +++ b/framework/helpers/widgets/CDataForm.php @@ -354,7 +354,7 @@ public static function init($params = array()) } elseif ($fieldType == 'image') { unset($recordsAssoc[$field]); } elseif ($fieldType == 'data') { - $fieldValue = self::keyAt('default', $fieldInfo, ''); + $fieldValue = self::keyAt('default', $fieldInfo, null); } elseif ($fieldType == 'imageupload') { if (!empty($_FILES[$field]['name'])) { $targetPath = self::keyAt('validation.targetPath', $fieldInfo, ''); diff --git a/framework/helpers/widgets/CFormValidation.php b/framework/helpers/widgets/CFormValidation.php index a53afc7..8c98ea4 100644 --- a/framework/helpers/widgets/CFormValidation.php +++ b/framework/helpers/widgets/CFormValidation.php @@ -520,7 +520,7 @@ private static function _validateMaxLength($fieldValue, $maxLength, $title, $msg } } } elseif (!CValidator::validateMaxLength($fieldValue, $maxLength)) { - self::$_errorMessage = A::t($msgSource, 'The {title} field length may be {max_length} characters maximum! Please re-enter.', array('{title}' => $title, '{max_length}' => $maxLength)); + self::$_errorMessage = A::t($msgSource, 'The {title} field length may be {max_length} characters maximum! Please re-enter.', array('{title}' => $title, '{max_length}' => number_format($maxLength))); $result = false; } diff --git a/framework/helpers/widgets/CFormView.php b/framework/helpers/widgets/CFormView.php index 780fa7b..c9aac59 100644 --- a/framework/helpers/widgets/CFormView.php +++ b/framework/helpers/widgets/CFormView.php @@ -725,7 +725,7 @@ private static function _formField($field, $fieldInfo, $events, $formName = '', case 'textarea': $maxLength = (int)self::keyAt('maxLength', $htmlOptions, 0); - if ($maxLength > 0) $appendLabel = '
    ' . A::t('core', 'max.: {maxchars} chars', array('{maxchars}' => $maxLength)); + if ($maxLength > 0) $appendLabel = '
    ' . A::t('core', 'max.: {maxchars} chars', array('{maxchars}' => number_format($maxLength))); $fieldHtml = CHtml::textArea($field, $value, $htmlOptions); break; From f08fc4429e36d5f2b0a9a70c1815a5e8ad90a98b Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Tue, 2 Jun 2020 22:37:22 +0300 Subject: [PATCH 19/45] Added __isset to some classes --- framework/db/CActiveRecord.php | 29 ++++++++++++++++++++--------- framework/db/CRecordEntity.php | 17 ++++++++++++++--- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/framework/db/CActiveRecord.php b/framework/db/CActiveRecord.php index eaab3b9..105c919 100644 --- a/framework/db/CActiveRecord.php +++ b/framework/db/CActiveRecord.php @@ -20,14 +20,15 @@ * __construct _relations _parentModel (static) * __set _customFields _createObjectFromTable * __get _encryptedFields _getRelations - * __unset _beforeSave _getCustomFields - * __callStatic _afterSave _addCustomFields - * _beforeDelete _removeCustomFields - * init (static) _afterDelete _prepareLimit - * set _tableName - * get _isEncryptedField - * resultArray _getEncryptedFields - * allowedColumns _getEncryptedField + * __isset _beforeSave _getCustomFields + * __unset _afterSave _addCustomFields + * __callStatic _beforeDelete _removeCustomFields + * _afterDelete _prepareLimit + * init (static) _tableName + * set _isEncryptedField + * get _getEncryptedFields + * resultArray _getEncryptedField + * allowedColumns * isColumnExists * setSpecialField * getSpecialField @@ -191,7 +192,17 @@ public function __get($index) return ''; } } - + + /** + * Checks if active record property exists + * @param string $index + * @return bool + */ + public function __isset($index) + { + return array_key_exists($index, $this->_columns) ? true : false; + } + /** * Sets a active record property to be null * @param string $index diff --git a/framework/db/CRecordEntity.php b/framework/db/CRecordEntity.php index 6d58427..f2a1c15 100644 --- a/framework/db/CRecordEntity.php +++ b/framework/db/CRecordEntity.php @@ -1,7 +1,7 @@ @@ -15,6 +15,7 @@ * __construct * __set * __get + * __isset * __unset * set * get @@ -79,9 +80,19 @@ public function __get($index) return ''; } } - + + /** + * Checks if record entity property exists + * @param string $index + * @return bool + */ + public function __isset($index) + { + return array_key_exists($index, $this->_columns) ? true : false; + } + /** - * Sets a active record property to be null + * Sets a record entity property to be null * @param string $index * @return void */ From 61d2f3cf6b8c539088205da3b5eaefbcd014c2e0 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Tue, 7 Jul 2020 22:10:32 +0300 Subject: [PATCH 20/45] Fix for PHP5-7 syntac nusoap classes --- framework/vendors/nusoap/nusoap.php | 482 ++++++++++++++-------------- 1 file changed, 233 insertions(+), 249 deletions(-) diff --git a/framework/vendors/nusoap/nusoap.php b/framework/vendors/nusoap/nusoap.php index bc061a0..d18f2cb 100644 --- a/framework/vendors/nusoap/nusoap.php +++ b/framework/vendors/nusoap/nusoap.php @@ -49,6 +49,11 @@ * RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies * RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1 * RFC 2617 HTTP Authentication: Basic and Digest Access Authentication + * + * FIXES by ApPHP: + * -------- + * 07/07/2020 - class declaration changed to PHP5-7 + * 07/07/2020 - undefined var fix */ /* load classes @@ -90,35 +95,35 @@ class nusoap_base { * @var string * @access private */ - var $title = 'NuSOAP'; + public $title = 'NuSOAP'; /** * Version for HTTP headers. * * @var string * @access private */ - var $version = '0.9.5'; + public $version = '0.9.5'; /** * CVS revision for HTTP headers. * * @var string * @access private */ - var $revision = '$Revision: 1.123 $'; + public $revision = '$Revision: 1.123 $'; /** * Current error string (manipulated by getError/setError) * * @var string * @access private */ - var $error_str = ''; + public $error_str = ''; /** * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment) * * @var string * @access private */ - var $debug_str = ''; + public $debug_str = ''; /** * toggles automatic encoding of special characters as entities * (should always be true, I think) @@ -126,14 +131,14 @@ class nusoap_base { * @var boolean * @access private */ - var $charencoding = true; + public $charencoding = true; /** * the debug level for this instance * * @var integer * @access private */ - var $debugLevel; + public $debugLevel; /** * set schema version @@ -141,7 +146,7 @@ class nusoap_base { * @var string * @access public */ - var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema'; + public $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema'; /** * charset encoding for outgoing messages @@ -149,8 +154,8 @@ class nusoap_base { * @var string * @access public */ - var $soap_defencoding = 'ISO-8859-1'; - //var $soap_defencoding = 'UTF-8'; + public $soap_defencoding = 'ISO-8859-1'; + //public $soap_defencoding = 'UTF-8'; /** * namespaces in an array of prefix => uri @@ -160,7 +165,7 @@ class nusoap_base { * @var array * @access public */ - var $namespaces = array( + public $namespaces = array( 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/', 'xsd' => 'http://www.w3.org/2001/XMLSchema', 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance', @@ -173,7 +178,7 @@ class nusoap_base { * @var array * @access private */ - var $usedNamespaces = array(); + public $usedNamespaces = array(); /** * XML Schema types in an array of uri => (array of xml type => php type) @@ -182,7 +187,7 @@ class nusoap_base { * @var array * @access public */ - var $typemap = array( + public $typemap = array( 'http://www.w3.org/2001/XMLSchema' => array( 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double', 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'', @@ -215,7 +220,7 @@ class nusoap_base { * @deprecated * @see expandEntities */ - var $xmlEntities = array('quot' => '"','amp' => '&', + public $xmlEntities = array('quot' => '"','amp' => '&', 'lt' => '<','gt' => '>','apos' => "'"); /** @@ -223,7 +228,7 @@ class nusoap_base { * * @access public */ - function nusoap_base() { + function __construct() { $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel']; } @@ -993,9 +998,6 @@ function usleepWindows($usec) while ($timePassed < $usec); } -?>faultcode = $faultcode; $this->faultactor = $faultactor; @@ -1080,9 +1082,6 @@ function serialize(){ class soap_fault extends nusoap_fault { } -?>debug('nusoap_xmlschema class instantiated, inside constructor'); // files @@ -1878,27 +1877,28 @@ function getTypeDef($type){ */ function serializeTypeDef($type){ //print "in sTD() for type $type
    "; - if($typeDef = $this->getTypeDef($type)){ - $str .= '<'.$type; - if(is_array($typeDef['attrs'])){ - foreach($typeDef['attrs'] as $attName => $data){ - $str .= " $attName=\"{type = ".$data['type']."}\""; - } - } - $str .= " xmlns=\"".$this->schema['targetNamespace']."\""; - if(count($typeDef['elements']) > 0){ - $str .= ">"; - foreach($typeDef['elements'] as $element => $eData){ - $str .= $this->serializeTypeDef($element); - } - $str .= ""; - } elseif($typeDef['typeClass'] == 'element') { - $str .= ">"; - } else { - $str .= "/>"; - } - return $str; - } + if($typeDef = $this->getTypeDef($type)){ + $str = '<'.$type; + if (is_array($typeDef['attrs'])) { + foreach ($typeDef['attrs'] as $attName => $data) { + $str .= " $attName=\"{type = ".$data['type']."}\""; + } + } + $str .= " xmlns=\"".$this->schema['targetNamespace']."\""; + if (count($typeDef['elements']) > 0) { + $str .= ">"; + foreach ($typeDef['elements'] as $element => $eData) { + $str .= $this->serializeTypeDef($element); + } + $str .= ""; + } elseif ($typeDef['typeClass'] == 'element') { + $str .= ">"; + } else { + $str .= "/>"; + } + + return $str; + } return false; } @@ -1913,6 +1913,7 @@ function serializeTypeDef($type){ * @deprecated */ function typeToForm($name,$type){ + $buffer = ''; // get typedef if($typeDef = $this->getTypeDef($type)){ // if struct @@ -2050,9 +2051,6 @@ function addElement($attrs) { class XMLSchema extends nusoap_xmlschema { } -?>name = $name; $this->type = $type; @@ -2154,10 +2152,6 @@ function decode(){ -?>debug("ctor url=$url use_curl=$use_curl curl_options:"); $this->appendDebug($this->varDump($curl_options)); @@ -3458,9 +3452,6 @@ function getCookiesForRequest($cookies, $secure=false) { } } -?> opData; operations are added by the register() @@ -3601,25 +3592,25 @@ class nusoap_server extends nusoap_base { * @var array * @access private */ - var $operations = array(); + public $operations = array(); /** * wsdl instance (if one) * @var mixed * @access private */ - var $wsdl = false; + public $wsdl = false; /** * URL for WSDL (if one) * @var mixed * @access private */ - var $externalWSDLURL = false; + public $externalWSDLURL = false; /** * whether to append debug to response as XML comment * @var boolean * @access public */ - var $debug_flag = false; + public $debug_flag = false; /** @@ -3629,7 +3620,7 @@ class nusoap_server extends nusoap_base { * @param mixed $wsdl file path or URL (string), or wsdl instance (object) * @access public */ - function nusoap_server($wsdl=false){ + function __construct($wsdl=false){ parent::nusoap_base(); // turn on debugging? global $debug; @@ -4582,9 +4573,6 @@ function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style= class soap_server extends nusoap_server { } -?>debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout"); $this->proxyhost = $proxyhost; @@ -6517,8 +6505,6 @@ function addOperation($name, $in = false, $out = false, $namespace = false, $soa return true; } } -?> pos - var $ids = array(); + public $ids = array(); // array of id => hrefs => pos - var $multirefs = array(); + public $multirefs = array(); // toggle for auto-decoding element content - var $decode_utf8 = true; + public $decode_utf8 = true; /** * constructor that actually does the parsing @@ -6575,7 +6561,7 @@ class nusoap_parser extends nusoap_base { * @param string $decode_utf8 whether to decode UTF-8 to ISO-8859-1 * @access public */ - function nusoap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=true){ + function __construct($xml,$encoding='UTF-8',$method='',$decode_utf8=true){ parent::nusoap_base(); $this->xml = $xml; $this->xml_encoding = $encoding; @@ -7049,6 +7035,7 @@ function buildVal($pos){ } $this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']); // if there are children... + $params = []; if($this->message[$pos]['children'] != ''){ $this->debug('in buildVal, there are children'); $children = explode('|',$this->message[$pos]['children']); @@ -7157,9 +7144,6 @@ function buildVal($pos){ class soap_parser extends nusoap_parser { } -?>endpoint = $endpoint; $this->proxyhost = $proxyhost; From ba69464c219bb88264ba5add53644b7cff0c9a32 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Tue, 7 Jul 2020 22:11:29 +0300 Subject: [PATCH 21/45] Fix for PHP5-7 syntac tmhOAuth classe --- .../opauth/Strategy/Twitter/Vendor/tmhOAuth/tmhOAuth.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/framework/vendors/opauth/Strategy/Twitter/Vendor/tmhOAuth/tmhOAuth.php b/framework/vendors/opauth/Strategy/Twitter/Vendor/tmhOAuth/tmhOAuth.php index 01e51df..a7b9598 100644 --- a/framework/vendors/opauth/Strategy/Twitter/Vendor/tmhOAuth/tmhOAuth.php +++ b/framework/vendors/opauth/Strategy/Twitter/Vendor/tmhOAuth/tmhOAuth.php @@ -10,11 +10,16 @@ * @version 0.7.1 * * 27 October 2012 + * + * FIXES by ApPHP: + * -------- + * 07/07/2020 - class declaration changed to PHP5-7 + * */ class tmhOAuth { const VERSION = '0.7.1'; - var $response = array(); + public $response = array(); /** * Creates a new tmhOAuth object From 20fbe10cfe9835cb2012b9216217ea92448d1fbe Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 25 Jul 2020 17:39:32 +0300 Subject: [PATCH 22/45] Chunk --- demos/simple-blog/protected/config/db.php | 12 ++ demos/simple-blog/protected/config/main.php | 193 ++++++++++++++++++ .../protected/controllers/PostsController.php | 15 +- 3 files changed, 218 insertions(+), 2 deletions(-) create mode 100644 demos/simple-blog/protected/config/db.php create mode 100644 demos/simple-blog/protected/config/main.php diff --git a/demos/simple-blog/protected/config/db.php b/demos/simple-blog/protected/config/db.php new file mode 100644 index 0000000..f0681cd --- /dev/null +++ b/demos/simple-blog/protected/config/db.php @@ -0,0 +1,12 @@ + array( + 'driver' => 'mysql', + 'host' => 'localhost', + 'database' => 'test', + 'username' => 'root', + 'password' => '', + 'prefix' => 'mb_', + ) +); \ No newline at end of file diff --git a/demos/simple-blog/protected/config/main.php b/demos/simple-blog/protected/config/main.php new file mode 100644 index 0000000..7af26d2 --- /dev/null +++ b/demos/simple-blog/protected/config/main.php @@ -0,0 +1,193 @@ + 'Simple Blog', + 'version' => '1.0.2', + + // Directy CMF data + 'directy_cmf_version' => '', + + // installation settings + 'installationKey' => '2x4686fpyk', + + // Password keys settings (for database passwords only) + // Remember: changing these settings after installation may lead to unstable work of application + // encryptAlgorithm - md5, sha1 (not recommended), sha256, whirlpool, etc + 'password' => array( + 'encryption' => true, + 'encryptAlgorithm' => 'sha256', + 'encryptSalt' => true, + 'hashKey' => 'apphp_directy_login_system', + ), + + // Text encryption settings (for database text fields only) + // Remember: changing these settings after installation may lead to unstable work of application + // Encryption level - PHP or DB + // encryptAlgorithm - PHP: aes-256-cbc DB: AES + 'text' => array( + 'encryption' => true, + 'encryptAlgorithm' => 'aes-256-cbc', + 'encryptKey' => 'apphp_directy_cmf', + ), + + // Default email settings + 'email' => array( + 'mailer' => 'smtpMailer', /* phpMail | phpMailer | smtpMailer */ + 'from' => 'info@email.me', + 'fromName' => '', /* John Smith */ + 'isHtml' => true, + 'smtp' => array( + 'auth' => true, /* true or false */ + 'secure' => 'ssl', /* 'ssl', 'tls' or '' */ + 'host' => 'smtp.gmail.com', + 'port' => '465', + 'username' => '', + 'password' => '', + ), + ), + + // Validations + // Define array of 'excluded' controllers, ex.: array('PaymentProviders', 'Checkout') + // Token type: 'session', 'cookie' or 'multipages' + 'validation' => array( + 'csrf' => array('enable' => false, 'exclude' => array('PaymentProviders'), 'tokenType' => 'session'), + 'bruteforce' => array('enable' => true, 'badLogins' => 5, 'badRestores' => 5, 'redirectDelay' => 3) + ), + + // Exception handling + // Define exceptions exceptions in application + 'exceptionHandling' => array( + 'enable' => true, + 'level' => 'global' + ), + + // Output compression + 'compression' => array( + 'gzip' => array('enable' => false), + 'html' => array('enable' => false), + 'css' => array('enable' => false, 'path' => 'assets/minified/css/', 'minify' => true), + 'js' => array('enable' => false, 'path' => 'assets/minified/js/', 'minify' => true), + ), + + // Session settings + 'session' => array( + 'customStorage' => false, /* true value means use a custom storage (database), false - standard storage */ + 'cacheLimiter' => '', /* to prevent 'Web Page expired' message for POST request use "private,must-revalidate" */ + 'lifetime' => 24, /* session timeout in minutes, default: 24 min = 1440 sec */ + ), + + // Cookies settings + 'cookies' => array( + 'domain' => '', + 'path' => '/' + ), + + // Cache settings + 'cache' => array( + 'enable' => false, + 'type' => 'auto', /* 'auto' or 'manual' */ + 'lifetime' => 20, /* in minutes */ + 'path' => 'protected/tmp/cache/' + ), + + // Logger settings + 'log' => array( + 'enable' => false, + 'path' => 'protected/tmp/logs/', + 'fileExtension' => 'php', + 'dateFormat' => 'Y-m-d H:i:s', + 'threshold' => 1, + 'filePermissions' => 0644, + 'lifetime' => 30 /* in days */ + ), + + // RSS Feed settings + 'rss' => array( + 'path' => 'feeds/' + ), + + // Datetime settings + 'defaultTimeZone' => 'UTC', + + // Template default settings + 'template' => array( + 'default' => 'default' + ), + + // Layout default settings + 'layouts' => array( + 'enable' => false, + 'default' => 'default' + ), + + // Layout default settings + 'layouts' => array( + 'enable' => array('frontend' => false, 'backend' => false), + 'default' => 'default' + ), + + // Application default settings + 'defaultBackendDirectory' => 'backoffice', /* default backoffice directory */ + 'defaultErrorController' => 'Error', /* may be overridden by module settings */ + 'defaultController' => 'Index', /* may be overridden by module settings */ + 'defaultAction' => 'index', /* may be overridden by module settings */ + + // Application Backend settings + 'restoreAdminPassword' => array( + 'enable' => true, + 'recoveryType' => 'direct' /* 'direct' - send new password directly, 'recovery' - send link to recovery page */ + ), + + // Application components + 'components' => array( + 'Bootstrap' => array('enable' => true, 'class' => 'Bootstrap'), + 'BlogMenu' => array('enable' => true, 'class' => 'BlogMenu'), + ), + + // Logger settings + 'log' => array( + 'enable' => false, + 'path' => 'protected/tmp/logs/', + 'fileExtension' => 'php', + 'dateFormat' => 'Y-m-d H:i:s', + 'threshold' => 1, + 'filePermissions' => 0644, + 'lifetime' => 30 /* in days */ + ), + + // Widget settings + 'widgets' => array( + 'paramKeysSensitive' => true + ), + + // Application helpers + 'helpers' => array( + //'helper' => array('enable' => true, 'class' => 'Helper'), + ), + + // Application modules + 'modules' => array( + 'setup' => array('enable' => true, 'removable' => false, 'backendDefaultUrl' => ''), + ), + + // Url manager + 'urlManager' => array( + 'urlFormat' => 'shortPath', /* get | path | shortPath */ + 'rules' => array( + // Required by payments module. If you remove these rules - make sure you define full path URL for pyment providers + //'paymentProviders/handlePayment/provider/([a-zA-Z0-9\_]+)/handler/([a-zA-Z0-9\_]+)/module/([a-zA-Z0-9\_]+)[\/]?$' => 'paymentProviders/handlePayment/provider/{$0}/handler/{$1}/module/{$2}', + 'paymentProviders/handlePayment/([a-zA-Z0-9\_]+)/([a-zA-Z0-9\_]+)/([a-zA-Z0-9\_]+)[\/]?$' => 'paymentProviders/handlePayment/provider/{$0}/handler/{$1}/module/{$2}', + //'paymentProviders/handlePayment/provider/([a-zA-Z0-9\_]+)/handler/([a-zA-Z0-9\_]+)[\/]?$' => 'paymentProviders/handlePayment/provider/{$0}/handler/{$1}', + 'paymentProviders/handlePayment/([a-zA-Z0-9\_]+)/([a-zA-Z0-9\_]+)[\/]?$' => 'paymentProviders/handlePayment/provider/{$0}/handler/{$1}', + //'paymentProviders/handlePayment/provider/([a-zA-Z0-9\_]+)[\/]?$' => 'paymentProviders/handlePayment/provider/{$0}', + 'paymentProviders/handlePayment/([a-zA-Z0-9\_]+)[\/]?$' => 'paymentProviders/handlePayment/provider/{$0}', + // Required by dynamic pages, if you want to use user-friendly URLs + //'controller/action/value1/value2' => 'controllerName/action/param1/value1/param2/value2', + //'sitepages/show/example-page-1' => 'sitePages/show/name/about-us', + //'value1' => 'controllerName/action/param1/value1', + //'about-us' => 'sitePages/show/name/about-us', + ), + ), + +); diff --git a/demos/simple-blog/protected/controllers/PostsController.php b/demos/simple-blog/protected/controllers/PostsController.php index 3b58c0f..cb363f8 100644 --- a/demos/simple-blog/protected/controllers/PostsController.php +++ b/demos/simple-blog/protected/controllers/PostsController.php @@ -135,10 +135,21 @@ public function indexAction($msg = '') if (!$this->_view->currentPage) { $this->_view->actionMessage = CWidget::create('CMessage', array('error', 'Wrong parameter passed! Please try again later.', array('button' => true))); } else { - $this->_view->posts = Posts::model()->findAll(array( +/* $this->_view->posts = Posts::model()->findAll(array( 'limit' => (($this->_view->currentPage - 1) * $this->_view->pageSize) . ', ' . $this->_view->pageSize, 'order' => 'post_datetime DESC', - )); + ));*/ + + $posts = null; + Posts::model()->chunk(2, function ($records) use(&$posts){ + foreach ($records as $key => $record) { + $posts[] = $record; + } + //CDebug::d($record); + }); + //CDebug::dd($posts); + + $this->_view->posts = $posts; } $this->_view->render('posts/index'); From a28fc02b504bb277ab3f686de24ffac76a4a5366 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 25 Jul 2020 18:16:03 +0300 Subject: [PATCH 23/45] Added possibility to close debug panel to minimum size --- CHANGELOG | 1 + framework/core/CDebug.php | 16 ++++++++++++++-- framework/db/CActiveRecord.php | 27 +++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index f08bb95..97820c3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ Version 1.4.x - ---------------------------- - Enh: added possibility to hide system queries in debug panel +- Enh: added possibility to close debug panel to minimum size - Bug: fixed wrong assignment of _isRendered in CView diff --git a/framework/core/CDebug.php b/framework/core/CDebug.php index 8d2ffe7..5f47cbf 100644 --- a/framework/core/CDebug.php +++ b/framework/core/CDebug.php @@ -416,10 +416,12 @@ function appGetCookie(name){ if(document.cookie.length > 0){ start_c = document. function appTabsMiddle(){ appExpandTabs("middle", appGetCookie("debugBarTab")); } function appTabsMaximize(){ appExpandTabs("max", appGetCookie("debugBarTab")); } function appTabsMinimize(){ appExpandTabs("min", "General"); } + function appTabsClose(){ appExpandTabs("close", appGetCookie("debugBarTab")); } function appExpandTabs(act, key){ if(act == "max"){ debugTabsHeight = "500px"; } else if(act == "middle"){ debugTabsHeight = "200px"; } else if(act == "min"){ debugTabsHeight = "0px"; } + else if(act == "close"){ debugTabsHeight = "0px"; } else if(act == "auto"){ if(debugTabsHeight == "0px"){ debugTabsHeight = "200px"; act = "middle"; } else if(debugTabsHeight == "200px"){ act = "middle"; } @@ -437,6 +439,14 @@ function appExpandTabs(act, key){ } } if(act != "min"){ + x = document.getElementsByClassName("item"); + if(act == "close"){ + for (i = 0; i < x.length; i++) x[i].style.display = "none"; + document.getElementsByClassName("narrow-close")[0].style.display = "none"; + }else{ + for (i = 0; i < x.length; i++) x[i].style.display = ""; + document.getElementsByClassName("narrow-close")[0].style.display = ""; + } document.getElementById("content"+keyTab).style.display = ""; document.getElementById("content"+keyTab).style.cssText = "width:100%;height:"+debugTabsHeight+";overflow-y:auto;"; if(document.getElementById("tab"+keyTab).className == "tab-orange"){ @@ -458,7 +468,7 @@ function appExpandTabs(act, key){
    • - + logo ' . A::t('core', 'Debug') . ': 
    • @@ -474,7 +484,7 @@ function appExpandTabs(act, key){
    • -
    • ×
    • +
    • ×
    @@ -685,6 +695,8 @@ function appExpandTabs(act, key){ $output .= ''; } elseif ($debugBarState == 'middle') { $output .= ''; + } elseif ($debugBarState == 'close') { + $output .= ''; } else { $output .= ''; } diff --git a/framework/db/CActiveRecord.php b/framework/db/CActiveRecord.php index 105c919..57839ac 100644 --- a/framework/db/CActiveRecord.php +++ b/framework/db/CActiveRecord.php @@ -43,6 +43,8 @@ * getTranslations * saveTranslations * + * chunk + * * find * findByPk * findByAttributes @@ -576,6 +578,31 @@ private function _createObjectFromTable() return true; } + + /** + * Split AR result into parts (chunks) + * @param int $size + * @param null $callback + */ + public function chunk(int $size, callable $callback = null) + { + if (is_int($size) && $size > 0 && !empty($callback)) { + $from = 0; +// echo('limit'."$from, $size"); + while ($result = $this->findAll(array('limit'=>"$from, $size"))){ + $callback($result); + $from += $size; +// echo('limit'."$from, $size"); +// if ($from > 10){ +// return; +// } + } + } else { + CDebug::AddMessage('errors', 'chunk', A::t('core', 'Wrong params for chunk: {size} or callback method is callable.', array('{size}' => $size))); + } + + return null; + } /** * This method queries your database to find first related object From e76f979c7a4a1b19e63bfca2f921f9647507af80 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 25 Jul 2020 18:30:38 +0300 Subject: [PATCH 24/45] Added padding to command line commands output --- framework/console/CConsole.php | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/framework/console/CConsole.php b/framework/console/CConsole.php index 4d6961b..bef0ea2 100644 --- a/framework/console/CConsole.php +++ b/framework/console/CConsole.php @@ -73,13 +73,26 @@ public static function yellow($string = '') /** * Draw line with red background + * * @param string $string + * @param bool $padding + * * @return string */ - public static function redbg($string = '') + public static function redbg($string = '', $padding = true) { - return "\e[0;41m".$string."\e[0m"; - } + $length = strlen($string) + 4; + $output = ''; + + if ($padding) { + $output .= "\e[0;41m".str_pad(' ', $length, " ", STR_PAD_LEFT)."\e[0m" . PHP_EOL; + } + $output .= "\e[0;41m".($padding ? ' ' : '').$string.($padding ? ' ' : '')."\e[0m".PHP_EOL; + if ($padding) { + $output .= "\e[0;41m".str_pad(' ', $length, " ", STR_PAD_LEFT)."\e[0m" . PHP_EOL; + } + return $output; + } } \ No newline at end of file From 60fcdd07d8c0a23c72b5f01222626122c7adf9b4 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 25 Jul 2020 19:00:52 +0300 Subject: [PATCH 25/45] Console command changes, implemented IConsoleCommand interfaces --- bin/aii.php | 4 +- bin/protected/tmp/logs/error.log | 8 --- framework/Apphp.php | 10 +-- framework/console/CCacheClearCommand.php | 71 +++++++++++++++++++- framework/console/CConsole.php | 2 + framework/console/CConsoleCommand.php | 43 ++---------- framework/console/CHelpCommand.php | 13 +++- framework/console/CMakeControllerCommand.php | 34 ++++++++++ framework/console/CVersionCommand.php | 6 +- framework/core/interfaces.php | 12 ++++ 10 files changed, 147 insertions(+), 56 deletions(-) delete mode 100644 bin/protected/tmp/logs/error.log create mode 100644 framework/console/CMakeControllerCommand.php diff --git a/bin/aii.php b/bin/aii.php index 8e211a6..c7d402a 100644 --- a/bin/aii.php +++ b/bin/aii.php @@ -14,8 +14,8 @@ require_once($apphp); A::init($config)->run(); - -$console = new CConsole($argv); +// We get automatically $argv and $argc, as we run command line command +$console = new CConsole($argv); $consoleCommand = new CConsoleCommand( $console->getCommand(), $console->getParams() diff --git a/bin/protected/tmp/logs/error.log b/bin/protected/tmp/logs/error.log deleted file mode 100644 index 98bf975..0000000 --- a/bin/protected/tmp/logs/error.log +++ /dev/null @@ -1,8 +0,0 @@ -[28-Mar-2020 13:28:18 UTC] PHP Fatal error: Uncaught Error: Class 'Modules\Setup\Controllers\SetupController' not found in C:\xampp\htdocs\git\php-mvc-framework\framework\core\CRouter.php:203 -Stack trace: -#0 C:\xampp\htdocs\git\php-mvc-framework\framework\Apphp.php(548): CRouter->route() -#1 C:\xampp\htdocs\git\php-mvc-framework\framework\Apphp.php(321): A->_runApp() -#2 C:\xampp\htdocs\git\php-mvc-framework\bin\aii.php(15): A->run() -#3 C:\xampp\htdocs\git\php-mvc-framework\bin\aii(15): require_once('C:\\xampp\\htdocs...') -#4 {main} - thrown in C:\xampp\htdocs\git\php-mvc-framework\framework\core\CRouter.php on line 203 diff --git a/framework/Apphp.php b/framework/Apphp.php index 1f2e1a1..27e0a87 100644 --- a/framework/Apphp.php +++ b/framework/Apphp.php @@ -97,10 +97,12 @@ class A ); /** @var array */ private static $_coreConsoleClasses = array( - 'CConsole' => 'console/CConsole.php', - 'CConsoleCommand' => 'console/CConsoleCommand.php', - 'CHelpCommand' => 'console/CHelpCommand.php', - 'CVersionCommand' => 'console/CVersionCommand.php', + 'CConsole' => 'console/CConsole.php', + 'CConsoleCommand' => 'console/CConsoleCommand.php', + 'CHelpCommand' => 'console/CHelpCommand.php', + 'CVersionCommand' => 'console/CVersionCommand.php', + 'CCacheClearCommand' => 'console/CCacheClearCommand.php', + 'CMakeControllerCommand' => 'console/CMakeControllerCommand.php', ); /** @var array */ private static $_coreComponents = array( diff --git a/framework/console/CCacheClearCommand.php b/framework/console/CCacheClearCommand.php index b9e54f1..288f0ec 100644 --- a/framework/console/CCacheClearCommand.php +++ b/framework/console/CCacheClearCommand.php @@ -1,5 +1,72 @@ + * @link http://www.apphpframework.com/ + * @copyright Copyright (c) 2012 - 2020 ApPHP Framework + * @license http://www.apphpframework.com/license/ + * + * PUBLIC (static): PROTECTED: PRIVATE (static): + * --------------- --------------- --------------- + * handle (static) + */ + +class CCacheClearCommand implements IConsoleCommand +{ + + /** + * Handle specific console command + * @param string $param + * @return string + */ + public static function handle($param = '') + { + $output = ''; + + //var_dump($argv); + //var_dump($argc); + + if (empty($param)) { + $output .= CConsole::redbg("No cache type for deleting is defined. Type cache:clear -help") . PHP_EOL; +// } elseif ($param === '-h' || $param === '-help') { +// $output .= CConsole::yellow("Usage:") . PHP_EOL; +// $output .= " cache:clear-all\tFlush all application cache". PHP_EOL; +// $output .= " cache:clear [type]\tFlush specific application cache". PHP_EOL; +// $output .= " \t\t\t[type] - the type of cache to be removed: 'db', 'css', 'js' or 'all'". PHP_EOL; +// } elseif (in_array($param, array('db', 'css', 'js', 'all'))) { +// if($param == 'db' || $param == 'all'){ +// if (CConfig::get('cache.db.path') == '') { +// $output .= CConsole::redbg("Config value 'cache.db.path' is not defined. Check your configuration file.") . PHP_EOL; +// }else{ +// $result = CFile::emptyDirectory(CConfig::get('cache.db.path'), array('index.html')); +// $output .= 'DB cache ' . ($result ? 'successfully cleaned' : 'error'); +// } +// } +// if($param == 'css' || $param == 'all'){ +// if (CConfig::get('compression.css.path') == '') { +// $output .= CConsole::redbg("Config value 'compression.css.path' is not defined. Check your configuration file.") . PHP_EOL; +// }else{ +// $result = CFile::emptyDirectory(CConfig::get('compression.css.path'), array('index.html')); +// $output .= 'CSS cache ' . ($result ? 'successfully cleaned' : 'error'); +// } +// } +// if($param == 'js' || $param == 'all'){ +// if (CConfig::get('compression.js.path') == '') { +// $output .= CConsole::redbg("Config value 'compression.js.path' is not defined. Check your configuration file.") . PHP_EOL; +// }else{ +// $result = CFile::emptyDirectory(CConfig::get('compression.js.path'), array('index.html')); +// $output .= 'JS cache ' . ($result ? 'successfully cleaned' : 'error'); +// } +// } + } + + + return $output; + } + +} + diff --git a/framework/console/CConsole.php b/framework/console/CConsole.php index bef0ea2..46c544d 100644 --- a/framework/console/CConsole.php +++ b/framework/console/CConsole.php @@ -27,6 +27,8 @@ class CConsole /** * Class constructor + * + * @param array $argv */ public function __construct($argv = array()) { diff --git a/framework/console/CConsoleCommand.php b/framework/console/CConsoleCommand.php index 99f7168..9e10aed 100644 --- a/framework/console/CConsoleCommand.php +++ b/framework/console/CConsoleCommand.php @@ -46,64 +46,31 @@ public function run($return = false) switch ($this->command) { - case '': case '-h': case '--help': - + case 'help': $output .= CHelpCommand::handle(); break; case '-v': case '--version': - $output .= CVersionCommand::handle(); break; case 'cache:clear': case 'cache:clear-all': - if ($this->command === 'cache:clear-all') { $this->param = 'all'; } - if (empty($this->param)) { - $output .= CConsole::redbg("No cache type for deleting is defined. Type cache:clear -help") . PHP_EOL; - } elseif ($this->param === '-h' || $this->param === '-help') { - $output .= CConsole::yellow("Usage:") . PHP_EOL; - $output .= " cache:clear-all\tFlush all application cache". PHP_EOL; - $output .= " cache:clear [type]\tFlush specific application cache". PHP_EOL; - $output .= " \t\t\t[type] - the type of cache to be removed: 'db', 'css', 'js' or 'all'". PHP_EOL; - } elseif (in_array($this->param, array('db', 'css', 'js', 'all'))) { - if($this->param == 'db' || $this->param == 'all'){ - if (CConfig::get('cache.db.path') == '') { - $output .= CConsole::redbg("Config value 'cache.db.path' is not defined. Check your configuration file.") . PHP_EOL; - }else{ - $result = CFile::emptyDirectory(CConfig::get('cache.db.path'), array('index.html')); - $output .= 'DB cache ' . ($result ? 'successfully cleaned' : 'error'); - } - } - if($this->param == 'css' || $this->param == 'all'){ - if (CConfig::get('compression.css.path') == '') { - $output .= CConsole::redbg("Config value 'compression.css.path' is not defined. Check your configuration file.") . PHP_EOL; - }else{ - $result = CFile::emptyDirectory(CConfig::get('compression.css.path'), array('index.html')); - $output .= 'CSS cache ' . ($result ? 'successfully cleaned' : 'error'); - } - } - if($this->param == 'js' || $this->param == 'all'){ - if (CConfig::get('compression.js.path') == '') { - $output .= CConsole::redbg("Config value 'compression.js.path' is not defined. Check your configuration file.") . PHP_EOL; - }else{ - $result = CFile::emptyDirectory(CConfig::get('compression.js.path'), array('index.html')); - $output .= 'JS cache ' . ($result ? 'successfully cleaned' : 'error'); - } - } - } + $output .= CCacheClearCommand::handle($this->param); + break; + case 'make:controller': + $output .= CMakeControllerCommand::handle($this->param); break; default: - $output .= PHP_EOL; $output .= CConsole::redbg("Command '".$this->command."' is not defined.") . PHP_EOL; $output .= 'Type "bin/aii --help" to check all commands and options.'; diff --git a/framework/console/CHelpCommand.php b/framework/console/CHelpCommand.php index 9351237..39677ed 100644 --- a/framework/console/CHelpCommand.php +++ b/framework/console/CHelpCommand.php @@ -14,9 +14,13 @@ * handle (static) */ -class CHelpCommand +class CHelpCommand implements IConsoleCommand { + /** + * Handle specific console command + * @return string + */ public static function handle() { $output = ''; @@ -35,9 +39,16 @@ public static function handle() $output .= PHP_EOL; $output .= CConsole::yellow("Available commands:") . PHP_EOL; + + $output .= " ".CConsole::green("help")."\t\t\tHelp on console commands". PHP_EOL; + + $output .= CConsole::yellow("cache") . PHP_EOL; $output .= " ".CConsole::green("cache:clear")."\t\tFlush specific application cache". PHP_EOL; $output .= " ".CConsole::green("cache:clear-all")."\tFlush all application cache". PHP_EOL; + $output .= CConsole::yellow("make") . PHP_EOL; + $output .= " ".CConsole::green("make:controller")."\tCreate controller". PHP_EOL; + return $output; } diff --git a/framework/console/CMakeControllerCommand.php b/framework/console/CMakeControllerCommand.php new file mode 100644 index 0000000..cced01f --- /dev/null +++ b/framework/console/CMakeControllerCommand.php @@ -0,0 +1,34 @@ + + * @link http://www.apphpframework.com/ + * @copyright Copyright (c) 2012 - 2020 ApPHP Framework + * @license http://www.apphpframework.com/license/ + * + * PUBLIC (static): PROTECTED: PRIVATE (static): + * --------------- --------------- --------------- + * handle (static) + */ + +class CMakeControllerCommand implements IConsoleCommand +{ + + /** + * Handle specific console command + * + * @param string $param + * + * @return string + */ + public static function handle($param = '') + { + $output = 'Controller created: ' . $param; + + return $output; + } + +} diff --git a/framework/console/CVersionCommand.php b/framework/console/CVersionCommand.php index 5004ed7..11c0e5b 100644 --- a/framework/console/CVersionCommand.php +++ b/framework/console/CVersionCommand.php @@ -14,9 +14,13 @@ * handle (static) */ -class CVersionCommand +class CVersionCommand implements IConsoleCommand { + /** + * Handle specific console command + * @return string + */ public static function handle() { $output = 'ApPHP Framework ' . CConsole::green(A::version()); diff --git a/framework/core/interfaces.php b/framework/core/interfaces.php index 740300e..caa1d25 100644 --- a/framework/core/interfaces.php +++ b/framework/core/interfaces.php @@ -21,3 +21,15 @@ interface IActiveRecord */ public static function model(); } + + +/** + * IConsoleCommand is the interface that must be implemented by console command classes + */ +interface IConsoleCommand +{ + /** + * Handle specific console command + */ + public static function handle(); +} From c66e3987bc9e3c21b33b72ec9a691c4feb46776d Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 1 Aug 2020 23:22:30 +0300 Subject: [PATCH 26/45] Chunk implementation for AR --- .../protected/controllers/PostsController.php | 34 ++++++---- framework/db/CActiveRecord.php | 65 +++++++++++++------ framework/messages/ar/core.php | 1 + framework/messages/de/core.php | 1 + framework/messages/en/core.php | 1 + framework/messages/es/core.php | 1 + framework/messages/fr/core.php | 1 + framework/messages/he/core.php | 1 + framework/messages/it/core.php | 1 + framework/messages/nl/core.php | 3 +- framework/messages/pl/core.php | 1 + framework/messages/ru/core.php | 1 + 12 files changed, 76 insertions(+), 35 deletions(-) diff --git a/demos/simple-blog/protected/controllers/PostsController.php b/demos/simple-blog/protected/controllers/PostsController.php index cb363f8..1f04906 100644 --- a/demos/simple-blog/protected/controllers/PostsController.php +++ b/demos/simple-blog/protected/controllers/PostsController.php @@ -135,21 +135,27 @@ public function indexAction($msg = '') if (!$this->_view->currentPage) { $this->_view->actionMessage = CWidget::create('CMessage', array('error', 'Wrong parameter passed! Please try again later.', array('button' => true))); } else { -/* $this->_view->posts = Posts::model()->findAll(array( - 'limit' => (($this->_view->currentPage - 1) * $this->_view->pageSize) . ', ' . $this->_view->pageSize, - 'order' => 'post_datetime DESC', - ));*/ + $conditions = array( + 'limit' => (($this->_view->currentPage - 1) * $this->_view->pageSize) . ', ' . $this->_view->pageSize, + 'order' => 'post_datetime DESC', + ); - $posts = null; - Posts::model()->chunk(2, function ($records) use(&$posts){ - foreach ($records as $key => $record) { - $posts[] = $record; - } - //CDebug::d($record); - }); - //CDebug::dd($posts); - - $this->_view->posts = $posts; + if (!true) { + $this->_view->posts = Posts::model()->findAll(array( + 'limit' => (($this->_view->currentPage - 1) * $this->_view->pageSize) . ', ' . $this->_view->pageSize, + 'order' => 'post_datetime DESC', + )); + }else{ + $posts = null; + Posts::model()->chunk($conditions, [], -2, function ($records) use(&$posts){ + foreach ($records as $key => $record) { + $posts[] = $record; + } + //CDebug::d($record); + }); + //CDebug::dd($posts); + $this->_view->posts = $posts; + } } $this->_view->render('posts/index'); diff --git a/framework/db/CActiveRecord.php b/framework/db/CActiveRecord.php index 57839ac..cb2a0a7 100644 --- a/framework/db/CActiveRecord.php +++ b/framework/db/CActiveRecord.php @@ -581,24 +581,46 @@ private function _createObjectFromTable() /** * Split AR result into parts (chunks) + * Ex.: chunk(array('condition'=>'post_id = :postID AND is_active = :isActive', 'select'=>'', 'group|groupBy'=>'', 'order|orderBy'=>'id DESC', 'limit'=>'0, 10'), array(':postID'=>10, ':isActive'=>1)); + * Ex.: chunk(CConfig::get('db.prefix').$this->_tableTranslation.'.news_text LIKE :keywords', array(':keywords'=>'%'.$keywords.'%')); + * + * @param array $conditions + * @param array $params * @param int $size - * @param null $callback + * @param callable $callback + * + * @return null */ - public function chunk(int $size, callable $callback = null) + public function chunk(array $conditions = [], array $params = [], int $size = 0, callable $callback = null) { if (is_int($size) && $size > 0 && !empty($callback)) { - $from = 0; -// echo('limit'."$from, $size"); - while ($result = $this->findAll(array('limit'=>"$from, $size"))){ + if (!isset($conditions['limit'])) { + $from = 0; + $limitSize = $size; + } else { + $limitParts = explode(',', $conditions['limit']); + $from = isset($limitParts[0]) ? $limitParts[0] : 0; + $limitSize = isset($limitParts[1]) ? $limitParts[1] : $size; + if ($size >= $limitSize) { + $size = $limitSize; + } + } + + $conditions['limit'] = "$from, $size"; + $count = 0; + + while ($result = $this->findAll($conditions, $params)){ $callback($result); $from += $size; -// echo('limit'."$from, $size"); -// if ($from > 10){ -// return; -// } + $conditions['limit'] = "$from, $size"; + + $count += $size; + if ($count >= $limitSize) { + break; + } } } else { - CDebug::AddMessage('errors', 'chunk', A::t('core', 'Wrong params for chunk: {size} or callback method is callable.', array('{size}' => $size))); + CDebug::AddMessage('errors', 'chunk', A::t('core', 'Wrong params for chunk size: {size} or callback method is callable.', array('{size}' => $size))); } return null; @@ -713,16 +735,19 @@ public function findByPk($pk, $conditions = '', $params = array(), $cacheId = fa return null; } } - - /** - * This method queries your database to find related objects by attributes - * Ex.: findByAttributes($attributes, 'postID = :postID AND isActive = :isActive', array(':postID'=>10, ':isActive'=>1)); - * Ex.: findByAttributes($attributes, array('condition'=>'postID = :postID AND isActive = :isActive', 'order|orderBy'=>'id DESC', 'limit'=>'0, 10'), 'params'=>array(':postID'=>10, ':isActive'=>1)); - * Ex.: $attributes = array('first_name'=>$firstName, 'last_name'=>$lastName); - * @param array $attributes - * @param mixed $conditions - * @param array $params - */ + + /** + * This method queries your database to find related objects by attributes + * Ex.: findByAttributes($attributes, 'postID = :postID AND isActive = :isActive', array(':postID'=>10, ':isActive'=>1)); + * Ex.: findByAttributes($attributes, array('condition'=>'postID = :postID AND isActive = :isActive', 'order|orderBy'=>'id DESC', 'limit'=>'0, 10'), 'params'=>array(':postID'=>10, ':isActive'=>1)); + * Ex.: $attributes = array('first_name'=>$firstName, 'last_name'=>$lastName); + * + * @param array $attributes + * @param mixed $conditions + * @param array $params + * + * @return mixed + */ public function findByAttributes($attributes, $conditions = '', $params = array()) { if (is_array($conditions)) { diff --git a/framework/messages/ar/core.php b/framework/messages/ar/core.php index ff94c84..fc4f20e 100644 --- a/framework/messages/ar/core.php +++ b/framework/messages/ar/core.php @@ -186,4 +186,5 @@ 'You cannot delete the last remaining record in table {table}!' => 'لا يمكنك حذف السجل الأخير المتبقي في الجدول {table}!', 'Warnings' => 'تحذيرات', 'Wrong column name: {index} in table {table}' => 'اسم عمود غير صحيح: "{index}" في الجدول "{table}" - لا يمكن الوصول إلى خاصية غير موجودة لكائن AR', + 'Wrong params for chunk size: {size} or callback method is callable.' => 'Wrong params for chunk size: {size} or callback method is callable.', ); \ No newline at end of file diff --git a/framework/messages/de/core.php b/framework/messages/de/core.php index 79861e3..d2939ca 100644 --- a/framework/messages/de/core.php +++ b/framework/messages/de/core.php @@ -184,4 +184,5 @@ 'You cannot delete the last remaining record in table {table}!' => 'Sie können die letzten verbliebenen Satz in der Tabelle {table} nicht löschen!', 'Warnings' => 'Warnungen', 'Wrong column name: {index} in table {table}' => 'Falsche Spalte name: {index} in Tabelle {table}', +'Wrong params for chunk size: {size} or callback method is callable.' => 'Wrong params for chunk size: {size} or callback method is callable.', ); \ No newline at end of file diff --git a/framework/messages/en/core.php b/framework/messages/en/core.php index 6e34165..162f20d 100644 --- a/framework/messages/en/core.php +++ b/framework/messages/en/core.php @@ -186,4 +186,5 @@ 'You cannot delete the last remaining record in table {table}!' => 'You cannot delete the last remaining record in table {table}!', 'Warnings' => 'Warnings', 'Wrong column name: {index} in table {table}' => 'Wrong column name: "{index}" in table "{table}" - can\'t access non existent property of AR object', + 'Wrong params for chunk size: {size} or callback method is callable.' => 'Wrong params for chunk size: {size} or callback method is callable.', ); \ No newline at end of file diff --git a/framework/messages/es/core.php b/framework/messages/es/core.php index d399f6b..c0b51b9 100644 --- a/framework/messages/es/core.php +++ b/framework/messages/es/core.php @@ -186,4 +186,5 @@ 'You cannot delete the last remaining record in table {table}!' => 'No se puede eliminar el único registro existente en la tabla {table}.', 'Warnings' => 'Advertencias', 'Wrong column name: {index} in table {table}' => 'Nombre de columna incorrecta: {index} en la tabla {table}.', + 'Wrong params for chunk size: {size} or callback method is callable.' => 'Wrong params for chunk size: {size} or callback method is callable.', ); \ No newline at end of file diff --git a/framework/messages/fr/core.php b/framework/messages/fr/core.php index 98ef71e..721bcd3 100644 --- a/framework/messages/fr/core.php +++ b/framework/messages/fr/core.php @@ -186,4 +186,5 @@ 'You cannot delete the last remaining record in table {table}!' => 'Vous ne pouvez pas supprimer le dernier enregistrement restante dans le tableau {table}!', 'Warnings' => 'Avertissements', 'Wrong column name: {index} in table {table}' => 'Nom de colonne incorrect: {index} dans la table {table}', + 'Wrong params for chunk size: {size} or callback method is callable.' => 'Wrong params for chunk size: {size} or callback method is callable.', ); \ No newline at end of file diff --git a/framework/messages/he/core.php b/framework/messages/he/core.php index 11d2307..364e6b7 100644 --- a/framework/messages/he/core.php +++ b/framework/messages/he/core.php @@ -186,4 +186,5 @@ 'You cannot delete the last remaining record in table {table}!' => 'לא ניתן למחוק את הרשומה האחרונה שנותרה בטבלה {table}!', 'Warnings' => 'אזהרות', 'Wrong column name: {index} in table {table}' => 'שם עמוד שגוי: {index} בטבלה {table}', + 'Wrong params for chunk size: {size} or callback method is callable.' => 'Wrong params for chunk size: {size} or callback method is callable.', ); \ No newline at end of file diff --git a/framework/messages/it/core.php b/framework/messages/it/core.php index ced6c4d..a9b904e 100644 --- a/framework/messages/it/core.php +++ b/framework/messages/it/core.php @@ -186,4 +186,5 @@ 'You cannot delete the last remaining record in table {table}!' => 'Non è possibile eliminare l\'ultimo record rimasto nella tabella {table}!', 'Warnings' => 'Avvertenze', 'Wrong column name: {index} in table {table}' => 'Colonna sbagliato nome: {index} nella tabella {table}', + 'Wrong params for chunk size: {size} or callback method is callable.' => 'Wrong params for chunk size: {size} or callback method is callable.', ); \ No newline at end of file diff --git a/framework/messages/nl/core.php b/framework/messages/nl/core.php index 3d06763..1ce9f5a 100644 --- a/framework/messages/nl/core.php +++ b/framework/messages/nl/core.php @@ -181,9 +181,10 @@ 'Unable to find the model class "{model}".' => 'Kan het model de klas "{model}".', 'Unknown' => 'Onbekend', 'Unknown operator "{operator}".' => 'Onbekende operator "{operator}".', - 'Uploaded {file} is not a valid image! Please check carefully the file type.' => 'Ge�ploade file {file} is geen geldige afbeelding! Gelieve zorgvuldig te controleren het bestandstype.', + 'Uploaded {file} is not a valid image! Please check carefully the file type.' => 'Geploade file {file} is geen geldige afbeelding! Gelieve zorgvuldig te controleren het bestandstype.', 'version' => 'versie', 'You cannot delete the last remaining record in table {table}!' => 'U kunt de laatst overgebleven record niet verwijderen in tabel {table}!', 'Warnings' => 'Waarschuwingen', 'Wrong column name: {index} in table {table}' => 'naam verkeerd column: {index} in tabel {table}', + 'Wrong params for chunk size: {size} or callback method is callable.' => 'Wrong params for chunk size: {size} or callback method is callable.', ); \ No newline at end of file diff --git a/framework/messages/pl/core.php b/framework/messages/pl/core.php index 0a70a8c..0c14653 100644 --- a/framework/messages/pl/core.php +++ b/framework/messages/pl/core.php @@ -186,4 +186,5 @@ 'You cannot delete the last remaining record in table {table}!' => 'Nie możesz skasować ostatniego rekordu który pozostał {table}!', 'Warnings' => 'Ostrzeżenia', 'Wrong column name: {index} in table {table}' => 'Zła nazwa kolumny: {index} w tablicy {table}', + 'Wrong params for chunk size: {size} or callback method is callable.' => 'Wrong params for chunk size: {size} or callback method is callable.', ); \ No newline at end of file diff --git a/framework/messages/ru/core.php b/framework/messages/ru/core.php index 60f6b41..0957afd 100644 --- a/framework/messages/ru/core.php +++ b/framework/messages/ru/core.php @@ -186,4 +186,5 @@ 'You cannot delete the last remaining record in table {table}!' => 'Вы не можете удалить последнюю оставшуюся запись в таблице {table}!', 'Warnings' => 'Предупреждения', 'Wrong column name: {index} in table {table}' => 'Неверное имя колонки: {index} в таблице {table}', + 'Wrong params for chunk size: {size} or callback method is callable.' => 'Wrong params for chunk size: {size} or callback method is callable.', ); \ No newline at end of file From 6b1f76a61e90ff378877e234a29cdc9a751bc4cd Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 1 Aug 2020 23:42:16 +0300 Subject: [PATCH 27/45] Redo array() to [] --- .../protected/components/Bootstrap.php | 18 +- .../controllers/CategoriesController.php | 81 +- .../protected/controllers/PostsController.php | 2 +- demos/simple-blog/protected/models/Posts.php | 42 +- .../modules/setup/templates/default.php | 32 +- .../modules/setup/views/setup/index.php | 28 +- .../protected/views/categories/index.php | 25 +- .../protected/views/categories/view.php | 22 +- .../controllers/AdminsController.php | 353 +- .../setup/templates/views/setup/database.php | 8 +- framework/components/CClientScript.php | 1150 +++--- framework/components/CComponent.php | 103 +- framework/components/CDbHttpSession.php | 842 +++-- framework/components/CHttpCookie.php | 289 +- framework/components/CHttpRequest.php | 2009 +++++----- framework/components/CHttpSession.php | 585 +-- framework/components/CLocalTime.php | 1274 +++++-- framework/components/CLogger.php | 298 +- framework/components/CMessageSource.php | 196 +- framework/components/CMobileDetect.php | 50 +- framework/components/CShoppingCart.php | 890 ++--- framework/components/CUri.php | 651 ++-- framework/console/CCacheClearCommand.php | 6 +- framework/console/CConsole.php | 16 +- framework/console/CConsoleCommand.php | 9 +- framework/console/CHelpCommand.php | 27 +- framework/console/CMakeControllerCommand.php | 2 +- framework/console/CVersionCommand.php | 3 +- framework/db/CActiveRecord.php | 3229 +++++++++-------- framework/db/CDatabase.php | 1996 +++++----- framework/db/CDbCommand.php | 1592 ++++---- framework/db/CRecordEntity.php | 433 ++- framework/helpers/widgets/CBreadCrumbs.php | 133 +- .../helpers/widgets/CLanguageSelector.php | 219 +- framework/helpers/widgets/CPagination.php | 398 +- framework/helpers/widgets/CTabs.php | 252 +- tests/framework/helpers/CArrayTest.php | 192 +- tests/framework/helpers/CAuthTest.php | 6 +- tests/framework/helpers/CValidatorTest.php | 70 +- 39 files changed, 9594 insertions(+), 7937 deletions(-) diff --git a/demos/simple-blog/protected/components/Bootstrap.php b/demos/simple-blog/protected/components/Bootstrap.php index 76fa107..51f8e6e 100644 --- a/demos/simple-blog/protected/components/Bootstrap.php +++ b/demos/simple-blog/protected/components/Bootstrap.php @@ -24,15 +24,15 @@ class Bootstrap extends CComponent */ function __construct() { - A::app()->attachEventHandler('_onBeginRequest', array($this, 'setTimeZone')); - A::app()->attachEventHandler('_onBeginRequest', array($this, 'setSslMode')); - A::app()->attachEventHandler('_onBeginRequest', array($this, 'setCron')); - - A::app()->attachEventHandler('_onEndRequest', array($this, 'setLastVisitedPage')); - } - - /** - * Returns the instance of object + A::app()->attachEventHandler('_onBeginRequest', [$this, 'setTimeZone']); + A::app()->attachEventHandler('_onBeginRequest', [$this, 'setSslMode']); + A::app()->attachEventHandler('_onBeginRequest', [$this, 'setCron']); + + A::app()->attachEventHandler('_onEndRequest', [$this, 'setLastVisitedPage']); + } + + /** + * Returns the instance of object * @return current class */ public static function init() diff --git a/demos/simple-blog/protected/controllers/CategoriesController.php b/demos/simple-blog/protected/controllers/CategoriesController.php index de9be60..88a4687 100644 --- a/demos/simple-blog/protected/controllers/CategoriesController.php +++ b/demos/simple-blog/protected/controllers/CategoriesController.php @@ -52,8 +52,8 @@ public function viewAction($categoryId = 0) //All posts from the selected category $postsModel = Posts::model(); - if (!$postsModel->count('category_id = :category_id', array(':category_id' => $categoryId))) { - $msgType = 'warning'; + if ( ! $postsModel->count('category_id = :category_id', [':category_id' => $categoryId])) { + $msgType = 'warning'; $msg = (!empty($catName)) ? 'There are still no posts in category ' . $catName . '.' : 'Wrong parameter passed, please try again later.'; } else { @@ -61,25 +61,26 @@ public function viewAction($categoryId = 0) $this->_view->targetPage = 'categories/view/id/' . $categoryId; $this->_view->currentPage = A::app()->getRequest()->getQuery('page', 'integer', 1); $this->_view->pageSize = '5'; - $this->_view->totalRecords = Posts::model()->count(array( - 'condition' => 'category_id = :category_id', - ), - array(':category_id' => $categoryId) - ); - - $msgType = 'info'; + $this->_view->totalRecords = Posts::model()->count( + ['condition' => 'category_id = :category_id',], + [':category_id' => $categoryId] + ); + + $msgType = 'info'; $msg = 'Category: ' . $catName; - - $this->_view->posts = $postsModel->findAll(array( - 'condition' => 'category_id = :category_id', - 'limit' => (($this->_view->currentPage - 1) * $this->_view->pageSize) . ', ' . $this->_view->pageSize, - 'order' => 'post_datetime DESC', - ), - array(':category_id' => $categoryId) - ); - } - $this->_view->mainText = CWidget::create('CMessage', array($msgType, $msg, array('button' => false))); - $this->_view->render('categories/view'); + + $this->_view->posts = $postsModel->findAll( + [ + 'condition' => 'category_id = :category_id', + 'limit' => (($this->_view->currentPage - 1) * $this->_view->pageSize).', ' + .$this->_view->pageSize, + 'order' => 'post_datetime DESC', + ], + [':category_id' => $categoryId] + ); + } + $this->_view->mainText = CWidget::create('CMessage', [$msgType, $msg, ['button' => false]]); + $this->_view->render('categories/view'); } public function indexAction($msg = '') @@ -107,25 +108,35 @@ public function indexAction($msg = '') $msgType = 'Wrong parameter passed! Check category ID.'; $msgType = 'error'; } - if (!empty($msgType)) $this->_view->actionMessage = CWidget::create('CMessage', array($msgType, $msgType, array('button' => true))); - } - - // prepare pagination vars + if ( ! empty($msgType)) { + $this->_view->actionMessage = CWidget::create('CMessage', [$msgType, $msgType, ['button' => true]]); + } + } + + // prepare pagination vars $this->_view->targetPage = 'categories/index'; $this->_view->currentPage = A::app()->getRequest()->getQuery('page', 'integer', 1); $this->_view->pageSize = '15'; $this->_view->totalRecords = Categories::model()->count(); - - if (!$this->_view->currentPage) { - $this->_view->actionMessage = CWidget::create('CMessage', array('error', 'Wrong parameter passed! Please try again later.', array('button' => true))); - } else { - $this->_view->categories = Categories::model()->findAll(array( - 'limit' => (($this->_view->currentPage - 1) * $this->_view->pageSize) . ', ' . $this->_view->pageSize, - 'order' => 'id ASC', - )); - } - - $this->_view->render('categories/index'); + + if ( ! $this->_view->currentPage) { + $this->_view->actionMessage = CWidget::create('CMessage', + [ + 'error', + 'Wrong parameter passed! Please try again later.', + ['button' => true] + ] + ); + } else { + $this->_view->categories = Categories::model()->findAll( + [ + 'limit' => (($this->_view->currentPage - 1) * $this->_view->pageSize).', '.$this->_view->pageSize, + 'order' => 'id ASC', + ] + ); + } + + $this->_view->render('categories/index'); } public function addAction() diff --git a/demos/simple-blog/protected/controllers/PostsController.php b/demos/simple-blog/protected/controllers/PostsController.php index 1f04906..b6e00c0 100644 --- a/demos/simple-blog/protected/controllers/PostsController.php +++ b/demos/simple-blog/protected/controllers/PostsController.php @@ -147,7 +147,7 @@ public function indexAction($msg = '') )); }else{ $posts = null; - Posts::model()->chunk($conditions, [], -2, function ($records) use(&$posts){ + Posts::model()->chunk($conditions, [], 2, function ($records) use(&$posts){ foreach ($records as $key => $record) { $posts[] = $record; } diff --git a/demos/simple-blog/protected/models/Posts.php b/demos/simple-blog/protected/models/Posts.php index 549b86e..9d08728 100644 --- a/demos/simple-blog/protected/models/Posts.php +++ b/demos/simple-blog/protected/models/Posts.php @@ -19,12 +19,12 @@ class Posts extends CActiveRecord public $categoryOldId; /** @var */ - protected $_fillable = array(); - /** @var */ - protected $_guarded = array('post_datetime'); + protected $_fillable = []; + /** @var */ + protected $_guarded = ['post_datetime']; - - public function __construct() + + public function __construct() { parent::__construct(); } @@ -42,13 +42,27 @@ public static function model() */ protected function _relations() { - return array( - 'author_id' => array(self::HAS_ONE, 'authors', 'id', 'condition' => '', 'joinType' => self::LEFT_OUTER_JOIN, 'fields' => array('login' => '')), - 'category_id' => array(self::BELONGS_TO, 'categories', 'id', 'condition' => '', 'joinType' => self::LEFT_OUTER_JOIN, 'fields' => array('name' => 'category_name')), - ); - } - - protected function _afterSave($pk = '') + return [ + 'author_id' => [ + self::HAS_ONE, + 'authors', + 'id', + 'condition' => '', + 'joinType' => self::LEFT_OUTER_JOIN, + 'fields' => ['login' => ''] + ], + 'category_id' => [ + self::BELONGS_TO, + 'categories', + 'id', + 'condition' => '', + 'joinType' => self::LEFT_OUTER_JOIN, + 'fields' => ['name' => 'category_name'] + ], + ]; + } + + protected function _afterSave($pk = '') { if ($this->categoryOldId != $this->category_id) { $this->_updatePostsCount($this->categoryOldId); @@ -65,7 +79,7 @@ protected function _afterDelete($pk = '') private function _updatePostsCount($pKey) { // update total count of posts in categories table - $totalPosts = self::model()->count('category_id = :category_id', array(':category_id' => $pKey)); - $this->_db->update('categories', array('posts_count' => $totalPosts), 'id = ' . (int)$pKey); + $totalPosts = self::model()->count('category_id = :category_id', [':category_id' => $pKey]); + $this->_db->update('categories', array('posts_count' => $totalPosts), 'id = ' . (int)$pKey); } } diff --git a/demos/simple-blog/protected/modules/setup/templates/default.php b/demos/simple-blog/protected/modules/setup/templates/default.php index 1a3982a..2496d87 100644 --- a/demos/simple-blog/protected/modules/setup/templates/default.php +++ b/demos/simple-blog/protected/modules/setup/templates/default.php @@ -27,21 +27,25 @@
    'vertical', - 'items'=>array( - array('label'=>'1. Server Requirements', 'url'=>'setup/index', 'readonly'=>true), - array('label'=>'2. Database Settings', 'url'=>'setup/database', 'readonly'=>true), - array('label'=>'3. Administrator Account', 'url'=>'setup/administrator', 'readonly'=>true), - array('label'=>'4. Ready to Install', 'url'=>'setup/ready', 'readonly'=>true), - array('label'=>'5. Completed', 'url'=>'setup/completed', 'readonly'=>true), - ), - 'selected'=>$this->_activeMenu, - 'return'=>false - )); + + CWidget::create( + 'CMenu', + [ + 'type' => 'vertical', + 'items' => [ + ['label' => '1. Server Requirements', 'url' => 'setup/index', 'readonly' => true], + ['label' => '2. Database Settings', 'url' => 'setup/database', 'readonly' => true], + ['label' => '3. Administrator Account', 'url' => 'setup/administrator', 'readonly' => true], + ['label' => '4. Ready to Install', 'url' => 'setup/ready', 'readonly' => true], + ['label' => '5. Completed', 'url' => 'setup/completed', 'readonly' => true], + ], + 'selected' => $this->_activeMenu, + 'return' => false + ] + ); ?> - -
    + +
    view->getContent(); ?>
    diff --git a/demos/simple-blog/protected/modules/setup/views/setup/index.php b/demos/simple-blog/protected/modules/setup/views/setup/index.php index 6a70e66..d1fbcec 100644 --- a/demos/simple-blog/protected/modules/setup/views/setup/index.php +++ b/demos/simple-blog/protected/modules/setup/views/setup/index.php @@ -10,17 +10,21 @@
    'setup/index', - 'method' => 'post', - 'htmlOptions' => array( - 'name' => 'frmSetup', - ), - 'fields' => $formFields, - 'buttons' => array( - 'submit' => array('type' => 'submit', 'value' => A::t('setup', 'Next'), 'htmlOptions' => array('name' => '')), - ), - 'return' => true, -)); + +echo CWidget::create( + 'CFormView', + [ + 'action' => 'setup/index', + 'method' => 'post', + 'htmlOptions' => [ + 'name' => 'frmSetup', + ], + 'fields' => $formFields, + 'buttons' => [ + 'submit' => ['type' => 'submit', 'value' => A::t('setup', 'Next'), 'htmlOptions' => ['name' => '']], + ], + 'return' => true, + ] +); ?>
    diff --git a/demos/simple-blog/protected/views/categories/index.php b/demos/simple-blog/protected/views/categories/index.php index 5c47b1d..6c49c04 100644 --- a/demos/simple-blog/protected/views/categories/index.php +++ b/demos/simple-blog/protected/views/categories/index.php @@ -31,16 +31,19 @@ } echo ''; echo ''; - - echo CWidget::create('CPagination', array( - 'actionPath' => 'categories/index', - 'currentPage' => $currentPage, - 'pageSize' => $pageSize, - 'totalRecords' => $totalRecords, - 'linkType' => 1, - 'paginationType' => 'fullNumbers', - )); - } - ?> + + echo CWidget::create( + 'CPagination', + [ + 'actionPath' => 'categories/index', + 'currentPage' => $currentPage, + 'pageSize' => $pageSize, + 'totalRecords' => $totalRecords, + 'linkType' => 1, + 'paginationType' => 'fullNumbers', + ] + ); + } + ?>

    diff --git a/demos/simple-blog/protected/views/categories/view.php b/demos/simple-blog/protected/views/categories/view.php index cabba2f..1d0220e 100644 --- a/demos/simple-blog/protected/views/categories/view.php +++ b/demos/simple-blog/protected/views/categories/view.php @@ -47,17 +47,19 @@ } if (count($posts) > 1) { - echo CWidget::create('CPagination', array( - 'actionPath' => 'posts/view', - 'currentPage' => $currentPage, - 'pageSize' => $pageSize, - 'totalRecords' => $totalRecords, - 'showResultsOfTotal' => false, - 'linkType' => 0, - 'paginationType' => 'prevNext', - )); + echo CWidget::create( + 'CPagination', + [ + 'actionPath' => 'posts/view', + 'currentPage' => $currentPage, + 'pageSize' => $pageSize, + 'totalRecords' => $totalRecords, + 'showResultsOfTotal' => false, + 'linkType' => 0, + 'paginationType' => 'prevNext', + ] + ); } - } ?> diff --git a/demos/simple-cms/protected/controllers/AdminsController.php b/demos/simple-cms/protected/controllers/AdminsController.php index 9864918..d4ce082 100644 --- a/demos/simple-cms/protected/controllers/AdminsController.php +++ b/demos/simple-cms/protected/controllers/AdminsController.php @@ -12,178 +12,187 @@ * addAction * deleteAction */ + class AdminsController extends CController { - public function __construct() - { - parent::__construct(); - - // block access to this controller for not-logged users - CAuth::handleLogin(); - - $this->_loggedId = CAuth::getLoggedId(); - - $settings = Settings::model()->findByPk(1); - $this->_view->setMetaTags('title', 'Account | ' . $settings->metatag_title); - $this->_view->setMetaTags('keywords', $settings->metatag_keywords); - $this->_view->setMetaTags('description', $settings->metatag_description); - $this->_view->cmsName = $settings->site_name; - $this->_view->cmsSlogan = $settings->slogan; - $this->_view->cmsFooter = $settings->footer; - - $this->_view->activeLink = 'home'; - $this->_view->viewRightMenu = false; - $this->_view->errorField = ''; - $this->_view->actionMessage = ''; - - // prepare list of roles that the logged admin can deal with - $allRolesList = array(); - $rolesList = array(); - - if (CAuth::isLoggedInAs('owner')) { - $rolesList = array('mainadmin' => 'mainadmin', 'admin' => 'admin'); - } elseif (CAuth::isLoggedInAs('mainadmin')) { - $rolesList = array('admin' => 'admin'); - } - $roles = array( - array('code' => 'owner', 'name' => 'Owner'), - array('code' => 'mainadmin', 'name' => 'Main Admin'), - array('code' => 'admin', 'name' => 'Admin'), - ); - if (is_array($roles)) { - foreach ($roles as $role) { - $allRolesList[$role['code']] = $role['name']; - if (in_array($role['code'], $rolesList)) { - $rolesList[$role['code']] = $role['name']; - } - } - } - $this->_view->rolesListStr = "'" . implode("','", array_keys($rolesList)) . "'"; - $this->_view->rolesList = $rolesList; - $this->_view->allRolesList = $allRolesList; - - $this->_view->dateTimeFormat = 'm F, Y H:i:s'; - } - - public function indexAction() - { - $this->redirect('admins/view'); - } - - /** - * View admins action handler - * @param string $msg - */ - public function viewAction($msg = '') - { - $this->_view->activeLink = 'admins'; - switch ($msg) { - case 'added': - $message = A::t('core', 'The adding operation has been successfully completed!'); - break; - case 'updated': - $message = A::t('core', 'The updating operation has been successfully completed!'); - break; - default: - $message = ''; - } - if (!empty($message)) { - $this->_view->actionMessage = CWidget::create('CMessage', array('success', $message, array('button' => true))); - } - $this->_view->render('admins/view'); - } - - /** - * Edit admin action handler - * @param int $id The admin id - */ - public function editAction($id = 0) - { - $this->_view->activeLink = 'admins'; - - //$this->_view->activeLink = 'admins'; - $admin = Admins::model()->findByPk((int)$id); - if (!$admin) { - $this->redirect('backend/index'); - } - $this->_view->isMyAccount = ($admin->id == $this->_loggedId ? true : false); - if ($this->_view->isMyAccount == true) $this->_view->activeLink = 'myAccount'; - - // allow access to edit other admins only to site owner or main admin - if (!$this->_view->isMyAccount && - !CAuth::isLoggedInAs('owner', 'mainadmin') && - !in_array($admin->role, array_keys($this->_view->rolesList))) { - $this->redirect('backend/index'); - } - $this->_view->admin = $admin; - $this->_view->password = ''; - $this->_view->passwordRetype = ''; - - $this->_view->render('admins/edit'); - } - - - /** - * My Account action handler - * Calls the editAction with id of logged admin. - */ - public function myAccountAction() - { - $this->_view->activeLink = 'myAccount'; - $this->editAction($this->_loggedId); - } - - /* - * Add new admin action handler - */ - public function addAction() - { - // allow access only to site owner or main admin - if (!CAuth::isLoggedInAs('owner', 'mainadmin')) { - $this->redirect('backend/index'); - } - $this->_view->render('admins/add'); - } - - /** - * Delete admin action handler - * @param int $id The admin id - */ - public function deleteAction($id = 0) - { - // allow access only to site owner or main admin - if (!CAuth::isLoggedInAs('owner', 'mainadmin')) { - $this->redirect('backend/index'); - } - - $msg = ''; - $msgType = ''; - - $admin = Admins::model()->findByPk((int)$id); - if (!$admin) { - $this->redirect('admins/view'); - } - - // check if this delete operation is allowed - if (!in_array($admin->role, array_keys($this->_view->rolesList))) { - $msg = A::t('core', 'Operation Blocked Error Message'); - $msgType = 'error'; - // delete the admin - } elseif ($admin->delete()) { - $msg = A::t('core', 'Deleting operation has been successfully completed!'); - $msgType = 'success'; - } else { - if (APPHP_MODE == 'demo') { - $msg = CDatabase::init()->getErrorMessage(); - } else { - $msg = A::t('core', 'An error occurred while deleting the record!'); - } - $msgType = 'error'; - } - if (!empty($msg)) { - $this->_view->actionMessage = CWidget::create('CMessage', array($msgType, $msg, array('button' => true))); - } - $this->_view->render('admins/view'); - } - + public function __construct() + { + parent::__construct(); + + // block access to this controller for not-logged users + CAuth::handleLogin(); + + $this->_loggedId = CAuth::getLoggedId(); + + $settings = Settings::model()->findByPk(1); + $this->_view->setMetaTags('title', 'Account | '.$settings->metatag_title); + $this->_view->setMetaTags('keywords', $settings->metatag_keywords); + $this->_view->setMetaTags('description', $settings->metatag_description); + $this->_view->cmsName = $settings->site_name; + $this->_view->cmsSlogan = $settings->slogan; + $this->_view->cmsFooter = $settings->footer; + + $this->_view->activeLink = 'home'; + $this->_view->viewRightMenu = false; + $this->_view->errorField = ''; + $this->_view->actionMessage = ''; + + // prepare list of roles that the logged admin can deal with + $allRolesList = []; + $rolesList = []; + + if (CAuth::isLoggedInAs('owner')) { + $rolesList = ['mainadmin' => 'mainadmin', 'admin' => 'admin']; + } elseif (CAuth::isLoggedInAs('mainadmin')) { + $rolesList = ['admin' => 'admin']; + } + $roles = [ + ['code' => 'owner', 'name' => 'Owner'], + ['code' => 'mainadmin', 'name' => 'Main Admin'], + ['code' => 'admin', 'name' => 'Admin'], + ]; + if (is_array($roles)) { + foreach ($roles as $role) { + $allRolesList[$role['code']] = $role['name']; + if (in_array($role['code'], $rolesList)) { + $rolesList[$role['code']] = $role['name']; + } + } + } + $this->_view->rolesListStr = "'".implode("','", array_keys($rolesList))."'"; + $this->_view->rolesList = $rolesList; + $this->_view->allRolesList = $allRolesList; + + $this->_view->dateTimeFormat = 'm F, Y H:i:s'; + } + + public function indexAction() + { + $this->redirect('admins/view'); + } + + /** + * View admins action handler + * + * @param string $msg + */ + public function viewAction($msg = '') + { + $this->_view->activeLink = 'admins'; + switch ($msg) { + case 'added': + $message = A::t('core', 'The adding operation has been successfully completed!'); + break; + case 'updated': + $message = A::t('core', 'The updating operation has been successfully completed!'); + break; + default: + $message = ''; + } + if ( ! empty($message)) { + $this->_view->actionMessage = CWidget::create('CMessage', ['success', $message, ['button' => true]]); + } + $this->_view->render('admins/view'); + } + + /** + * Edit admin action handler + * + * @param int $id The admin id + */ + public function editAction($id = 0) + { + $this->_view->activeLink = 'admins'; + + //$this->_view->activeLink = 'admins'; + $admin = Admins::model()->findByPk((int)$id); + if ( ! $admin) { + $this->redirect('backend/index'); + } + $this->_view->isMyAccount = ($admin->id == $this->_loggedId ? true : false); + if ($this->_view->isMyAccount == true) { + $this->_view->activeLink = 'myAccount'; + } + + // allow access to edit other admins only to site owner or main admin + if ( ! $this->_view->isMyAccount + && + ! CAuth::isLoggedInAs('owner', 'mainadmin') + && + ! in_array($admin->role, array_keys($this->_view->rolesList)) + ) { + $this->redirect('backend/index'); + } + $this->_view->admin = $admin; + $this->_view->password = ''; + $this->_view->passwordRetype = ''; + + $this->_view->render('admins/edit'); + } + + + /** + * My Account action handler + * Calls the editAction with id of logged admin. + */ + public function myAccountAction() + { + $this->_view->activeLink = 'myAccount'; + $this->editAction($this->_loggedId); + } + + /* + * Add new admin action handler + */ + public function addAction() + { + // allow access only to site owner or main admin + if ( ! CAuth::isLoggedInAs('owner', 'mainadmin')) { + $this->redirect('backend/index'); + } + $this->_view->render('admins/add'); + } + + /** + * Delete admin action handler + * + * @param int $id The admin id + */ + public function deleteAction($id = 0) + { + // allow access only to site owner or main admin + if ( ! CAuth::isLoggedInAs('owner', 'mainadmin')) { + $this->redirect('backend/index'); + } + + $msg = ''; + $msgType = ''; + + $admin = Admins::model()->findByPk((int)$id); + if ( ! $admin) { + $this->redirect('admins/view'); + } + + // check if this delete operation is allowed + if ( ! in_array($admin->role, array_keys($this->_view->rolesList))) { + $msg = A::t('core', 'Operation Blocked Error Message'); + $msgType = 'error'; + // delete the admin + } elseif ($admin->delete()) { + $msg = A::t('core', 'Deleting operation has been successfully completed!'); + $msgType = 'success'; + } else { + if (APPHP_MODE == 'demo') { + $msg = CDatabase::init()->getErrorMessage(); + } else { + $msg = A::t('core', 'An error occurred while deleting the record!'); + } + $msgType = 'error'; + } + if ( ! empty($msg)) { + $this->_view->actionMessage = CWidget::create('CMessage', [$msgType, $msg, ['button' => true]]); + } + $this->_view->render('admins/view'); + } + } \ No newline at end of file diff --git a/demos/simple-cms/protected/modules/setup/templates/views/setup/database.php b/demos/simple-cms/protected/modules/setup/templates/views/setup/database.php index e8290f4..bccdff4 100644 --- a/demos/simple-cms/protected/modules/setup/templates/views/setup/database.php +++ b/demos/simple-cms/protected/modules/setup/templates/views/setup/database.php @@ -21,8 +21,12 @@ ), 'fields'=>$formFields, 'buttons'=>array( - 'back'=>array('type'=>'button', 'value'=>'Previous', 'htmlOptions'=>array('name'=>'', 'onclick'=>"$(location).attr('href','setup/index');")), - 'submit'=>array('type'=>'submit', 'value'=>'Next', 'htmlOptions'=>array('name'=>'')) + 'back' => array( + 'type' => 'button', + 'value' => 'Previous', + 'htmlOptions' => array('name' => '', 'onclick' => "$(location).attr('href','setup/index');") + ), + 'submit' => array('type' => 'submit', 'value' => 'Next', 'htmlOptions' => array('name' => '')) ), 'events'=>array( 'focus'=>array('field'=>$errorField) diff --git a/framework/components/CClientScript.php b/framework/components/CClientScript.php index 84cd838..7cc2d5c 100644 --- a/framework/components/CClientScript.php +++ b/framework/components/CClientScript.php @@ -29,532 +29,626 @@ class CClientScript extends CComponent { - /** The script is rendered in the */ - const POS_HEAD = 0; - /** The script is rendered at the beginning of the */ - const POS_BODY_BEGIN = 1; - /** The script is rendered at the end of the */ - const POS_BODY_END = 2; - /** The script is rendered inside window onload function */ - const POS_ON_LOAD = 3; - /** The body script is rendered inside a jQuery ready function */ - const POS_JQUERY_READY = 4; - /** The script is rendered inside document ready function */ - const POS_DOC_READY = 5; - - /** The limit in amount of css minify files */ - const CSS_MINIFY_LIMIT = 100; - /** The limit in amount of js minify files */ - const JS_MINIFY_LIMIT = 100; - - /** @var boolean */ - public $enableJavaScript = true; - /** @var array */ - protected $_cssFiles = array(); - /** @var int */ - protected $_countCompressedCssFiles = 0; - /** @var array */ - protected $_css = array(); - /** @var array */ - protected $_scriptFiles = array(); - /** @var int */ - protected $_countCompressedJsFiles = 0; - /** @var array */ - protected $_scripts = array(); - /** @var boolean */ - protected $_hasStyles = false; - /** @var boolean */ - protected $_hasScripts = false; - /** @var string */ - protected $_countJsFiles = 0; - /** @var string */ - protected $_countCssFiles = 0; - - - /** - * Class default constructor - */ - function __construct() - { - - } - - /** - * Returns the instance of object - * @return current class - */ - public static function init() - { - return parent::init(__CLASS__); - } - - /** - * Registers a piece of CSS code - * @param string $id - * @param string $css - * @param string $media - * @return void - */ - public function registerCss($id, $css, $media = '') - { - if (!empty($css)) { - if (!$this->_hasStyles) $this->_hasStyles = true; - $this->_css[$id] = array($css, $media); - } - } - - /** - * Registers CSS file - * @param string $url - * @param string $media - * @param string $level - * @return void - */ - public function registerCssFile($url, $media = 'all', $level = '') - { - if (!empty($url)) { - if (!$this->_hasStyles) $this->_hasStyles = true; - if (!isset($this->_cssFiles[$media])) $this->_cssFiles[$media] = array(); - if (!in_array($url, $this->_cssFiles[$media])) { - if (!empty($level)) { - if (isset($this->_cssFiles[$media][$level])) { - CDebug::addMessage('warnings', 'css-file-exists', A::t('core', 'CSS file with the same level "{level}" already registered: "{file}"', array('{level}' => $level, '{file}' => $url))); - } - $this->_cssFiles[$media][$level] = $url; - } else { - $this->_cssFiles[$media][$this->_countCssFiles++] = $url; - } - } - } - } - - /** - * Registers CSS files - * @param string $urls - * @param string $path - * @return void - */ - public function registerCssFiles($urls, $path = '') - { - if (!empty($urls) && array($urls)) { - foreach ($urls as $key => $url) { - if (empty($url)) continue; - $path = !empty($path) ? trim($path, '/') . '/' : ''; - $url = $path . (is_array($url) ? $key : $url); - $media = (is_array($url) && !empty($url['media'])) ? ' media="' . $url['media'] . '"' : 'all'; - $this->registerCssFile($url, $media); - } - } - } - - /** - * Registers a piece of javascript code - * @param string $id - * @param string $script - * @param integer $position - * @return void - */ - public function registerScript($id, $script, $position = self::POS_JQUERY_READY) - { - if (!empty($script)) { - if (!$this->_hasScripts) $this->_hasScripts = true; - $this->_scripts[$position][$id] = $script; - if ($position === self::POS_JQUERY_READY || $position === self::POS_ON_LOAD) { - $this->registerCoreScript('jquery'); - } - } - } - - /** - * Registers javascript file - * @param string $url - * @param integer $position self::POS_HEAD|self::POS_BODY_BEGIN|self::POS_BODY_END - * @param string $level - * @return void - */ - public function registerScriptFile($url, $position = self::POS_HEAD, $level = '') - { - if (!empty($url)) { - if (!$this->_hasScripts) $this->_hasScripts = true; - if (!isset($this->_scriptFiles[$position])) $this->_scriptFiles[$position] = array(); - if (!in_array($url, $this->_scriptFiles[$position])) { - if (!empty($level)) { - if (isset($this->_scriptFiles[$position][$level])) { - CDebug::addMessage('warnings', 'js-file-exists', A::t('core', 'Javascript file with the same level "{level}" already registered: "{file}"', array('{level}' => $level, '{file}' => $url))); - } - $this->_scriptFiles[$position][$level] = $url; - } else { - $this->_scriptFiles[$position][$this->_countJsFiles++] = $url; - } - } - } - } - - /** - * Registers a required javascript file - * @param string $url - * @param string $path - * @param integer $position self::POS_HEAD|self::POS_BODY_BEGIN|self::POS_BODY_END - * @return void - */ - public function registerScriptFiles($urls, $path = '', $position = self::POS_HEAD) - { - if (!empty($urls) && array($urls)) { - foreach ($urls as $key => $url) { - $path = !empty($path) ? trim($path, '/') . '/' : ''; - $url = $path . (is_array($url) ? $key : $url); - $position = (is_array($url) && !empty($url['position'])) ? $url['position'] : $position; - $this->registerScriptFile($url, $position); - } - } - } - - /** - * Registers a core script package - * @param string $name - * @return void - */ - public function registerCoreScript($name) - { - // Registers core script - } - - /** - * Renders the registered scripts in our class - * This method is called in View->render() class - * @param string &$output - * @return void|bool - */ - public function render(&$output) - { - if (!$this->_hasStyles && !$this->_hasScripts) { - return false; - } - - // Sort CSS according by level - $this->_sortByLevel($this->_cssFiles); - - // Sort JS scripts by level - if ($this->enableJavaScript) { - $this->_sortByLevel($this->_scriptFiles); - } - - $this->_cssToCompression(); - $this->_jsToCompression(); - $this->renderHead($output); - if ($this->enableJavaScript) { - $this->renderBodyBegin($output); - $this->renderBodyEnd($output); - } - } - - /** - * Inserts the js scripts/css in the head section - * @param string &$output - * @return void - */ - public function renderHead(&$output) - { - $html = ''; - $version = '?v=' . CConfig::get('version'); - - ///CDebug::d($this->_cssFiles); - ///CDebug::d($this->_scriptFiles); - - foreach ($this->_cssFiles as $media => $cssFiles) { - foreach ($cssFiles as $level => $cssFile) { - $html .= CHtml::cssFile($cssFile . $version, $media); - } - } - foreach ($this->_css as $css) { - $html .= CHtml::css($css[0], $css[1]); - } - - if ($this->enableJavaScript) { - if (isset($this->_scriptFiles[self::POS_HEAD])) { - foreach ($this->_scriptFiles[self::POS_HEAD] as $level => $scriptFile) { - $html .= CHtml::scriptFile($scriptFile . $version); - } - } - if (isset($this->_scripts[self::POS_HEAD])) { - $html .= CHtml::script(implode("\n", $this->_scripts[self::POS_HEAD])) . "\n"; - } - } - - if ($html !== '') { - $count = 0; - $output = preg_replace('/(]*>|<\\/head\s*>)/is', '<%%%head%%%>$1', $output, 1, $count); - if ($count) { - $output = str_replace('<%%%head%%%>', $html, $output); - } else { - $output = $html . $output; - } - } - } - - /** - * Inserts the scripts at the beginning of the - * @param string &$output - * @return void - */ - public function renderBodyBegin(&$output) - { - $html = ''; - if (isset($this->_scriptFiles[self::POS_BODY_BEGIN])) { - foreach ($this->_scriptFiles[self::POS_BODY_BEGIN] as $level => $scriptFile) { - $html .= CHtml::scriptFile($scriptFile); - } - } - if (isset($this->_scripts[self::POS_BODY_BEGIN])) { - $html .= CHtml::script(implode("\n", $this->_scripts[self::POS_BODY_BEGIN])) . "\n"; - } - - if ($html !== '') { - $count = 0; - $output = preg_replace('/(]*>)/is', '$1<%%%begin%%%>', $output, 1, $count); - if ($count) { - $output = str_replace('<%%%begin%%%>', $html, $output); - } else { - $output = $html . $output; - } - } - } - - /** - * Inserts the scripts at the end of the - * @param string &$output - * @return void - */ - public function renderBodyEnd(&$output) - { - if (!isset($this->_scriptFiles[self::POS_BODY_END]) && - !isset($this->_scripts[self::POS_BODY_END]) && - !isset($this->_scripts[self::POS_JQUERY_READY]) && - !isset($this->_scripts[self::POS_DOC_READY]) && - !isset($this->_scripts[self::POS_ON_LOAD])) - return; - - $completePage = 0; - $output = preg_replace('/(<\\/body\s*>)/is', '<%%%end%%%>$1', $output, 1, $completePage); - $html = ''; - if (isset($this->_scriptFiles[self::POS_BODY_END])) { - foreach ($this->_scriptFiles[self::POS_BODY_END] as $level => $scriptFile) { - $html .= CHtml::scriptFile($scriptFile); - } - } - - $scripts = isset($this->_scripts[self::POS_BODY_END]) ? $this->_scripts[self::POS_BODY_END] : array(); - if (isset($this->_scripts[self::POS_JQUERY_READY])) { - if ($completePage) { - $scripts[] = "jQuery(function($){\n" . implode("\n", $this->_scripts[self::POS_JQUERY_READY]) . "\n});"; - } else { - $scripts[] = implode("\n", $this->_scripts[self::POS_JQUERY_READY]); - } - } - if (isset($this->_scripts[self::POS_DOC_READY])) { - if ($completePage) { - $scripts[] = "jQuery(document).ready(function(){\n" . implode("\n", $this->_scripts[self::POS_DOC_READY]) . "\n});"; - } else { - $scripts[] = implode("\n", $this->_scripts[self::POS_DOC_READY]); - } - } - if (isset($this->_scripts[self::POS_ON_LOAD])) { - if ($completePage) { - $scripts[] = "jQuery(window).load(function(){\n" . implode("\n", $this->_scripts[self::POS_ON_LOAD]) . "\n});"; - } else { - $scripts[] = implode("\n", $this->_scripts[self::POS_ON_LOAD]); - } - } - if (!empty($scripts)) $html .= CHtml::script(implode("\n", $scripts)) . "\n"; - - if ($completePage) { - $output = str_replace('<%%%end%%%>', $html, $output); - } else { - $output = $output . $html; - } - } - - /** - * Returns count of compressed files - * @param string $type - * @returm int - */ - public function countCompressedFiles($type = 'css') - { - if ($type == 'css') { - return $this->_countCompressedCssFiles; - } elseif ($type == 'js') { - return $this->_countCompressedJsFiles; - } - - return 0; - } - - /** - * Prepare css files to compression - * @returm bool - */ - protected function _cssToCompression() - { - if (!CConfig::get('compression.css.enable')) { - return false; - } - - if (is_array($this->_cssFiles)) { - $tempCssFiles = array(); - foreach ($this->_cssFiles as $media => $styleFiles) { - - $this->_countCompressedCssFiles = count($styleFiles); - $cssFilesHash = md5(serialize($styleFiles)); - $minifiedDir = CConfig::get('compression.css.path'); - $minifyCss = CConfig::get('compression.css.minify.' . (A::app()->view->getTemplate() === 'backend' ? 'backend' : 'frontend')); - $baseUrl = A::app()->getRequest()->getBaseUrl(); - $controller = A::app()->view->getController(); - $action = A::app()->view->getAction(); - $minifiedFile = md5($baseUrl . $controller . '/' . $action . '/' . $this->_countCompressedCssFiles . '/' . $cssFilesHash) . '.css'; - $cssMinifiedFile = $minifiedDir . $minifiedFile; - - // Fix - skip assets directory - if (in_array(strtolower($controller), array('assets'))) { - continue; - } - - // Check if minified file exists and exit - if (!empty($minifiedFile) && file_exists($minifiedDir . $minifiedFile) && (filesize($minifiedDir . $minifiedFile) > 0)) { - $tempCssFiles[$media][] = $cssMinifiedFile; - continue; - } - - // Collect CSS files content - $count = 0; - $cssContent = ''; - $baseUrl = str_ireplace(array('http:', 'https:'), '', $baseUrl); - foreach ($styleFiles as $key => $cssFile) { - $fileContent = CFile::getFileContent($cssFile); - if ($fileContent) { - if ($minifyCss) { - $fileContent = CMinify::css($fileContent); - } - - // Replace relative paths with absolute - $dirName = dirname($cssFile); - - // ../../ : ../../templates/default/css => //domain.com/templates/default/css - $dirNameLevel2 = explode('/', $dirName); - array_pop($dirNameLevel2); - array_pop($dirNameLevel2); - $dirNameLevel2 = $baseUrl . implode('/', $dirNameLevel2) . '/'; - $fileContent = str_ireplace(array("url('../../", "url(../../"), array("url('" . $dirNameLevel2, "url(" . $dirNameLevel2), $fileContent); - - // ../ : ../templates/default/css => //domain.com/templates/default/css - $dirNameLevel1 = explode('/', $dirName); - array_pop($dirNameLevel1); - $dirNameLevel1 = $baseUrl . implode('/', $dirNameLevel1) . '/'; - $fileContent = str_ireplace(array("url('../", "url(../"), array("url('" . $dirNameLevel1, "url(" . $dirNameLevel1), $fileContent); - - // url('') : url('fonts/font.eot') => url('//domain.com/fonts/font.eot') - $dirNameLevel0 = explode('/', $dirName); - $dirNameLevel0 = $baseUrl . implode('/', $dirNameLevel0) . '/'; - $fileContent = str_ireplace(array("url('font", "url(font"), array("url('" . $dirNameLevel0 . "font", "url(" . $dirNameLevel0 . "font"), $fileContent); - - $cssContent .= "/* CSS File " . ++$count . ": " . $cssFile . " */" . PHP_EOL . $fileContent . PHP_EOL . PHP_EOL; - } - } - - if (!empty($cssContent)) { - // Remove oldest file if the limit of minified is reached - if (CFile::getDirectoryFilesCount($minifiedDir, '.css') >= self::CSS_MINIFY_LIMIT) { - CFile::removeDirectoryOldestFile($minifiedDir, 0, array('index.html')); - } - - CFile::writeToFile($minifiedDir . $minifiedFile, $cssContent); - $tempCssFiles[$media][] = $cssMinifiedFile; - } - } - $this->_cssFiles = $tempCssFiles; - } - - return true; - } - - /** - * Prepare js files to compression - * @returm bool - */ - protected function _jsToCompression() - { - if (!CConfig::get('compression.js.enable')) { - return false; - } - - if (is_array($this->_scriptFiles)) { - $tempJsFiles = array(); - foreach ($this->_scriptFiles as $position => $scriptFiles) { - - $countCompressedJsFiles = count($scriptFiles); - $this->_countCompressedJsFiles += $countCompressedJsFiles; - $jsFilesHash = md5(serialize($scriptFiles)); - $minifiedDir = CConfig::get('compression.js.path'); - $minifyJs = CConfig::get('compression.js.minify.' . (A::app()->view->getTemplate() === 'backend' ? 'backend' : 'frontend')); - $baseUrl = A::app()->getRequest()->getBaseUrl(); - $controller = A::app()->view->getController(); - $action = A::app()->view->getAction(); - - $minifiedFile = md5($baseUrl . $controller . '/' . $action . '/' . $position . '/' . $countCompressedJsFiles . '/' . $jsFilesHash) . '.js'; - $jsMinifiedFile = $minifiedDir . $minifiedFile; - - // Fix - skip assets directory - if (in_array(strtolower($controller), array('assets'))) { - continue; - } - - // Check if minified file exists and exit - if (!empty($minifiedFile) && file_exists($minifiedDir . $minifiedFile) && (filesize($minifiedDir . $minifiedFile) > 0)) { - $tempJsFiles[$position][] = $jsMinifiedFile; - continue; - } - - // Collect JS files content - $count = 0; - $jsContent = ''; - $baseUrl = str_ireplace(array('http:', 'https:'), '', $baseUrl); - foreach ($scriptFiles as $key => $url) { - $fileContent = CFile::getFileContent($url); - if ($fileContent) { - if ($minifyJs) { - $fileContent = CMinify::js($fileContent); - } - $jsContent .= "/* JS File " . ++$count . ": " . $url . " */" . PHP_EOL . $fileContent . PHP_EOL . PHP_EOL; - } - } - - if (!empty($jsContent)) { - // Remove oldest file if the limit of minified is reached - if (CFile::getDirectoryFilesCount($minifiedDir, '.js') >= self::JS_MINIFY_LIMIT) { - CFile::removeDirectoryOldestFile($minifiedDir, 0, array('index.html')); - } - - CFile::writeToFile($minifiedDir . $minifiedFile, $jsContent); - $tempJsFiles[$position][] = $jsMinifiedFile; - } - } - $this->_scriptFiles = $tempJsFiles; - } - - return true; - } - - /** - * Returns CSS or JS array of files, sorted by level - * @param array &$filesArray - * @returm voies - */ - private function _sortByLevel(&$filesArray = array()) - { - foreach ($filesArray as $key => $files) { - ksort($files); - $filesArray[$key] = $files; - } - } - + /** The script is rendered in the */ + const POS_HEAD = 0; + /** The script is rendered at the beginning of the */ + const POS_BODY_BEGIN = 1; + /** The script is rendered at the end of the */ + const POS_BODY_END = 2; + /** The script is rendered inside window onload function */ + const POS_ON_LOAD = 3; + /** The body script is rendered inside a jQuery ready function */ + const POS_JQUERY_READY = 4; + /** The script is rendered inside document ready function */ + const POS_DOC_READY = 5; + + /** The limit in amount of css minify files */ + const CSS_MINIFY_LIMIT = 100; + /** The limit in amount of js minify files */ + const JS_MINIFY_LIMIT = 100; + + /** @var boolean */ + public $enableJavaScript = true; + /** @var array */ + protected $_cssFiles = []; + /** @var int */ + protected $_countCompressedCssFiles = 0; + /** @var array */ + protected $_css = []; + /** @var array */ + protected $_scriptFiles = []; + /** @var int */ + protected $_countCompressedJsFiles = 0; + /** @var array */ + protected $_scripts = []; + /** @var boolean */ + protected $_hasStyles = false; + /** @var boolean */ + protected $_hasScripts = false; + /** @var string */ + protected $_countJsFiles = 0; + /** @var string */ + protected $_countCssFiles = 0; + + + /** + * Class default constructor + */ + function __construct() + { + } + + /** + * Returns the instance of object + * + * @return current class + */ + public static function init() + { + return parent::init(__CLASS__); + } + + /** + * Registers a piece of CSS code + * + * @param string $id + * @param string $css + * @param string $media + * + * @return void + */ + public function registerCss($id, $css, $media = '') + { + if ( ! empty($css)) { + if ( ! $this->_hasStyles) { + $this->_hasStyles = true; + } + $this->_css[$id] = [$css, $media]; + } + } + + /** + * Registers CSS file + * + * @param string $url + * @param string $media + * @param string $level + * + * @return void + */ + public function registerCssFile($url, $media = 'all', $level = '') + { + if ( ! empty($url)) { + if ( ! $this->_hasStyles) { + $this->_hasStyles = true; + } + if ( ! isset($this->_cssFiles[$media])) { + $this->_cssFiles[$media] = []; + } + if ( ! in_array($url, $this->_cssFiles[$media])) { + if ( ! empty($level)) { + if (isset($this->_cssFiles[$media][$level])) { + CDebug::addMessage( + 'warnings', + 'css-file-exists', + A::t( + 'core', + 'CSS file with the same level "{level}" already registered: "{file}"', + ['{level}' => $level, '{file}' => $url] + ) + ); + } + $this->_cssFiles[$media][$level] = $url; + } else { + $this->_cssFiles[$media][$this->_countCssFiles++] = $url; + } + } + } + } + + /** + * Registers CSS files + * + * @param string $urls + * @param string $path + * + * @return void + */ + public function registerCssFiles($urls, $path = '') + { + if ( ! empty($urls) && [$urls]) { + foreach ($urls as $key => $url) { + if (empty($url)) { + continue; + } + $path = ! empty($path) ? trim($path, '/').'/' : ''; + $url = $path.(is_array($url) ? $key : $url); + $media = (is_array($url) && ! empty($url['media'])) ? ' media="'.$url['media'].'"' : 'all'; + $this->registerCssFile($url, $media); + } + } + } + + /** + * Registers a piece of javascript code + * + * @param string $id + * @param string $script + * @param integer $position + * + * @return void + */ + public function registerScript($id, $script, $position = self::POS_JQUERY_READY) + { + if ( ! empty($script)) { + if ( ! $this->_hasScripts) { + $this->_hasScripts = true; + } + $this->_scripts[$position][$id] = $script; + if ($position === self::POS_JQUERY_READY || $position === self::POS_ON_LOAD) { + $this->registerCoreScript('jquery'); + } + } + } + + /** + * Registers javascript file + * + * @param string $url + * @param integer $position self::POS_HEAD|self::POS_BODY_BEGIN|self::POS_BODY_END + * @param string $level + * + * @return void + */ + public function registerScriptFile($url, $position = self::POS_HEAD, $level = '') + { + if ( ! empty($url)) { + if ( ! $this->_hasScripts) { + $this->_hasScripts = true; + } + if ( ! isset($this->_scriptFiles[$position])) { + $this->_scriptFiles[$position] = []; + } + if ( ! in_array($url, $this->_scriptFiles[$position])) { + if ( ! empty($level)) { + if (isset($this->_scriptFiles[$position][$level])) { + CDebug::addMessage( + 'warnings', + 'js-file-exists', + A::t( + 'core', + 'Javascript file with the same level "{level}" already registered: "{file}"', + ['{level}' => $level, '{file}' => $url] + ) + ); + } + $this->_scriptFiles[$position][$level] = $url; + } else { + $this->_scriptFiles[$position][$this->_countJsFiles++] = $url; + } + } + } + } + + /** + * Registers a required javascript file + * + * @param string $url + * @param string $path + * @param integer $position self::POS_HEAD|self::POS_BODY_BEGIN|self::POS_BODY_END + * + * @return void + */ + public function registerScriptFiles($urls, $path = '', $position = self::POS_HEAD) + { + if ( ! empty($urls) && [$urls]) { + foreach ($urls as $key => $url) { + $path = ! empty($path) ? trim($path, '/').'/' : ''; + $url = $path.(is_array($url) ? $key : $url); + $position = (is_array($url) && ! empty($url['position'])) ? $url['position'] : $position; + $this->registerScriptFile($url, $position); + } + } + } + + /** + * Registers a core script package + * + * @param string $name + * + * @return void + */ + public function registerCoreScript($name) + { + // Registers core script + } + + /** + * Renders the registered scripts in our class + * This method is called in View->render() class + * + * @param string &$output + * + * @return void|bool + */ + public function render(&$output) + { + if ( ! $this->_hasStyles && ! $this->_hasScripts) { + return false; + } + + // Sort CSS according by level + $this->_sortByLevel($this->_cssFiles); + + // Sort JS scripts by level + if ($this->enableJavaScript) { + $this->_sortByLevel($this->_scriptFiles); + } + + $this->_cssToCompression(); + $this->_jsToCompression(); + $this->renderHead($output); + if ($this->enableJavaScript) { + $this->renderBodyBegin($output); + $this->renderBodyEnd($output); + } + } + + /** + * Inserts the js scripts/css in the head section + * + * @param string &$output + * + * @return void + */ + public function renderHead(&$output) + { + $html = ''; + $version = '?v='.CConfig::get('version'); + + ///CDebug::d($this->_cssFiles); + ///CDebug::d($this->_scriptFiles); + + foreach ($this->_cssFiles as $media => $cssFiles) { + foreach ($cssFiles as $level => $cssFile) { + $html .= CHtml::cssFile($cssFile.$version, $media); + } + } + foreach ($this->_css as $css) { + $html .= CHtml::css($css[0], $css[1]); + } + + if ($this->enableJavaScript) { + if (isset($this->_scriptFiles[self::POS_HEAD])) { + foreach ($this->_scriptFiles[self::POS_HEAD] as $level => $scriptFile) { + $html .= CHtml::scriptFile($scriptFile.$version); + } + } + if (isset($this->_scripts[self::POS_HEAD])) { + $html .= CHtml::script(implode("\n", $this->_scripts[self::POS_HEAD]))."\n"; + } + } + + if ($html !== '') { + $count = 0; + $output = preg_replace('/(]*>|<\\/head\s*>)/is', '<%%%head%%%>$1', $output, 1, $count); + if ($count) { + $output = str_replace('<%%%head%%%>', $html, $output); + } else { + $output = $html.$output; + } + } + } + + /** + * Inserts the scripts at the beginning of the + * + * @param string &$output + * + * @return void + */ + public function renderBodyBegin(&$output) + { + $html = ''; + if (isset($this->_scriptFiles[self::POS_BODY_BEGIN])) { + foreach ($this->_scriptFiles[self::POS_BODY_BEGIN] as $level => $scriptFile) { + $html .= CHtml::scriptFile($scriptFile); + } + } + if (isset($this->_scripts[self::POS_BODY_BEGIN])) { + $html .= CHtml::script(implode("\n", $this->_scripts[self::POS_BODY_BEGIN]))."\n"; + } + + if ($html !== '') { + $count = 0; + $output = preg_replace('/(]*>)/is', '$1<%%%begin%%%>', $output, 1, $count); + if ($count) { + $output = str_replace('<%%%begin%%%>', $html, $output); + } else { + $output = $html.$output; + } + } + } + + /** + * Inserts the scripts at the end of the + * + * @param string &$output + * + * @return void + */ + public function renderBodyEnd(&$output) + { + if ( ! isset($this->_scriptFiles[self::POS_BODY_END]) + && + ! isset($this->_scripts[self::POS_BODY_END]) + && + ! isset($this->_scripts[self::POS_JQUERY_READY]) + && + ! isset($this->_scripts[self::POS_DOC_READY]) + && + ! isset($this->_scripts[self::POS_ON_LOAD]) + ) { + return; + } + + $completePage = 0; + $output = preg_replace('/(<\\/body\s*>)/is', '<%%%end%%%>$1', $output, 1, $completePage); + $html = ''; + if (isset($this->_scriptFiles[self::POS_BODY_END])) { + foreach ($this->_scriptFiles[self::POS_BODY_END] as $level => $scriptFile) { + $html .= CHtml::scriptFile($scriptFile); + } + } + + $scripts = isset($this->_scripts[self::POS_BODY_END]) ? $this->_scripts[self::POS_BODY_END] : []; + if (isset($this->_scripts[self::POS_JQUERY_READY])) { + if ($completePage) { + $scripts[] = "jQuery(function($){\n".implode("\n", $this->_scripts[self::POS_JQUERY_READY])."\n});"; + } else { + $scripts[] = implode("\n", $this->_scripts[self::POS_JQUERY_READY]); + } + } + if (isset($this->_scripts[self::POS_DOC_READY])) { + if ($completePage) { + $scripts[] = "jQuery(document).ready(function(){\n".implode("\n", $this->_scripts[self::POS_DOC_READY]) + ."\n});"; + } else { + $scripts[] = implode("\n", $this->_scripts[self::POS_DOC_READY]); + } + } + if (isset($this->_scripts[self::POS_ON_LOAD])) { + if ($completePage) { + $scripts[] = "jQuery(window).load(function(){\n".implode("\n", $this->_scripts[self::POS_ON_LOAD]) + ."\n});"; + } else { + $scripts[] = implode("\n", $this->_scripts[self::POS_ON_LOAD]); + } + } + if ( ! empty($scripts)) { + $html .= CHtml::script(implode("\n", $scripts))."\n"; + } + + if ($completePage) { + $output = str_replace('<%%%end%%%>', $html, $output); + } else { + $output = $output.$html; + } + } + + /** + * Returns count of compressed files + * + * @param string $type + * + * @returm int + */ + public function countCompressedFiles($type = 'css') + { + if ($type == 'css') { + return $this->_countCompressedCssFiles; + } elseif ($type == 'js') { + return $this->_countCompressedJsFiles; + } + + return 0; + } + + /** + * Prepare css files to compression + * + * @returm bool + */ + protected function _cssToCompression() + { + if ( ! CConfig::get('compression.css.enable')) { + return false; + } + + if (is_array($this->_cssFiles)) { + $tempCssFiles = []; + foreach ($this->_cssFiles as $media => $styleFiles) { + $this->_countCompressedCssFiles = count($styleFiles); + $cssFilesHash = md5(serialize($styleFiles)); + $minifiedDir = CConfig::get('compression.css.path'); + $minifyCss = CConfig::get( + 'compression.css.minify.'.(A::app()->view->getTemplate() === 'backend' ? 'backend' : 'frontend') + ); + $baseUrl = A::app()->getRequest()->getBaseUrl(); + $controller = A::app()->view->getController(); + $action = A::app()->view->getAction(); + $minifiedFile = md5( + $baseUrl.$controller.'/'.$action.'/'.$this->_countCompressedCssFiles.'/'.$cssFilesHash + ).'.css'; + $cssMinifiedFile = $minifiedDir.$minifiedFile; + + // Fix - skip assets directory + if (in_array(strtolower($controller), ['assets'])) { + continue; + } + + // Check if minified file exists and exit + if ( ! empty($minifiedFile) && file_exists($minifiedDir.$minifiedFile) + && (filesize( + $minifiedDir.$minifiedFile + ) > 0) + ) { + $tempCssFiles[$media][] = $cssMinifiedFile; + continue; + } + + // Collect CSS files content + $count = 0; + $cssContent = ''; + $baseUrl = str_ireplace(['http:', 'https:'], '', $baseUrl); + foreach ($styleFiles as $key => $cssFile) { + $fileContent = CFile::getFileContent($cssFile); + if ($fileContent) { + if ($minifyCss) { + $fileContent = CMinify::css($fileContent); + } + + // Replace relative paths with absolute + $dirName = dirname($cssFile); + + // ../../ : ../../templates/default/css => //domain.com/templates/default/css + $dirNameLevel2 = explode('/', $dirName); + array_pop($dirNameLevel2); + array_pop($dirNameLevel2); + $dirNameLevel2 = $baseUrl.implode('/', $dirNameLevel2).'/'; + $fileContent = str_ireplace( + ["url('../../", "url(../../"], + ["url('".$dirNameLevel2, "url(".$dirNameLevel2], + $fileContent + ); + + // ../ : ../templates/default/css => //domain.com/templates/default/css + $dirNameLevel1 = explode('/', $dirName); + array_pop($dirNameLevel1); + $dirNameLevel1 = $baseUrl.implode('/', $dirNameLevel1).'/'; + $fileContent = str_ireplace( + ["url('../", "url(../"], + ["url('".$dirNameLevel1, "url(".$dirNameLevel1], + $fileContent + ); + + // url('') : url('fonts/font.eot') => url('//domain.com/fonts/font.eot') + $dirNameLevel0 = explode('/', $dirName); + $dirNameLevel0 = $baseUrl.implode('/', $dirNameLevel0).'/'; + $fileContent = str_ireplace( + ["url('font", "url(font"], + ["url('".$dirNameLevel0."font", "url(".$dirNameLevel0."font"], + $fileContent + ); + + $cssContent .= "/* CSS File ".++$count.": ".$cssFile." */".PHP_EOL.$fileContent.PHP_EOL.PHP_EOL; + } + } + + if ( ! empty($cssContent)) { + // Remove oldest file if the limit of minified is reached + if (CFile::getDirectoryFilesCount($minifiedDir, '.css') >= self::CSS_MINIFY_LIMIT) { + CFile::removeDirectoryOldestFile($minifiedDir, 0, ['index.html']); + } + + CFile::writeToFile($minifiedDir.$minifiedFile, $cssContent); + $tempCssFiles[$media][] = $cssMinifiedFile; + } + } + $this->_cssFiles = $tempCssFiles; + } + + return true; + } + + /** + * Prepare js files to compression + * + * @returm bool + */ + protected function _jsToCompression() + { + if ( ! CConfig::get('compression.js.enable')) { + return false; + } + + if (is_array($this->_scriptFiles)) { + $tempJsFiles = []; + foreach ($this->_scriptFiles as $position => $scriptFiles) { + $countCompressedJsFiles = count($scriptFiles); + $this->_countCompressedJsFiles += $countCompressedJsFiles; + $jsFilesHash = md5(serialize($scriptFiles)); + $minifiedDir = CConfig::get('compression.js.path'); + $minifyJs = CConfig::get( + 'compression.js.minify.'.(A::app()->view->getTemplate() === 'backend' ? 'backend' : 'frontend') + ); + $baseUrl = A::app()->getRequest()->getBaseUrl(); + $controller = A::app()->view->getController(); + $action = A::app()->view->getAction(); + + $minifiedFile = md5( + $baseUrl.$controller.'/'.$action.'/'.$position.'/'.$countCompressedJsFiles.'/'.$jsFilesHash + ).'.js'; + $jsMinifiedFile = $minifiedDir.$minifiedFile; + + // Fix - skip assets directory + if (in_array(strtolower($controller), ['assets'])) { + continue; + } + + // Check if minified file exists and exit + if ( ! empty($minifiedFile) && file_exists($minifiedDir.$minifiedFile) + && (filesize( + $minifiedDir.$minifiedFile + ) > 0) + ) { + $tempJsFiles[$position][] = $jsMinifiedFile; + continue; + } + + // Collect JS files content + $count = 0; + $jsContent = ''; + $baseUrl = str_ireplace(['http:', 'https:'], '', $baseUrl); + foreach ($scriptFiles as $key => $url) { + $fileContent = CFile::getFileContent($url); + if ($fileContent) { + if ($minifyJs) { + $fileContent = CMinify::js($fileContent); + } + $jsContent .= "/* JS File ".++$count.": ".$url." */".PHP_EOL.$fileContent.PHP_EOL.PHP_EOL; + } + } + + if ( ! empty($jsContent)) { + // Remove oldest file if the limit of minified is reached + if (CFile::getDirectoryFilesCount($minifiedDir, '.js') >= self::JS_MINIFY_LIMIT) { + CFile::removeDirectoryOldestFile($minifiedDir, 0, ['index.html']); + } + + CFile::writeToFile($minifiedDir.$minifiedFile, $jsContent); + $tempJsFiles[$position][] = $jsMinifiedFile; + } + } + $this->_scriptFiles = $tempJsFiles; + } + + return true; + } + + /** + * Returns CSS or JS array of files, sorted by level + * + * @param array &$filesArray + * + * @returm void + */ + private function _sortByLevel(&$filesArray = []) + { + foreach ($filesArray as $key => $files) { + ksort($files); + $filesArray[$key] = $files; + } + } + } \ No newline at end of file diff --git a/framework/components/CComponent.php b/framework/components/CComponent.php index c8d2b4e..b0174cd 100644 --- a/framework/components/CComponent.php +++ b/framework/components/CComponent.php @@ -17,54 +17,57 @@ class CComponent { - - /* class name => component */ - private static $_components = array(); - - /** - * Class constructor - * @return void - */ - function __construct() - { - - } - - /** - * Triggered when invoking inaccessible methods in an object context - * We use this method to avoid calling model($className = __CLASS__) in derived class - * @param string $method - * @param array $args - * @return mixed - */ - public static function __callStatic($method, $args) - { - if (strtolower($method) == 'init') { - if (count($args) == 1) { - return self::_parentInit($args[0]); - } - } - } - - /** - * Returns the static component of the specified class - * @param string $className - * - * EVERY derived component class must override this method in following way, - *
    -	 * public static function init()
    -	 * {
    -	 *     return parent::init(__CLASS__);
    -	 * }
    -	 * 
    - */ - private static function _parentInit($className = __CLASS__) - { - if (isset(self::$_components[$className])) { - return self::$_components[$className]; - } else { - return self::$_components[$className] = new $className(null); - } - } - + + /* class name => component */ + private static $_components = []; + + /** + * Class constructor + * + * @return void + */ + function __construct() + { + } + + /** + * Triggered when invoking inaccessible methods in an object context + * We use this method to avoid calling model($className = __CLASS__) in derived class + * + * @param string $method + * @param array $args + * + * @return mixed + */ + public static function __callStatic($method, $args) + { + if (strtolower($method) == 'init') { + if (count($args) == 1) { + return self::_parentInit($args[0]); + } + } + } + + /** + * Returns the static component of the specified class + * + * @param string $className + * + * EVERY derived component class must override this method in following way, + *
    +     * public static function init()
    +     * {
    +     *     return parent::init(__CLASS__);
    +     * }
    +     * 
    + */ + private static function _parentInit($className = __CLASS__) + { + if (isset(self::$_components[$className])) { + return self::$_components[$className]; + } else { + return self::$_components[$className] = new $className(null); + } + } + } \ No newline at end of file diff --git a/framework/components/CDbHttpSession.php b/framework/components/CDbHttpSession.php index 19c06cf..45fc208 100644 --- a/framework/components/CDbHttpSession.php +++ b/framework/components/CDbHttpSession.php @@ -39,402 +39,448 @@ class CDbHttpSession extends CComponent { - - /** @var boolean */ - protected $_autoStart = true; - /** @var string */ - protected $_defaultSessionName = 'apphp_framework'; - /** @var string */ - protected $_defaultSessionPrefix = 'apphp_'; - /** - * @var int - * @deprecated since v0.1.0 - * 0 - use name prefix, 1 - use session name (default) - */ - protected $_multiSiteSupportType = 1; - /** - * @var mixed - */ - protected $_prefix = ''; - - /** @var Database */ - private $_db; - - - /** - * Class default constructor - */ - function __construct() - { - $this->_db = CDatabase::init(); - - @session_set_save_handler( - array($this, 'openSession'), - array($this, 'closeSession'), - array($this, 'readSession'), - array($this, 'writeSession'), - array($this, 'destroySession'), - array($this, 'gcSession') - ); - - // The following prevents unexpected effects when using objects as save handlers - register_shutdown_function('session_write_close'); - - if ($this->_multiSiteSupportType) { - $this->setSessionName('apphp_' . CConfig::get('installationKey')); - } else { - $this->setSessionPrefix('apphp_' . CConfig::get('installationKey')); - } - - if ($this->_autoStart) $this->_startSession(); - } - - /** - * Returns the instance of object - * @return current class - */ - public static function init() - { - return parent::init(__CLASS__); - } - - /** - * Sets session variable - * @param string $name - * @param mixed $value - */ - public function set($name, $value) - { - $_SESSION[$name] = $value; - } - - /** - * Returns session variable - * @param string $name - * @param mixed $default - */ - public function get($name, $default = '') - { - return isset($_SESSION[$name]) ? $_SESSION[$name] : $default; - } - - /** - * Removes session variable - * @param string $name - */ - public function remove($name) - { - if (isset($_SESSION[$name])) { - unset($_SESSION[$name]); - return true; - } - - return false; - } - - /** - * Removes all session variable - * @return void - */ - public function removeAll() - { - @session_unset(); - if (is_array($_SESSION)) { - foreach ($_SESSION as $key => $val) { - unset($_SESSION[$key]); - } - } - } - - /** - * Checks if session variable exists - * @param string $name - */ - public function isExists($name) - { - return isset($_SESSION[$name]) ? true : false; - } - - /** - * Sets session flash data - * @param string $name - * @param mixed $value - */ - public function setFlash($name, $value) - { - $_SESSION[$this->_prefix . '_flash'][$name] = $value; - } - - /** - * Returns session flash data - * @param string $name - * @param mixed $default - */ - public function getFlash($name, $default = '') - { - if (isset($_SESSION[$this->_prefix . '_flash'][$name])) { - $result = $_SESSION[$this->_prefix . '_flash'][$name]; - unset($_SESSION[$this->_prefix . '_flash'][$name]); - } else { - $result = $default; - } - return $result; - } - - /** - * Checks if has flash data - * @param string $name - * @return bool - */ - public function hasFlash($name) - { - return isset($_SESSION[$this->_prefix . '_flash'][$name]) ? true : false; - } - - /** - * Sets session name - * @param string $value - */ - public function setSessionName($value) - { - if (empty($value)) $value = $this->_defaultSessionName; - session_name($value); - } - - /** - * Sets session name - * @param string $value - */ - public function setSessionPrefix($value) - { - if (empty($value)) $value = $this->_defaultSessionPrefix; - $this->_prefix = $value; - } - - /** - * Gets session name - * @return string - */ - public function getSessionName() - { - return session_name(); - } - - /** - * Destroys the session - */ - public function endSession() - { - if (session_id() !== '') { - @session_unset(); - @session_destroy(); - } - } - - /** - * Gets cookie mode - * @return string - */ - public function getCookieMode() - { - if (ini_get('session.use_cookies') === '0') { - return 'none'; - } elseif (ini_get('session.use_only_cookies') === '0') { - return 'allow'; - } else { - return 'only'; - } - } - - /** - * Session open handler - * Do not call this method directly - * @param string $savePath - * @param string $sessionName - * @return boolean - */ - public function openSession($savePath, $sessionName) - { - $this->_deleteExpiredSessions(); - return true; - } - - /** - * Session close handler - * Do not call this method directly - * @return boolean - */ - public function closeSession() - { - if (session_id() !== '') @session_write_close(); - return true; - } - - /** - * Session read handler - * Do not call this method directly - * @param string $id - * @return bool - */ - public function readSession($id) - { - $result = $this->_db->select('SELECT session_data FROM `' . CConfig::get('db.prefix') . 'sessions` WHERE session_id = :session_id', array(':session_id' => $id)); - - // Read session data and store it into $_SESSION array - if (isset($result[0]['session_data'])) { - - $dataPairs = explode('|', $result[0]['session_data']); - - // Prepare array of session variables in the following format: - // [var_name_1] => serialized data - // [var_name_2] => serialized data - // etc. - $previousData = ''; - $previousName = ''; - $dataPairsNew = array(); - foreach ($dataPairs as $key => $val) { - if (!empty($previousData)) { - - $previousDataRev = strrev($previousData); - $po1 = strpos($previousDataRev, ';'); - $po2 = strpos($previousDataRev, '}'); - - if ((!empty($po1) && empty($po2)) || (!empty($po1) && !empty($po2) && $po1 < $po2)) { - $divider = ';'; - } else { - $divider = '}'; - } - - $previousDataParts = explode($divider, $previousData); - $previousDataCount = count($previousDataParts); - $paramName = isset($previousDataParts[$previousDataCount - 1]) ? $previousDataParts[$previousDataCount - 1] : ''; - unset($previousDataParts[$previousDataCount - 1]); - $paramValue = implode($divider, $previousDataParts); - - $dataPairsNew[$previousName] = $paramValue; - if ($paramValue[0] == 'a') { - $dataPairsNew[$previousName] .= '}'; - } - } else { - $paramName = $val; - } - $previousName = $paramName; - $previousData = $val; - } - - $dataPairsNew[$previousName] = $dataPairs[count($dataPairs) - 1]; - - // Store session variables in global array $_SESSION - foreach ($dataPairsNew as $key => $val) { - if (!empty($key)) { - $_SESSION[$key] = unserialize($val); - } - } - } - - return true; - } - - /** - * Session write handler - * Do not call this method directly - * @param string $id - * @param string $data - * @return boolean - */ - public function writeSession($id, $data) - { - $result = $this->_db->select('SELECT * from `' . CConfig::get('db.prefix') . 'sessions` WHERE session_id = :session_id', array(':session_id' => $id)); - if (isset($result[0])) { - $result = $this->_db->update( - 'sessions', - array( - 'expires_at' => time() + $this->getTimeout(), - 'session_data' => $data, - ), - 'session_id = :session_id', - array(':session_id' => $id) - ); - } else { - $result = $this->_db->insert( - 'sessions', - array( - 'session_id' => $id, - 'expires_at' => time() + $this->getTimeout(), - 'session_data' => $data, - ) - ); - } - - return true; - } - - /** - * Session destroy handler - * Do not call this method directly - * @param string $id - * @return boolean - */ - public function destroySession($id) - { - return $this->_db->delete('sessions', "session_id = :session_id", array(':session_id' => $id)); - } - - /** - * Session garbage collection handler - * Do not call this method directly - * @param int $maxLifetime - * @return boolean - */ - public function gcSession($maxLifetime) - { - return $this->_deleteExpiredSessions(); - } - - /** - * Sets the number of seconds after which data will be seen as 'garbage' and cleaned up - * @param int $value - */ - public function setTimeout($value) - { - ini_set('session.gc_maxlifetime', (int)$value); - } - - /** - * Returns the number of seconds after which data will be seen as 'garbage' and cleaned up - * @return integer - */ - public function getTimeout() - { - // Get lifetime value from configuration file (in minutes) - $maxlifetime = CConfig::get('session.lifetime'); - return (!empty($maxlifetime)) ? (int)($maxlifetime * 60) : (int)ini_get('session.gc_maxlifetime'); - } - - /** - * Starts the session if it has not started yet - */ - private function _startSession() - { - // Set lifetime value from configuration file (in minutes) - $maxLifetime = CConfig::get('session.lifetime'); - if (!empty($maxLifetime) && $maxLifetime != ini_get('session.gc_maxlifetime')) { - $this->setTimeout($maxLifetime); - } - - @session_start(); - if (APPHP_MODE == 'debug' && session_id() == '') { - CDebug::addMessage('errors', 'session', A::t('core', 'Failed to start session')); - } - } - - /** - * Deletes expired sessions - * @return bool - */ - private function _deleteExpiredSessions() - { - return $this->_db->delete('sessions', 'expires_at < :expires_at', array(':expires_at' => time())); - } - + + /** @var boolean */ + protected $_autoStart = true; + /** @var string */ + protected $_defaultSessionName = 'apphp_framework'; + /** @var string */ + protected $_defaultSessionPrefix = 'apphp_'; + /** + * @var int + * @deprecated since v0.1.0 + * 0 - use name prefix, 1 - use session name (default) + */ + protected $_multiSiteSupportType = 1; + /** + * @var mixed + */ + protected $_prefix = ''; + + /** @var Database */ + private $_db; + + + /** + * Class default constructor + */ + function __construct() + { + $this->_db = CDatabase::init(); + + @session_set_save_handler( + [$this, 'openSession'], + [$this, 'closeSession'], + [$this, 'readSession'], + [$this, 'writeSession'], + [$this, 'destroySession'], + [$this, 'gcSession'] + ); + + // The following prevents unexpected effects when using objects as save handlers + register_shutdown_function('session_write_close'); + + if ($this->_multiSiteSupportType) { + $this->setSessionName('apphp_'.CConfig::get('installationKey')); + } else { + $this->setSessionPrefix('apphp_'.CConfig::get('installationKey')); + } + + if ($this->_autoStart) { + $this->_startSession(); + } + } + + /** + * Returns the instance of object + * + * @return current class + */ + public static function init() + { + return parent::init(__CLASS__); + } + + /** + * Sets session variable + * + * @param string $name + * @param mixed $value + */ + public function set($name, $value) + { + $_SESSION[$name] = $value; + } + + /** + * Returns session variable + * + * @param string $name + * @param mixed $default + */ + public function get($name, $default = '') + { + return isset($_SESSION[$name]) ? $_SESSION[$name] : $default; + } + + /** + * Removes session variable + * + * @param string $name + */ + public function remove($name) + { + if (isset($_SESSION[$name])) { + unset($_SESSION[$name]); + + return true; + } + + return false; + } + + /** + * Removes all session variable + * + * @return void + */ + public function removeAll() + { + @session_unset(); + if (is_array($_SESSION)) { + foreach ($_SESSION as $key => $val) { + unset($_SESSION[$key]); + } + } + } + + /** + * Checks if session variable exists + * + * @param string $name + */ + public function isExists($name) + { + return isset($_SESSION[$name]) ? true : false; + } + + /** + * Sets session flash data + * + * @param string $name + * @param mixed $value + */ + public function setFlash($name, $value) + { + $_SESSION[$this->_prefix.'_flash'][$name] = $value; + } + + /** + * Returns session flash data + * + * @param string $name + * @param mixed $default + */ + public function getFlash($name, $default = '') + { + if (isset($_SESSION[$this->_prefix.'_flash'][$name])) { + $result = $_SESSION[$this->_prefix.'_flash'][$name]; + unset($_SESSION[$this->_prefix.'_flash'][$name]); + } else { + $result = $default; + } + + return $result; + } + + /** + * Checks if has flash data + * + * @param string $name + * + * @return bool + */ + public function hasFlash($name) + { + return isset($_SESSION[$this->_prefix.'_flash'][$name]) ? true : false; + } + + /** + * Sets session name + * + * @param string $value + */ + public function setSessionName($value) + { + if (empty($value)) { + $value = $this->_defaultSessionName; + } + session_name($value); + } + + /** + * Sets session name + * + * @param string $value + */ + public function setSessionPrefix($value) + { + if (empty($value)) { + $value = $this->_defaultSessionPrefix; + } + $this->_prefix = $value; + } + + /** + * Gets session name + * + * @return string + */ + public function getSessionName() + { + return session_name(); + } + + /** + * Destroys the session + */ + public function endSession() + { + if (session_id() !== '') { + @session_unset(); + @session_destroy(); + } + } + + /** + * Gets cookie mode + * + * @return string + */ + public function getCookieMode() + { + if (ini_get('session.use_cookies') === '0') { + return 'none'; + } elseif (ini_get('session.use_only_cookies') === '0') { + return 'allow'; + } else { + return 'only'; + } + } + + /** + * Session open handler + * Do not call this method directly + * + * @param string $savePath + * @param string $sessionName + * + * @return boolean + */ + public function openSession($savePath, $sessionName) + { + $this->_deleteExpiredSessions(); + + return true; + } + + /** + * Session close handler + * Do not call this method directly + * + * @return boolean + */ + public function closeSession() + { + if (session_id() !== '') { + @session_write_close(); + } + + return true; + } + + /** + * Session read handler + * Do not call this method directly + * + * @param string $id + * + * @return bool + */ + public function readSession($id) + { + $result = $this->_db->select( + 'SELECT session_data FROM `'.CConfig::get('db.prefix').'sessions` WHERE session_id = :session_id', + [':session_id' => $id] + ); + + // Read session data and store it into $_SESSION array + if (isset($result[0]['session_data'])) { + $dataPairs = explode('|', $result[0]['session_data']); + + // Prepare array of session variables in the following format: + // [var_name_1] => serialized data + // [var_name_2] => serialized data + // etc. + $previousData = ''; + $previousName = ''; + $dataPairsNew = []; + foreach ($dataPairs as $key => $val) { + if ( ! empty($previousData)) { + $previousDataRev = strrev($previousData); + $po1 = strpos($previousDataRev, ';'); + $po2 = strpos($previousDataRev, '}'); + + if (( ! empty($po1) && empty($po2)) || ( ! empty($po1) && ! empty($po2) && $po1 < $po2)) { + $divider = ';'; + } else { + $divider = '}'; + } + + $previousDataParts = explode($divider, $previousData); + $previousDataCount = count($previousDataParts); + $paramName = isset($previousDataParts[$previousDataCount - 1]) + ? $previousDataParts[$previousDataCount - 1] : ''; + unset($previousDataParts[$previousDataCount - 1]); + $paramValue = implode($divider, $previousDataParts); + + $dataPairsNew[$previousName] = $paramValue; + if ($paramValue[0] == 'a') { + $dataPairsNew[$previousName] .= '}'; + } + } else { + $paramName = $val; + } + $previousName = $paramName; + $previousData = $val; + } + + $dataPairsNew[$previousName] = $dataPairs[count($dataPairs) - 1]; + + // Store session variables in global array $_SESSION + foreach ($dataPairsNew as $key => $val) { + if ( ! empty($key)) { + $_SESSION[$key] = unserialize($val); + } + } + } + + return true; + } + + /** + * Session write handler + * Do not call this method directly + * + * @param string $id + * @param string $data + * + * @return boolean + */ + public function writeSession($id, $data) + { + $result = $this->_db->select( + 'SELECT * from `'.CConfig::get('db.prefix').'sessions` WHERE session_id = :session_id', + [':session_id' => $id] + ); + if (isset($result[0])) { + $result = $this->_db->update( + 'sessions', + [ + 'expires_at' => time() + $this->getTimeout(), + 'session_data' => $data, + ], + 'session_id = :session_id', + [':session_id' => $id] + ); + } else { + $result = $this->_db->insert( + 'sessions', + [ + 'session_id' => $id, + 'expires_at' => time() + $this->getTimeout(), + 'session_data' => $data, + ] + ); + } + + return true; + } + + /** + * Session destroy handler + * Do not call this method directly + * + * @param string $id + * + * @return boolean + */ + public function destroySession($id) + { + return $this->_db->delete('sessions', "session_id = :session_id", [':session_id' => $id]); + } + + /** + * Session garbage collection handler + * Do not call this method directly + * + * @param int $maxLifetime + * + * @return boolean + */ + public function gcSession($maxLifetime) + { + return $this->_deleteExpiredSessions(); + } + + /** + * Sets the number of seconds after which data will be seen as 'garbage' and cleaned up + * + * @param int $value + */ + public function setTimeout($value) + { + ini_set('session.gc_maxlifetime', (int)$value); + } + + /** + * Returns the number of seconds after which data will be seen as 'garbage' and cleaned up + * + * @return integer + */ + public function getTimeout() + { + // Get lifetime value from configuration file (in minutes) + $maxlifetime = CConfig::get('session.lifetime'); + + return ( ! empty($maxlifetime)) ? (int)($maxlifetime * 60) : (int)ini_get('session.gc_maxlifetime'); + } + + /** + * Starts the session if it has not started yet + */ + private function _startSession() + { + // Set lifetime value from configuration file (in minutes) + $maxLifetime = CConfig::get('session.lifetime'); + if ( ! empty($maxLifetime) && $maxLifetime != ini_get('session.gc_maxlifetime')) { + $this->setTimeout($maxLifetime); + } + + @session_start(); + if (APPHP_MODE == 'debug' && session_id() == '') { + CDebug::addMessage('errors', 'session', A::t('core', 'Failed to start session')); + } + } + + /** + * Deletes expired sessions + * + * @return bool + */ + private function _deleteExpiredSessions() + { + return $this->_db->delete('sessions', 'expires_at < :expires_at', [':expires_at' => time()]); + } + } diff --git a/framework/components/CHttpCookie.php b/framework/components/CHttpCookie.php index 1f4370f..60eb8d7 100644 --- a/framework/components/CHttpCookie.php +++ b/framework/components/CHttpCookie.php @@ -26,138 +26,159 @@ class CHttpCookie extends CComponent { - /** @var integer - timestamp at which the cookie expires. Default 0 means "until the browser is closed" */ - public $expire = 0; - /** @var boolean */ - public $secure = false; - /** @var boolean - defines whether the cookie should be accessible only through the HTTP protocol or not */ - public $httpOnly = true; - - /** @var string - the domain that the cookie is available to */ - private $_domain = ''; - /** @var string - path on the server where the cookie will be available on. The default is '/' */ - private $_path = '/'; - - /** - * Class default constructor - */ - function __construct() - { - if (CConfig::get('cookies.domain') != '') $this->setDomain(CConfig::get('cookies.domain')); - if (CConfig::get('cookies.path') != '') $this->setPath(CConfig::get('cookies.path')); - } - - /** - * Returns the instance of object - * @return current class - */ - public static function init() - { - return parent::init(__CLASS__); - } - - /** - * Sets cookie domain - * @param string $domain - */ - public function setDomain($domain = '') - { - $this->_domain = $domain; - } - - /** - * Sets cookie path - * @param string $path - */ - public function setPath($path = '') - { - $this->_path = $path; - } - - /** - * Sets cookie - * @param string $name - * @param mixed $value - * @param mixed $expire - * @param mixed $path - * @param mixed $domain - */ - public function set($name, $value = '', $expire = '', $path = '', $domain = '') - { - $expire = (!empty($expire)) ? $expire : $this->expire; - $path = (!empty($path)) ? $path : $this->_path; - $domain = (!empty($domain)) ? $domain : $this->_domain; - - setcookie($name, $value, $expire, $path, $domain, $this->secure, $this->httpOnly); - } - - /** - * Returns cookie value - * @param string $name - * @return mixed - */ - public function get($name) - { - return isset($_COOKIE[$name]) ? $_COOKIE[$name] : ''; - } - - /** - * Checks if cookie variable exists - * @param string $name - * @return bool - */ - public function isExists($name) - { - return isset($_COOKIE[$name]) ? true : false; - } - - /** - * Deletes cookie - * @param string $name - * @return void - */ - public function remove($name) - { - if (isset($_COOKIE[$name]) ){ - unset($_COOKIE[$name]); - }; - setcookie($name, '', time() - 3600, $this->_path, $this->_domain, $this->secure, $this->httpOnly); - } - - /** - * Delete cookie - * @param string $name - * @return void|string - */ - public function clear($name) - { - if (!isset($_COOKIE)) return ''; - - if (isset($_COOKIE[$name])) { - $this->remove($name); - } - } - - /** - * Deletes all cookie - * @return void|string - */ - public function clearAll() - { - if (!isset($_COOKIE)) return ''; - - foreach ($_COOKIE as $key => $value) { - $this->remove($key); - } - } - - /** - * Get all cookies - */ - public function getAll() - { - return isset($_COOKIE) ? $_COOKIE : array(); - } - - + /** @var integer - timestamp at which the cookie expires. Default 0 means "until the browser is closed" */ + public $expire = 0; + /** @var boolean */ + public $secure = false; + /** @var boolean - defines whether the cookie should be accessible only through the HTTP protocol or not */ + public $httpOnly = true; + + /** @var string - the domain that the cookie is available to */ + private $_domain = ''; + /** @var string - path on the server where the cookie will be available on. The default is '/' */ + private $_path = '/'; + + /** + * Class default constructor + */ + function __construct() + { + if (CConfig::get('cookies.domain') != '') { + $this->setDomain(CConfig::get('cookies.domain')); + } + if (CConfig::get('cookies.path') != '') { + $this->setPath(CConfig::get('cookies.path')); + } + } + + /** + * Returns the instance of object + * + * @return current class + */ + public static function init() + { + return parent::init(__CLASS__); + } + + /** + * Sets cookie domain + * + * @param string $domain + */ + public function setDomain($domain = '') + { + $this->_domain = $domain; + } + + /** + * Sets cookie path + * + * @param string $path + */ + public function setPath($path = '') + { + $this->_path = $path; + } + + /** + * Sets cookie + * + * @param string $name + * @param mixed $value + * @param mixed $expire + * @param mixed $path + * @param mixed $domain + */ + public function set($name, $value = '', $expire = '', $path = '', $domain = '') + { + $expire = ( ! empty($expire)) ? $expire : $this->expire; + $path = ( ! empty($path)) ? $path : $this->_path; + $domain = ( ! empty($domain)) ? $domain : $this->_domain; + + setcookie($name, $value, $expire, $path, $domain, $this->secure, $this->httpOnly); + } + + /** + * Returns cookie value + * + * @param string $name + * + * @return mixed + */ + public function get($name) + { + return isset($_COOKIE[$name]) ? $_COOKIE[$name] : ''; + } + + /** + * Checks if cookie variable exists + * + * @param string $name + * + * @return bool + */ + public function isExists($name) + { + return isset($_COOKIE[$name]) ? true : false; + } + + /** + * Deletes cookie + * + * @param string $name + * + * @return void + */ + public function remove($name) + { + if (isset($_COOKIE[$name])) { + unset($_COOKIE[$name]); + }; + setcookie($name, '', time() - 3600, $this->_path, $this->_domain, $this->secure, $this->httpOnly); + } + + /** + * Delete cookie + * + * @param string $name + * + * @return void|string + */ + public function clear($name) + { + if ( ! isset($_COOKIE)) { + return ''; + } + + if (isset($_COOKIE[$name])) { + $this->remove($name); + } + } + + /** + * Deletes all cookie + * + * @return void|string + */ + public function clearAll() + { + if ( ! isset($_COOKIE)) { + return ''; + } + + foreach ($_COOKIE as $key => $value) { + $this->remove($key); + } + } + + /** + * Get all cookies + */ + public function getAll() + { + return isset($_COOKIE) ? $_COOKIE : []; + } + + } \ No newline at end of file diff --git a/framework/components/CHttpRequest.php b/framework/components/CHttpRequest.php index 4224a7b..fa09c27 100644 --- a/framework/components/CHttpRequest.php +++ b/framework/components/CHttpRequest.php @@ -60,951 +60,1066 @@ class CHttpRequest extends CComponent { - - /** @var string */ - private $_baseUrl; - /** @var string */ - private $_hostInfo; - /** @var string */ - private $_hostName; - /** @var string */ - private $_basePath = '/'; - /** @var boolean to enable cookies validation to be sure they are not tampered (defaults - false) */ - public $cookieValidation = false; - /** @var boolean whether to enable CSRF (Cross-Site Request Forgery) validation (defaults - false) */ - private $_csrfValidation = false; - /** @var string excluding controllers */ - private $_csrfExclude = array(); - /** @var boolean to enable gzip output compression */ - private $_gzipCompression = false; - /** @var string */ - private $_csrfTokenKey = 'APPHP_CSRF_TOKEN'; - /** @var string */ - private $_csrfTokenValue = null; - /** @var string session, cookie, multipages or multiforms */ - private $_csrfTokenType = 'session'; - /** @var int */ - private $_csrfMaxTokenedPages = 20; - /** @var int port number */ - private $_port = null; - /** @var int secure port number */ - private $_securePort = null; - /** @var boolean - * whether to enable referrer storage in session - has potential risk - * requires special handling to prevent endless loops on redirection on the same page - */ - private $_referrerInSession = false; - - - /** - * Class default constructor - */ - function __construct() - { - $this->_csrfValidation = (CConfig::get('validation.csrf.enable') === true) ? true : false; - $this->_csrfExclude = CConfig::exists('validation.csrf.exclude') ? CConfig::get('validation.csrf.exclude') : array(); - $this->_gzipCompression = (CConfig::get('compression.gzip.enable') === true) ? true : false; - $csrfTokenType = CConfig::get('validation.csrf.tokenType'); - $this->_csrfTokenType = ($csrfTokenType !== '' && in_array($csrfTokenType, array('session', 'cookie', 'multipages', 'multiforms'))) ? $csrfTokenType : 'session'; - - $this->_cleanRequest(); - $this->_baseUrl = $this->setBaseUrl(); - } - - /** - * Triggered when invoking inaccessible methods in an object context - * @param string $method - * @param array $args - * @return mixed - */ - public function __call($method, $args) - { - switch (strtolower($method)) { - - case 'get': - case 'post': - case 'request': - - if ($method == 'get') { - $innerGet = 'getQuery'; - $innerSet = 'setQuery'; - } elseif ($method == 'post') { - $innerGet = 'getPost'; - $innerSet = 'setPost'; - } else { - $innerGet = 'getRequest'; - $innerSet = 'getRequest'; - } - - if (count($args) == 0) { - return $this->_getAll($method); - } elseif (count($args) == 1) { - return $this->$innerGet($args[0]); - } elseif (count($args) == 2) { - return $this->$innerSet($args[0], $args[1]); - } elseif (count($args) == 3) { - return $this->$innerGet($args[0], $args[1], $args[2]); - } elseif (count($args) == 4) { - return $this->$innerGet($args[0], $args[1], $args[2], $args[3]); - } - - break; - - case 'getAll': - return $this->_getAll('get'); - - case 'postAll': - return $this->_getAll('post'); - - case 'postWith': - if (count($args) == 1) { - return $this->getPostWith($args[0]); - } - break; - } - } - - /** - * Returns the instance of object - * @return current class - */ - public static function init() - { - return parent::init(__CLASS__); - } - - /** - * Strips slashes from data - * @param mixed $data input data to be processed - * @return mixed processed data - */ - public function stripSlashes(&$data) - { - return is_array($data) ? array_map(array($this, 'stripSlashes'), $data) : stripslashes($data); - } - - /** - * Gets base URL - * @return string - */ - public function getBaseUrl() - { - return $this->_baseUrl; - } - - /** - * Gets Request URI - * @return string - */ - public function getRequestUri() - { - return isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; - } - - /** - * Gets Server Name - * @return string - */ - public function getServerName() - { - return isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : ''; - } - - /** - * Gets IP address of visitor - * @return string - */ - public function getUserHostAddress() - { - return isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1'; - } - - /** - * Returns the schema and host part of the current request URL - * The returned URL does not have an ending slash - * By default this is determined based on the user request information. - * You may explicitly specify it by setting the setHostInfo()[hostInfo]] property. - * @return string|null - */ - public function getHostInfo() - { - if ($this->_hostInfo === null) { - $secure = $this->isSecureConnection(); - $http = $secure ? 'https' : 'http'; - if (isset($_SERVER['HTTP_HOST'])) { - $this->_hostInfo = $http . '://' . $_SERVER['HTTP_HOST']; - } elseif (isset($_SERVER['SERVER_NAME'])) { - $this->_hostInfo = $http . '://' . $_SERVER['SERVER_NAME']; - $port = $secure ? $this->getSecurePort() : $this->getPort(); - if (($port !== 80 && !$secure) || ($port !== 443 && $secure)) { - $this->_hostInfo .= ':' . $port; - } - } - } - - return $this->_hostInfo; - } - - /** - * Returns the host part of the current request URL (ex.: apphp.com) - * Value is calculated from current getHostInfo()[hostInfo] property - * @return string|null - * @see getHostInfo() - * @since 0.9.0 - */ - public function getHostName() - { - if ($this->_hostName === null) { - $this->_hostName = parse_url($this->getHostInfo(), PHP_URL_HOST); - } - - return $this->_hostName; - } - - /** - * Gets a string denoting the user agent being which is accessing the page. - * A typical example is: Mozilla/4.5 [en] (X11; U; Linux 2.2.9 i586). - * @return string - */ - public function getUserAgent() - { - return isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : ''; - } - - /** - * Gets base path - * @return string - */ - public function getBasePath() - { - return $this->_basePath; - } - - /** - * Sets base URL - * @param boolean $useAbsolutePath - * @return string - */ - public function setBaseUrl($useAbsolutePath = true) - { - $absolutePart = ($useAbsolutePath) ? $this->_getProtocolAndHost() : ''; - - $scriptName = basename($_SERVER['SCRIPT_FILENAME']); - if (basename($_SERVER['SCRIPT_NAME']) === $scriptName) { - $scriptUrl = $_SERVER['SCRIPT_NAME']; - } elseif (basename($_SERVER['PHP_SELF']) === $scriptName) { - $scriptUrl = $_SERVER['PHP_SELF']; - } elseif (isset($_SERVER['ORIG_SCRIPT_NAME']) && basename($_SERVER['ORIG_SCRIPT_NAME']) === $scriptName) { - $scriptUrl = $_SERVER['ORIG_SCRIPT_NAME']; - } elseif (($pos = strpos($_SERVER['PHP_SELF'], '/' . $scriptName)) !== false) { - $scriptUrl = substr($_SERVER['SCRIPT_NAME'], 0, $pos) . '/' . $scriptName; - } elseif (isset($_SERVER['DOCUMENT_ROOT']) && strpos($_SERVER['SCRIPT_FILENAME'], $_SERVER['DOCUMENT_ROOT']) === 0) { - $scriptUrl = str_replace('\\', '/', str_replace($_SERVER['DOCUMENT_ROOT'], '', $_SERVER['SCRIPT_FILENAME'])); - } else { - CDebug::addMessage('error', 'entry_script', A::t('core', 'Framework is unable to determine the entry script URL')); - } - - $this->_basePath = rtrim(dirname($scriptUrl), '\\/') . '/'; - - return $absolutePart . $this->_basePath; - } - - /** - * Returns parameter from global array $_GET - * @param string $name - * @param string|array $filters - * @param string $default - * @param array $allowedValues - * @see CFilter - * @return mixed - */ - public function getQuery($name = '', $filters = '', $default = '', $allowedValues = array()) - { - if (empty($name)) { - return $this->_getAll('get'); - } else { - return $this->_getParam('get', $name, $default, $filters, $allowedValues); - } - } - - /** - * Sets value to global array $_GET - * @param string $name - * @param string $value - * @return bool - */ - public function setQuery($name, $value = '') - { - if (isset($_GET)) { - $_GET[$name] = $value; - return true; - } - - return false; - } - - /** - * Returns parameter from global array $_POST - * @param string $name - * @param string|array $filters - * @param string $default - * @param array $allowedValues - * @see CFilter - * @return mixed - */ - public function getPost($name = '', $filters = '', $default = '', $allowedValues = array()) - { - if (empty($name)) { - return $this->_getAll('post'); - } else { - return $this->_getParam('post', $name, $default, $filters, $allowedValues); - } - } - - /** - * Returns variables from global array $_POST with certain parameter - * @param string $name - * @param string|array $filters - * @param string $default - * @param array $allowedValues - * @return array - */ - public function getPostWith($name, $filters = '', $default = '', $allowedValues = array()) - { - $result = array(); - if (!isset($_POST) || !is_array($_POST)) return $result; - - foreach ($_POST as $key => $val) { - if (preg_match('/' . $name . '/i', $key)) { - $result[$key] = $this->_getParam('post', $key, $default, $filters, $allowedValues); - } - } - - return $result; - } - - /** - * Sets value to global array $_POST - * @param string $name - * @param string $value - * @return bool - */ - public function setPost($name, $value = '') - { - if (isset($_POST)) { - $_POST[$name] = $value; - return true; - } - - return false; - } - - /** - * Returns parameter from global array $_GET or $_POST - * @param string $name - * @param string|array $filters - * @param string $default - * @param array $allowedValues - * @return mixed - */ - public function getRequest($name = '', $filters = '', $default = '', $allowedValues = array()) - { - if (empty($name)) { - return $this->_getAll('request'); - } else { - return $this->_getParam('request', $name, $default, $filters, $allowedValues); - } - } - - /** - * Returns whether there is an AJAX (XMLHttpRequest) request - * @return boolean - * @since 0.6.0 - */ - public function isAjaxRequest() - { - return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest'; - } - - /** - * Returns whether there is a PUT request - * @return boolean - * @since 0.6.0 - */ - public function isPutRequest() - { - return isset($_SERVER['REQUEST_METHOD']) && !strcasecmp($_SERVER['REQUEST_METHOD'], 'PUT'); - } - - /** - * Returns whether there is a DELETE request - * @return boolean - * @since 0.6.0 - */ - public function isDeleteRequest() - { - return isset($_SERVER['REQUEST_METHOD']) && !strcasecmp($_SERVER['REQUEST_METHOD'], 'DELETE'); - } - - /** - * Returns whether there is a POST request - * @return boolean - */ - public function isPostRequest() - { - return isset($_SERVER['REQUEST_METHOD']) && !strcasecmp($_SERVER['REQUEST_METHOD'], 'POST'); - } - - /** - * Returns whether there is a POST variable exists - * @param string $name - * @return boolean - */ - public function isPostExists($name) - { - return isset($_POST[$name]); - } - - /** - * Return if the request is sent via secure channel (https) - * @return boolean - */ - public function isSecureConnection() - { - return (isset($_SERVER['HTTPS']) && (strcasecmp($_SERVER['HTTPS'], 'on') === 0 || $_SERVER['HTTPS'] == 1)) - || - (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strcasecmp($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') === 0); - } - - /** - * Returns if csrf validation is used - * @return string - */ - public function getCsrfValidation() - { - if (!empty($this->_csrfExclude) && is_array($this->_csrfExclude)) { - // Retrirve current controller - // TODO: this is a simplest code, we need to improve it and use URL rules - $request = isset($_GET['url']) ? $_GET['url'] : ''; - $split = explode('/', trim($request, '/')); - $controller = !empty($split[0]) ? $split[0] : CConfig::get('defaultController'); - - if (in_array(strtolower($controller), array_map('strtolower', $this->_csrfExclude))) { - return false; - } - } - - return $this->_csrfValidation; - } - - /** - * Returns CSRF token key name - * @return string - */ - public function getCsrfTokenKey() - { - return $this->_csrfTokenKey; - } - - /** - * Returns the random token value used to perform CSRF validation - * @param string $formId - * @return string - * @see $this->_csrfValidation() - */ - public function getCsrfTokenValue($formId = '') - { - // Check and set token - $csrfTokenValue = md5(uniqid(rand(), true)); - - if ($this->_csrfTokenType == 'session') { - if ($this->_csrfTokenValue === null) { - $this->_csrfTokenValue = $csrfTokenValue; - A::app()->getSession()->set('token', $this->_csrfTokenValue); - } - } elseif ($this->_csrfTokenType == 'cookie') { - if ($this->_csrfTokenValue === null) { - $this->_csrfTokenValue = $csrfTokenValue; - A::app()->getCookie()->set('token', $this->_csrfTokenValue); - } - } elseif ($this->_csrfTokenType == 'multipages' || $this->_csrfTokenType == 'multiforms') { - if ($this->_csrfTokenType == 'multipages') { - // Get page ID - $tokenId = $this->_getControllerAndAction(); - } else { - $tokenId = $formId; - } - if (CString::length($tokenId) < 100 && CValidator::isVariable($tokenId)) { - if ($this->_csrfTokenValue === null) { - $this->_csrfTokenValue = $csrfTokenValue; - } - // Get array and validate - $csrfTokenValues = A::app()->getSession()->get('token'); - if (empty($csrfTokenValues) || !is_array($csrfTokenValues)) { - $csrfTokenValues = array(); - } - // Save data - $csrfTokenValues[$tokenId] = ($this->_csrfTokenValue !== null) ? $this->_csrfTokenValue : $csrfTokenValue; - if (count($csrfTokenValues) > $this->_csrfMaxTokenedPages) { - array_shift($csrfTokenValues); - } - A::app()->getSession()->set('token', $csrfTokenValues); - } - } - - return $this->_csrfTokenValue; - } - - /** - * Performs the CSRF validation - * @param string $formId - * @return void - */ - public function validateCsrfToken($formId = '') - { - // Validate only POST requests - if ($this->isPostRequest()) { - - $valid = false; - $tokenFromPost = isset($_POST[$this->_csrfTokenKey]) ? $_POST[$this->_csrfTokenKey] : null; - - if ($this->_csrfTokenType == 'session') { - if (A::app()->getSession()->isExists('token') && isset($_POST[$this->_csrfTokenKey])) { - $tokenFromSession = A::app()->getSession()->get('token'); - $valid = ($tokenFromSession === $tokenFromPost); - } - } elseif ($this->_csrfTokenType == 'cookie') { - if (A::app()->getCookie()->isExists('token') && isset($_POST[$this->_csrfTokenKey])) { - $tokenFromCookie = A::app()->getCookie()->get('token'); - $valid = ($tokenFromCookie === $tokenFromPost); - } - } elseif ($this->_csrfTokenType == 'multipages' || $this->_csrfTokenType == 'multiforms') { - if ($this->_csrfTokenType == 'multipages') { - // Get page ID - $tokenId = $this->_getControllerAndAction(); - } else { - $tokenId = $formId; - } - if (A::app()->getSession()->isExists('token') && isset($_POST[$this->_csrfTokenKey])) { - $tokenFromSession = A::app()->getSession()->get('token'); - $tokenFromSession = isset($tokenFromSession[$tokenId]) ? $tokenFromSession[$tokenId] : ''; - $valid = ($tokenFromSession === $tokenFromPost); - } - } - - if (!$valid) { - unset($_POST); - A::app()->getSession()->setFlash( - 'csrfError', - CWidget::create('CMessage', array('warning', A::t('core', 'The CSRF token has expired or invalid. Please try to refresh page and resubmit the form.'))) - ); - CDebug::addMessage('warnings', 'csrf_token', A::t('core', 'The CSRF token could not be verified.'), 'session'); - A::app()->getClientScript()->registerScript( - 'csrfError', - 'function csrf_refresh_page(){location.href = location.href + \'?\' + Math.random();}', - 2 - ); - } - } - } - - /** - * Set GZIP compression handler - */ - public function setGzipHandler() - { - if (isset($_SERVER['HTTP_ACCEPT_ENCODING']) && substr_count($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')) { - // Fix for warning: ob_start() [ref.outcontrol]: output handler 'ob_gzhandler' conflicts with zlib output compression' - if (extension_loaded('zlib')) { - if (ob_get_length()) { - ob_end_clean(); - } - } - ob_start('ob_gzhandler'); - } else { - ob_start(); - } - } - - /** - * Cleans the request data - * This method removes slashes from request data if get_magic_quotes_gpc() is turned on - * Also performs CSRF validation if {@link _csrfValidation} is true - */ - protected function _cleanRequest() - { - // 01.12.2018 - DEPRECATED - // Clean request only for PHP < 5.3, in greater versions of PHP 'magic' functions are deprecated - //if(version_compare(phpversion(), '5.3.0', '<')){ - // if(function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()){ - // $_GET = $this->stripSlashes($_GET); - // $_POST = $this->stripSlashes($_POST); - // $_REQUEST = $this->stripSlashes($_REQUEST); - // $_COOKIE = $this->stripSlashes($_COOKIE); - // } - //} - - if ($this->getCsrfValidation()) A::app()->attachEventHandler('_onBeginRequest', array($this, 'validateCsrfToken')); - if ($this->_gzipCompression) A::app()->attachEventHandler('_onBeginRequest', array($this, 'setGzipHandler')); - if ($this->_referrerInSession) A::app()->attachEventHandler('_onBeginRequest', array($this, 'setHttpReferrer')); - } - - /** - * Returns protocol and host - * @param bool $usePort - * @return string - */ - protected function _getProtocolAndHost($usePort = true) - { - $protocol = 'http://'; - $port = ''; - $httpHost = isset($_SERVER['HTTP_HOST']) ? htmlentities($_SERVER['HTTP_HOST']) : ''; - $serverProtocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : ''; - - if ((isset($_SERVER['HTTPS']) && (strtolower($_SERVER['HTTPS']) != 'off')) || strtolower(substr($serverProtocol, 0, 5)) == 'https') { - $protocol = 'https://'; - } - - if ($usePort) { - $portNumber = $this->getPort(); - if ($portNumber != '80' && !strpos($httpHost, ':')) { - $port = ':' . $portNumber; - } - } - - return $protocol . $httpHost . $port; - } - - /** - * Returns controller and action from URL - * @return string - */ - protected function _getControllerAndAction() - { - $request = isset($_GET['url']) ? $_GET['url'] : ''; - $split = explode('/', trim($request, '/')); - $pageId = isset($split[0]) ? $split[0] : ''; - $pageId .= isset($split[1]) ? '_' . $split[1] : ''; - - return $pageId; - } - - /** - * Returns parameter from global arrays $_GET or $_POST according to the type of request - * @param string $type - * @param string $name - * @param string|array $filters - * @param array $allowedValues - * @param string $default - * @return mixed - */ - private function _getParam($type = 'get', $name = '', $default = '', $filters = '', $allowedValues = array()) - { - $value = null; - - if ($type == 'get') { - if (isset($_GET[$name])) { - $value = $_GET[$name]; - } else { - // Check for variant - // URL: http://localhost/site/page/contact/param1/aaa/param2/bbb/param3/ccc - $request = isset($_GET['url']) ? $_GET['url'] : ''; - $split = explode('/', trim($request, '/')); - - $temp = array(); - foreach ($split as $index => $part) { - if (!$temp || end($temp) !== null) { - $temp[$part] = null; - } else { - $arrayArg = array_keys($temp); - $tempEnd = end($arrayArg); - $temp[$tempEnd] = $part; - } - } - $temp = array_slice($temp, 1); - if (isset($temp[$name])) $value = $temp[$name]; - } - } elseif ($type == 'post' && isset($_POST[$name])) { - $value = $_POST[$name]; - } elseif ($type == 'request' && (isset($_GET[$name]) || isset($_POST[$name]))) { - $value = isset($_GET[$name]) ? $_GET[$name] : $_POST[$name]; - } - - if ($value !== null) { - // Validate allowed values - if (!empty($allowedValues)) { - if (!is_array($allowedValues)) $allowedValues = array($allowedValues); - if (!in_array($value, $allowedValues)) { - $value = $default; - } - } - - // Filter values - if (!empty($filters)) { - if (!is_array($filters)) $filters = array($filters); - foreach ($filters as $filter) { - $value = CFilter::sanitize($filter, $value); - } - } - } else { - $value = $default; - } - - return $value; - } - - /** - * Returns global arrays: $_GET, $_POST or $_REQUEST according to given type - * @param string $type - * @return array - */ - private function _getAll($type = 'get') - { - if ($type == 'get') { - return isset($_GET) ? $_GET : array(); - } elseif ($type == 'post') { - return isset($_POST) ? $_POST : array(); - } elseif ($type == 'request' && (isset($_GET) || isset($_POST))) { - return isset($_GET) ? $_GET : $_POST; - } - - return array(); - } - - /** - * Downloads a content as file from browser to user - * @param string $fileName - * @param string $content - * @param string $mimeType - * @param boolean $terminate - */ - public function downloadContent($fileName, $content, $mimeType = null, $terminate = true) - { - if ($mimeType === null) $mimeType = 'text/plain'; - - header('Pragma: public'); - header('Expires: 0'); - header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); - header('Content-type: ' . $mimeType); - if (ob_get_length() === false) { - header('Content-Length: ' . (function_exists('mb_strlen') ? mb_strlen($content, '8bit') : strlen($content))); - } - header('Content-Disposition: attachment; filename="' . $fileName . '"'); - header('Content-Transfer-Encoding: binary'); - echo $content; - - if ($terminate) exit(0); - } - - /** - * Downloads a file from browser to user - * @param string $file - * @param string $mimeType - * @param boolean $terminate - */ - public function downloadFile($file, $mimeType = null, $terminate = true) - { - if ($mimeType === null) { - $mimeType = CFile::getMimeType($file); - } - - header('Pragma: public'); - header('Expires: 0'); - header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); - header('Content-type: ' . $mimeType); - header('Content-Length: ' . filesize($file)); - header('Content-Disposition: attachment; filename="' . basename($file) . '"'); - header('Content-Transfer-Encoding: binary'); - readfile($file); - - if ($terminate) exit(0); - } - - /** - * Returns information about the browser of user - * @param string $key - * @param string $userAgent - * @return array - * @see http://www.php.net/manual/en/function.get-browser.php - */ - public function getBrowser($key = '', $userAgent = null) - { - $browser = get_browser($userAgent, true); - - if (!empty($key)) { - return isset($browser[$key]) ? $browser[$key] : ''; - } - - return $browser; - } - - /** - * Sets HTTP Referrer - * Has potential risk because can insert current URL as a referrer and lead to endless loops on redirection - * Ex.: language or currency changes - */ - public function setHttpReferrer() - { - // Save current data as previous referrer - A::app()->getSession()->set('http_referrer_previous', A::app()->getSession()->get('http_referrer_current')); - // Save current link as referrer - $httpReferrerCurrent = $this->_getProtocolAndHost() . $this->getRequestUri(); - A::app()->getSession()->set('http_referrer_current', $httpReferrerCurrent); - } - - /** - * Returns the URL referrer, null if not present - */ - public function getUrlReferrer() - { - $serverReferrer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null; - $sessionReferrer = A::app()->getSession()->get('http_referrer_previous'); - - if (!empty($serverReferrer)) { - return $serverReferrer; - } elseif (!empty($sessionReferrer)) { - return $sessionReferrer; - } else { - return null; - } - } - - /** - * Returns the port to use for insecure requests - * Defaults to 80 or the port specified by the server (if the current request is insecure) - * @return int - * @since 0.7.0 - */ - public function getPort() - { - if ($this->_port === null) { - $this->_port = !$this->isSecureConnection() && isset($_SERVER['SERVER_PORT']) ? (int)$_SERVER['SERVER_PORT'] : 80; - } - - return $this->_port; - } - - /** - * Returns the port to use for secure requests - * Defaults to 443, or the port specified by the server (if the current request is secure) - * @return int - * @since 0.7.0 - */ - public function getSecurePort() - { - if ($this->_securePort === null) { - $this->_securePort = $this->isSecureConnection() && isset($_SERVER['SERVER_PORT']) ? (int)$_SERVER['SERVER_PORT'] : 443; - } - - return $this->_securePort; - } - - /** - * Returns content of the given URL - * @param string $url - * @param string $method - * @param string $data - * @param string $params - * @param string $function 'file_get_contents' or 'curl' - * @return mixed - */ - function getUrlContent($url = '', $method = 'get', $data = array(), $params = array(), $function = 'file_get_contents') - { - - # Validate function argumanets - $method = strtolower($method); - $data = (array)$data; - - if (empty($url) && !in_array($method, array('get', 'post'))) { - return true; - } - - # Get parameters - $ajaxCall = isset($params['ajax']) ? (bool)$params['ajax'] : false; - $showErrors = isset($params['errors']) ? (bool)$params['errors'] : false; - $json = isset($params['json']) ? (bool)$params['json'] : false; - $sslVerifyHost = isset($params['ssl_verify_host']) ? (bool)$params['ssl_verify_host'] : false; - $sslVerifyPeer = isset($params['ssl_verify_peer']) ? (bool)$params['ssl_verify_peer'] : false; - $result = NULL; - - if ($function == 'curl') { - # Init curl - $ch = curl_init(); - - # Set options - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 0); - curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)'); - - # Fake AJAX call - if ($ajaxCall) { - curl_setopt($ch, CURLOPT_HTTPHEADER, array("X-Requested-With: XMLHttpRequest")); - } - - # SSL verification - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, ($sslVerifyHost ? 2 : 0)); - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, ($sslVerifyPeer ? 1 : 0)); - - if ($method == 'post') { - # Set the HEADER, number of POST vars, POST data - if ($json) { - curl_setopt($ch, CURLOPT_HEADER, false); - curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-type: application/json")); - curl_setopt($ch, CURLOPT_POST, count($data)); - curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); - } else { - curl_setopt($ch, CURLOPT_POST, count($data)); - curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); - } - } - - if ($showErrors) { - # Check for errors and include in the error message - $error = ''; - if ($errno = curl_errno($ch)) { - $errorMessage = function_exists('curl_strerror') ? curl_strerror($errno) : ''; - $error = "cURL error ({$errno}):\n {$errorMessage}"; - } - - $result['result'] = curl_exec($ch); - $result['error'] = $error; - } else { - $result = curl_exec($ch); - } - - # Close connection - curl_close($ch); - } else { - $context = NULL; - - # Use key 'http' even if you send the request to https:// - if ($method == 'post') { - $options = array( - 'http' => array( - 'header' => "Content-type: application/x-www-form-urlencoded\r\n" . - ($ajaxCall ? "X-Requested-With: XMLHttpRequest\r\n" : ''), - 'method' => 'POST', - 'content' => http_build_query($data), - ), - ); - - # Disable SSL verification - if (!$sslVerifyPeer) { - $options['ssl'] = array( - 'verify_peer' => false, - 'verify_peer_name' => false, - ); - } - - $context = stream_context_create($options); - } - - $result = file_get_contents($url, false, $context); - } - - return $result; - } - + + /** @var string */ + private $_baseUrl; + /** @var string */ + private $_hostInfo; + /** @var string */ + private $_hostName; + /** @var string */ + private $_basePath = '/'; + /** @var boolean to enable cookies validation to be sure they are not tampered (defaults - false) */ + public $cookieValidation = false; + /** @var boolean whether to enable CSRF (Cross-Site Request Forgery) validation (defaults - false) */ + private $_csrfValidation = false; + /** @var string excluding controllers */ + private $_csrfExclude = []; + /** @var boolean to enable gzip output compression */ + private $_gzipCompression = false; + /** @var string */ + private $_csrfTokenKey = 'APPHP_CSRF_TOKEN'; + /** @var string */ + private $_csrfTokenValue = null; + /** @var string session, cookie, multipages or multiforms */ + private $_csrfTokenType = 'session'; + /** @var int */ + private $_csrfMaxTokenedPages = 20; + /** @var int port number */ + private $_port = null; + /** @var int secure port number */ + private $_securePort = null; + /** @var boolean + * whether to enable referrer storage in session - has potential risk + * requires special handling to prevent endless loops on redirection on the same page + */ + private $_referrerInSession = false; + + + /** + * Class default constructor + */ + function __construct() + { + $this->_csrfValidation = (CConfig::get('validation.csrf.enable') === true) ? true : false; + $this->_csrfExclude = CConfig::exists('validation.csrf.exclude') ? CConfig::get('validation.csrf.exclude') + : []; + $this->_gzipCompression = (CConfig::get('compression.gzip.enable') === true) ? true : false; + $csrfTokenType = CConfig::get('validation.csrf.tokenType'); + $this->_csrfTokenType = ($csrfTokenType !== '' + && in_array( + $csrfTokenType, + ['session', 'cookie', 'multipages', 'multiforms'] + )) ? $csrfTokenType : 'session'; + + $this->_cleanRequest(); + $this->_baseUrl = $this->setBaseUrl(); + } + + /** + * Triggered when invoking inaccessible methods in an object context + * + * @param string $method + * @param array $args + * + * @return mixed + */ + public function __call($method, $args) + { + switch (strtolower($method)) { + case 'get': + case 'post': + case 'request': + + if ($method == 'get') { + $innerGet = 'getQuery'; + $innerSet = 'setQuery'; + } elseif ($method == 'post') { + $innerGet = 'getPost'; + $innerSet = 'setPost'; + } else { + $innerGet = 'getRequest'; + $innerSet = 'getRequest'; + } + + if (count($args) == 0) { + return $this->_getAll($method); + } elseif (count($args) == 1) { + return $this->$innerGet($args[0]); + } elseif (count($args) == 2) { + return $this->$innerSet($args[0], $args[1]); + } elseif (count($args) == 3) { + return $this->$innerGet($args[0], $args[1], $args[2]); + } elseif (count($args) == 4) { + return $this->$innerGet($args[0], $args[1], $args[2], $args[3]); + } + + break; + + case 'getAll': + return $this->_getAll('get'); + + case 'postAll': + return $this->_getAll('post'); + + case 'postWith': + if (count($args) == 1) { + return $this->getPostWith($args[0]); + } + break; + } + } + + /** + * Returns the instance of object + * + * @return current class + */ + public static function init() + { + return parent::init(__CLASS__); + } + + /** + * Strips slashes from data + * + * @param mixed $data input data to be processed + * + * @return mixed processed data + */ + public function stripSlashes(&$data) + { + return is_array($data) ? array_map([$this, 'stripSlashes'], $data) : stripslashes($data); + } + + /** + * Gets base URL + * + * @return string + */ + public function getBaseUrl() + { + return $this->_baseUrl; + } + + /** + * Gets Request URI + * + * @return string + */ + public function getRequestUri() + { + return isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; + } + + /** + * Gets Server Name + * + * @return string + */ + public function getServerName() + { + return isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : ''; + } + + /** + * Gets IP address of visitor + * + * @return string + */ + public function getUserHostAddress() + { + return isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1'; + } + + /** + * Returns the schema and host part of the current request URL + * The returned URL does not have an ending slash + * By default this is determined based on the user request information. + * You may explicitly specify it by setting the setHostInfo()[hostInfo]] property. + * + * @return string|null + */ + public function getHostInfo() + { + if ($this->_hostInfo === null) { + $secure = $this->isSecureConnection(); + $http = $secure ? 'https' : 'http'; + if (isset($_SERVER['HTTP_HOST'])) { + $this->_hostInfo = $http.'://'.$_SERVER['HTTP_HOST']; + } elseif (isset($_SERVER['SERVER_NAME'])) { + $this->_hostInfo = $http.'://'.$_SERVER['SERVER_NAME']; + $port = $secure ? $this->getSecurePort() : $this->getPort(); + if (($port !== 80 && ! $secure) || ($port !== 443 && $secure)) { + $this->_hostInfo .= ':'.$port; + } + } + } + + return $this->_hostInfo; + } + + /** + * Returns the host part of the current request URL (ex.: apphp.com) + * Value is calculated from current getHostInfo()[hostInfo] property + * + * @return string|null + * @see getHostInfo() + * @since 0.9.0 + */ + public function getHostName() + { + if ($this->_hostName === null) { + $this->_hostName = parse_url($this->getHostInfo(), PHP_URL_HOST); + } + + return $this->_hostName; + } + + /** + * Gets a string denoting the user agent being which is accessing the page. + * A typical example is: Mozilla/4.5 [en] (X11; U; Linux 2.2.9 i586). + * + * @return string + */ + public function getUserAgent() + { + return isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : ''; + } + + /** + * Gets base path + * + * @return string + */ + public function getBasePath() + { + return $this->_basePath; + } + + /** + * Sets base URL + * + * @param boolean $useAbsolutePath + * + * @return string + */ + public function setBaseUrl($useAbsolutePath = true) + { + $absolutePart = ($useAbsolutePath) ? $this->_getProtocolAndHost() : ''; + + $scriptName = basename($_SERVER['SCRIPT_FILENAME']); + if (basename($_SERVER['SCRIPT_NAME']) === $scriptName) { + $scriptUrl = $_SERVER['SCRIPT_NAME']; + } elseif (basename($_SERVER['PHP_SELF']) === $scriptName) { + $scriptUrl = $_SERVER['PHP_SELF']; + } elseif (isset($_SERVER['ORIG_SCRIPT_NAME']) && basename($_SERVER['ORIG_SCRIPT_NAME']) === $scriptName) { + $scriptUrl = $_SERVER['ORIG_SCRIPT_NAME']; + } elseif (($pos = strpos($_SERVER['PHP_SELF'], '/'.$scriptName)) !== false) { + $scriptUrl = substr($_SERVER['SCRIPT_NAME'], 0, $pos).'/'.$scriptName; + } elseif (isset($_SERVER['DOCUMENT_ROOT']) + && strpos($_SERVER['SCRIPT_FILENAME'], $_SERVER['DOCUMENT_ROOT']) === 0 + ) { + $scriptUrl = str_replace( + '\\', + '/', + str_replace($_SERVER['DOCUMENT_ROOT'], '', $_SERVER['SCRIPT_FILENAME']) + ); + } else { + CDebug::addMessage( + 'error', + 'entry_script', + A::t('core', 'Framework is unable to determine the entry script URL') + ); + } + + $this->_basePath = rtrim(dirname($scriptUrl), '\\/').'/'; + + return $absolutePart.$this->_basePath; + } + + /** + * Returns parameter from global array $_GET + * + * @param string $name + * @param string|array $filters + * @param string $default + * @param array $allowedValues + * + * @return mixed + * @see CFilter + */ + public function getQuery($name = '', $filters = '', $default = '', $allowedValues = []) + { + if (empty($name)) { + return $this->_getAll('get'); + } else { + return $this->_getParam('get', $name, $default, $filters, $allowedValues); + } + } + + /** + * Sets value to global array $_GET + * + * @param string $name + * @param string $value + * + * @return bool + */ + public function setQuery($name, $value = '') + { + if (isset($_GET)) { + $_GET[$name] = $value; + + return true; + } + + return false; + } + + /** + * Returns parameter from global array $_POST + * + * @param string $name + * @param string|array $filters + * @param string $default + * @param array $allowedValues + * + * @return mixed + * @see CFilter + */ + public function getPost($name = '', $filters = '', $default = '', $allowedValues = []) + { + if (empty($name)) { + return $this->_getAll('post'); + } else { + return $this->_getParam('post', $name, $default, $filters, $allowedValues); + } + } + + /** + * Returns variables from global array $_POST with certain parameter + * + * @param string $name + * @param string|array $filters + * @param string $default + * @param array $allowedValues + * + * @return array + */ + public function getPostWith($name, $filters = '', $default = '', $allowedValues = []) + { + $result = []; + if ( ! isset($_POST) || ! is_array($_POST)) { + return $result; + } + + foreach ($_POST as $key => $val) { + if (preg_match('/'.$name.'/i', $key)) { + $result[$key] = $this->_getParam('post', $key, $default, $filters, $allowedValues); + } + } + + return $result; + } + + /** + * Sets value to global array $_POST + * + * @param string $name + * @param string $value + * + * @return bool + */ + public function setPost($name, $value = '') + { + if (isset($_POST)) { + $_POST[$name] = $value; + + return true; + } + + return false; + } + + /** + * Returns parameter from global array $_GET or $_POST + * + * @param string $name + * @param string|array $filters + * @param string $default + * @param array $allowedValues + * + * @return mixed + */ + public function getRequest($name = '', $filters = '', $default = '', $allowedValues = []) + { + if (empty($name)) { + return $this->_getAll('request'); + } else { + return $this->_getParam('request', $name, $default, $filters, $allowedValues); + } + } + + /** + * Returns whether there is an AJAX (XMLHttpRequest) request + * + * @return boolean + * @since 0.6.0 + */ + public function isAjaxRequest() + { + return isset($_SERVER['HTTP_X_REQUESTED_WITH']) + && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest'; + } + + /** + * Returns whether there is a PUT request + * + * @return boolean + * @since 0.6.0 + */ + public function isPutRequest() + { + return isset($_SERVER['REQUEST_METHOD']) && ! strcasecmp($_SERVER['REQUEST_METHOD'], 'PUT'); + } + + /** + * Returns whether there is a DELETE request + * + * @return boolean + * @since 0.6.0 + */ + public function isDeleteRequest() + { + return isset($_SERVER['REQUEST_METHOD']) && ! strcasecmp($_SERVER['REQUEST_METHOD'], 'DELETE'); + } + + /** + * Returns whether there is a POST request + * + * @return boolean + */ + public function isPostRequest() + { + return isset($_SERVER['REQUEST_METHOD']) && ! strcasecmp($_SERVER['REQUEST_METHOD'], 'POST'); + } + + /** + * Returns whether there is a POST variable exists + * + * @param string $name + * + * @return boolean + */ + public function isPostExists($name) + { + return isset($_POST[$name]); + } + + /** + * Return if the request is sent via secure channel (https) + * + * @return boolean + */ + public function isSecureConnection() + { + return (isset($_SERVER['HTTPS']) && (strcasecmp($_SERVER['HTTPS'], 'on') === 0 || $_SERVER['HTTPS'] == 1)) + || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) + && strcasecmp($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') === 0); + } + + /** + * Returns if csrf validation is used + * + * @return string + */ + public function getCsrfValidation() + { + if ( ! empty($this->_csrfExclude) && is_array($this->_csrfExclude)) { + // Retrirve current controller + // TODO: this is a simplest code, we need to improve it and use URL rules + $request = isset($_GET['url']) ? $_GET['url'] : ''; + $split = explode('/', trim($request, '/')); + $controller = ! empty($split[0]) ? $split[0] : CConfig::get('defaultController'); + + if (in_array(strtolower($controller), array_map('strtolower', $this->_csrfExclude))) { + return false; + } + } + + return $this->_csrfValidation; + } + + /** + * Returns CSRF token key name + * + * @return string + */ + public function getCsrfTokenKey() + { + return $this->_csrfTokenKey; + } + + /** + * Returns the random token value used to perform CSRF validation + * + * @param string $formId + * + * @return string + * @see $this->_csrfValidation() + */ + public function getCsrfTokenValue($formId = '') + { + // Check and set token + $csrfTokenValue = md5(uniqid(rand(), true)); + + if ($this->_csrfTokenType == 'session') { + if ($this->_csrfTokenValue === null) { + $this->_csrfTokenValue = $csrfTokenValue; + A::app()->getSession()->set('token', $this->_csrfTokenValue); + } + } elseif ($this->_csrfTokenType == 'cookie') { + if ($this->_csrfTokenValue === null) { + $this->_csrfTokenValue = $csrfTokenValue; + A::app()->getCookie()->set('token', $this->_csrfTokenValue); + } + } elseif ($this->_csrfTokenType == 'multipages' || $this->_csrfTokenType == 'multiforms') { + if ($this->_csrfTokenType == 'multipages') { + // Get page ID + $tokenId = $this->_getControllerAndAction(); + } else { + $tokenId = $formId; + } + if (CString::length($tokenId) < 100 && CValidator::isVariable($tokenId)) { + if ($this->_csrfTokenValue === null) { + $this->_csrfTokenValue = $csrfTokenValue; + } + // Get array and validate + $csrfTokenValues = A::app()->getSession()->get('token'); + if (empty($csrfTokenValues) || ! is_array($csrfTokenValues)) { + $csrfTokenValues = []; + } + // Save data + $csrfTokenValues[$tokenId] = ($this->_csrfTokenValue !== null) ? $this->_csrfTokenValue + : $csrfTokenValue; + if (count($csrfTokenValues) > $this->_csrfMaxTokenedPages) { + array_shift($csrfTokenValues); + } + A::app()->getSession()->set('token', $csrfTokenValues); + } + } + + return $this->_csrfTokenValue; + } + + /** + * Performs the CSRF validation + * + * @param string $formId + * + * @return void + */ + public function validateCsrfToken($formId = '') + { + // Validate only POST requests + if ($this->isPostRequest()) { + $valid = false; + $tokenFromPost = isset($_POST[$this->_csrfTokenKey]) ? $_POST[$this->_csrfTokenKey] : null; + + if ($this->_csrfTokenType == 'session') { + if (A::app()->getSession()->isExists('token') && isset($_POST[$this->_csrfTokenKey])) { + $tokenFromSession = A::app()->getSession()->get('token'); + $valid = ($tokenFromSession === $tokenFromPost); + } + } elseif ($this->_csrfTokenType == 'cookie') { + if (A::app()->getCookie()->isExists('token') && isset($_POST[$this->_csrfTokenKey])) { + $tokenFromCookie = A::app()->getCookie()->get('token'); + $valid = ($tokenFromCookie === $tokenFromPost); + } + } elseif ($this->_csrfTokenType == 'multipages' || $this->_csrfTokenType == 'multiforms') { + if ($this->_csrfTokenType == 'multipages') { + // Get page ID + $tokenId = $this->_getControllerAndAction(); + } else { + $tokenId = $formId; + } + if (A::app()->getSession()->isExists('token') && isset($_POST[$this->_csrfTokenKey])) { + $tokenFromSession = A::app()->getSession()->get('token'); + $tokenFromSession = isset($tokenFromSession[$tokenId]) ? $tokenFromSession[$tokenId] : ''; + $valid = ($tokenFromSession === $tokenFromPost); + } + } + + if ( ! $valid) { + unset($_POST); + A::app()->getSession()->setFlash( + 'csrfError', + CWidget::create( + 'CMessage', + [ + 'warning', + A::t( + 'core', + 'The CSRF token has expired or invalid. Please try to refresh page and resubmit the form.' + ) + ] + ) + ); + CDebug::addMessage( + 'warnings', + 'csrf_token', + A::t('core', 'The CSRF token could not be verified.'), + 'session' + ); + A::app()->getClientScript()->registerScript( + 'csrfError', + 'function csrf_refresh_page(){location.href = location.href + \'?\' + Math.random();}', + 2 + ); + } + } + } + + /** + * Set GZIP compression handler + */ + public function setGzipHandler() + { + if (isset($_SERVER['HTTP_ACCEPT_ENCODING']) && substr_count($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')) { + // Fix for warning: ob_start() [ref.outcontrol]: output handler 'ob_gzhandler' conflicts with zlib output compression' + if (extension_loaded('zlib')) { + if (ob_get_length()) { + ob_end_clean(); + } + } + ob_start('ob_gzhandler'); + } else { + ob_start(); + } + } + + /** + * Cleans the request data + * This method removes slashes from request data if get_magic_quotes_gpc() is turned on + * Also performs CSRF validation if {@link _csrfValidation} is true + */ + protected function _cleanRequest() + { + // 01.12.2018 - DEPRECATED + // Clean request only for PHP < 5.3, in greater versions of PHP 'magic' functions are deprecated + //if(version_compare(phpversion(), '5.3.0', '<')){ + // if(function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()){ + // $_GET = $this->stripSlashes($_GET); + // $_POST = $this->stripSlashes($_POST); + // $_REQUEST = $this->stripSlashes($_REQUEST); + // $_COOKIE = $this->stripSlashes($_COOKIE); + // } + //} + + if ($this->getCsrfValidation()) { + A::app()->attachEventHandler('_onBeginRequest', [$this, 'validateCsrfToken']); + } + if ($this->_gzipCompression) { + A::app()->attachEventHandler('_onBeginRequest', [$this, 'setGzipHandler']); + } + if ($this->_referrerInSession) { + A::app()->attachEventHandler('_onBeginRequest', [$this, 'setHttpReferrer']); + } + } + + /** + * Returns protocol and host + * + * @param bool $usePort + * + * @return string + */ + protected function _getProtocolAndHost($usePort = true) + { + $protocol = 'http://'; + $port = ''; + $httpHost = isset($_SERVER['HTTP_HOST']) ? htmlentities($_SERVER['HTTP_HOST']) : ''; + $serverProtocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : ''; + + if ((isset($_SERVER['HTTPS']) && (strtolower($_SERVER['HTTPS']) != 'off')) + || strtolower( + substr($serverProtocol, 0, 5) + ) == 'https' + ) { + $protocol = 'https://'; + } + + if ($usePort) { + $portNumber = $this->getPort(); + if ($portNumber != '80' && ! strpos($httpHost, ':')) { + $port = ':'.$portNumber; + } + } + + return $protocol.$httpHost.$port; + } + + /** + * Returns controller and action from URL + * + * @return string + */ + protected function _getControllerAndAction() + { + $request = isset($_GET['url']) ? $_GET['url'] : ''; + $split = explode('/', trim($request, '/')); + $pageId = isset($split[0]) ? $split[0] : ''; + $pageId .= isset($split[1]) ? '_'.$split[1] : ''; + + return $pageId; + } + + /** + * Returns parameter from global arrays $_GET or $_POST according to the type of request + * + * @param string $type + * @param string $name + * @param string|array $filters + * @param array $allowedValues + * @param string $default + * + * @return mixed + */ + private function _getParam($type = 'get', $name = '', $default = '', $filters = '', $allowedValues = []) + { + $value = null; + + if ($type == 'get') { + if (isset($_GET[$name])) { + $value = $_GET[$name]; + } else { + // Check for variant + // URL: http://localhost/site/page/contact/param1/aaa/param2/bbb/param3/ccc + $request = isset($_GET['url']) ? $_GET['url'] : ''; + $split = explode('/', trim($request, '/')); + + $temp = []; + foreach ($split as $index => $part) { + if ( ! $temp || end($temp) !== null) { + $temp[$part] = null; + } else { + $arrayArg = array_keys($temp); + $tempEnd = end($arrayArg); + $temp[$tempEnd] = $part; + } + } + $temp = array_slice($temp, 1); + if (isset($temp[$name])) { + $value = $temp[$name]; + } + } + } elseif ($type == 'post' && isset($_POST[$name])) { + $value = $_POST[$name]; + } elseif ($type == 'request' && (isset($_GET[$name]) || isset($_POST[$name]))) { + $value = isset($_GET[$name]) ? $_GET[$name] : $_POST[$name]; + } + + if ($value !== null) { + // Validate allowed values + if ( ! empty($allowedValues)) { + if ( ! is_array($allowedValues)) { + $allowedValues = [$allowedValues]; + } + if ( ! in_array($value, $allowedValues)) { + $value = $default; + } + } + + // Filter values + if ( ! empty($filters)) { + if ( ! is_array($filters)) { + $filters = [$filters]; + } + foreach ($filters as $filter) { + $value = CFilter::sanitize($filter, $value); + } + } + } else { + $value = $default; + } + + return $value; + } + + /** + * Returns global arrays: $_GET, $_POST or $_REQUEST according to given type + * + * @param string $type + * + * @return array + */ + private function _getAll($type = 'get') + { + if ($type == 'get') { + return isset($_GET) ? $_GET : []; + } elseif ($type == 'post') { + return isset($_POST) ? $_POST : []; + } elseif ($type == 'request' && (isset($_GET) || isset($_POST))) { + return isset($_GET) ? $_GET : $_POST; + } + + return []; + } + + /** + * Downloads a content as file from browser to user + * + * @param string $fileName + * @param string $content + * @param string $mimeType + * @param boolean $terminate + */ + public function downloadContent($fileName, $content, $mimeType = null, $terminate = true) + { + if ($mimeType === null) { + $mimeType = 'text/plain'; + } + + header('Pragma: public'); + header('Expires: 0'); + header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + header('Content-type: '.$mimeType); + if (ob_get_length() === false) { + header('Content-Length: '.(function_exists('mb_strlen') ? mb_strlen($content, '8bit') : strlen($content))); + } + header('Content-Disposition: attachment; filename="'.$fileName.'"'); + header('Content-Transfer-Encoding: binary'); + echo $content; + + if ($terminate) { + exit(0); + } + } + + /** + * Downloads a file from browser to user + * + * @param string $file + * @param string $mimeType + * @param boolean $terminate + */ + public function downloadFile($file, $mimeType = null, $terminate = true) + { + if ($mimeType === null) { + $mimeType = CFile::getMimeType($file); + } + + header('Pragma: public'); + header('Expires: 0'); + header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + header('Content-type: '.$mimeType); + header('Content-Length: '.filesize($file)); + header('Content-Disposition: attachment; filename="'.basename($file).'"'); + header('Content-Transfer-Encoding: binary'); + readfile($file); + + if ($terminate) { + exit(0); + } + } + + /** + * Returns information about the browser of user + * + * @param string $key + * @param string $userAgent + * + * @return array + * @see http://www.php.net/manual/en/function.get-browser.php + */ + public function getBrowser($key = '', $userAgent = null) + { + $browser = get_browser($userAgent, true); + + if ( ! empty($key)) { + return isset($browser[$key]) ? $browser[$key] : ''; + } + + return $browser; + } + + /** + * Sets HTTP Referrer + * Has potential risk because can insert current URL as a referrer and lead to endless loops on redirection + * Ex.: language or currency changes + */ + public function setHttpReferrer() + { + // Save current data as previous referrer + A::app()->getSession()->set('http_referrer_previous', A::app()->getSession()->get('http_referrer_current')); + // Save current link as referrer + $httpReferrerCurrent = $this->_getProtocolAndHost().$this->getRequestUri(); + A::app()->getSession()->set('http_referrer_current', $httpReferrerCurrent); + } + + /** + * Returns the URL referrer, null if not present + */ + public function getUrlReferrer() + { + $serverReferrer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null; + $sessionReferrer = A::app()->getSession()->get('http_referrer_previous'); + + if ( ! empty($serverReferrer)) { + return $serverReferrer; + } elseif ( ! empty($sessionReferrer)) { + return $sessionReferrer; + } else { + return null; + } + } + + /** + * Returns the port to use for insecure requests + * Defaults to 80 or the port specified by the server (if the current request is insecure) + * + * @return int + * @since 0.7.0 + */ + public function getPort() + { + if ($this->_port === null) { + $this->_port = ! $this->isSecureConnection() && isset($_SERVER['SERVER_PORT']) + ? (int)$_SERVER['SERVER_PORT'] : 80; + } + + return $this->_port; + } + + /** + * Returns the port to use for secure requests + * Defaults to 443, or the port specified by the server (if the current request is secure) + * + * @return int + * @since 0.7.0 + */ + public function getSecurePort() + { + if ($this->_securePort === null) { + $this->_securePort = $this->isSecureConnection() && isset($_SERVER['SERVER_PORT']) + ? (int)$_SERVER['SERVER_PORT'] : 443; + } + + return $this->_securePort; + } + + /** + * Returns content of the given URL + * + * @param string $url + * @param string $method + * @param string $data + * @param string $params + * @param string $function 'file_get_contents' or 'curl' + * + * @return mixed + */ + function getUrlContent($url = '', $method = 'get', $data = [], $params = [], $function = 'file_get_contents') + { + # Validate function argumanets + $method = strtolower($method); + $data = (array)$data; + + if (empty($url) && ! in_array($method, ['get', 'post'])) { + return true; + } + + # Get parameters + $ajaxCall = isset($params['ajax']) ? (bool)$params['ajax'] : false; + $showErrors = isset($params['errors']) ? (bool)$params['errors'] : false; + $json = isset($params['json']) ? (bool)$params['json'] : false; + $sslVerifyHost = isset($params['ssl_verify_host']) ? (bool)$params['ssl_verify_host'] : false; + $sslVerifyPeer = isset($params['ssl_verify_peer']) ? (bool)$params['ssl_verify_peer'] : false; + $result = null; + + if ($function == 'curl') { + # Init curl + $ch = curl_init(); + + # Set options + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 0); + curl_setopt( + $ch, + CURLOPT_USERAGENT, + 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)' + ); + + # Fake AJAX call + if ($ajaxCall) { + curl_setopt($ch, CURLOPT_HTTPHEADER, ["X-Requested-With: XMLHttpRequest"]); + } + + # SSL verification + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, ($sslVerifyHost ? 2 : 0)); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, ($sslVerifyPeer ? 1 : 0)); + + if ($method == 'post') { + # Set the HEADER, number of POST vars, POST data + if ($json) { + curl_setopt($ch, CURLOPT_HEADER, false); + curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-type: application/json"]); + curl_setopt($ch, CURLOPT_POST, count($data)); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); + } else { + curl_setopt($ch, CURLOPT_POST, count($data)); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); + } + } + + if ($showErrors) { + # Check for errors and include in the error message + $error = ''; + if ($errno = curl_errno($ch)) { + $errorMessage = function_exists('curl_strerror') ? curl_strerror($errno) : ''; + $error = "cURL error ({$errno}):\n {$errorMessage}"; + } + + $result['result'] = curl_exec($ch); + $result['error'] = $error; + } else { + $result = curl_exec($ch); + } + + # Close connection + curl_close($ch); + } else { + $context = null; + + # Use key 'http' even if you send the request to https:// + if ($method == 'post') { + $options = [ + 'http' => [ + 'header' => "Content-type: application/x-www-form-urlencoded\r\n". + ($ajaxCall ? "X-Requested-With: XMLHttpRequest\r\n" : ''), + 'method' => 'POST', + 'content' => http_build_query($data), + ], + ]; + + # Disable SSL verification + if ( ! $sslVerifyPeer) { + $options['ssl'] = [ + 'verify_peer' => false, + 'verify_peer_name' => false, + ]; + } + + $context = stream_context_create($options); + } + + $result = file_get_contents($url, false, $context); + } + + return $result; + } + } diff --git a/framework/components/CHttpSession.php b/framework/components/CHttpSession.php index 37b087d..5514c92 100644 --- a/framework/components/CHttpSession.php +++ b/framework/components/CHttpSession.php @@ -35,280 +35,313 @@ class CHttpSession extends CComponent { - - /** @var boolean */ - protected $_autoStart = true; - /** @var string */ - protected $_defaultSessionName = 'apphp_framework'; - /** @var string */ - protected $_defaultSessionPrefix = 'apphp_'; - /** - * @var int - * @deprecated since v0.1.0 - * 0 - use name prefix, 1 - use session name (default) - */ - protected $_multiSiteSupportType = 1; - /** - * @var mixed - */ - protected $_prefix = ''; - /** - * @var string - * only | allow | none - */ - protected $_cookieMode = 'allow'; - - - /** - * Class default constructor - */ - function __construct() - { - if ($this->_cookieMode !== 'only') { - $this->_setCookieMode($this->_cookieMode); - } - - if ($this->_multiSiteSupportType) { - $this->setSessionName('apphp_' . CConfig::get('installationKey')); - } else { - $this->setSessionPrefix('apphp_' . CConfig::get('installationKey')); - } - - if ($this->_autoStart) $this->startSession(); - } - - /** - * Returns the instance of object - * @return current class - */ - public static function init() - { - return parent::init(__CLASS__); - } - - /** - * Sets session variable - * @param string $name - * @param mixed $value - */ - public function set($name, $value) - { - $_SESSION[$this->_prefix . $name] = $value; - } - - /** - * Returns session variable - * @param string $name - * @param mixed $default - * @return mixed - */ - public function get($name, $default = '') - { - return isset($_SESSION[$this->_prefix . $name]) ? $_SESSION[$this->_prefix . $name] : $default; - } - - /** - * Returns all session variables - * @return mixed - */ - public function getAll() - { - return isset($_SESSION) ? $_SESSION : null; - } - - /** - * Removes session variable - * @param string $name - */ - public function remove($name) - { - if (isset($_SESSION[$this->_prefix . $name])) { - unset($_SESSION[$this->_prefix . $name]); - return true; - } - - return false; - } - - /** - * Removes all session variable - * @return void - */ - public function removeAll() - { - @session_unset(); - if (is_array($_SESSION)) { - foreach ($_SESSION as $key => $val) { - unset($_SESSION[$key]); - } - } - } - - /** - * Checks if session variable exists - * @param string $name - */ - public function isExists($name) - { - return isset($_SESSION[$this->_prefix . $name]) ? true : false; - } - - /** - * Sets session flash data - * @param string $name - * @param mixed $value - */ - public function setFlash($name, $value) - { - $_SESSION[$this->_prefix . '_flash'][$name] = $value; - } - - /** - * Returns session flash data - * @param string $name - * @param mixed $default - */ - public function getFlash($name, $default = '') - { - if (isset($_SESSION[$this->_prefix . '_flash'][$name])) { - $result = $_SESSION[$this->_prefix . '_flash'][$name]; - unset($_SESSION[$this->_prefix . '_flash'][$name]); - } else { - $result = $default; - } - return $result; - } - - /** - * Checks if has flash data - * @param string $name - * @return bool - */ - public function hasFlash($name) - { - return isset($_SESSION[$this->_prefix . '_flash'][$name]) ? true : false; - } - - /** - * Sets session name - * @param string $value - */ - public function setSessionName($value) - { - if (empty($value)) $value = $this->_defaultSessionName; - session_name($value); - } - - /** - * Sets session name - * @param string $value - */ - public function setSessionPrefix($value) - { - if (empty($value)) $value = $this->_defaultSessionPrefix; - $this->_prefix = $value; - } - - /** - * Gets session name - * @return string - */ - public function getSessionName() - { - return session_name(); - } - - /** - * Sets the number of seconds after which data will be seen as 'garbage' and cleaned up - * @param int $value - */ - public function setTimeout($value) - { - ini_set('session.gc_maxlifetime', (int)$value); - } - - /** - * Returns the number of seconds after which data will be seen as 'garbage' and cleaned up - * @return integer - */ - public function getTimeout() - { - // Get lifetime value from configuration file (in minutes) - $maxlifetime = CConfig::get('session.lifetime'); - return (!empty($maxlifetime)) ? (int)($maxlifetime * 60) : (int)ini_get('session.gc_maxlifetime'); - } - - /** - * Destroys the session - */ - public function endSession() - { - if (session_id() !== '') { - @session_unset(); - @session_destroy(); - } - } - - /** - * Gets cookie mode - * @return string - */ - public function getCookieMode() - { - if (ini_get('session.use_cookies') === '0') { - return 'none'; - } elseif (ini_get('session.use_only_cookies') === '0') { - return 'allow'; - } else { - return 'only'; - } - } - - /** - * Session close handler - * Do not call this method directly - * @return boolean - */ - public function closeSession() - { - return true; - } - - /** - * Starts the session if it has not started yet - */ - public function startSession() - { - // Set lifetime value from configuration file (in minutes) - $maxLifetime = CConfig::get('session.lifetime'); - if (!empty($maxLifetime) && $maxLifetime != ini_get('session.gc_maxlifetime')) { - $this->setTimeout($maxLifetime); - } - - @session_start(); - if (APPHP_MODE == 'debug' && session_id() == '') { - CDebug::addMessage('errors', 'session', A::t('core', 'Failed to start session')); - } - } - - /** - * Sets cookie mode - * @value string - */ - private function _setCookieMode($value = '') - { - if ($value === 'none') { - ini_set('session.use_cookies', '0'); - ini_set('session.use_only_cookies', '0'); - } elseif ($value === 'allow') { - ini_set('session.use_cookies', '1'); - ini_set('session.use_only_cookies', '0'); - } elseif ($value === 'only') { - ini_set('session.use_cookies', '1'); - ini_set('session.use_only_cookies', '1'); - } else { - CDebug::addMessage('warnings', 'session_cookie_mode', A::t('core', 'HttpSession.cookieMode can only be "none", "allow" or "only".')); - } - } - + + /** @var boolean */ + protected $_autoStart = true; + /** @var string */ + protected $_defaultSessionName = 'apphp_framework'; + /** @var string */ + protected $_defaultSessionPrefix = 'apphp_'; + /** + * @var int + * @deprecated since v0.1.0 + * 0 - use name prefix, 1 - use session name (default) + */ + protected $_multiSiteSupportType = 1; + /** + * @var mixed + */ + protected $_prefix = ''; + /** + * @var string + * only | allow | none + */ + protected $_cookieMode = 'allow'; + + + /** + * Class default constructor + */ + function __construct() + { + if ($this->_cookieMode !== 'only') { + $this->_setCookieMode($this->_cookieMode); + } + + if ($this->_multiSiteSupportType) { + $this->setSessionName('apphp_'.CConfig::get('installationKey')); + } else { + $this->setSessionPrefix('apphp_'.CConfig::get('installationKey')); + } + + if ($this->_autoStart) { + $this->startSession(); + } + } + + /** + * Returns the instance of object + * + * @return current class + */ + public static function init() + { + return parent::init(__CLASS__); + } + + /** + * Sets session variable + * + * @param string $name + * @param mixed $value + */ + public function set($name, $value) + { + $_SESSION[$this->_prefix.$name] = $value; + } + + /** + * Returns session variable + * + * @param string $name + * @param mixed $default + * + * @return mixed + */ + public function get($name, $default = '') + { + return isset($_SESSION[$this->_prefix.$name]) ? $_SESSION[$this->_prefix.$name] : $default; + } + + /** + * Returns all session variables + * + * @return mixed + */ + public function getAll() + { + return isset($_SESSION) ? $_SESSION : null; + } + + /** + * Removes session variable + * + * @param string $name + */ + public function remove($name) + { + if (isset($_SESSION[$this->_prefix.$name])) { + unset($_SESSION[$this->_prefix.$name]); + + return true; + } + + return false; + } + + /** + * Removes all session variable + * + * @return void + */ + public function removeAll() + { + @session_unset(); + if (is_array($_SESSION)) { + foreach ($_SESSION as $key => $val) { + unset($_SESSION[$key]); + } + } + } + + /** + * Checks if session variable exists + * + * @param string $name + */ + public function isExists($name) + { + return isset($_SESSION[$this->_prefix.$name]) ? true : false; + } + + /** + * Sets session flash data + * + * @param string $name + * @param mixed $value + */ + public function setFlash($name, $value) + { + $_SESSION[$this->_prefix.'_flash'][$name] = $value; + } + + /** + * Returns session flash data + * + * @param string $name + * @param mixed $default + */ + public function getFlash($name, $default = '') + { + if (isset($_SESSION[$this->_prefix.'_flash'][$name])) { + $result = $_SESSION[$this->_prefix.'_flash'][$name]; + unset($_SESSION[$this->_prefix.'_flash'][$name]); + } else { + $result = $default; + } + + return $result; + } + + /** + * Checks if has flash data + * + * @param string $name + * + * @return bool + */ + public function hasFlash($name) + { + return isset($_SESSION[$this->_prefix.'_flash'][$name]) ? true : false; + } + + /** + * Sets session name + * + * @param string $value + */ + public function setSessionName($value) + { + if (empty($value)) { + $value = $this->_defaultSessionName; + } + session_name($value); + } + + /** + * Sets session name + * + * @param string $value + */ + public function setSessionPrefix($value) + { + if (empty($value)) { + $value = $this->_defaultSessionPrefix; + } + $this->_prefix = $value; + } + + /** + * Gets session name + * + * @return string + */ + public function getSessionName() + { + return session_name(); + } + + /** + * Sets the number of seconds after which data will be seen as 'garbage' and cleaned up + * + * @param int $value + */ + public function setTimeout($value) + { + ini_set('session.gc_maxlifetime', (int)$value); + } + + /** + * Returns the number of seconds after which data will be seen as 'garbage' and cleaned up + * + * @return integer + */ + public function getTimeout() + { + // Get lifetime value from configuration file (in minutes) + $maxlifetime = CConfig::get('session.lifetime'); + + return ( ! empty($maxlifetime)) ? (int)($maxlifetime * 60) : (int)ini_get('session.gc_maxlifetime'); + } + + /** + * Destroys the session + */ + public function endSession() + { + if (session_id() !== '') { + @session_unset(); + @session_destroy(); + } + } + + /** + * Gets cookie mode + * + * @return string + */ + public function getCookieMode() + { + if (ini_get('session.use_cookies') === '0') { + return 'none'; + } elseif (ini_get('session.use_only_cookies') === '0') { + return 'allow'; + } else { + return 'only'; + } + } + + /** + * Session close handler + * Do not call this method directly + * + * @return boolean + */ + public function closeSession() + { + return true; + } + + /** + * Starts the session if it has not started yet + */ + public function startSession() + { + // Set lifetime value from configuration file (in minutes) + $maxLifetime = CConfig::get('session.lifetime'); + if ( ! empty($maxLifetime) && $maxLifetime != ini_get('session.gc_maxlifetime')) { + $this->setTimeout($maxLifetime); + } + + @session_start(); + if (APPHP_MODE == 'debug' && session_id() == '') { + CDebug::addMessage('errors', 'session', A::t('core', 'Failed to start session')); + } + } + + /** + * Sets cookie mode + * + * @value string + */ + private function _setCookieMode($value = '') + { + if ($value === 'none') { + ini_set('session.use_cookies', '0'); + ini_set('session.use_only_cookies', '0'); + } elseif ($value === 'allow') { + ini_set('session.use_cookies', '1'); + ini_set('session.use_only_cookies', '0'); + } elseif ($value === 'only') { + ini_set('session.use_cookies', '1'); + ini_set('session.use_only_cookies', '1'); + } else { + CDebug::addMessage( + 'warnings', + 'session_cookie_mode', + A::t('core', 'HttpSession.cookieMode can only be "none", "allow" or "only".') + ); + } + } + } \ No newline at end of file diff --git a/framework/components/CLocalTime.php b/framework/components/CLocalTime.php index f901e94..8bfd7fb 100644 --- a/framework/components/CLocalTime.php +++ b/framework/components/CLocalTime.php @@ -22,380 +22,902 @@ class CLocalTime extends CComponent { - - /** - * Class default constructor - */ - function __construct() - { - - } - - /** - * Returns the instance of object - * @return current class - */ - public static function init() - { - return parent::init(__CLASS__); - } - - /** - * Sets the time zone used by the application - * @param string $value - * @see http://php.net/manual/en/function.date-default-timezone-set.php - */ - public function setTimeZone($value) - { - date_default_timezone_set($value); - } - - /** - * Returns the time zone used by the application - * @return string - * @see http://php.net/manual/en/function.date-default-timezone-set.php - */ - public function getTimeZone() - { - return date_default_timezone_get(); - } - - /** - * Returns a list of locales - * @return array - */ - public function getLocales() - { - return array( - 'sq_AL' => A::t('i18n', 'languages.sq') . ' - ' . A::t('i18n', 'countries.al'), - 'ar_AE' => A::t('i18n', 'languages.ar') . ' - ' . A::t('i18n', 'countries.ae'), - 'ar_BH' => A::t('i18n', 'languages.ar') . ' - ' . A::t('i18n', 'countries.bh'), - 'ar_DZ' => A::t('i18n', 'languages.ar') . ' - ' . A::t('i18n', 'countries.dz'), - 'ar_EG' => A::t('i18n', 'languages.ar') . ' - ' . A::t('i18n', 'countries.eg'), - 'ar_IN' => A::t('i18n', 'languages.ar') . ' - ' . A::t('i18n', 'countries.in'), - 'ar_IQ' => A::t('i18n', 'languages.ar') . ' - ' . A::t('i18n', 'countries.iq'), - 'ar_JO' => A::t('i18n', 'languages.ar') . ' - ' . A::t('i18n', 'countries.jo'), - 'ar_KW' => A::t('i18n', 'languages.ar') . ' - ' . A::t('i18n', 'countries.kw'), - 'ar_LB' => A::t('i18n', 'languages.ar') . ' - ' . A::t('i18n', 'countries.lb'), - 'ar_LY' => A::t('i18n', 'languages.ar') . ' - ' . A::t('i18n', 'countries.ly'), - 'ar_MA' => A::t('i18n', 'languages.ar') . ' - ' . A::t('i18n', 'countries.ma'), - 'ar_OM' => A::t('i18n', 'languages.ar') . ' - ' . A::t('i18n', 'countries.om'), - 'ar_QA' => A::t('i18n', 'languages.ar') . ' - ' . A::t('i18n', 'countries.qa'), - 'ar_SA' => A::t('i18n', 'languages.ar') . ' - ' . A::t('i18n', 'countries.sa'), - 'ar_SD' => A::t('i18n', 'languages.ar') . ' - ' . A::t('i18n', 'countries.sd'), - 'ar_SY' => A::t('i18n', 'languages.ar') . ' - ' . A::t('i18n', 'countries.sy'), - 'ar_TN' => A::t('i18n', 'languages.ar') . ' - ' . A::t('i18n', 'countries.tn'), - 'ar_YE' => A::t('i18n', 'languages.ar') . ' - ' . A::t('i18n', 'countries.ye'), - 'eu_ES' => A::t('i18n', 'languages.eu') . ' - ' . A::t('i18n', 'countries.es'), - 'be_BY' => A::t('i18n', 'languages.be') . ' - ' . A::t('i18n', 'countries.by'), - 'bg_BG' => A::t('i18n', 'languages.bg') . ' - ' . A::t('i18n', 'countries.bg'), - 'ca_ES' => A::t('i18n', 'languages.ca') . ' - ' . A::t('i18n', 'countries.es'), - 'zh_CN' => A::t('i18n', 'languages.zh') . ' - ' . A::t('i18n', 'countries.cn'), - 'zh_HK' => A::t('i18n', 'languages.zh') . ' - ' . A::t('i18n', 'countries.hk'), - 'zh_TW' => A::t('i18n', 'languages.zh') . ' - ' . A::t('i18n', 'countries.tw'), - 'hr_HR' => A::t('i18n', 'languages.hr') . ' - ' . A::t('i18n', 'countries.hr'), - 'cs_CZ' => A::t('i18n', 'languages.cs') . ' - ' . A::t('i18n', 'countries.cz'), - 'da_DK' => A::t('i18n', 'languages.da') . ' - ' . A::t('i18n', 'countries.dk'), - 'nl_BE' => A::t('i18n', 'languages.nl') . ' - ' . A::t('i18n', 'countries.be'), - 'nl_NL' => A::t('i18n', 'languages.nl') . ' - ' . A::t('i18n', 'countries.nl'), - 'de_AT' => A::t('i18n', 'languages.de') . ' - ' . A::t('i18n', 'countries.at'), - 'de_BE' => A::t('i18n', 'languages.de') . ' - ' . A::t('i18n', 'countries.be'), - 'de_CH' => A::t('i18n', 'languages.de') . ' - ' . A::t('i18n', 'countries.ch'), - 'de_DE' => A::t('i18n', 'languages.de') . ' - ' . A::t('i18n', 'countries.de'), - 'de_LU' => A::t('i18n', 'languages.de') . ' - ' . A::t('i18n', 'countries.lu'), - 'en_AU' => A::t('i18n', 'languages.en') . ' - ' . A::t('i18n', 'countries.au'), - 'en_CA' => A::t('i18n', 'languages.en') . ' - ' . A::t('i18n', 'countries.ca'), - 'en_GB' => A::t('i18n', 'languages.en') . ' - ' . A::t('i18n', 'countries.gb'), - 'en_IN' => A::t('i18n', 'languages.en') . ' - ' . A::t('i18n', 'countries.in'), - 'en_NZ' => A::t('i18n', 'languages.en') . ' - ' . A::t('i18n', 'countries.nz'), - 'en_PH' => A::t('i18n', 'languages.en') . ' - ' . A::t('i18n', 'countries.ph'), - 'en_US' => A::t('i18n', 'languages.en') . ' - ' . A::t('i18n', 'countries.us'), - 'en_ZA' => A::t('i18n', 'languages.en') . ' - ' . A::t('i18n', 'countries.za'), - 'en_ZW' => A::t('i18n', 'languages.en') . ' - ' . A::t('i18n', 'countries.zw'), - 'et_EE' => A::t('i18n', 'languages.et') . ' - ' . A::t('i18n', 'countries.ee'), - 'fi_FI' => A::t('i18n', 'languages.fi') . ' - ' . A::t('i18n', 'countries.fi'), - 'fo_FO' => A::t('i18n', 'languages.fo') . ' - ' . A::t('i18n', 'countries.fo'), - 'fr_BE' => A::t('i18n', 'languages.fr') . ' - ' . A::t('i18n', 'countries.be'), - 'fr_CA' => A::t('i18n', 'languages.fr') . ' - ' . A::t('i18n', 'countries.ca'), - 'fr_CH' => A::t('i18n', 'languages.fr') . ' - ' . A::t('i18n', 'countries.ch'), - 'fr_FR' => A::t('i18n', 'languages.fr') . ' - ' . A::t('i18n', 'countries.fr'), - 'fr_LU' => A::t('i18n', 'languages.fr') . ' - ' . A::t('i18n', 'countries.lu'), - 'gl_ES' => A::t('i18n', 'languages.gl') . ' - ' . A::t('i18n', 'countries.es'), - 'el_GR' => A::t('i18n', 'languages.el') . ' - ' . A::t('i18n', 'countries.gr'), - 'gu_IN' => A::t('i18n', 'languages.gu') . ' - ' . A::t('i18n', 'countries.in'), - 'he_IL' => A::t('i18n', 'languages.he') . ' - ' . A::t('i18n', 'countries.il'), - 'hi_IN' => A::t('i18n', 'languages.hi') . ' - ' . A::t('i18n', 'countries.in'), - 'hu_HU' => A::t('i18n', 'languages.hu') . ' - ' . A::t('i18n', 'countries.hu'), - 'id_ID' => A::t('i18n', 'languages.id') . ' - ' . A::t('i18n', 'countries.id'), - 'is_IS' => A::t('i18n', 'languages.is') . ' - ' . A::t('i18n', 'countries.is'), - 'it_CH' => A::t('i18n', 'languages.it') . ' - ' . A::t('i18n', 'countries.ch'), - 'it_IT' => A::t('i18n', 'languages.it') . ' - ' . A::t('i18n', 'countries.it'), - 'ja_JP' => A::t('i18n', 'languages.ja') . ' - ' . A::t('i18n', 'countries.jp'), - 'ko_KR' => A::t('i18n', 'languages.ko') . ' - ' . A::t('i18n', 'countries.kr'), - 'lt_LT' => A::t('i18n', 'languages.lt') . ' - ' . A::t('i18n', 'countries.lt'), - 'lv_LV' => A::t('i18n', 'languages.lv') . ' - ' . A::t('i18n', 'countries.lv'), - 'mk_MK' => A::t('i18n', 'languages.mk') . ' - ' . A::t('i18n', 'countries.mk'), - 'mn_MN' => A::t('i18n', 'languages.mn') . ' - ' . A::t('i18n', 'countries.mn'), - 'ms_MY' => A::t('i18n', 'languages.ms') . ' - ' . A::t('i18n', 'countries.my'), - 'nb_NO' => A::t('i18n', 'languages.nb') . ' - ' . A::t('i18n', 'countries.no'), - 'no_NO' => A::t('i18n', 'languages.no') . ' - ' . A::t('i18n', 'countries.no'), - 'pl_PL' => A::t('i18n', 'languages.pl') . ' - ' . A::t('i18n', 'countries.pl'), - 'pt_BR' => A::t('i18n', 'languages.pt') . ' - ' . A::t('i18n', 'countries.br'), - 'pt_PT' => A::t('i18n', 'languages.pt') . ' - ' . A::t('i18n', 'countries.pt'), - 'ro_RO' => A::t('i18n', 'languages.ro') . ' - ' . A::t('i18n', 'countries.ro'), - 'ru_RU' => A::t('i18n', 'languages.ru') . ' - ' . A::t('i18n', 'countries.ru'), - 'ru_UA' => A::t('i18n', 'languages.ru') . ' - ' . A::t('i18n', 'countries.ua'), - 'sk_SK' => A::t('i18n', 'languages.sk') . ' - ' . A::t('i18n', 'countries.sk'), - 'sl_SI' => A::t('i18n', 'languages.sl') . ' - ' . A::t('i18n', 'countries.si'), - 'sr_YU' => A::t('i18n', 'languages.sr') . ' - ' . A::t('i18n', 'countries.rs'), - 'es_AR' => A::t('i18n', 'languages.es') . ' - ' . A::t('i18n', 'countries.ar'), - 'es_BO' => A::t('i18n', 'languages.es') . ' - ' . A::t('i18n', 'countries.bo'), - 'es_CL' => A::t('i18n', 'languages.es') . ' - ' . A::t('i18n', 'countries.cl'), - 'es_CO' => A::t('i18n', 'languages.es') . ' - ' . A::t('i18n', 'countries.co'), - 'es_CR' => A::t('i18n', 'languages.es') . ' - ' . A::t('i18n', 'countries.cr'), - 'es_DO' => A::t('i18n', 'languages.es') . ' - ' . A::t('i18n', 'countries.do'), - 'es_EC' => A::t('i18n', 'languages.es') . ' - ' . A::t('i18n', 'countries.ec'), - 'es_ES' => A::t('i18n', 'languages.es') . ' - ' . A::t('i18n', 'countries.es'), - 'es_GT' => A::t('i18n', 'languages.es') . ' - ' . A::t('i18n', 'countries.gt'), - 'es_HN' => A::t('i18n', 'languages.es') . ' - ' . A::t('i18n', 'countries.hn'), - 'es_MX' => A::t('i18n', 'languages.es') . ' - ' . A::t('i18n', 'countries.mx'), - 'es_NI' => A::t('i18n', 'languages.es') . ' - ' . A::t('i18n', 'countries.ni'), - 'es_PA' => A::t('i18n', 'languages.es') . ' - ' . A::t('i18n', 'countries.pa'), - 'es_PE' => A::t('i18n', 'languages.es') . ' - ' . A::t('i18n', 'countries.pe'), - 'es_PR' => A::t('i18n', 'languages.es') . ' - ' . A::t('i18n', 'countries.pr'), - 'es_PY' => A::t('i18n', 'languages.es') . ' - ' . A::t('i18n', 'countries.py'), - 'es_SV' => A::t('i18n', 'languages.es') . ' - ' . A::t('i18n', 'countries.sv'), - 'es_US' => A::t('i18n', 'languages.es') . ' - ' . A::t('i18n', 'countries.us'), - 'es_UY' => A::t('i18n', 'languages.es') . ' - ' . A::t('i18n', 'countries.uy'), - 'es_VE' => A::t('i18n', 'languages.es') . ' - ' . A::t('i18n', 'countries.ve'), - 'sv_FI' => A::t('i18n', 'languages.sv') . ' - ' . A::t('i18n', 'countries.fi'), - 'sv_SE' => A::t('i18n', 'languages.sv') . ' - ' . A::t('i18n', 'countries.se'), - 'ta_IN' => A::t('i18n', 'languages.ta') . ' - ' . A::t('i18n', 'countries.in'), - 'te_IN' => A::t('i18n', 'languages.te') . ' - ' . A::t('i18n', 'countries.in'), - 'th_TH' => A::t('i18n', 'languages.th') . ' - ' . A::t('i18n', 'countries.th'), - 'tr_TR' => A::t('i18n', 'languages.tr') . ' - ' . A::t('i18n', 'countries.tr'), - 'uk_UA' => A::t('i18n', 'languages.uk') . ' - ' . A::t('i18n', 'countries.ua'), - 'ur_PK' => A::t('i18n', 'languages.ur') . ' - ' . A::t('i18n', 'countries.pk'), - 'vi_VN' => A::t('i18n', 'languages.vi') . ' - ' . A::t('i18n', 'countries.vn'), - ); - } - - /** - * Returns a timzone offset or full name by time zone name - * @param string $name - * @param string $type 'offset' - default, 'offset_name' or 'full_name' - * @return float|string - */ - public function getTimeZoneInfo($name = '', $type = 'offset') - { - $return = ''; - - if (!empty($name)) { - $timeZones = $this->getTimeZones(); - foreach ($timeZones as $timeZone) { - foreach ($timeZone as $zoneName => $zoneInfo) { - if (strtolower($zoneName) == strtolower($name)) { - if ($type == 'offset') { - $return = isset($zoneInfo['offset']) ? $zoneInfo['offset'] : ''; - } elseif ($type == 'offset_name') { - $return = (isset($zoneInfo['offset_text']) && isset($zoneInfo['name'])) ? $zoneInfo['offset_text'] : ''; - } elseif ($type == 'full_name') { - $return = (isset($zoneInfo['offset_text']) && isset($zoneInfo['name'])) ? $zoneInfo['offset_text'] . ' ' . $zoneInfo['name'] : ''; - } - break(2); - } - } - } - } - - return $return; - } - - /** - * Returns a nested array of timzones by continents - * @return array - */ - public function getTimeZones() - { - return array( - 'Africa' => array( - 'Africa/Casablanca' => array('offset' => '0', 'offset_text' => '[GMT+00:00]', 'name' => 'Western European Time (Africa/ Casablanca)'), - 'Africa/Algiers' => array('offset' => '1', 'offset_text' => '[GMT+01:00]', 'name' => 'Central European Time (Africa/ Algiers)'), - 'Africa/Bangui' => array('offset' => '1', 'offset_text' => '[GMT+01:00]', 'name' => 'Western African Time (Africa/ Bangui)'), - 'Africa/Windhoek' => array('offset' => '1', 'offset_text' => '[GMT+01:00]', 'name' => 'Western African Time (Africa/ Windhoek)'), - 'Africa/Tripoli' => array('offset' => '2', 'offset_text' => '[GMT+02:00]', 'name' => 'Eastern European Time (Africa/ Tripoli)'), - 'Africa/Johannesburg' => array('offset' => '2', 'offset_text' => '[GMT+02:00]', 'name' => 'South Africa Standard Time (Africa/ Johannesburg)'), - 'Africa/Dar_es_Salaam' => array('offset' => '3', 'offset_text' => '[GMT+03:00]', 'name' => 'Eastern African Time (EAT)'), - ), - 'America (North & South)' => array( - 'America/Scoresbysund' => array('offset' => '-1', 'offset_text' => '[GMT-01:00]', 'name' => 'Eastern Greenland Time (America/ Scoresbysund)'), - 'America/Noronha' => array('offset' => '-2', 'offset_text' => '[GMT-02:00]', 'name' => 'Fernando de Noronha Time (America/ Noronha)'), - 'America/Argentina/Buenos_Aires' => array('offset' => '-3', 'offset_text' => '[GMT-03:00]', 'name' => 'Argentine Time (AGT)'), - 'America/Belem' => array('offset' => '-3', 'offset_text' => '[GMT-03:00]', 'name' => 'Brazil Time (America/ Belem)'), - 'America/Sao_Paulo' => array('offset' => '-3', 'offset_text' => '[GMT-03:00]', 'name' => 'Brazil Time (BET)'), - 'America/Cayenne' => array('offset' => '-3', 'offset_text' => '[GMT-03:00]', 'name' => 'French Guiana Time (America/ Cayenne)'), - 'America/Miquelon' => array('offset' => '-3', 'offset_text' => '[GMT-03:00]', 'name' => 'Pierre & Miquelon Standard Time (America/ Miquelon)'), - 'America/Paramaribo' => array('offset' => '-3', 'offset_text' => '[GMT-03:00]', 'name' => 'Suriname Time (America/ Paramaribo)'), - 'America/Montevideo' => array('offset' => '-3', 'offset_text' => '[GMT-03:00]', 'name' => 'Uruguay Time (America/ Montevideo)'), - 'America/Godthab' => array('offset' => '-3', 'offset_text' => '[GMT-03:00]', 'name' => 'Western Greenland Time (America/ Godthab)'), - 'America/St_Johns' => array('offset' => '-3', 'offset_text' => '[GMT-03:30]', 'name' => 'Newfoundland Standard Time (America/ St Johns)'), - 'America/Cuiaba' => array('offset' => '-4', 'offset_text' => '[GMT-04:00]', 'name' => 'Amazon Standard Time (America/ Cuiaba)'), - 'America/Glace_Bay' => array('offset' => '-4', 'offset_text' => '[GMT-04:00]', 'name' => 'Atlantic Standard Time (America/ Glace Bay)'), - 'America/La_Paz' => array('offset' => '-4', 'offset_text' => '[GMT-04:00]', 'name' => 'Bolivia Time (America/ La Paz)'), - 'America/Santiago' => array('offset' => '-4', 'offset_text' => '[GMT-04:00]', 'name' => 'Chile Time (America/ Santiago)'), - 'America/Guyana' => array('offset' => '-4', 'offset_text' => '[GMT-04:00]', 'name' => 'Guyana Time (America/ Guyana)'), - 'America/Asuncion' => array('offset' => '-4', 'offset_text' => '[GMT-04:00]', 'name' => 'Paraguay Time (America/ Asuncion)'), - 'America/Caracas' => array('offset' => '-4', 'offset_text' => '[GMT-04:00]', 'name' => 'Venezuela Time (America/ Caracas)'), - 'America/Porto_Acre' => array('offset' => '-5', 'offset_text' => '[GMT-05:00]', 'name' => 'Acre Time (America/ Porto Acre)'), - 'America/Havana' => array('offset' => '-5', 'offset_text' => '[GMT-05:00]', 'name' => 'Central Standard Time (America/ Havana)'), - 'America/Bogota' => array('offset' => '-5', 'offset_text' => '[GMT-05:00]', 'name' => 'Colombia Time (America/ Bogota)'), - 'America/Jamaica' => array('offset' => '-5', 'offset_text' => '[GMT-05:00]', 'name' => 'Eastern Standard Time (America/ Jamaica)'), - 'America/Indianapolis' => array('offset' => '-5', 'offset_text' => '[GMT-05:00]', 'name' => 'Eastern Standard Time (US/ East-Indiana)'), - 'America/Guayaquil' => array('offset' => '-5', 'offset_text' => '[GMT-05:00]', 'name' => 'Ecuador Time (America/ Guayaquil)'), - 'America/Lima' => array('offset' => '-6', 'offset_text' => '[GMT-05:00]', 'name' => 'Peru Time (America/ Lima)'), - 'America/El_Salvador' => array('offset' => '-6', 'offset_text' => '[GMT-06:00]', 'name' => 'Central Standard Time (America/ El Salvador)'), - 'America/Regina' => array('offset' => '-6', 'offset_text' => '[GMT-06:00]', 'name' => 'Central Standard Time (Canada/ Saskatchewan)'), - 'America/Chicago' => array('offset' => '-6', 'offset_text' => '[GMT-06:00]', 'name' => 'Central Standard Time (US & Canada)'), - 'America/Phoenix' => array('offset' => '-7', 'offset_text' => '[GMT-07:00]', 'name' => 'Mountain Standard Time (US/ Arizona)'), - 'America/Los_Angeles' => array('offset' => '-8', 'offset_text' => '[GMT-08:00]', 'name' => 'Pacific Standard Time (US & Canada)'), - 'America/Anchorage' => array('offset' => '-9', 'offset_text' => '[GMT-09:00]', 'name' => 'Alaska Standard Time (AST)'), - 'America/Adak' => array('offset' => '-10', 'offset_text' => '[GMT-10:00]', 'name' => 'Hawaii-Aleutian Standard Time (America/ Adak)'), - ), - 'Antarctica' => array( - 'Antarctica/Syowa' => array('offset' => '3', 'offset_text' => '[GMT+03:00]', 'name' => 'Syowa Time (Antarctica/ Syowa)'), - 'Antarctica/Mawson' => array('offset' => '6', 'offset_text' => '[GMT+06:00]', 'name' => 'Mawson Time (Antarctica/ Mawson)'), - 'Antarctica/Vostok' => array('offset' => '6', 'offset_text' => '[GMT+06:00]', 'name' => 'Vostok Time (Antarctica/ Vostok)'), - 'Antarctica/Davis' => array('offset' => '7', 'offset_text' => '[GMT+07:00]', 'name' => 'Davis Time (Antarctica/ Davis)'), - 'Antarctica/DumontDUrville' => array('offset' => '10', 'offset_text' => '[GMT+10:00]', 'name' => 'Dumont-d\'Urville Time (Antarctica/ DumontDUrville)'), - 'Antarctica/Rothera' => array('offset' => '-3', 'offset_text' => '[GMT-03:00]', 'name' => 'Rothera Time (Antarctica/ Rothera)'), - ), - 'Asia' => array( - 'Asia/Jerusalem' => array('offset' => '2', 'offset_text' => '[GMT+02:00]', 'name' => 'Israel Standard Time (Asia/ Jerusalem)'), - 'Asia/Baghdad' => array('offset' => '3', 'offset_text' => '[GMT+03:00]', 'name' => 'Arabia Standard Time (Asia/ Baghdad)'), - 'Asia/Kuwait' => array('offset' => '3', 'offset_text' => '[GMT+03:00]', 'name' => 'Arabia Standard Time (Asia/ Kuwait)'), - 'Asia/Tehran' => array('offset' => '3.5', 'offset_text' => '[GMT+03:30]', 'name' => 'Iran Standard Time (Asia/ Tehran)'), - 'Asia/Aqtau' => array('offset' => '4', 'offset_text' => '[GMT+04:00]', 'name' => 'Aqtau Time (Asia/ Aqtau)'), - 'Asia/Yerevan' => array('offset' => '4', 'offset_text' => '[GMT+04:00]', 'name' => 'Armenia Time (NET)'), - 'Asia/Baku' => array('offset' => '4', 'offset_text' => '[GMT+04:00]', 'name' => 'Azerbaijan Time (Asia/ Baku)'), - 'Asia/Tbilisi' => array('offset' => '4', 'offset_text' => '[GMT+04:00]', 'name' => 'Georgia Time (Asia/ Tbilisi)'), - 'Asia/Dubai' => array('offset' => '4', 'offset_text' => '[GMT+04:00]', 'name' => 'Gulf Standard Time (Asia/ Dubai)'), - 'Asia/Oral' => array('offset' => '4', 'offset_text' => '[GMT+04:00]', 'name' => 'Oral Time (Asia/ Oral)'), - 'Asia/Kabul' => array('offset' => '4.5', 'offset_text' => '[GMT+04:30]', 'name' => 'Afghanistan Time (Asia/ Kabul)'), - 'Asia/Aqtobe' => array('offset' => '5', 'offset_text' => '[GMT+05:00]', 'name' => 'Aqtobe Time (Asia/ Aqtobe)'), - 'Asia/Bishkek' => array('offset' => '5', 'offset_text' => '[GMT+05:00]', 'name' => 'Kirgizstan Time (Asia/ Bishkek)'), - 'Asia/Karachi' => array('offset' => '5', 'offset_text' => '[GMT+05:00]', 'name' => 'Pakistan Time (PLT)'), - 'Asia/Dushanbe' => array('offset' => '5', 'offset_text' => '[GMT+05:00]', 'name' => 'Tajikistan Time (Asia/ Dushanbe)'), - 'Asia/Ashgabat' => array('offset' => '5', 'offset_text' => '[GMT+05:00]', 'name' => 'Turkmenistan Time (Asia/ Ashgabat)'), - 'Asia/Tashkent' => array('offset' => '5', 'offset_text' => '[GMT+05:00]', 'name' => 'Uzbekistan Time (Asia/ Tashkent)'), - 'Asia/Yekaterinburg' => array('offset' => '5', 'offset_text' => '[GMT+05:00]', 'name' => 'Yekaterinburg Time (Asia/ Yekaterinburg)'), - 'Asia/Katmandu' => array('offset' => '5.75', 'offset_text' => '[GMT+05:45]', 'name' => 'Nepal Time (Asia/ Katmandu)'), - 'Asia/Almaty' => array('offset' => '6', 'offset_text' => '[GMT+06:00]', 'name' => 'Alma-Ata Time (Asia/ Almaty)'), - 'Asia/Thimbu' => array('offset' => '6', 'offset_text' => '[GMT+06:00]', 'name' => 'Bhutan Time (Asia/ Thimbu)'), - 'Asia/Novosibirsk' => array('offset' => '6', 'offset_text' => '[GMT+06:00]', 'name' => 'Novosibirsk Time (Asia/ Novosibirsk)'), - 'Asia/Omsk' => array('offset' => '6', 'offset_text' => '[GMT+06:00]', 'name' => 'Omsk Time (Asia/ Omsk)'), - 'Asia/Qyzylorda' => array('offset' => '6', 'offset_text' => '[GMT+06:00]', 'name' => 'Qyzylorda Time (Asia/ Qyzylorda)'), - 'Asia/Colombo' => array('offset' => '6', 'offset_text' => '[GMT+06:00]', 'name' => 'Sri Lanka Time (Asia/ Colombo)'), - 'Asia/Rangoon' => array('offset' => '6.5', 'offset_text' => '[GMT+06:30]', 'name' => 'Myanmar Time (Asia/ Rangoon)'), - 'Asia/Hovd' => array('offset' => '7', 'offset_text' => '[GMT+07:00]', 'name' => 'Hovd Time (Asia/ Hovd)'), - 'Asia/Krasnoyarsk' => array('offset' => '7', 'offset_text' => '[GMT+07:00]', 'name' => 'Krasnoyarsk Time (Asia/ Krasnoyarsk)'), - 'Asia/Jakarta' => array('offset' => '7', 'offset_text' => '[GMT+07:00]', 'name' => 'West Indonesia Time (Asia/ Jakarta)'), - 'Asia/Brunei' => array('offset' => '8', 'offset_text' => '[GMT+08:00]', 'name' => 'Brunei Time (Asia/ Brunei)'), - 'Asia/Makassar' => array('offset' => '8', 'offset_text' => '[GMT+08:00]', 'name' => 'Central Indonesia Time (Asia/ Makassar)'), - 'Asia/Hong_Kong' => array('offset' => '8', 'offset_text' => '[GMT+08:00]', 'name' => 'Hong Kong Time (Asia/ Hong Kong)'), - 'Asia/Irkutsk' => array('offset' => '8', 'offset_text' => '[GMT+08:00]', 'name' => 'Irkutsk Time (Asia/ Irkutsk)'), - 'Asia/Kuala_Lumpur' => array('offset' => '8', 'offset_text' => '[GMT+08:00]', 'name' => 'Malaysia Time (Asia/ Kuala Lumpur)'), - 'Asia/Manila' => array('offset' => '8', 'offset_text' => '[GMT+08:00]', 'name' => 'Philippines Time (Asia/ Manila)'), - 'Asia/Shanghai' => array('offset' => '8', 'offset_text' => '[GMT+08:00]', 'name' => 'Shanghai Time (Asia/ Shanghai)'), - 'Asia/Singapore' => array('offset' => '8', 'offset_text' => '[GMT+08:00]', 'name' => 'Singapore Time (Asia/ Singapore)'), - 'Asia/Taipei' => array('offset' => '8', 'offset_text' => '[GMT+08:00]', 'name' => 'Taipei Time (Asia/ Taipei)'), - 'Asia/Ulaanbaatar' => array('offset' => '8', 'offset_text' => '[GMT+08:00]', 'name' => 'Ulaanbaatar Time (Asia/ Ulaanbaatar)'), - 'Asia/Choibalsan' => array('offset' => '9', 'offset_text' => '[GMT+09:00]', 'name' => 'Choibalsan Time (Asia/ Choibalsan)'), - 'Asia/Jayapura' => array('offset' => '9', 'offset_text' => '[GMT+09:00]', 'name' => 'East Indonesia Time (Asia/ Jayapura)'), - 'Asia/Dili' => array('offset' => '9', 'offset_text' => '[GMT+09:00]', 'name' => 'East Timor Time (Asia/ Dili)'), - 'Asia/Tokyo' => array('offset' => '9', 'offset_text' => '[GMT+09:00]', 'name' => 'Japan Standard Time (JST)'), - 'Asia/Seoul' => array('offset' => '9', 'offset_text' => '[GMT+09:00]', 'name' => 'Korea Standard Time (Asia/ Seoul)'), - 'Asia/Yakutsk' => array('offset' => '9', 'offset_text' => '[GMT+09:00]', 'name' => 'Yakutsk Time (Asia/ Yakutsk)'), - 'Asia/Sakhalin' => array('offset' => '10', 'offset_text' => '[GMT+10:00]', 'name' => 'Sakhalin Time (Asia/ Sakhalin)'), - 'Asia/Vladivostok' => array('offset' => '10', 'offset_text' => '[GMT+10:00]', 'name' => 'Vladivostok Time (Asia/ Vladivostok)'), - 'Asia/Magadan' => array('offset' => '11', 'offset_text' => '[GMT+11:00]', 'name' => 'Magadan Time (Asia/ Magadan)'), - 'Asia/Anadyr' => array('offset' => '12', 'offset_text' => '[GMT+12:00]', 'name' => 'Anadyr Time (Asia/ Anadyr)'), - 'Asia/Kamchatka' => array('offset' => '12', 'offset_text' => '[GMT+12:00]', 'name' => 'Petropavlovsk-Kamchatski Time (Asia/ Kamchatka)'), - ), - 'Atlantic Ocean' => array( - 'Atlantic/Jan_Mayen' => array('offset' => '1', 'offset_text' => '[GMT+01:00]', 'name' => 'Eastern Greenland Time (Atlantic/ Jan Mayen)'), - 'Atlantic/Azores' => array('offset' => '-1', 'offset_text' => '[GMT-01:00]', 'name' => 'Azores Time (Atlantic/ Azores)'), - 'Atlantic/Cape_Verde' => array('offset' => '-1', 'offset_text' => '[GMT-01:00]', 'name' => 'Cape Verde Time (Atlantic/ Cape Verde)'), - 'Atlantic/South_Georgia' => array('offset' => '-2', 'offset_text' => '[GMT-02:00]', 'name' => 'South Georgia Standard Time (Atlantic/ South Georgia)'), - 'Atlantic/Bermuda' => array('offset' => '-4', 'offset_text' => '[GMT-04:00]', 'name' => 'Atlantic Standard Time (Atlantic/ Bermuda)'), - 'Atlantic/Stanley' => array('offset' => '-4', 'offset_text' => '[GMT-04:00]', 'name' => 'Falkland Is. Time (Atlantic/ Stanley)'), - ), - 'Australia' => array( - 'Australia/Perth' => array('offset' => '8', 'offset_text' => '[GMT+08:00]', 'name' => 'Western Standard Time (Australia) (Australia/ Perth)'), - 'Australia/Broken_Hill' => array('offset' => '9.5', 'offset_text' => '[GMT+09:30]', 'name' => 'Central Standard Time (Australia/ Broken Hill)'), - 'Australia/Darwin' => array('offset' => '9.5', 'offset_text' => '[GMT+09:30]', 'name' => 'Central Standard Time (Northern Territory) (ACT)'), - 'Australia/Adelaide' => array('offset' => '9.5', 'offset_text' => '[GMT+09:30]', 'name' => 'Central Standard Time (South Australia) (Australia/ Adelaide)'), - 'Australia/Sydney' => array('offset' => '10', 'offset_text' => '[GMT+10:00]', 'name' => 'Eastern Standard Time (New South Wales) (Australia/ Sydney)'), - 'Australia/Brisbane' => array('offset' => '10', 'offset_text' => '[GMT+10:00]', 'name' => 'Eastern Standard Time (Queensland) (Australia/ Brisbane)'), - 'Australia/Hobart' => array('offset' => '10', 'offset_text' => '[GMT+10:00]', 'name' => 'Eastern Standard Time (Tasmania) (Australia/ Hobart)'), - 'Australia/Melbourne' => array('offset' => '10', 'offset_text' => '[GMT+10:00]', 'name' => 'Eastern Standard Time (Victoria) (Australia/ Melbourne)'), - 'Australia/Lord_Howe' => array('offset' => '10.5', 'offset_text' => '[GMT+10:30]', 'name' => 'Load Howe Standard Time (Australia/ Lord Howe)'), - ), - 'Europe' => array( - 'Europe/Lisbon' => array('offset' => '0', 'offset_text' => '[GMT+00:00]', 'name' => 'Western European Time (Europe/ Lisbon)'), - 'Europe/Berlin' => array('offset' => '1', 'offset_text' => '[GMT+01:00]', 'name' => 'Central European Time (Europe/ Berlin)'), - 'Europe/Istanbul' => array('offset' => '2', 'offset_text' => '[GMT+02:00]', 'name' => 'Eastern European Time (Europe/ Istanbul)'), - 'Europe/Moscow' => array('offset' => '3', 'offset_text' => '[GMT+03:00]', 'name' => 'Moscow Standard Time (Europe/ Moscow)'), - 'Europe/Samara' => array('offset' => '4', 'offset_text' => '[GMT+04:00]', 'name' => 'Samara Time (Europe/ Samara)'), - ), - 'Indian' => array( - 'Indian/Antananarivo' => array('offset' => '3', 'offset_text' => '[GMT+03:00]', 'name' => 'Antananarivo Time (Indian/ Antananarivo)'), - 'Indian/Comoro' => array('offset' => '3', 'offset_text' => '[GMT+03:00]', 'name' => 'Comoro Time (Indian/ Comoro)'), - 'Indian/Mayotte' => array('offset' => '3', 'offset_text' => '[GMT+03:00]', 'name' => 'Mayotte Time (Indian/ Mayotte)'), - 'Indian/Mauritius' => array('offset' => '4', 'offset_text' => '[GMT+04:00]', 'name' => 'Mauritius Time (Indian/ Mauritius)'), - 'Indian/Reunion' => array('offset' => '4', 'offset_text' => '[GMT+04:00]', 'name' => 'Reunion Time (Indian/ Reunion)'), - 'Indian/Mahe' => array('offset' => '4', 'offset_text' => '[GMT+04:00]', 'name' => 'Seychelles Time (Indian/ Mahe)'), - 'Indian/Kerguelen' => array('offset' => '5', 'offset_text' => '[GMT+05:00]', 'name' => 'French Southern & Antarctic Lands Time (Indian/ Kerguelen)'), - 'Indian/Maldives' => array('offset' => '5', 'offset_text' => '[GMT+05:00]', 'name' => 'Maldives Time (Indian/ Maldives)'), - 'Indian/IST' => array('offset' => '5.5', 'offset_text' => '[GMT+05:30]', 'name' => 'India Standard Time (India Time / IST)'), - 'Indian/Chagos' => array('offset' => '6', 'offset_text' => '[GMT+06:00]', 'name' => 'Indian Ocean Territory Time (Indian/ Chagos)'), - 'Indian/Cocos' => array('offset' => '6.5', 'offset_text' => '[GMT+06:30]', 'name' => 'Cocos Islands Time (Indian/ Cocos)'), - 'Indian/Christmas' => array('offset' => '7', 'offset_text' => '[GMT+07:00]', 'name' => 'Christmas Island Time (Indian/ Christmas)'), - ), - 'Pacific Ocean' => array( - 'Pacific/Palau' => array('offset' => '9', 'offset_text' => '[GMT+09:00]', 'name' => 'Palau Time (Pacific/ Palau)'), - 'Pacific/Guam' => array('offset' => '10', 'offset_text' => '[GMT+10:00]', 'name' => 'Chamorro Standard Time (Pacific/ Guam)'), - 'Pacific/Port_Moresby' => array('offset' => '10', 'offset_text' => '[GMT+10:00]', 'name' => 'Papua New Guinea Time (Pacific/ Port Moresby)'), - 'Pacific/Truk' => array('offset' => '10', 'offset_text' => '[GMT+10:00]', 'name' => 'Truk Time (Pacific/ Truk)'), - 'Pacific/Yap' => array('offset' => '10', 'offset_text' => '[GMT+10:00]', 'name' => 'Yap Time (Pacific/ Yap)'), - 'Pacific/Kosrae' => array('offset' => '11', 'offset_text' => '[GMT+11:00]', 'name' => 'Kosrae Time (Pacific/ Kosrae)'), - 'Pacific/Noumea' => array('offset' => '11', 'offset_text' => '[GMT+11:00]', 'name' => 'New Caledonia Time (Pacific/ Noumea)'), - 'Pacific/Ponape' => array('offset' => '11', 'offset_text' => '[GMT+11:00]', 'name' => 'Ponape Time (Pacific/ Ponape)'), - 'Pacific/Efate' => array('offset' => '11', 'offset_text' => '[GMT+11:00]', 'name' => 'Vanuatu Time (Pacific/ Efate)'), - 'Pacific/Norfolk' => array('offset' => '11.5', 'offset_text' => '[GMT+11:30]', 'name' => 'Norfolk Time (Pacific/ Norfolk)'), - 'Pacific/Fiji' => array('offset' => '12', 'offset_text' => '[GMT+12:00]', 'name' => 'Fiji Time (Pacific/ Fiji)'), - 'Pacific/Tarawa' => array('offset' => '12', 'offset_text' => '[GMT+12:00]', 'name' => 'Gilbert Is. Time (Pacific/ Tarawa)'), - 'Pacific/Majuro' => array('offset' => '12', 'offset_text' => '[GMT+12:00]', 'name' => 'Marshall Islands Time (Pacific/ Majuro)'), - 'Pacific/Nauru' => array('offset' => '12', 'offset_text' => '[GMT+12:00]', 'name' => 'Nauru Time (Pacific/ Nauru)'), - 'Pacific/Auckland' => array('offset' => '12', 'offset_text' => '[GMT+12:00]', 'name' => 'New Zealand Standard Time (Pacific/ Auckland)'), - 'Pacific/Funafuti' => array('offset' => '12', 'offset_text' => '[GMT+12:00]', 'name' => 'Tuvalu Time (Pacific/ Funafuti)'), - 'Pacific/Wake' => array('offset' => '12', 'offset_text' => '[GMT+12:00]', 'name' => 'Wake Time (Pacific/ Wake)'), - 'Pacific/Wallis' => array('offset' => '12', 'offset_text' => '[GMT+12:00]', 'name' => 'Wallis & Futuna Time (Pacific/ Wallis)'), - 'Pacific/Chatham' => array('offset' => '12.75', 'offset_text' => '[GMT+12:45]', 'name' => 'Chatham Standard Time (Pacific/ Chatham)'), - 'Pacific/Enderbury' => array('offset' => '13', 'offset_text' => '[GMT+13:00]', 'name' => 'Phoenix Is. Time (Pacific/ Enderbury)'), - 'Pacific/Tongatapu' => array('offset' => '13', 'offset_text' => '[GMT+13:00]', 'name' => 'Tonga Time (Pacific/ Tongatapu)'), - 'Pacific/Kiritimati' => array('offset' => '14', 'offset_text' => '[GMT+14:00]', 'name' => 'Line Is. Time (Pacific/ Kiritimati)'), - 'Pacific/Easter' => array('offset' => '-6', 'offset_text' => '[GMT-06:00]', 'name' => 'Easter Is. Time (Pacific/ Easter)'), - 'Pacific/Galapagos' => array('offset' => '-6', 'offset_text' => '[GMT-06:00]', 'name' => 'Galapagos Time (Pacific/ Galapagos)'), - 'Pacific/Pitcairn' => array('offset' => '-8', 'offset_text' => '[GMT-08:00]', 'name' => 'Pitcairn Standard Time (Pacific/ Pitcairn)'), - 'Pacific/Gambier' => array('offset' => '-9', 'offset_text' => '[GMT-09:00]', 'name' => 'Gambier Time (Pacific/ Gambier)'), - 'Pacific/Marquesas' => array('offset' => '-9.5', 'offset_text' => '[GMT-09:30]', 'name' => 'Marquesas Time (Pacific/ Marquesas)'), - 'Pacific/Rarotonga' => array('offset' => '-10', 'offset_text' => '[GMT-10:00]', 'name' => 'Cook Is. Time (Pacific/ Rarotonga)'), - 'Pacific/Tahiti' => array('offset' => '-10', 'offset_text' => '[GMT-10:00]', 'name' => 'Tahiti Time (Pacific/ Tahiti)'), - 'Pacific/Fakaofo' => array('offset' => '-10', 'offset_text' => '[GMT-10:00]', 'name' => 'Tokelau Time (Pacific/ Fakaofo)'), - 'Pacific/Niue' => array('offset' => '-11', 'offset_text' => '[GMT-11:00]', 'name' => 'Niue Time (Pacific/ Niue)'), - 'Pacific/Apia' => array('offset' => '-11', 'offset_text' => '[GMT-11:00]', 'name' => 'West Samoa Time (MIT)'), - ), - ); - } - + + /** + * Class default constructor + */ + function __construct() + { + } + + /** + * Returns the instance of object + * + * @return current class + */ + public static function init() + { + return parent::init(__CLASS__); + } + + /** + * Sets the time zone used by the application + * + * @param string $value + * + * @see http://php.net/manual/en/function.date-default-timezone-set.php + */ + public function setTimeZone($value) + { + date_default_timezone_set($value); + } + + /** + * Returns the time zone used by the application + * + * @return string + * @see http://php.net/manual/en/function.date-default-timezone-set.php + */ + public function getTimeZone() + { + return date_default_timezone_get(); + } + + /** + * Returns a list of locales + * + * @return array + */ + public function getLocales() + { + return [ + 'sq_AL' => A::t('i18n', 'languages.sq').' - '.A::t('i18n', 'countries.al'), + 'ar_AE' => A::t('i18n', 'languages.ar').' - '.A::t('i18n', 'countries.ae'), + 'ar_BH' => A::t('i18n', 'languages.ar').' - '.A::t('i18n', 'countries.bh'), + 'ar_DZ' => A::t('i18n', 'languages.ar').' - '.A::t('i18n', 'countries.dz'), + 'ar_EG' => A::t('i18n', 'languages.ar').' - '.A::t('i18n', 'countries.eg'), + 'ar_IN' => A::t('i18n', 'languages.ar').' - '.A::t('i18n', 'countries.in'), + 'ar_IQ' => A::t('i18n', 'languages.ar').' - '.A::t('i18n', 'countries.iq'), + 'ar_JO' => A::t('i18n', 'languages.ar').' - '.A::t('i18n', 'countries.jo'), + 'ar_KW' => A::t('i18n', 'languages.ar').' - '.A::t('i18n', 'countries.kw'), + 'ar_LB' => A::t('i18n', 'languages.ar').' - '.A::t('i18n', 'countries.lb'), + 'ar_LY' => A::t('i18n', 'languages.ar').' - '.A::t('i18n', 'countries.ly'), + 'ar_MA' => A::t('i18n', 'languages.ar').' - '.A::t('i18n', 'countries.ma'), + 'ar_OM' => A::t('i18n', 'languages.ar').' - '.A::t('i18n', 'countries.om'), + 'ar_QA' => A::t('i18n', 'languages.ar').' - '.A::t('i18n', 'countries.qa'), + 'ar_SA' => A::t('i18n', 'languages.ar').' - '.A::t('i18n', 'countries.sa'), + 'ar_SD' => A::t('i18n', 'languages.ar').' - '.A::t('i18n', 'countries.sd'), + 'ar_SY' => A::t('i18n', 'languages.ar').' - '.A::t('i18n', 'countries.sy'), + 'ar_TN' => A::t('i18n', 'languages.ar').' - '.A::t('i18n', 'countries.tn'), + 'ar_YE' => A::t('i18n', 'languages.ar').' - '.A::t('i18n', 'countries.ye'), + 'eu_ES' => A::t('i18n', 'languages.eu').' - '.A::t('i18n', 'countries.es'), + 'be_BY' => A::t('i18n', 'languages.be').' - '.A::t('i18n', 'countries.by'), + 'bg_BG' => A::t('i18n', 'languages.bg').' - '.A::t('i18n', 'countries.bg'), + 'ca_ES' => A::t('i18n', 'languages.ca').' - '.A::t('i18n', 'countries.es'), + 'zh_CN' => A::t('i18n', 'languages.zh').' - '.A::t('i18n', 'countries.cn'), + 'zh_HK' => A::t('i18n', 'languages.zh').' - '.A::t('i18n', 'countries.hk'), + 'zh_TW' => A::t('i18n', 'languages.zh').' - '.A::t('i18n', 'countries.tw'), + 'hr_HR' => A::t('i18n', 'languages.hr').' - '.A::t('i18n', 'countries.hr'), + 'cs_CZ' => A::t('i18n', 'languages.cs').' - '.A::t('i18n', 'countries.cz'), + 'da_DK' => A::t('i18n', 'languages.da').' - '.A::t('i18n', 'countries.dk'), + 'nl_BE' => A::t('i18n', 'languages.nl').' - '.A::t('i18n', 'countries.be'), + 'nl_NL' => A::t('i18n', 'languages.nl').' - '.A::t('i18n', 'countries.nl'), + 'de_AT' => A::t('i18n', 'languages.de').' - '.A::t('i18n', 'countries.at'), + 'de_BE' => A::t('i18n', 'languages.de').' - '.A::t('i18n', 'countries.be'), + 'de_CH' => A::t('i18n', 'languages.de').' - '.A::t('i18n', 'countries.ch'), + 'de_DE' => A::t('i18n', 'languages.de').' - '.A::t('i18n', 'countries.de'), + 'de_LU' => A::t('i18n', 'languages.de').' - '.A::t('i18n', 'countries.lu'), + 'en_AU' => A::t('i18n', 'languages.en').' - '.A::t('i18n', 'countries.au'), + 'en_CA' => A::t('i18n', 'languages.en').' - '.A::t('i18n', 'countries.ca'), + 'en_GB' => A::t('i18n', 'languages.en').' - '.A::t('i18n', 'countries.gb'), + 'en_IN' => A::t('i18n', 'languages.en').' - '.A::t('i18n', 'countries.in'), + 'en_NZ' => A::t('i18n', 'languages.en').' - '.A::t('i18n', 'countries.nz'), + 'en_PH' => A::t('i18n', 'languages.en').' - '.A::t('i18n', 'countries.ph'), + 'en_US' => A::t('i18n', 'languages.en').' - '.A::t('i18n', 'countries.us'), + 'en_ZA' => A::t('i18n', 'languages.en').' - '.A::t('i18n', 'countries.za'), + 'en_ZW' => A::t('i18n', 'languages.en').' - '.A::t('i18n', 'countries.zw'), + 'et_EE' => A::t('i18n', 'languages.et').' - '.A::t('i18n', 'countries.ee'), + 'fi_FI' => A::t('i18n', 'languages.fi').' - '.A::t('i18n', 'countries.fi'), + 'fo_FO' => A::t('i18n', 'languages.fo').' - '.A::t('i18n', 'countries.fo'), + 'fr_BE' => A::t('i18n', 'languages.fr').' - '.A::t('i18n', 'countries.be'), + 'fr_CA' => A::t('i18n', 'languages.fr').' - '.A::t('i18n', 'countries.ca'), + 'fr_CH' => A::t('i18n', 'languages.fr').' - '.A::t('i18n', 'countries.ch'), + 'fr_FR' => A::t('i18n', 'languages.fr').' - '.A::t('i18n', 'countries.fr'), + 'fr_LU' => A::t('i18n', 'languages.fr').' - '.A::t('i18n', 'countries.lu'), + 'gl_ES' => A::t('i18n', 'languages.gl').' - '.A::t('i18n', 'countries.es'), + 'el_GR' => A::t('i18n', 'languages.el').' - '.A::t('i18n', 'countries.gr'), + 'gu_IN' => A::t('i18n', 'languages.gu').' - '.A::t('i18n', 'countries.in'), + 'he_IL' => A::t('i18n', 'languages.he').' - '.A::t('i18n', 'countries.il'), + 'hi_IN' => A::t('i18n', 'languages.hi').' - '.A::t('i18n', 'countries.in'), + 'hu_HU' => A::t('i18n', 'languages.hu').' - '.A::t('i18n', 'countries.hu'), + 'id_ID' => A::t('i18n', 'languages.id').' - '.A::t('i18n', 'countries.id'), + 'is_IS' => A::t('i18n', 'languages.is').' - '.A::t('i18n', 'countries.is'), + 'it_CH' => A::t('i18n', 'languages.it').' - '.A::t('i18n', 'countries.ch'), + 'it_IT' => A::t('i18n', 'languages.it').' - '.A::t('i18n', 'countries.it'), + 'ja_JP' => A::t('i18n', 'languages.ja').' - '.A::t('i18n', 'countries.jp'), + 'ko_KR' => A::t('i18n', 'languages.ko').' - '.A::t('i18n', 'countries.kr'), + 'lt_LT' => A::t('i18n', 'languages.lt').' - '.A::t('i18n', 'countries.lt'), + 'lv_LV' => A::t('i18n', 'languages.lv').' - '.A::t('i18n', 'countries.lv'), + 'mk_MK' => A::t('i18n', 'languages.mk').' - '.A::t('i18n', 'countries.mk'), + 'mn_MN' => A::t('i18n', 'languages.mn').' - '.A::t('i18n', 'countries.mn'), + 'ms_MY' => A::t('i18n', 'languages.ms').' - '.A::t('i18n', 'countries.my'), + 'nb_NO' => A::t('i18n', 'languages.nb').' - '.A::t('i18n', 'countries.no'), + 'no_NO' => A::t('i18n', 'languages.no').' - '.A::t('i18n', 'countries.no'), + 'pl_PL' => A::t('i18n', 'languages.pl').' - '.A::t('i18n', 'countries.pl'), + 'pt_BR' => A::t('i18n', 'languages.pt').' - '.A::t('i18n', 'countries.br'), + 'pt_PT' => A::t('i18n', 'languages.pt').' - '.A::t('i18n', 'countries.pt'), + 'ro_RO' => A::t('i18n', 'languages.ro').' - '.A::t('i18n', 'countries.ro'), + 'ru_RU' => A::t('i18n', 'languages.ru').' - '.A::t('i18n', 'countries.ru'), + 'ru_UA' => A::t('i18n', 'languages.ru').' - '.A::t('i18n', 'countries.ua'), + 'sk_SK' => A::t('i18n', 'languages.sk').' - '.A::t('i18n', 'countries.sk'), + 'sl_SI' => A::t('i18n', 'languages.sl').' - '.A::t('i18n', 'countries.si'), + 'sr_YU' => A::t('i18n', 'languages.sr').' - '.A::t('i18n', 'countries.rs'), + 'es_AR' => A::t('i18n', 'languages.es').' - '.A::t('i18n', 'countries.ar'), + 'es_BO' => A::t('i18n', 'languages.es').' - '.A::t('i18n', 'countries.bo'), + 'es_CL' => A::t('i18n', 'languages.es').' - '.A::t('i18n', 'countries.cl'), + 'es_CO' => A::t('i18n', 'languages.es').' - '.A::t('i18n', 'countries.co'), + 'es_CR' => A::t('i18n', 'languages.es').' - '.A::t('i18n', 'countries.cr'), + 'es_DO' => A::t('i18n', 'languages.es').' - '.A::t('i18n', 'countries.do'), + 'es_EC' => A::t('i18n', 'languages.es').' - '.A::t('i18n', 'countries.ec'), + 'es_ES' => A::t('i18n', 'languages.es').' - '.A::t('i18n', 'countries.es'), + 'es_GT' => A::t('i18n', 'languages.es').' - '.A::t('i18n', 'countries.gt'), + 'es_HN' => A::t('i18n', 'languages.es').' - '.A::t('i18n', 'countries.hn'), + 'es_MX' => A::t('i18n', 'languages.es').' - '.A::t('i18n', 'countries.mx'), + 'es_NI' => A::t('i18n', 'languages.es').' - '.A::t('i18n', 'countries.ni'), + 'es_PA' => A::t('i18n', 'languages.es').' - '.A::t('i18n', 'countries.pa'), + 'es_PE' => A::t('i18n', 'languages.es').' - '.A::t('i18n', 'countries.pe'), + 'es_PR' => A::t('i18n', 'languages.es').' - '.A::t('i18n', 'countries.pr'), + 'es_PY' => A::t('i18n', 'languages.es').' - '.A::t('i18n', 'countries.py'), + 'es_SV' => A::t('i18n', 'languages.es').' - '.A::t('i18n', 'countries.sv'), + 'es_US' => A::t('i18n', 'languages.es').' - '.A::t('i18n', 'countries.us'), + 'es_UY' => A::t('i18n', 'languages.es').' - '.A::t('i18n', 'countries.uy'), + 'es_VE' => A::t('i18n', 'languages.es').' - '.A::t('i18n', 'countries.ve'), + 'sv_FI' => A::t('i18n', 'languages.sv').' - '.A::t('i18n', 'countries.fi'), + 'sv_SE' => A::t('i18n', 'languages.sv').' - '.A::t('i18n', 'countries.se'), + 'ta_IN' => A::t('i18n', 'languages.ta').' - '.A::t('i18n', 'countries.in'), + 'te_IN' => A::t('i18n', 'languages.te').' - '.A::t('i18n', 'countries.in'), + 'th_TH' => A::t('i18n', 'languages.th').' - '.A::t('i18n', 'countries.th'), + 'tr_TR' => A::t('i18n', 'languages.tr').' - '.A::t('i18n', 'countries.tr'), + 'uk_UA' => A::t('i18n', 'languages.uk').' - '.A::t('i18n', 'countries.ua'), + 'ur_PK' => A::t('i18n', 'languages.ur').' - '.A::t('i18n', 'countries.pk'), + 'vi_VN' => A::t('i18n', 'languages.vi').' - '.A::t('i18n', 'countries.vn'), + ]; + } + + /** + * Returns a timzone offset or full name by time zone name + * + * @param string $name + * @param string $type 'offset' - default, 'offset_name' or 'full_name' + * + * @return float|string + */ + public function getTimeZoneInfo($name = '', $type = 'offset') + { + $return = ''; + + if ( ! empty($name)) { + $timeZones = $this->getTimeZones(); + foreach ($timeZones as $timeZone) { + foreach ($timeZone as $zoneName => $zoneInfo) { + if (strtolower($zoneName) == strtolower($name)) { + if ($type == 'offset') { + $return = isset($zoneInfo['offset']) ? $zoneInfo['offset'] : ''; + } elseif ($type == 'offset_name') { + $return = (isset($zoneInfo['offset_text']) && isset($zoneInfo['name'])) + ? $zoneInfo['offset_text'] : ''; + } elseif ($type == 'full_name') { + $return = (isset($zoneInfo['offset_text']) && isset($zoneInfo['name'])) + ? $zoneInfo['offset_text'].' '.$zoneInfo['name'] : ''; + } + break(2); + } + } + } + } + + return $return; + } + + /** + * Returns a nested array of timzones by continents + * + * @return array + */ + public function getTimeZones() + { + return [ + 'Africa' => [ + 'Africa/Casablanca' => [ + 'offset' => '0', + 'offset_text' => '[GMT+00:00]', + 'name' => 'Western European Time (Africa/ Casablanca)' + ], + 'Africa/Algiers' => [ + 'offset' => '1', + 'offset_text' => '[GMT+01:00]', + 'name' => 'Central European Time (Africa/ Algiers)' + ], + 'Africa/Bangui' => [ + 'offset' => '1', + 'offset_text' => '[GMT+01:00]', + 'name' => 'Western African Time (Africa/ Bangui)' + ], + 'Africa/Windhoek' => [ + 'offset' => '1', + 'offset_text' => '[GMT+01:00]', + 'name' => 'Western African Time (Africa/ Windhoek)' + ], + 'Africa/Tripoli' => [ + 'offset' => '2', + 'offset_text' => '[GMT+02:00]', + 'name' => 'Eastern European Time (Africa/ Tripoli)' + ], + 'Africa/Johannesburg' => [ + 'offset' => '2', + 'offset_text' => '[GMT+02:00]', + 'name' => 'South Africa Standard Time (Africa/ Johannesburg)' + ], + 'Africa/Dar_es_Salaam' => [ + 'offset' => '3', + 'offset_text' => '[GMT+03:00]', + 'name' => 'Eastern African Time (EAT)' + ], + ], + 'America (North & South)' => [ + 'America/Scoresbysund' => [ + 'offset' => '-1', + 'offset_text' => '[GMT-01:00]', + 'name' => 'Eastern Greenland Time (America/ Scoresbysund)' + ], + 'America/Noronha' => [ + 'offset' => '-2', + 'offset_text' => '[GMT-02:00]', + 'name' => 'Fernando de Noronha Time (America/ Noronha)' + ], + 'America/Argentina/Buenos_Aires' => ['offset' => '-3', + 'offset_text' => '[GMT-03:00]', + 'name' => 'Argentine Time (AGT)' + ], + 'America/Belem' => ['offset' => '-3', + 'offset_text' => '[GMT-03:00]', + 'name' => 'Brazil Time (America/ Belem)' + ], + 'America/Sao_Paulo' => ['offset' => '-3', + 'offset_text' => '[GMT-03:00]', + 'name' => 'Brazil Time (BET)' + ], + 'America/Cayenne' => ['offset' => '-3', + 'offset_text' => '[GMT-03:00]', + 'name' => 'French Guiana Time (America/ Cayenne)' + ], + 'America/Miquelon' => ['offset' => '-3', + 'offset_text' => '[GMT-03:00]', + 'name' => 'Pierre & Miquelon Standard Time (America/ Miquelon)' + ], + 'America/Paramaribo' => ['offset' => '-3', + 'offset_text' => '[GMT-03:00]', + 'name' => 'Suriname Time (America/ Paramaribo)' + ], + 'America/Montevideo' => ['offset' => '-3', + 'offset_text' => '[GMT-03:00]', + 'name' => 'Uruguay Time (America/ Montevideo)' + ], + 'America/Godthab' => ['offset' => '-3', + 'offset_text' => '[GMT-03:00]', + 'name' => 'Western Greenland Time (America/ Godthab)' + ], + 'America/St_Johns' => ['offset' => '-3', + 'offset_text' => '[GMT-03:30]', + 'name' => 'Newfoundland Standard Time (America/ St Johns)' + ], + 'America/Cuiaba' => ['offset' => '-4', + 'offset_text' => '[GMT-04:00]', + 'name' => 'Amazon Standard Time (America/ Cuiaba)' + ], + 'America/Glace_Bay' => ['offset' => '-4', + 'offset_text' => '[GMT-04:00]', + 'name' => 'Atlantic Standard Time (America/ Glace Bay)' + ], + 'America/La_Paz' => ['offset' => '-4', + 'offset_text' => '[GMT-04:00]', + 'name' => 'Bolivia Time (America/ La Paz)' + ], + 'America/Santiago' => ['offset' => '-4', + 'offset_text' => '[GMT-04:00]', + 'name' => 'Chile Time (America/ Santiago)' + ], + 'America/Guyana' => ['offset' => '-4', + 'offset_text' => '[GMT-04:00]', + 'name' => 'Guyana Time (America/ Guyana)' + ], + 'America/Asuncion' => ['offset' => '-4', + 'offset_text' => '[GMT-04:00]', + 'name' => 'Paraguay Time (America/ Asuncion)' + ], + 'America/Caracas' => ['offset' => '-4', + 'offset_text' => '[GMT-04:00]', + 'name' => 'Venezuela Time (America/ Caracas)' + ], + 'America/Porto_Acre' => ['offset' => '-5', + 'offset_text' => '[GMT-05:00]', + 'name' => 'Acre Time (America/ Porto Acre)' + ], + 'America/Havana' => ['offset' => '-5', + 'offset_text' => '[GMT-05:00]', + 'name' => 'Central Standard Time (America/ Havana)' + ], + 'America/Bogota' => ['offset' => '-5', + 'offset_text' => '[GMT-05:00]', + 'name' => 'Colombia Time (America/ Bogota)' + ], + 'America/Jamaica' => ['offset' => '-5', + 'offset_text' => '[GMT-05:00]', + 'name' => 'Eastern Standard Time (America/ Jamaica)' + ], + 'America/Indianapolis' => ['offset' => '-5', + 'offset_text' => '[GMT-05:00]', + 'name' => 'Eastern Standard Time (US/ East-Indiana)' + ], + 'America/Guayaquil' => ['offset' => '-5', + 'offset_text' => '[GMT-05:00]', + 'name' => 'Ecuador Time (America/ Guayaquil)' + ], + 'America/Lima' => ['offset' => '-6', + 'offset_text' => '[GMT-05:00]', + 'name' => 'Peru Time (America/ Lima)' + ], + 'America/El_Salvador' => ['offset' => '-6', + 'offset_text' => '[GMT-06:00]', + 'name' => 'Central Standard Time (America/ El Salvador)' + ], + 'America/Regina' => ['offset' => '-6', + 'offset_text' => '[GMT-06:00]', + 'name' => 'Central Standard Time (Canada/ Saskatchewan)' + ], + 'America/Chicago' => ['offset' => '-6', + 'offset_text' => '[GMT-06:00]', + 'name' => 'Central Standard Time (US & Canada)' + ], + 'America/Phoenix' => ['offset' => '-7', + 'offset_text' => '[GMT-07:00]', + 'name' => 'Mountain Standard Time (US/ Arizona)' + ], + 'America/Los_Angeles' => ['offset' => '-8', + 'offset_text' => '[GMT-08:00]', + 'name' => 'Pacific Standard Time (US & Canada)' + ], + 'America/Anchorage' => ['offset' => '-9', + 'offset_text' => '[GMT-09:00]', + 'name' => 'Alaska Standard Time (AST)' + ], + 'America/Adak' => ['offset' => '-10', + 'offset_text' => '[GMT-10:00]', + 'name' => 'Hawaii-Aleutian Standard Time (America/ Adak)' + ], + ], + 'Antarctica' => [ + 'Antarctica/Syowa' => [ + 'offset' => '3', + 'offset_text' => '[GMT+03:00]', + 'name' => 'Syowa Time (Antarctica/ Syowa)' + ], + 'Antarctica/Mawson' => [ + 'offset' => '6', + 'offset_text' => '[GMT+06:00]', + 'name' => 'Mawson Time (Antarctica/ Mawson)' + ], + 'Antarctica/Vostok' => [ + 'offset' => '6', + 'offset_text' => '[GMT+06:00]', + 'name' => 'Vostok Time (Antarctica/ Vostok)' + ], + 'Antarctica/Davis' => [ + 'offset' => '7', + 'offset_text' => '[GMT+07:00]', + 'name' => 'Davis Time (Antarctica/ Davis)' + ], + 'Antarctica/DumontDUrville' => ['offset' => '10', + 'offset_text' => '[GMT+10:00]', + 'name' => 'Dumont-d\'Urville Time (Antarctica/ DumontDUrville)' + ], + 'Antarctica/Rothera' => ['offset' => '-3', + 'offset_text' => '[GMT-03:00]', + 'name' => 'Rothera Time (Antarctica/ Rothera)' + ], + ], + 'Asia' => [ + 'Asia/Jerusalem' => [ + 'offset' => '2', + 'offset_text' => '[GMT+02:00]', + 'name' => 'Israel Standard Time (Asia/ Jerusalem)' + ], + 'Asia/Baghdad' => [ + 'offset' => '3', + 'offset_text' => '[GMT+03:00]', + 'name' => 'Arabia Standard Time (Asia/ Baghdad)' + ], + 'Asia/Kuwait' => [ + 'offset' => '3', + 'offset_text' => '[GMT+03:00]', + 'name' => 'Arabia Standard Time (Asia/ Kuwait)' + ], + 'Asia/Tehran' => [ + 'offset' => '3.5', + 'offset_text' => '[GMT+03:30]', + 'name' => 'Iran Standard Time (Asia/ Tehran)' + ], + 'Asia/Aqtau' => [ + 'offset' => '4', + 'offset_text' => '[GMT+04:00]', + 'name' => 'Aqtau Time (Asia/ Aqtau)' + ], + 'Asia/Yerevan' => ['offset' => '4', + 'offset_text' => '[GMT+04:00]', + 'name' => 'Armenia Time (NET)' + ], + 'Asia/Baku' => [ + 'offset' => '4', + 'offset_text' => '[GMT+04:00]', + 'name' => 'Azerbaijan Time (Asia/ Baku)' + ], + 'Asia/Tbilisi' => [ + 'offset' => '4', + 'offset_text' => '[GMT+04:00]', + 'name' => 'Georgia Time (Asia/ Tbilisi)' + ], + 'Asia/Dubai' => [ + 'offset' => '4', + 'offset_text' => '[GMT+04:00]', + 'name' => 'Gulf Standard Time (Asia/ Dubai)' + ], + 'Asia/Oral' => [ + 'offset' => '4', + 'offset_text' => '[GMT+04:00]', + 'name' => 'Oral Time (Asia/ Oral)' + ], + 'Asia/Kabul' => [ + 'offset' => '4.5', + 'offset_text' => '[GMT+04:30]', + 'name' => 'Afghanistan Time (Asia/ Kabul)' + ], + 'Asia/Aqtobe' => [ + 'offset' => '5', + 'offset_text' => '[GMT+05:00]', + 'name' => 'Aqtobe Time (Asia/ Aqtobe)' + ], + 'Asia/Bishkek' => [ + 'offset' => '5', + 'offset_text' => '[GMT+05:00]', + 'name' => 'Kirgizstan Time (Asia/ Bishkek)' + ], + 'Asia/Karachi' => ['offset' => '5', + 'offset_text' => '[GMT+05:00]', + 'name' => 'Pakistan Time (PLT)' + ], + 'Asia/Dushanbe' => [ + 'offset' => '5', + 'offset_text' => '[GMT+05:00]', + 'name' => 'Tajikistan Time (Asia/ Dushanbe)' + ], + 'Asia/Ashgabat' => [ + 'offset' => '5', + 'offset_text' => '[GMT+05:00]', + 'name' => 'Turkmenistan Time (Asia/ Ashgabat)' + ], + 'Asia/Tashkent' => [ + 'offset' => '5', + 'offset_text' => '[GMT+05:00]', + 'name' => 'Uzbekistan Time (Asia/ Tashkent)' + ], + 'Asia/Yekaterinburg' => ['offset' => '5', + 'offset_text' => '[GMT+05:00]', + 'name' => 'Yekaterinburg Time (Asia/ Yekaterinburg)' + ], + 'Asia/Katmandu' => ['offset' => '5.75', + 'offset_text' => '[GMT+05:45]', + 'name' => 'Nepal Time (Asia/ Katmandu)' + ], + 'Asia/Almaty' => ['offset' => '6', + 'offset_text' => '[GMT+06:00]', + 'name' => 'Alma-Ata Time (Asia/ Almaty)' + ], + 'Asia/Thimbu' => ['offset' => '6', + 'offset_text' => '[GMT+06:00]', + 'name' => 'Bhutan Time (Asia/ Thimbu)' + ], + 'Asia/Novosibirsk' => ['offset' => '6', + 'offset_text' => '[GMT+06:00]', + 'name' => 'Novosibirsk Time (Asia/ Novosibirsk)' + ], + 'Asia/Omsk' => ['offset' => '6', + 'offset_text' => '[GMT+06:00]', + 'name' => 'Omsk Time (Asia/ Omsk)' + ], + 'Asia/Qyzylorda' => ['offset' => '6', + 'offset_text' => '[GMT+06:00]', + 'name' => 'Qyzylorda Time (Asia/ Qyzylorda)' + ], + 'Asia/Colombo' => ['offset' => '6', + 'offset_text' => '[GMT+06:00]', + 'name' => 'Sri Lanka Time (Asia/ Colombo)' + ], + 'Asia/Rangoon' => ['offset' => '6.5', + 'offset_text' => '[GMT+06:30]', + 'name' => 'Myanmar Time (Asia/ Rangoon)' + ], + 'Asia/Hovd' => ['offset' => '7', + 'offset_text' => '[GMT+07:00]', + 'name' => 'Hovd Time (Asia/ Hovd)' + ], + 'Asia/Krasnoyarsk' => ['offset' => '7', + 'offset_text' => '[GMT+07:00]', + 'name' => 'Krasnoyarsk Time (Asia/ Krasnoyarsk)' + ], + 'Asia/Jakarta' => ['offset' => '7', + 'offset_text' => '[GMT+07:00]', + 'name' => 'West Indonesia Time (Asia/ Jakarta)' + ], + 'Asia/Brunei' => ['offset' => '8', + 'offset_text' => '[GMT+08:00]', + 'name' => 'Brunei Time (Asia/ Brunei)' + ], + 'Asia/Makassar' => ['offset' => '8', + 'offset_text' => '[GMT+08:00]', + 'name' => 'Central Indonesia Time (Asia/ Makassar)' + ], + 'Asia/Hong_Kong' => ['offset' => '8', + 'offset_text' => '[GMT+08:00]', + 'name' => 'Hong Kong Time (Asia/ Hong Kong)' + ], + 'Asia/Irkutsk' => ['offset' => '8', + 'offset_text' => '[GMT+08:00]', + 'name' => 'Irkutsk Time (Asia/ Irkutsk)' + ], + 'Asia/Kuala_Lumpur' => ['offset' => '8', + 'offset_text' => '[GMT+08:00]', + 'name' => 'Malaysia Time (Asia/ Kuala Lumpur)' + ], + 'Asia/Manila' => ['offset' => '8', + 'offset_text' => '[GMT+08:00]', + 'name' => 'Philippines Time (Asia/ Manila)' + ], + 'Asia/Shanghai' => ['offset' => '8', + 'offset_text' => '[GMT+08:00]', + 'name' => 'Shanghai Time (Asia/ Shanghai)' + ], + 'Asia/Singapore' => ['offset' => '8', + 'offset_text' => '[GMT+08:00]', + 'name' => 'Singapore Time (Asia/ Singapore)' + ], + 'Asia/Taipei' => ['offset' => '8', + 'offset_text' => '[GMT+08:00]', + 'name' => 'Taipei Time (Asia/ Taipei)' + ], + 'Asia/Ulaanbaatar' => ['offset' => '8', + 'offset_text' => '[GMT+08:00]', + 'name' => 'Ulaanbaatar Time (Asia/ Ulaanbaatar)' + ], + 'Asia/Choibalsan' => ['offset' => '9', + 'offset_text' => '[GMT+09:00]', + 'name' => 'Choibalsan Time (Asia/ Choibalsan)' + ], + 'Asia/Jayapura' => ['offset' => '9', + 'offset_text' => '[GMT+09:00]', + 'name' => 'East Indonesia Time (Asia/ Jayapura)' + ], + 'Asia/Dili' => ['offset' => '9', + 'offset_text' => '[GMT+09:00]', + 'name' => 'East Timor Time (Asia/ Dili)' + ], + 'Asia/Tokyo' => ['offset' => '9', + 'offset_text' => '[GMT+09:00]', + 'name' => 'Japan Standard Time (JST)' + ], + 'Asia/Seoul' => ['offset' => '9', + 'offset_text' => '[GMT+09:00]', + 'name' => 'Korea Standard Time (Asia/ Seoul)' + ], + 'Asia/Yakutsk' => ['offset' => '9', + 'offset_text' => '[GMT+09:00]', + 'name' => 'Yakutsk Time (Asia/ Yakutsk)' + ], + 'Asia/Sakhalin' => ['offset' => '10', + 'offset_text' => '[GMT+10:00]', + 'name' => 'Sakhalin Time (Asia/ Sakhalin)' + ], + 'Asia/Vladivostok' => ['offset' => '10', + 'offset_text' => '[GMT+10:00]', + 'name' => 'Vladivostok Time (Asia/ Vladivostok)' + ], + 'Asia/Magadan' => ['offset' => '11', + 'offset_text' => '[GMT+11:00]', + 'name' => 'Magadan Time (Asia/ Magadan)' + ], + 'Asia/Anadyr' => ['offset' => '12', + 'offset_text' => '[GMT+12:00]', + 'name' => 'Anadyr Time (Asia/ Anadyr)' + ], + 'Asia/Kamchatka' => ['offset' => '12', + 'offset_text' => '[GMT+12:00]', + 'name' => 'Petropavlovsk-Kamchatski Time (Asia/ Kamchatka)' + ], + ], + 'Atlantic Ocean' => [ + 'Atlantic/Jan_Mayen' => [ + 'offset' => '1', + 'offset_text' => '[GMT+01:00]', + 'name' => 'Eastern Greenland Time (Atlantic/ Jan Mayen)' + ], + 'Atlantic/Azores' => [ + 'offset' => '-1', + 'offset_text' => '[GMT-01:00]', + 'name' => 'Azores Time (Atlantic/ Azores)' + ], + 'Atlantic/Cape_Verde' => [ + 'offset' => '-1', + 'offset_text' => '[GMT-01:00]', + 'name' => 'Cape Verde Time (Atlantic/ Cape Verde)' + ], + 'Atlantic/South_Georgia' => ['offset' => '-2', + 'offset_text' => '[GMT-02:00]', + 'name' => 'South Georgia Standard Time (Atlantic/ South Georgia)' + ], + 'Atlantic/Bermuda' => ['offset' => '-4', + 'offset_text' => '[GMT-04:00]', + 'name' => 'Atlantic Standard Time (Atlantic/ Bermuda)' + ], + 'Atlantic/Stanley' => ['offset' => '-4', + 'offset_text' => '[GMT-04:00]', + 'name' => 'Falkland Is. Time (Atlantic/ Stanley)' + ], + ], + 'Australia' => [ + 'Australia/Perth' => [ + 'offset' => '8', + 'offset_text' => '[GMT+08:00]', + 'name' => 'Western Standard Time (Australia) (Australia/ Perth)' + ], + 'Australia/Broken_Hill' => ['offset' => '9.5', + 'offset_text' => '[GMT+09:30]', + 'name' => 'Central Standard Time (Australia/ Broken Hill)' + ], + 'Australia/Darwin' => ['offset' => '9.5', + 'offset_text' => '[GMT+09:30]', + 'name' => 'Central Standard Time (Northern Territory) (ACT)' + ], + 'Australia/Adelaide' => ['offset' => '9.5', + 'offset_text' => '[GMT+09:30]', + 'name' => 'Central Standard Time (South Australia) (Australia/ Adelaide)' + ], + 'Australia/Sydney' => ['offset' => '10', + 'offset_text' => '[GMT+10:00]', + 'name' => 'Eastern Standard Time (New South Wales) (Australia/ Sydney)' + ], + 'Australia/Brisbane' => ['offset' => '10', + 'offset_text' => '[GMT+10:00]', + 'name' => 'Eastern Standard Time (Queensland) (Australia/ Brisbane)' + ], + 'Australia/Hobart' => ['offset' => '10', + 'offset_text' => '[GMT+10:00]', + 'name' => 'Eastern Standard Time (Tasmania) (Australia/ Hobart)' + ], + 'Australia/Melbourne' => ['offset' => '10', + 'offset_text' => '[GMT+10:00]', + 'name' => 'Eastern Standard Time (Victoria) (Australia/ Melbourne)' + ], + 'Australia/Lord_Howe' => ['offset' => '10.5', + 'offset_text' => '[GMT+10:30]', + 'name' => 'Load Howe Standard Time (Australia/ Lord Howe)' + ], + ], + 'Europe' => [ + 'Europe/Lisbon' => [ + 'offset' => '0', + 'offset_text' => '[GMT+00:00]', + 'name' => 'Western European Time (Europe/ Lisbon)' + ], + 'Europe/Berlin' => [ + 'offset' => '1', + 'offset_text' => '[GMT+01:00]', + 'name' => 'Central European Time (Europe/ Berlin)' + ], + 'Europe/Istanbul' => ['offset' => '2', + 'offset_text' => '[GMT+02:00]', + 'name' => 'Eastern European Time (Europe/ Istanbul)' + ], + 'Europe/Moscow' => ['offset' => '3', + 'offset_text' => '[GMT+03:00]', + 'name' => 'Moscow Standard Time (Europe/ Moscow)' + ], + 'Europe/Samara' => ['offset' => '4', + 'offset_text' => '[GMT+04:00]', + 'name' => 'Samara Time (Europe/ Samara)' + ], + ], + 'Indian' => [ + 'Indian/Antananarivo' => ['offset' => '3', + 'offset_text' => '[GMT+03:00]', + 'name' => 'Antananarivo Time (Indian/ Antananarivo)' + ], + 'Indian/Comoro' => ['offset' => '3', + 'offset_text' => '[GMT+03:00]', + 'name' => 'Comoro Time (Indian/ Comoro)' + ], + 'Indian/Mayotte' => ['offset' => '3', + 'offset_text' => '[GMT+03:00]', + 'name' => 'Mayotte Time (Indian/ Mayotte)' + ], + 'Indian/Mauritius' => ['offset' => '4', + 'offset_text' => '[GMT+04:00]', + 'name' => 'Mauritius Time (Indian/ Mauritius)' + ], + 'Indian/Reunion' => ['offset' => '4', + 'offset_text' => '[GMT+04:00]', + 'name' => 'Reunion Time (Indian/ Reunion)' + ], + 'Indian/Mahe' => ['offset' => '4', + 'offset_text' => '[GMT+04:00]', + 'name' => 'Seychelles Time (Indian/ Mahe)' + ], + 'Indian/Kerguelen' => ['offset' => '5', + 'offset_text' => '[GMT+05:00]', + 'name' => 'French Southern & Antarctic Lands Time (Indian/ Kerguelen)' + ], + 'Indian/Maldives' => ['offset' => '5', + 'offset_text' => '[GMT+05:00]', + 'name' => 'Maldives Time (Indian/ Maldives)' + ], + 'Indian/IST' => ['offset' => '5.5', + 'offset_text' => '[GMT+05:30]', + 'name' => 'India Standard Time (India Time / IST)' + ], + 'Indian/Chagos' => ['offset' => '6', + 'offset_text' => '[GMT+06:00]', + 'name' => 'Indian Ocean Territory Time (Indian/ Chagos)' + ], + 'Indian/Cocos' => ['offset' => '6.5', + 'offset_text' => '[GMT+06:30]', + 'name' => 'Cocos Islands Time (Indian/ Cocos)' + ], + 'Indian/Christmas' => ['offset' => '7', + 'offset_text' => '[GMT+07:00]', + 'name' => 'Christmas Island Time (Indian/ Christmas)' + ], + ], + 'Pacific Ocean' => [ + 'Pacific/Palau' => [ + 'offset' => '9', + 'offset_text' => '[GMT+09:00]', + 'name' => 'Palau Time (Pacific/ Palau)' + ], + 'Pacific/Guam' => [ + 'offset' => '10', + 'offset_text' => '[GMT+10:00]', + 'name' => 'Chamorro Standard Time (Pacific/ Guam)' + ], + 'Pacific/Port_Moresby' => ['offset' => '10', + 'offset_text' => '[GMT+10:00]', + 'name' => 'Papua New Guinea Time (Pacific/ Port Moresby)' + ], + 'Pacific/Truk' => ['offset' => '10', + 'offset_text' => '[GMT+10:00]', + 'name' => 'Truk Time (Pacific/ Truk)' + ], + 'Pacific/Yap' => ['offset' => '10', + 'offset_text' => '[GMT+10:00]', + 'name' => 'Yap Time (Pacific/ Yap)' + ], + 'Pacific/Kosrae' => ['offset' => '11', + 'offset_text' => '[GMT+11:00]', + 'name' => 'Kosrae Time (Pacific/ Kosrae)' + ], + 'Pacific/Noumea' => ['offset' => '11', + 'offset_text' => '[GMT+11:00]', + 'name' => 'New Caledonia Time (Pacific/ Noumea)' + ], + 'Pacific/Ponape' => ['offset' => '11', + 'offset_text' => '[GMT+11:00]', + 'name' => 'Ponape Time (Pacific/ Ponape)' + ], + 'Pacific/Efate' => ['offset' => '11', + 'offset_text' => '[GMT+11:00]', + 'name' => 'Vanuatu Time (Pacific/ Efate)' + ], + 'Pacific/Norfolk' => ['offset' => '11.5', + 'offset_text' => '[GMT+11:30]', + 'name' => 'Norfolk Time (Pacific/ Norfolk)' + ], + 'Pacific/Fiji' => ['offset' => '12', + 'offset_text' => '[GMT+12:00]', + 'name' => 'Fiji Time (Pacific/ Fiji)' + ], + 'Pacific/Tarawa' => ['offset' => '12', + 'offset_text' => '[GMT+12:00]', + 'name' => 'Gilbert Is. Time (Pacific/ Tarawa)' + ], + 'Pacific/Majuro' => ['offset' => '12', + 'offset_text' => '[GMT+12:00]', + 'name' => 'Marshall Islands Time (Pacific/ Majuro)' + ], + 'Pacific/Nauru' => ['offset' => '12', + 'offset_text' => '[GMT+12:00]', + 'name' => 'Nauru Time (Pacific/ Nauru)' + ], + 'Pacific/Auckland' => ['offset' => '12', + 'offset_text' => '[GMT+12:00]', + 'name' => 'New Zealand Standard Time (Pacific/ Auckland)' + ], + 'Pacific/Funafuti' => ['offset' => '12', + 'offset_text' => '[GMT+12:00]', + 'name' => 'Tuvalu Time (Pacific/ Funafuti)' + ], + 'Pacific/Wake' => ['offset' => '12', + 'offset_text' => '[GMT+12:00]', + 'name' => 'Wake Time (Pacific/ Wake)' + ], + 'Pacific/Wallis' => ['offset' => '12', + 'offset_text' => '[GMT+12:00]', + 'name' => 'Wallis & Futuna Time (Pacific/ Wallis)' + ], + 'Pacific/Chatham' => ['offset' => '12.75', + 'offset_text' => '[GMT+12:45]', + 'name' => 'Chatham Standard Time (Pacific/ Chatham)' + ], + 'Pacific/Enderbury' => ['offset' => '13', + 'offset_text' => '[GMT+13:00]', + 'name' => 'Phoenix Is. Time (Pacific/ Enderbury)' + ], + 'Pacific/Tongatapu' => ['offset' => '13', + 'offset_text' => '[GMT+13:00]', + 'name' => 'Tonga Time (Pacific/ Tongatapu)' + ], + 'Pacific/Kiritimati' => ['offset' => '14', + 'offset_text' => '[GMT+14:00]', + 'name' => 'Line Is. Time (Pacific/ Kiritimati)' + ], + 'Pacific/Easter' => ['offset' => '-6', + 'offset_text' => '[GMT-06:00]', + 'name' => 'Easter Is. Time (Pacific/ Easter)' + ], + 'Pacific/Galapagos' => ['offset' => '-6', + 'offset_text' => '[GMT-06:00]', + 'name' => 'Galapagos Time (Pacific/ Galapagos)' + ], + 'Pacific/Pitcairn' => ['offset' => '-8', + 'offset_text' => '[GMT-08:00]', + 'name' => 'Pitcairn Standard Time (Pacific/ Pitcairn)' + ], + 'Pacific/Gambier' => ['offset' => '-9', + 'offset_text' => '[GMT-09:00]', + 'name' => 'Gambier Time (Pacific/ Gambier)' + ], + 'Pacific/Marquesas' => ['offset' => '-9.5', + 'offset_text' => '[GMT-09:30]', + 'name' => 'Marquesas Time (Pacific/ Marquesas)' + ], + 'Pacific/Rarotonga' => ['offset' => '-10', + 'offset_text' => '[GMT-10:00]', + 'name' => 'Cook Is. Time (Pacific/ Rarotonga)' + ], + 'Pacific/Tahiti' => ['offset' => '-10', + 'offset_text' => '[GMT-10:00]', + 'name' => 'Tahiti Time (Pacific/ Tahiti)' + ], + 'Pacific/Fakaofo' => ['offset' => '-10', + 'offset_text' => '[GMT-10:00]', + 'name' => 'Tokelau Time (Pacific/ Fakaofo)' + ], + 'Pacific/Niue' => ['offset' => '-11', + 'offset_text' => '[GMT-11:00]', + 'name' => 'Niue Time (Pacific/ Niue)' + ], + 'Pacific/Apia' => ['offset' => '-11', + 'offset_text' => '[GMT-11:00]', + 'name' => 'West Samoa Time (MIT)' + ], + ], + ]; + } + } diff --git a/framework/components/CLogger.php b/framework/components/CLogger.php index 6938a83..c975565 100644 --- a/framework/components/CLogger.php +++ b/framework/components/CLogger.php @@ -18,149 +18,157 @@ class CLogger extends CComponent { - - /** @var string - path to save log files */ - protected $_logPath; - /** @var int - permissions for log files */ - protected $_filePermissions = 0644; - /** @var int - log levels */ - protected $_threshold = 1; - /** @var array - array of threshold levels */ - protected $_thresholdArray = array(); - /** @var string - timestamp format */ - protected $_dateFormat = 'Y-m-d H:i:s'; - /** @var int - log files lifetime in days */ - protected $_lifetime = 30; - /** @var string - filename extension */ - protected $_fileExtension; - /** @var bool - whether logger can write or not to the log files */ - protected $_enabled = true; - /** @var array - array of logging levels */ - protected $_levels = array('error' => 1, 'debug' => 2, 'info' => 3, 'all' => 4); - - - /** - * Class default constructor - */ - function __construct() - { - $this->_enabled = CConfig::get('log.enable') !== '' ? CConfig::get('log.enable') : false; - $this->_logPath = APPHP_PATH.DS.(CConfig::get('log.path') !== '' ? CConfig::get('log.path') : 'protected/tmp/logs/'); - $this->_fileExtension = CConfig::exists('log.fileExtension') && CConfig::get('log.fileExtension') !== '' ? ltrim(CConfig::get('log.fileExtension'), '.') : 'php'; - $this->_dateFormat = CConfig::get('log.dateFormat') !== '' ? CConfig::get('log.dateFormat') : ''; - $this->_lifetime = CConfig::get('log.lifetime') !== '' ? CConfig::get('log.lifetime') : ''; - $logThreshold = CConfig::get('log.threshold') !== '' ? CConfig::get('log.threshold') : ''; - $logFilePermissions = CConfig::get('log.filePermissions') !== '' ? CConfig::get('log.filePermissions') : ''; - - if (!file_exists($this->_logPath)) { - mkdir($this->_logPath, 0755, true); - } - - if (!is_dir($this->_logPath) || !CFile::isWritable($this->_logPath)) { - $this->_enabled = false; - } - - if (is_numeric($logThreshold)) { - $this->_threshold = (int)$logThreshold; - } elseif (is_array($logThreshold)) { - $this->_threshold = 0; - $this->_thresholdArray = array_flip($logThreshold); - } - - if (!empty($this->$logFilePermissions) && is_int($this->$logFilePermissions)) { - $this->_filePermissions = $this->$logFilePermissions; - } - } - - /** - * Returns the instance of object - * @return current class - */ - public static function init() - { - return parent::init(__CLASS__); - } - - /** - * Write to log file - * This function will be called using the system helper CLog::addMessage() method - * @param string $level The error level: 'error', 'debug' or 'info' - * @param string $msg The error message - * @return bool - */ - public function writeLog($level, $msg = '') - { - if ($this->_enabled === false) { - return false; - } - - if ((!isset($this->_levels[$level]) || ($this->_levels[$level] > $this->_threshold)) - && !isset($this->_thresholdArray[$this->_levels[$level]])) { - return false; - } - - $filePath = $this->_logPath . 'log-' . date('Y-m-d') . '.' . $this->_fileExtension; - $message = ''; - - if (!file_exists($filePath)) { - $newFile = true; - // Only add protection to php files - if ($this->_fileExtension === 'php') { - $message .= "\n\n"; - } - - // Delete old log files - if (!empty($this->_lifetime) && is_int($this->_lifetime)) { - CFile::removeDirectoryOldestFile($this->_logPath, $this->_lifetime, array('error.log', 'payments.log')); - } - } - - // Open or create file for writing at end-of-file - if (!$fp = @fopen($filePath, 'ab')) { - return false; - } - - flock($fp, LOCK_EX); - - // Instantiating DateTime with microseconds appended to initial date is needed for proper support of this format - if (strpos($this->_dateFormat, 'u') !== false) { - $microtimeFull = microtime(true); - $microtimeShort = sprintf("%06d", ($microtimeFull - floor($microtimeFull)) * 1000000); - $date = new DateTime(date('Y-m-d H:i:s.' . $microtimeShort, $microtimeFull)); - $date = $date->format($this->_dateFormat); - } else { - $date = date($this->_dateFormat); - } - - $message .= $this->_formatLine(strtoupper($level), $date, $msg); - - for ($written = 0, $length = strlen($message); $written < $length; $written += $result) { - if (($result = fwrite($fp, substr($message, $written))) === false) { - break; - } - } - - flock($fp, LOCK_UN); - fclose($fp); - - if (isset($newFile) && $newFile === true) { - chmod($filePath, $this->_filePermissions); - } - - return is_int($result); - } - - /** - * Format the log line - * This function is used for extensibility of log formatting - * @param string $level The error level - * @param string $date Formatted date string - * @param string $message The log message - * @return string - */ - protected function _formatLine($level, $date, $message = '') - { - return $level . ' - ' . $date . ' --> ' . $message . "\n"; - } - + + /** @var string - path to save log files */ + protected $_logPath; + /** @var int - permissions for log files */ + protected $_filePermissions = 0644; + /** @var int - log levels */ + protected $_threshold = 1; + /** @var array - array of threshold levels */ + protected $_thresholdArray = []; + /** @var string - timestamp format */ + protected $_dateFormat = 'Y-m-d H:i:s'; + /** @var int - log files lifetime in days */ + protected $_lifetime = 30; + /** @var string - filename extension */ + protected $_fileExtension; + /** @var bool - whether logger can write or not to the log files */ + protected $_enabled = true; + /** @var array - array of logging levels */ + protected $_levels = ['error' => 1, 'debug' => 2, 'info' => 3, 'all' => 4]; + + + /** + * Class default constructor + */ + function __construct() + { + $this->_enabled = CConfig::get('log.enable') !== '' ? CConfig::get('log.enable') : false; + $this->_logPath = APPHP_PATH.DS.(CConfig::get('log.path') !== '' ? CConfig::get('log.path') + : 'protected/tmp/logs/'); + $this->_fileExtension = CConfig::exists('log.fileExtension') && CConfig::get('log.fileExtension') !== '' + ? ltrim(CConfig::get('log.fileExtension'), '.') : 'php'; + $this->_dateFormat = CConfig::get('log.dateFormat') !== '' ? CConfig::get('log.dateFormat') : ''; + $this->_lifetime = CConfig::get('log.lifetime') !== '' ? CConfig::get('log.lifetime') : ''; + $logThreshold = CConfig::get('log.threshold') !== '' ? CConfig::get('log.threshold') : ''; + $logFilePermissions = CConfig::get('log.filePermissions') !== '' ? CConfig::get('log.filePermissions') : ''; + + if ( ! file_exists($this->_logPath)) { + mkdir($this->_logPath, 0755, true); + } + + if ( ! is_dir($this->_logPath) || ! CFile::isWritable($this->_logPath)) { + $this->_enabled = false; + } + + if (is_numeric($logThreshold)) { + $this->_threshold = (int)$logThreshold; + } elseif (is_array($logThreshold)) { + $this->_threshold = 0; + $this->_thresholdArray = array_flip($logThreshold); + } + + if ( ! empty($this->$logFilePermissions) && is_int($this->$logFilePermissions)) { + $this->_filePermissions = $this->$logFilePermissions; + } + } + + /** + * Returns the instance of object + * + * @return current class + */ + public static function init() + { + return parent::init(__CLASS__); + } + + /** + * Write to log file + * This function will be called using the system helper CLog::addMessage() method + * + * @param string $level The error level: 'error', 'debug' or 'info' + * @param string $msg The error message + * + * @return bool + */ + public function writeLog($level, $msg = '') + { + if ($this->_enabled === false) { + return false; + } + + if (( ! isset($this->_levels[$level]) || ($this->_levels[$level] > $this->_threshold)) + && ! isset($this->_thresholdArray[$this->_levels[$level]]) + ) { + return false; + } + + $filePath = $this->_logPath.'log-'.date('Y-m-d').'.'.$this->_fileExtension; + $message = ''; + + if ( ! file_exists($filePath)) { + $newFile = true; + // Only add protection to php files + if ($this->_fileExtension === 'php') { + $message .= "\n\n"; + } + + // Delete old log files + if ( ! empty($this->_lifetime) && is_int($this->_lifetime)) { + CFile::removeDirectoryOldestFile($this->_logPath, $this->_lifetime, ['error.log', 'payments.log']); + } + } + + // Open or create file for writing at end-of-file + if ( ! $fp = @fopen($filePath, 'ab')) { + return false; + } + + flock($fp, LOCK_EX); + + // Instantiating DateTime with microseconds appended to initial date is needed for proper support of this format + if (strpos($this->_dateFormat, 'u') !== false) { + $microtimeFull = microtime(true); + $microtimeShort = sprintf("%06d", ($microtimeFull - floor($microtimeFull)) * 1000000); + $date = new DateTime(date('Y-m-d H:i:s.'.$microtimeShort, $microtimeFull)); + $date = $date->format($this->_dateFormat); + } else { + $date = date($this->_dateFormat); + } + + $message .= $this->_formatLine(strtoupper($level), $date, $msg); + + for ($written = 0, $length = strlen($message); $written < $length; $written += $result) { + if (($result = fwrite($fp, substr($message, $written))) === false) { + break; + } + } + + flock($fp, LOCK_UN); + fclose($fp); + + if (isset($newFile) && $newFile === true) { + chmod($filePath, $this->_filePermissions); + } + + return is_int($result); + } + + /** + * Format the log line + * This function is used for extensibility of log formatting + * + * @param string $level The error level + * @param string $date Formatted date string + * @param string $message The log message + * + * @return string + */ + protected function _formatLine($level, $date, $message = '') + { + return $level.' - '.$date.' --> '.$message."\n"; + } + } diff --git a/framework/components/CMessageSource.php b/framework/components/CMessageSource.php index 630f5da..3edc50c 100644 --- a/framework/components/CMessageSource.php +++ b/framework/components/CMessageSource.php @@ -16,97 +16,107 @@ class CMessageSource extends CComponent { - - /** @var string */ - private $_basePath; - /** @var array */ - private $_messages = array(); - - /** - * Class constructor - * @return void - */ - function __construct() - { - $this->_basePath = dirname(__FILE__); - } - - /** - * Returns the instance of object - * @return current class - */ - public static function init() - { - return parent::init(__CLASS__); - } - - /** - * Loads message translation for specified language and category - * @param string $category - * @param string $language - * @return array the loaded messages - */ - protected function _loadMessages($category, $language) - { - $messages = array(); - - if ($category == 'core') { - $messageFile = $this->_basePath . DS . '..' . DS . 'messages' . DS . $language . DS . $category . '.php'; - } elseif ($category == 'i18n') { - $messageFile = $this->_basePath . DS . '..' . DS . 'i18n' . DS . $language . '.php'; - } elseif ($category == 'setup') { - $messageFile = APPHP_PATH . DS . 'protected' . DS . 'modules' . DS . $category . DS . 'messages' . DS . $language . DS . $category . '.php'; - } else { - $messageFile = APPHP_PATH . DS . 'protected' . DS . 'messages' . DS . $language . DS . $category . '.php'; - } - - if (is_file($messageFile)) { - $messages = include($messageFile); - } - - return $messages; - } - - /** - * Translates a message to the specified language - * @param string $category - * @param string $message - * @param string $language - * @return string the translated message - */ - public function translate($category, $message, $language = null) - { - if ($language === null) { - $language = A::app()->getLanguage(); - } - - $key = $language . '.' . $category; - if (!isset($this->_messages[$key])) { - $this->_messages[$key] = $this->_loadMessages($category, $language); - } - - if (isset($this->_messages[$key][$message])) { - return $this->_messages[$key][$message]; - } elseif ($pos = strpos($message, '.') !== false) { - // Check sub-arrays (upto 2 levels) - $messageParts = explode('.', $message); - $parts = count($messageParts); - - if ($parts == 2) { - $arrMessages = isset($this->_messages[$key][$messageParts[0]]) ? $this->_messages[$key][$messageParts[0]] : ''; - if (is_array($arrMessages) && isset($arrMessages[$messageParts[1]])) { - return $arrMessages[$messageParts[1]]; - } - } elseif ($parts == 3) { - $arrSubMessages = isset($this->_messages[$key][$messageParts[0]][$messageParts[1]]) ? $this->_messages[$key][$messageParts[0]][$messageParts[1]] : ''; - if (is_array($arrSubMessages) && isset($arrSubMessages[$messageParts[2]])) { - return $arrSubMessages[$messageParts[2]]; - } - } - } - - // No message found, return it "as is" - return (APPHP_MODE == 'debug') ? '@@@' . $message : $message; - } - + + /** @var string */ + private $_basePath; + /** @var array */ + private $_messages = []; + + /** + * Class constructor + * + * @return void + */ + function __construct() + { + $this->_basePath = dirname(__FILE__); + } + + /** + * Returns the instance of object + * + * @return current class + */ + public static function init() + { + return parent::init(__CLASS__); + } + + /** + * Loads message translation for specified language and category + * + * @param string $category + * @param string $language + * + * @return array the loaded messages + */ + protected function _loadMessages($category, $language) + { + $messages = []; + + if ($category == 'core') { + $messageFile = $this->_basePath.DS.'..'.DS.'messages'.DS.$language.DS.$category.'.php'; + } elseif ($category == 'i18n') { + $messageFile = $this->_basePath.DS.'..'.DS.'i18n'.DS.$language.'.php'; + } elseif ($category == 'setup') { + $messageFile = APPHP_PATH.DS.'protected'.DS.'modules'.DS.$category.DS.'messages'.DS.$language.DS.$category.'.php'; + } else { + $messageFile = APPHP_PATH.DS.'protected'.DS.'messages'.DS.$language.DS.$category.'.php'; + } + + if (is_file($messageFile)) { + $messages = include($messageFile); + } + + return $messages; + } + + /** + * Translates a message to the specified language + * + * @param string $category + * @param string $message + * @param string $language + * + * @return string the translated message + */ + public function translate($category, $message, $language = null) + { + if ($language === null) { + $language = A::app()->getLanguage(); + } + + $key = $language.'.'.$category; + if ( ! isset($this->_messages[$key])) { + $this->_messages[$key] = $this->_loadMessages($category, $language); + } + + if (isset($this->_messages[$key][$message])) { + return $this->_messages[$key][$message]; + } elseif ($pos = strpos($message, '.') !== false) { + // Check sub-arrays (upto 2 levels) + $messageParts = explode('.', $message); + $parts = count($messageParts); + + if ($parts == 2) { + $arrMessages = isset($this->_messages[$key][$messageParts[0]]) + ? $this->_messages[$key][$messageParts[0]] + : ''; + if (is_array($arrMessages) && isset($arrMessages[$messageParts[1]])) { + return $arrMessages[$messageParts[1]]; + } + } elseif ($parts == 3) { + $arrSubMessages = isset($this->_messages[$key][$messageParts[0]][$messageParts[1]]) + ? $this->_messages[$key][$messageParts[0]][$messageParts[1]] + : ''; + if (is_array($arrSubMessages) && isset($arrSubMessages[$messageParts[2]])) { + return $arrSubMessages[$messageParts[2]]; + } + } + } + + // No message found, return it "as is" + return (APPHP_MODE == 'debug') ? '@@@'.$message : $message; + } + } \ No newline at end of file diff --git a/framework/components/CMobileDetect.php b/framework/components/CMobileDetect.php index 2c3a6af..950c05d 100644 --- a/framework/components/CMobileDetect.php +++ b/framework/components/CMobileDetect.php @@ -23,29 +23,29 @@ class CMobileDetect extends CComponent { - /** @var Mobile_detect */ - static private $_mobileDetect = null; - - - /** - * Class default constructor - */ - function __construct() - { - - } - - /** - * Returns the instance of object - * @return current class - */ - public static function init() - { - if (self::$_mobileDetect == null) { - self::$_mobileDetect = new Mobile_Detect(); - } - - return self::$_mobileDetect; - } - + /** @var Mobile_detect */ + static private $_mobileDetect = null; + + + /** + * Class default constructor + */ + function __construct() + { + } + + /** + * Returns the instance of object + * + * @return CMobileDetect + */ + public static function init() + { + if (self::$_mobileDetect == null) { + self::$_mobileDetect = new Mobile_Detect(); + } + + return self::$_mobileDetect; + } + } \ No newline at end of file diff --git a/framework/components/CShoppingCart.php b/framework/components/CShoppingCart.php index 1a00553..efd321e 100644 --- a/framework/components/CShoppingCart.php +++ b/framework/components/CShoppingCart.php @@ -29,411 +29,487 @@ class CShoppingCart extends CComponent { - - /** - * This is the regular expression rules that we use to validate the product ID - * They are: alpha-numeric, dashes, underscores or periods - * @var string - */ - protected $_productIdRules = '\.a-z0-9_-'; - /** - * This is the regular expression rules that we use to validate the product name - * alpha-numeric, dashes, underscores, colons or periods - * @var string - */ - protected $_productNameRules = '\w \-\.\:'; - /** - * Allow only safe product names - * @var bool - */ - protected $_productNameSafe = true; - /** - * Allow UFT-8 - * @var array - */ - protected $_utf8Enabled = true; - /** - * @var array - */ - protected $_cartContent = array(); - - - /** - * Class default constructor - */ - function __construct() - { - // Grab the shopping cart array from the session and initialize it - $this->_cartContent = A::app()->getSession()->get('shopping_cart_content', null); - if ($this->_cartContent === null) { - $this->_cartContent = array('cart_total' => 0, 'total_items' => 0); - } - } - - /** - * Returns the instance of object - * @return current class - */ - public static function init() - { - return parent::init(__CLASS__); - } - - /** - * Insert items into the cart and save them - * Ex.: $items = array( - * 'id' => 'SKU_123', - * 'qty' => 1, - * 'price' => 29.90, - * 'name' => 'T-Shirt', - * 'image' => 'images/product.png', - * 'options' => array('Size' => 'L', 'Color' => 'Red') - * ); - * @param array $items - * @return bool - */ - public function insert($items = array()) - { - // Check if any cart data was passed - if (!is_array($items) || count($items) === 0) { - return false; - } - - // We can insert a single product using a one-dimensional array or multiple products using a multi-dimensional one. - // The way we determine the array type is by looking for a required array key named "id" at the top level. - // If it's not found, we will assume it's a multi-dimensional array. - $saveCart = false; - if (isset($items['id'])) { - if (($rowId = $this->_insert($items))) { - $saveCart = true; - } - } else { - foreach ($items as $val) { - if (is_array($val) && isset($val['id'])) { - if ($this->_insert($val)) { - $saveCart = true; - } - } - } - } - - // Save the shopping cart data if insertion action was successful - if ($saveCart === true) { - $this->_saveCart(); - return isset($rowId) ? $rowId : true; - } - - return false; - } - - /** - * Update the cart - permits the quantity of a given item to be changed - * Ex.: $data = array( - * 'rowid' => 'b99ccdf16028f015540f341130b6d8ec', - * 'qty' => 3 - * ... - * ); - * @param array $items - * @return bool - */ - public function update($items = array()) - { - // Is any data passed? - if (!is_array($items) || count($items) === 0) { - return false; - } - - // You can either update a single product using a one-dimensional array, or multiple products using a multi-dimensional one. - // The way we determine the array type is by looking for a required array key named "rowid". - // If it's not found we assume it's a multi-dimensional array - $saveCart = false; - if (isset($items['rowid'])) { - if ($this->_update($items) === true) { - $saveCart = true; - } - } else { - foreach ($items as $val) { - if (is_array($val) && isset($val['rowid'])) { - if ($this->_update($val) === true) { - $saveCart = true; - } - } - } - } - - // Save the cart data if the insert was successful - if ($saveCart === true) { - $this->_saveCart(); - return true; - } - - return false; - } - - /** - * Remove Item - removes an item from the cart - * @param int - * @return bool - */ - public function remove($rowId) - { - // Unset & save - unset($this->_cartContent[$rowId]); - $this->_saveCart(); - - return true; - } - - - /** - * Destroy the cart - * Empties the cart and kills the cart session variable - * @return void - */ - public function destroy() - { - $this->_cartContent = array('cart_total' => 0, 'total_items' => 0); - A::app()->getSession()->remove('shopping_cart_content'); - } - - /** - * Cart Total returns count of items in cart - * @return int - */ - public function total() - { - return $this->_cartContent['cart_total']; - } - - /** - * Total Items - returns the total item count - * @return int - */ - public function totalItems() - { - return $this->_cartContent['total_items']; - } - - /** - * Cart Contents - * Returns the entire cart array - * @param bool - * @return array - */ - public function contents($newestFirst = false) - { - // Do we want the newest item first? - $cart = ($newestFirst) ? array_reverse($this->_cartContent) : $this->_cartContent; - - // Remove these so they don't create a problem when showing the cart table - if (isset($cart['total_items'])) unset($cart['total_items']); - if (isset($cart['cart_total'])) unset($cart['cart_total']); - - return $cart; - } - - /** - * Get cart item - * Returns the details of a specific item in the cart - * @param string $rowId - * @return array - */ - public function getItem($rowId) - { - return (in_array($rowId, array('total_items', 'cart_total'), true) || !isset($this->_cartContent[$rowId])) - ? false - : $this->_cartContent[$rowId]; - } - - /** - * Checks if cart item exists by row ID - * @param string $rowId - * @return bool - */ - public function itemExists($rowId) - { - return (in_array($rowId, array('total_items', 'cart_total'), true) || !isset($this->_cartContent[$rowId])) - ? false - : true; - } - - /** - * Checks if cart item exists - * @param string $productId - * @param int $returnType 0 - bool, 1 - rowId - * @return bool|string - */ - public function itemExistsByProductId($productId = null, $returnType = 0) - { - $return = false; - - foreach ($this->_cartContent as $key => $val) { - // Check if product with such ID exists - if ($val['id'] == $productId) { - $return = ($returnType == 1) ? $key : true; - break; - } - } - - return $return; - } - - /** - * Returns true value if the rowId that passed to this function correlates to an item that has options associated with it - * @param string $rowId - * @return bool - */ - public function hasOptions($rowId = '') - { - return (isset($this->_cartContent[$rowId]['options']) && count($this->_cartContent[$rowId]['options']) !== 0); - } - - /** - * Product options - * Returns the an array of options, for a particular product row ID - * @param string $rowId - * @return array - */ - public function productOptions($rowId = '') - { - return isset($this->_cartContent[$rowId]['options']) ? $this->_cartContent[$rowId]['options'] : array(); - } - - /** - * Insert single item into the cart and save them - * @param array $item - * @return bool - */ - protected function _insert($item = array()) - { - // Check if any cart data was passed - if (!is_array($item) || count($item) === 0) { - CDebug::addMessage('errors', 'cart_empty_data', A::t('core', 'The {method} method expects to be passed an array containing data.', array('{method}' => 'CShoppingCart::insert()'))); - return false; - } - - // Does the $item array contain an id, quantity, price, and name? These are required parameters. - if (!isset($item['id'], $item['qty'], $item['price'], $item['name'])) { - CDebug::addMessage('errors', 'cart_missing_params', A::t('core', 'The cart array must contain a product ID, quantity, price, and name.')); - return false; - } - - // Prepare the quantity. It can only be a number and trim any leading zeros - $item['qty'] = (float)$item['qty']; - - // If the quantity is zero or blank there's nothing for us to do - if ($item['qty'] == 0) { - return false; - } - - // Validate the product ID. It can only be alpha-numeric, dashes, underscores or periods - // Not totally sure we should impose this rule, but it seems prudent to standardize IDs. - // Note: These can be user-specified by setting the $this->_productIdRules variable. - if (!preg_match('/^[' . $this->_productIdRules . ']+$/i', $item['id'])) { - CDebug::addMessage('errors', 'cart_wrong_product_id', A::t('core', 'Invalid product ID. The product ID can only contain alpha-numeric characters, dashes underscores and periods.')); - return false; - } - - // Validate the product name. It can only be alpha-numeric, dashes, underscores, colons or periods. - // Note: These can be user-specified by setting the $this->_productNameRules variable. - if ($this->_productNameSafe && !preg_match('/^[' . $this->_productNameRules . ']+$/i' . ($this->_utf8Enabled ? 'u' : ''), $item['name'])) { - CDebug::addMessage('errors', 'cart_wrong_product_name', A::t('core', 'An invalid name was submitted as the product name: {item}. The name can only contain alpha-numeric characters, dashes, underscores, colons and spaces.', array('{item}' => $item['name']))); - return false; - } - - // Prep the price. Remove leading zeros and anything that isn't a number or decimal point. - $item['price'] = (float)$item['price']; - - // We now need to create a unique identifier for the item being inserted into the cart. - // Every time something is added to the cart it is stored in the master cart array. - // Each row in the cart array, however, must have a unique index that identifies not only - // a particular product, but makes it possible to store identical products with different options. - // If no options were submitted so we simply MD5 the product ID. - if (isset($item['options']) && count($item['options']) > 0) { - $rowId = md5($item['id'] . serialize($item['options'])); - } else { - $rowId = md5($item['id']); - } - - // Now that we have our unique "row ID", we'll add our cart items to the master array - // grab quantity if it's already there and add it on - $oldQuantity = isset($this->_cartContent[$rowId]['qty']) ? (int)$this->_cartContent[$rowId]['qty'] : 0; - - // Re-create the entry, just to make sure our index contains only the data from this submission - $item['rowid'] = $rowId; - $item['qty'] += $oldQuantity; - $this->_cartContent[$rowId] = $item; - - return $rowId; - } - - /** - * Update the cart - permits changing item properties - * @param array $items - * @return bool - */ - protected function _update($items = array()) - { - // Without these array indexes there is nothing we can do - if (!isset($items['rowid'], $this->_cartContent[$items['rowid']])) { - return false; - } - - // Prepare the quantity - if (isset($items['qty'])) { - $items['qty'] = (float)$items['qty']; - // Is the quantity zero - we remove the item from the cart - // If the quantity is greater than zero - we are update quantity - if ($items['qty'] == 0) { - unset($this->_cartContent[$items['rowid']]); - return true; - } - } - - // Find updatable keys - $keys = array_intersect(array_keys($this->_cartContent[$items['rowid']]), array_keys($items)); - // If a price was passed, make sure it contains a valid data - if (isset($items['price'])) { - $items['price'] = (float)$items['price']; - } - - // Product ID & name shouldn't be changed - foreach (array_diff($keys, array('id', 'name')) as $key) { - $this->_cartContent[$items['rowid']][$key] = $items[$key]; - } - - return true; - } - - /** - * Save the cart array to the session DB - * @return bool - */ - protected function _saveCart() - { - // Add the individual prices and set the cart sub-total - $this->_cartContent['total_items'] = $this->_cartContent['cart_total'] = 0; - foreach ($this->_cartContent as $key => $val) { - // We make sure the array contains the proper indexes - if (!is_array($val) || !isset($val['price'], $val['qty'])) { - continue; - } - - $this->_cartContent['cart_total'] += ($val['price'] * $val['qty']); - $this->_cartContent['total_items'] += $val['qty']; - $this->_cartContent[$key]['subtotal'] = ($this->_cartContent[$key]['price'] * $this->_cartContent[$key]['qty']); - } - - // If cart is empty - delete from the session cart content - if (count($this->_cartContent) <= 2) { - A::app()->getSession()->remove('shopping_cart_content'); - return false; - } - - // Pass to the session cart content - A::app()->getSession()->set('shopping_cart_content', $this->_cartContent); - - return true; - } - + + /** + * This is the regular expression rules that we use to validate the product ID + * They are: alpha-numeric, dashes, underscores or periods + * + * @var string + */ + protected $_productIdRules = '\.a-z0-9_-'; + /** + * This is the regular expression rules that we use to validate the product name + * alpha-numeric, dashes, underscores, colons or periods + * + * @var string + */ + protected $_productNameRules = '\w \-\.\:'; + /** + * Allow only safe product names + * + * @var bool + */ + protected $_productNameSafe = true; + /** + * Allow UFT-8 + * + * @var array + */ + protected $_utf8Enabled = true; + /** + * @var array + */ + protected $_cartContent = []; + + + /** + * Class default constructor + */ + function __construct() + { + // Grab the shopping cart array from the session and initialize it + $this->_cartContent = A::app()->getSession()->get('shopping_cart_content', null); + if ($this->_cartContent === null) { + $this->_cartContent = ['cart_total' => 0, 'total_items' => 0]; + } + } + + /** + * Returns the instance of object + * + * @return current class + */ + public static function init() + { + return parent::init(__CLASS__); + } + + /** + * Insert items into the cart and save them + * Ex.: $items = array( + * 'id' => 'SKU_123', + * 'qty' => 1, + * 'price' => 29.90, + * 'name' => 'T-Shirt', + * 'image' => 'images/product.png', + * 'options' => array('Size' => 'L', 'Color' => 'Red') + * ); + * + * @param array $items + * + * @return bool + */ + public function insert($items = []) + { + // Check if any cart data was passed + if ( ! is_array($items) || count($items) === 0) { + return false; + } + + // We can insert a single product using a one-dimensional array or multiple products using a multi-dimensional one. + // The way we determine the array type is by looking for a required array key named "id" at the top level. + // If it's not found, we will assume it's a multi-dimensional array. + $saveCart = false; + if (isset($items['id'])) { + if (($rowId = $this->_insert($items))) { + $saveCart = true; + } + } else { + foreach ($items as $val) { + if (is_array($val) && isset($val['id'])) { + if ($this->_insert($val)) { + $saveCart = true; + } + } + } + } + + // Save the shopping cart data if insertion action was successful + if ($saveCart === true) { + $this->_saveCart(); + + return isset($rowId) ? $rowId : true; + } + + return false; + } + + /** + * Update the cart - permits the quantity of a given item to be changed + * Ex.: $data = array( + * 'rowid' => 'b99ccdf16028f015540f341130b6d8ec', + * 'qty' => 3 + * ... + * ); + * + * @param array $items + * + * @return bool + */ + public function update($items = []) + { + // Is any data passed? + if ( ! is_array($items) || count($items) === 0) { + return false; + } + + // You can either update a single product using a one-dimensional array, or multiple products using a multi-dimensional one. + // The way we determine the array type is by looking for a required array key named "rowid". + // If it's not found we assume it's a multi-dimensional array + $saveCart = false; + if (isset($items['rowid'])) { + if ($this->_update($items) === true) { + $saveCart = true; + } + } else { + foreach ($items as $val) { + if (is_array($val) && isset($val['rowid'])) { + if ($this->_update($val) === true) { + $saveCart = true; + } + } + } + } + + // Save the cart data if the insert was successful + if ($saveCart === true) { + $this->_saveCart(); + + return true; + } + + return false; + } + + /** + * Remove Item - removes an item from the cart + * + * @param int + * + * @return bool + */ + public function remove($rowId) + { + // Unset & save + unset($this->_cartContent[$rowId]); + $this->_saveCart(); + + return true; + } + + + /** + * Destroy the cart + * Empties the cart and kills the cart session variable + * + * @return void + */ + public function destroy() + { + $this->_cartContent = ['cart_total' => 0, 'total_items' => 0]; + A::app()->getSession()->remove('shopping_cart_content'); + } + + /** + * Cart Total returns count of items in cart + * + * @return int + */ + public function total() + { + return $this->_cartContent['cart_total']; + } + + /** + * Total Items - returns the total item count + * + * @return int + */ + public function totalItems() + { + return $this->_cartContent['total_items']; + } + + /** + * Cart Contents + * Returns the entire cart array + * + * @param bool + * + * @return array + */ + public function contents($newestFirst = false) + { + // Do we want the newest item first? + $cart = ($newestFirst) ? array_reverse($this->_cartContent) : $this->_cartContent; + + // Remove these so they don't create a problem when showing the cart table + if (isset($cart['total_items'])) { + unset($cart['total_items']); + } + if (isset($cart['cart_total'])) { + unset($cart['cart_total']); + } + + return $cart; + } + + /** + * Get cart item + * Returns the details of a specific item in the cart + * + * @param string $rowId + * + * @return array + */ + public function getItem($rowId) + { + return (in_array($rowId, ['total_items', 'cart_total'], true) || ! isset($this->_cartContent[$rowId])) + ? false + : $this->_cartContent[$rowId]; + } + + /** + * Checks if cart item exists by row ID + * + * @param string $rowId + * + * @return bool + */ + public function itemExists($rowId) + { + return (in_array($rowId, ['total_items', 'cart_total'], true) || ! isset($this->_cartContent[$rowId])) + ? false + : true; + } + + /** + * Checks if cart item exists + * + * @param string $productId + * @param int $returnType 0 - bool, 1 - rowId + * + * @return bool|string + */ + public function itemExistsByProductId($productId = null, $returnType = 0) + { + $return = false; + + foreach ($this->_cartContent as $key => $val) { + // Check if product with such ID exists + if ($val['id'] == $productId) { + $return = ($returnType == 1) ? $key : true; + break; + } + } + + return $return; + } + + /** + * Returns true value if the rowId that passed to this function correlates to an item that has options associated with it + * + * @param string $rowId + * + * @return bool + */ + public function hasOptions($rowId = '') + { + return (isset($this->_cartContent[$rowId]['options']) && count($this->_cartContent[$rowId]['options']) !== 0); + } + + /** + * Product options + * Returns the an array of options, for a particular product row ID + * + * @param string $rowId + * + * @return array + */ + public function productOptions($rowId = '') + { + return isset($this->_cartContent[$rowId]['options']) ? $this->_cartContent[$rowId]['options'] : []; + } + + /** + * Insert single item into the cart and save them + * + * @param array $item + * + * @return bool + */ + protected function _insert($item = []) + { + // Check if any cart data was passed + if ( ! is_array($item) || count($item) === 0) { + CDebug::addMessage( + 'errors', + 'cart_empty_data', + A::t( + 'core', + 'The {method} method expects to be passed an array containing data.', + ['{method}' => 'CShoppingCart::insert()'] + ) + ); + + return false; + } + + // Does the $item array contain an id, quantity, price, and name? These are required parameters. + if ( ! isset($item['id'], $item['qty'], $item['price'], $item['name'])) { + CDebug::addMessage( + 'errors', + 'cart_missing_params', + A::t('core', 'The cart array must contain a product ID, quantity, price, and name.') + ); + + return false; + } + + // Prepare the quantity. It can only be a number and trim any leading zeros + $item['qty'] = (float)$item['qty']; + + // If the quantity is zero or blank there's nothing for us to do + if ($item['qty'] == 0) { + return false; + } + + // Validate the product ID. It can only be alpha-numeric, dashes, underscores or periods + // Not totally sure we should impose this rule, but it seems prudent to standardize IDs. + // Note: These can be user-specified by setting the $this->_productIdRules variable. + if ( ! preg_match('/^['.$this->_productIdRules.']+$/i', $item['id'])) { + CDebug::addMessage( + 'errors', + 'cart_wrong_product_id', + A::t( + 'core', + 'Invalid product ID. The product ID can only contain alpha-numeric characters, dashes underscores and periods.' + ) + ); + + return false; + } + + // Validate the product name. It can only be alpha-numeric, dashes, underscores, colons or periods. + // Note: These can be user-specified by setting the $this->_productNameRules variable. + if ($this->_productNameSafe + && ! preg_match( + '/^['.$this->_productNameRules.']+$/i'.($this->_utf8Enabled ? 'u' : ''), + $item['name'] + ) + ) { + CDebug::addMessage( + 'errors', + 'cart_wrong_product_name', + A::t( + 'core', + 'An invalid name was submitted as the product name: {item}. The name can only contain alpha-numeric characters, dashes, underscores, colons and spaces.', + ['{item}' => $item['name']] + ) + ); + + return false; + } + + // Prep the price. Remove leading zeros and anything that isn't a number or decimal point. + $item['price'] = (float)$item['price']; + + // We now need to create a unique identifier for the item being inserted into the cart. + // Every time something is added to the cart it is stored in the master cart array. + // Each row in the cart array, however, must have a unique index that identifies not only + // a particular product, but makes it possible to store identical products with different options. + // If no options were submitted so we simply MD5 the product ID. + if (isset($item['options']) && count($item['options']) > 0) { + $rowId = md5($item['id'].serialize($item['options'])); + } else { + $rowId = md5($item['id']); + } + + // Now that we have our unique "row ID", we'll add our cart items to the master array + // grab quantity if it's already there and add it on + $oldQuantity = isset($this->_cartContent[$rowId]['qty']) ? (int)$this->_cartContent[$rowId]['qty'] : 0; + + // Re-create the entry, just to make sure our index contains only the data from this submission + $item['rowid'] = $rowId; + $item['qty'] += $oldQuantity; + $this->_cartContent[$rowId] = $item; + + return $rowId; + } + + /** + * Update the cart - permits changing item properties + * + * @param array $items + * + * @return bool + */ + protected function _update($items = []) + { + // Without these array indexes there is nothing we can do + if ( ! isset($items['rowid'], $this->_cartContent[$items['rowid']])) { + return false; + } + + // Prepare the quantity + if (isset($items['qty'])) { + $items['qty'] = (float)$items['qty']; + // Is the quantity zero - we remove the item from the cart + // If the quantity is greater than zero - we are update quantity + if ($items['qty'] == 0) { + unset($this->_cartContent[$items['rowid']]); + + return true; + } + } + + // Find updatable keys + $keys = array_intersect(array_keys($this->_cartContent[$items['rowid']]), array_keys($items)); + // If a price was passed, make sure it contains a valid data + if (isset($items['price'])) { + $items['price'] = (float)$items['price']; + } + + // Product ID & name shouldn't be changed + foreach (array_diff($keys, ['id', 'name']) as $key) { + $this->_cartContent[$items['rowid']][$key] = $items[$key]; + } + + return true; + } + + /** + * Save the cart array to the session DB + * + * @return bool + */ + protected function _saveCart() + { + // Add the individual prices and set the cart sub-total + $this->_cartContent['total_items'] = $this->_cartContent['cart_total'] = 0; + foreach ($this->_cartContent as $key => $val) { + // We make sure the array contains the proper indexes + if ( ! is_array($val) || ! isset($val['price'], $val['qty'])) { + continue; + } + + $this->_cartContent['cart_total'] += ($val['price'] * $val['qty']); + $this->_cartContent['total_items'] += $val['qty']; + $this->_cartContent[$key]['subtotal'] = ($this->_cartContent[$key]['price'] + * $this->_cartContent[$key]['qty']); + } + + // If cart is empty - delete from the session cart content + if (count($this->_cartContent) <= 2) { + A::app()->getSession()->remove('shopping_cart_content'); + + return false; + } + + // Pass to the session cart content + A::app()->getSession()->set('shopping_cart_content', $this->_cartContent); + + return true; + } + } diff --git a/framework/components/CUri.php b/framework/components/CUri.php index 3d8e97d..17adf02 100644 --- a/framework/components/CUri.php +++ b/framework/components/CUri.php @@ -28,313 +28,346 @@ class CUri extends CComponent { - - /** @var array - list of cached URI segments */ - private $_keyVal = array(); - /** @var string - current URI string */ - private $_uriString = ''; - /** @var array - list of URI segments, starts at 0. */ - private $_segments = array(); - /** @var array - list of routed URI segments, starts at 0. */ - private $_rsegments = array(); - /** @var array - PCRE character group allowed in URI segments */ - private $_permittedUriChars = "a-z 0-9~%.:_\-"; - - - /** - * Class default constructor - */ - function __construct() - { - $this->_uriString = $this->_detectUri(); - $this->_explodeSegments(); - } - - /** - * Returns the instance of object - * @return current class - */ - public static function init() - { - return parent::init(__CLASS__); - } - - /** - * Fetch a URI Segment - * This function returns the URI segment based on the number provided. - * @param int $n - * @param bool $noResult - * @return string - */ - public function segment($n, $noResult = false) - { - return isset($this->_segments[$n]) ? $this->_segments[$n] : $noResult; - } - - /** - * Total number of segments - * @return int - */ - public function totalSegments() - { - return count($this->_segments); - } - - /** - * Total number of routed segments - * @return int - */ - public function rTotalSegments() - { - return count($this->_rsegments); - } - - /** - * Fetch the entire URI string - * @return string - */ - function uriString() - { - return $this->_uriString; - } - - /** - * Generate a key value pair from the URI string - * This function generates and associative array of URI data starting - * at the supplied segment. For example, if this is your URI: - * - * example.com/user/search/name/joe/location/UK/gender/male - * - * You can use this function to generate an array with this prototype: - * - * array ( - * name => joe - * location => UK - * gender => male - * ) - * - * @param int $n the starting segment number - * @param array $default an array of default values - * @return array - */ - public function uriToAssoc($n = 3, $default = array()) - { - return $this->_uriToAssoc($n, $default, 'segment'); - } - - /** - * Generate a URI string from an associative array - * @param array $array an associative array of key/values - * @return array - */ - public function assocToUri($array) - { - $temp = array(); - foreach ((array)$array as $key => $val) { - $temp[] = $key; - $temp[] = $val; - } - - return implode('/', $temp); - } - - /** - * Fetch a URI Segment and add a trailing slash - * @param int $n - * @param string $where - * @return string - */ - public function slashSegment($n, $where = 'trailing') - { - return $this->_slashSegment($n, $where, 'segment'); - } - - /** - * Fetch a URI Segment and add a trailing slash - * @param int $n - * @param string $where - * @return string - */ - public function rSlashSegment($n, $where = 'trailing') - { - return $this->_slashSegment($n, $where, 'rsegment'); - } - - /** - * Returns segment array - * @return array - */ - public function segmentArray() - { - return $this->_segments; - } - - /** - * Returns routed segment array - * @return array - */ - public function rSegmentArray() - { - return $this->_rsegments; - } - - /** - * Detects the URI - * This function will detect the URI automatically and fix the query string if necessary. - * @return string - */ - private function _detectUri() - { - if (!isset($_SERVER['REQUEST_URI']) || !isset($_SERVER['SCRIPT_NAME'])) { - return ''; - } - - $uri = $_SERVER['REQUEST_URI']; - if (strpos($uri, $_SERVER['SCRIPT_NAME']) === 0) { - $uri = substr($uri, strlen($_SERVER['SCRIPT_NAME'])); - } elseif (strpos($uri, dirname($_SERVER['SCRIPT_NAME'])) === 0) { - $uri = substr($uri, strlen(dirname($_SERVER['SCRIPT_NAME']))); - } - - // This section ensures that even on servers that require the URI to be in the query string (Nginx) - // a correct URI is found, and also fixes the QUERY_STRING server var. - if (strncmp($uri, '?/', 2) === 0) { - $uri = substr($uri, 2); - } - - if ($uri == '/' || empty($uri)) { - return '/'; - } - - $uri = parse_url($uri, PHP_URL_PATH); - - // Do some final cleaning of the URI and return it - return str_replace(array('//', '../'), '/', trim($uri, '/')); - } - - /** - * Filter segments for malicious characters - * @param string $str - * @return string - */ - private function _filterUri($str) - { - if ($str != '' && $this->_permittedUriChars != '') { - // preg_quote() in PHP 5.3 escapes -, so the str_replace() and addition of - to preg_quote() is to maintain backwards - // compatibility as many are unaware of how characters in the _permittedUriChars will be parsed as a regex pattern - if (!preg_match("|^[" . str_replace(array('\\-', '\-'), '-', preg_quote($this->_permittedUriChars, '-')) . "]+$|i", $str)) { - CDebug::addMessage('warnings', 'uri-disallowed-characters', A::t('core', 'The URI you submitted has disallowed characters.')); - } - } - - // Convert programmatic characters to entities - $bad = array('$', '(', ')', '%28', '%29'); - $good = array('$', '(', ')', '(', ')'); - - return str_replace($bad, $good, $str); - } - - /** - * Explode the URI Segments. The individual segments will be stored in the $this->_segments array. - * @return void - */ - private function _explodeSegments() - { - foreach (explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->_uriString)) as $val) { - // Filter segments for security - $val = trim($this->_filterUri($val)); - - if ($val != '') { - $this->_segments[] = $val; - } - } - } - - /** - * Generate a key value pair from the URI string or Re-routed URI string - * @param int $n the starting segment number - * @param array $default an array of default values - * @param string $which which array we should use - * @return array - */ - function _uriToAssoc($n = 3, $default = array(), $which = 'segment') - { - if ($which == 'segment') { - $total_segments = 'total_segments'; - $segment_array = 'segment_array'; - } else { - $total_segments = 'total_rsegments'; - $segment_array = 'rsegment_array'; - } - - if (!is_numeric($n)) { - return $default; - } - - if (isset($this->_keyVal[$n])) { - return $this->_keyVal[$n]; - } - - if ($this->$total_segments() < $n) { - if (count($default) == 0) { - return array(); - } - - $retval = array(); - foreach ($default as $val) { - $retval[$val] = FALSE; - } - return $retval; - } - - $segments = array_slice($this->$segment_array(), ($n - 1)); - - $i = 0; - $lastval = ''; - $retval = array(); - foreach ($segments as $seg) { - if ($i % 2) { - $retval[$lastval] = $seg; - } else { - $retval[$seg] = FALSE; - $lastval = $seg; - } - - $i++; - } - - if (count($default) > 0) { - foreach ($default as $val) { - if (!array_key_exists($val, $retval)) { - $retval[$val] = FALSE; - } - } - } - - // Cache the array for reuse - $this->_keyVal[$n] = $retval; - return $retval; - } - - /** - * Fetch a URI Segment and add a trailing slash - helper function - * @param int $n - * @param string $where - * @param string $which - * @return string - */ - private function _slashSegment($n, $where = 'trailing', $which = 'segment') - { - $leading = '/'; - $trailing = '/'; - - if ($where == 'trailing') { - $leading = ''; - } elseif ($where == 'leading') { - $trailing = ''; - } - - return $leading . $this->$which($n) . $trailing; - } - + + /** @var array - list of cached URI segments */ + private $_keyVal = []; + /** @var string - current URI string */ + private $_uriString = ''; + /** @var array - list of URI segments, starts at 0. */ + private $_segments = []; + /** @var array - list of routed URI segments, starts at 0. */ + private $_rsegments = []; + /** @var array - PCRE character group allowed in URI segments */ + private $_permittedUriChars = "a-z 0-9~%.:_\-"; + + + /** + * Class default constructor + */ + function __construct() + { + $this->_uriString = $this->_detectUri(); + $this->_explodeSegments(); + } + + /** + * Returns the instance of object + * + * @return current class + */ + public static function init() + { + return parent::init(__CLASS__); + } + + /** + * Fetch a URI Segment + * This function returns the URI segment based on the number provided. + * + * @param int $n + * @param bool $noResult + * + * @return string + */ + public function segment($n, $noResult = false) + { + return isset($this->_segments[$n]) ? $this->_segments[$n] : $noResult; + } + + /** + * Total number of segments + * + * @return int + */ + public function totalSegments() + { + return count($this->_segments); + } + + /** + * Total number of routed segments + * + * @return int + */ + public function rTotalSegments() + { + return count($this->_rsegments); + } + + /** + * Fetch the entire URI string + * + * @return string + */ + function uriString() + { + return $this->_uriString; + } + + /** + * Generate a key value pair from the URI string + * This function generates and associative array of URI data starting + * at the supplied segment. For example, if this is your URI: + * + * example.com/user/search/name/joe/location/UK/gender/male + * + * You can use this function to generate an array with this prototype: + * + * array ( + * name => joe + * location => UK + * gender => male + * ) + * + * @param int $n the starting segment number + * @param array $default an array of default values + * + * @return array + */ + public function uriToAssoc($n = 3, $default = []) + { + return $this->_uriToAssoc($n, $default, 'segment'); + } + + /** + * Generate a URI string from an associative array + * + * @param array $array an associative array of key/values + * + * @return array + */ + public function assocToUri($array) + { + $temp = []; + foreach ((array)$array as $key => $val) { + $temp[] = $key; + $temp[] = $val; + } + + return implode('/', $temp); + } + + /** + * Fetch a URI Segment and add a trailing slash + * + * @param int $n + * @param string $where + * + * @return string + */ + public function slashSegment($n, $where = 'trailing') + { + return $this->_slashSegment($n, $where, 'segment'); + } + + /** + * Fetch a URI Segment and add a trailing slash + * + * @param int $n + * @param string $where + * + * @return string + */ + public function rSlashSegment($n, $where = 'trailing') + { + return $this->_slashSegment($n, $where, 'rsegment'); + } + + /** + * Returns segment array + * + * @return array + */ + public function segmentArray() + { + return $this->_segments; + } + + /** + * Returns routed segment array + * + * @return array + */ + public function rSegmentArray() + { + return $this->_rsegments; + } + + /** + * Detects the URI + * This function will detect the URI automatically and fix the query string if necessary. + * + * @return string + */ + private function _detectUri() + { + if ( ! isset($_SERVER['REQUEST_URI']) || ! isset($_SERVER['SCRIPT_NAME'])) { + return ''; + } + + $uri = $_SERVER['REQUEST_URI']; + if (strpos($uri, $_SERVER['SCRIPT_NAME']) === 0) { + $uri = substr($uri, strlen($_SERVER['SCRIPT_NAME'])); + } elseif (strpos($uri, dirname($_SERVER['SCRIPT_NAME'])) === 0) { + $uri = substr($uri, strlen(dirname($_SERVER['SCRIPT_NAME']))); + } + + // This section ensures that even on servers that require the URI to be in the query string (Nginx) + // a correct URI is found, and also fixes the QUERY_STRING server var. + if (strncmp($uri, '?/', 2) === 0) { + $uri = substr($uri, 2); + } + + if ($uri == '/' || empty($uri)) { + return '/'; + } + + $uri = parse_url($uri, PHP_URL_PATH); + + // Do some final cleaning of the URI and return it + return str_replace(['//', '../'], '/', trim($uri, '/')); + } + + /** + * Filter segments for malicious characters + * + * @param string $str + * + * @return string + */ + private function _filterUri($str) + { + if ($str != '' && $this->_permittedUriChars != '') { + // preg_quote() in PHP 5.3 escapes -, so the str_replace() and addition of - to preg_quote() is to maintain backwards + // compatibility as many are unaware of how characters in the _permittedUriChars will be parsed as a regex pattern + if ( ! preg_match( + "|^[".str_replace(['\\-', '\-'], '-', preg_quote($this->_permittedUriChars, '-'))."]+$|i", + $str + ) + ) { + CDebug::addMessage( + 'warnings', + 'uri-disallowed-characters', + A::t('core', 'The URI you submitted has disallowed characters.') + ); + } + } + + // Convert programmatic characters to entities + $bad = ['$', '(', ')', '%28', '%29']; + $good = ['$', '(', ')', '(', ')']; + + return str_replace($bad, $good, $str); + } + + /** + * Explode the URI Segments. The individual segments will be stored in the $this->_segments array. + * + * @return void + */ + private function _explodeSegments() + { + foreach (explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->_uriString)) as $val) { + // Filter segments for security + $val = trim($this->_filterUri($val)); + + if ($val != '') { + $this->_segments[] = $val; + } + } + } + + /** + * Generate a key value pair from the URI string or Re-routed URI string + * + * @param int $n the starting segment number + * @param array $default an array of default values + * @param string $which which array we should use + * + * @return array + */ + function _uriToAssoc($n = 3, $default = [], $which = 'segment') + { + if ($which == 'segment') { + $total_segments = 'total_segments'; + $segment_array = 'segment_array'; + } else { + $total_segments = 'total_rsegments'; + $segment_array = 'rsegment_array'; + } + + if ( ! is_numeric($n)) { + return $default; + } + + if (isset($this->_keyVal[$n])) { + return $this->_keyVal[$n]; + } + + if ($this->$total_segments() < $n) { + if (count($default) == 0) { + return []; + } + + $retval = []; + foreach ($default as $val) { + $retval[$val] = false; + } + + return $retval; + } + + $segments = array_slice($this->$segment_array(), ($n - 1)); + + $i = 0; + $lastval = ''; + $retval = []; + foreach ($segments as $seg) { + if ($i % 2) { + $retval[$lastval] = $seg; + } else { + $retval[$seg] = false; + $lastval = $seg; + } + + $i++; + } + + if (count($default) > 0) { + foreach ($default as $val) { + if ( ! array_key_exists($val, $retval)) { + $retval[$val] = false; + } + } + } + + // Cache the array for reuse + $this->_keyVal[$n] = $retval; + + return $retval; + } + + /** + * Fetch a URI Segment and add a trailing slash - helper function + * + * @param int $n + * @param string $where + * @param string $which + * + * @return string + */ + private function _slashSegment($n, $where = 'trailing', $which = 'segment') + { + $leading = '/'; + $trailing = '/'; + + if ($where == 'trailing') { + $leading = ''; + } elseif ($where == 'leading') { + $trailing = ''; + } + + return $leading.$this->$which($n).$trailing; + } + } diff --git a/framework/console/CCacheClearCommand.php b/framework/console/CCacheClearCommand.php index 288f0ec..c571889 100644 --- a/framework/console/CCacheClearCommand.php +++ b/framework/console/CCacheClearCommand.php @@ -19,7 +19,9 @@ class CCacheClearCommand implements IConsoleCommand /** * Handle specific console command + * * @param string $param + * * @return string */ public static function handle($param = '') @@ -30,13 +32,13 @@ public static function handle($param = '') //var_dump($argc); if (empty($param)) { - $output .= CConsole::redbg("No cache type for deleting is defined. Type cache:clear -help") . PHP_EOL; + $output .= CConsole::redbg("No cache type for deleting is defined. Type cache:clear -help").PHP_EOL; // } elseif ($param === '-h' || $param === '-help') { // $output .= CConsole::yellow("Usage:") . PHP_EOL; // $output .= " cache:clear-all\tFlush all application cache". PHP_EOL; // $output .= " cache:clear [type]\tFlush specific application cache". PHP_EOL; // $output .= " \t\t\t[type] - the type of cache to be removed: 'db', 'css', 'js' or 'all'". PHP_EOL; -// } elseif (in_array($param, array('db', 'css', 'js', 'all'))) { +// } elseif (in_array($param, ['db', 'css', 'js', 'all'])) { // if($param == 'db' || $param == 'all'){ // if (CConfig::get('cache.db.path') == '') { // $output .= CConsole::redbg("Config value 'cache.db.path' is not defined. Check your configuration file.") . PHP_EOL; diff --git a/framework/console/CConsole.php b/framework/console/CConsole.php index 46c544d..f3879fb 100644 --- a/framework/console/CConsole.php +++ b/framework/console/CConsole.php @@ -30,32 +30,36 @@ class CConsole * * @param array $argv */ - public function __construct($argv = array()) + public function __construct($argv = []) { $this->argv = $argv; } /** * Get command + * * @return mixed|string */ public function getCommand() { - return !empty($this->argv[1]) ? $this->argv[1] : ''; + return ! empty($this->argv[1]) ? $this->argv[1] : ''; } /** * Get parameters + * * @return mixed|string */ public function getParams() { - return !empty($this->argv[2]) ? $this->argv[2] : ''; + return ! empty($this->argv[2]) ? $this->argv[2] : ''; } /** * Draw green line + * * @param string $string + * * @return string */ public static function green($string = '') @@ -65,7 +69,9 @@ public static function green($string = '') /** * Draw yellow line + * * @param string $string + * * @return string */ public static function yellow($string = '') @@ -87,11 +93,11 @@ public static function redbg($string = '', $padding = true) $output = ''; if ($padding) { - $output .= "\e[0;41m".str_pad(' ', $length, " ", STR_PAD_LEFT)."\e[0m" . PHP_EOL; + $output .= "\e[0;41m".str_pad(' ', $length, " ", STR_PAD_LEFT)."\e[0m".PHP_EOL; } $output .= "\e[0;41m".($padding ? ' ' : '').$string.($padding ? ' ' : '')."\e[0m".PHP_EOL; if ($padding) { - $output .= "\e[0;41m".str_pad(' ', $length, " ", STR_PAD_LEFT)."\e[0m" . PHP_EOL; + $output .= "\e[0;41m".str_pad(' ', $length, " ", STR_PAD_LEFT)."\e[0m".PHP_EOL; } return $output; diff --git a/framework/console/CConsoleCommand.php b/framework/console/CConsoleCommand.php index 9e10aed..905b5c6 100644 --- a/framework/console/CConsoleCommand.php +++ b/framework/console/CConsoleCommand.php @@ -32,12 +32,14 @@ class CConsoleCommand public function __construct($command = '', $param = '') { $this->command = $command; - $this->param = $param; + $this->param = $param; } /** * Run command - * @param bool $return + * + * @param bool $return + * * @return string */ public function run($return = false) @@ -45,7 +47,6 @@ public function run($return = false) $output = ''; switch ($this->command) { - case '-h': case '--help': case 'help': @@ -72,7 +73,7 @@ public function run($return = false) default: $output .= PHP_EOL; - $output .= CConsole::redbg("Command '".$this->command."' is not defined.") . PHP_EOL; + $output .= CConsole::redbg("Command '".$this->command."' is not defined.").PHP_EOL; $output .= 'Type "bin/aii --help" to check all commands and options.'; break; } diff --git a/framework/console/CHelpCommand.php b/framework/console/CHelpCommand.php index 39677ed..c56f99b 100644 --- a/framework/console/CHelpCommand.php +++ b/framework/console/CHelpCommand.php @@ -19,35 +19,36 @@ class CHelpCommand implements IConsoleCommand /** * Handle specific console command + * * @return string */ public static function handle() { $output = ''; - $output .= 'ApPHP Framework ' . CConsole::green(A::version()) . PHP_EOL; + $output .= 'ApPHP Framework '.CConsole::green(A::version()).PHP_EOL; $output .= PHP_EOL; - $output .= CConsole::yellow("Usage:") . PHP_EOL; - $output .= " command [options] [arguments]" . PHP_EOL . PHP_EOL; + $output .= CConsole::yellow("Usage:").PHP_EOL; + $output .= " command [options] [arguments]".PHP_EOL.PHP_EOL; - $output .= CConsole::yellow("Options:") . PHP_EOL; - $output .= " ".CConsole::green("-h, --help")."\t\tDisplay this help message". PHP_EOL; - $output .= " ".CConsole::green("-v, --version")."\t\tDisplay this application version". PHP_EOL; + $output .= CConsole::yellow("Options:").PHP_EOL; + $output .= " ".CConsole::green("-h, --help")."\t\tDisplay this help message".PHP_EOL; + $output .= " ".CConsole::green("-v, --version")."\t\tDisplay this application version".PHP_EOL; //-q, --quiet Do not output any message //-n, --no-interaction Do not ask any interactive question $output .= PHP_EOL; - $output .= CConsole::yellow("Available commands:") . PHP_EOL; + $output .= CConsole::yellow("Available commands:").PHP_EOL; - $output .= " ".CConsole::green("help")."\t\t\tHelp on console commands". PHP_EOL; + $output .= " ".CConsole::green("help")."\t\t\tHelp on console commands".PHP_EOL; - $output .= CConsole::yellow("cache") . PHP_EOL; - $output .= " ".CConsole::green("cache:clear")."\t\tFlush specific application cache". PHP_EOL; - $output .= " ".CConsole::green("cache:clear-all")."\tFlush all application cache". PHP_EOL; + $output .= CConsole::yellow("cache").PHP_EOL; + $output .= " ".CConsole::green("cache:clear")."\t\tFlush specific application cache".PHP_EOL; + $output .= " ".CConsole::green("cache:clear-all")."\tFlush all application cache".PHP_EOL; - $output .= CConsole::yellow("make") . PHP_EOL; - $output .= " ".CConsole::green("make:controller")."\tCreate controller". PHP_EOL; + $output .= CConsole::yellow("make").PHP_EOL; + $output .= " ".CConsole::green("make:controller")."\tCreate controller".PHP_EOL; return $output; } diff --git a/framework/console/CMakeControllerCommand.php b/framework/console/CMakeControllerCommand.php index cced01f..f74f6b6 100644 --- a/framework/console/CMakeControllerCommand.php +++ b/framework/console/CMakeControllerCommand.php @@ -26,7 +26,7 @@ class CMakeControllerCommand implements IConsoleCommand */ public static function handle($param = '') { - $output = 'Controller created: ' . $param; + $output = 'Controller created: '.$param; return $output; } diff --git a/framework/console/CVersionCommand.php b/framework/console/CVersionCommand.php index 11c0e5b..ef8953a 100644 --- a/framework/console/CVersionCommand.php +++ b/framework/console/CVersionCommand.php @@ -19,11 +19,12 @@ class CVersionCommand implements IConsoleCommand /** * Handle specific console command + * * @return string */ public static function handle() { - $output = 'ApPHP Framework ' . CConsole::green(A::version()); + $output = 'ApPHP Framework '.CConsole::green(A::version()); return $output; } diff --git a/framework/db/CActiveRecord.php b/framework/db/CActiveRecord.php index cb2a0a7..797c3d1 100644 --- a/framework/db/CActiveRecord.php +++ b/framework/db/CActiveRecord.php @@ -77,127 +77,144 @@ class CActiveRecord extends CModel { - /** @var object */ - private static $_instance; - /** @var string */ - private static $_className; - /** @var Database */ - protected $_db; - /** @var */ - protected $_dbDriver = ''; - /** @var */ - protected $_dbPrefix = ''; - /** @var boolean */ - protected $_error; - /** @var string */ - protected $_errorMessage; - - /** @var string */ - protected $_table = ''; - /** @var string */ - protected $_tableTranslation = ''; - /** @var */ - protected $_columns = array(); - /** @var used to store fields from $_POST or another tables */ - protected $_specialFields = array(); - /** @var allowed fields */ - protected $_fillable = array(); - /** @var guarded fields */ - protected $_guarded = array(); - /** @var char */ - private $_backQuote = '`'; - - /* class name => model */ - private static $_models = array(); - - /** @var */ - private $_columnTypes = array(); - /** @var */ - private $_pkValue = 0; - /** @var */ - private $_primaryKey; - /** @var */ - private $_isNewRecord = false; - - /** @var */ - private static $_joinTypes = array( - 'INNER JOIN', - 'OUTER JOIN', - 'LEFT JOIN', - 'LEFT OUTER JOIN', - 'RIGHT JOIN', - 'RIGHT OUTER JOIN', - 'JOIN', - ); - - const BELONGS_TO = 1; /* many-to-one */ - const HAS_ONE = 2; /* one-to-one */ - const HAS_MANY = 3; /* one-to-many */ - const MANY_MANY = 4; /* many-to-many */ - - const INNER_JOIN = 'INNER JOIN'; - const OUTER_JOIN = 'OUTER JOIN'; - const LEFT_JOIN = 'LEFT JOIN'; - const LEFT_OUTER_JOIN = 'LEFT OUTER JOIN'; - const RIGHT_JOIN = 'RIGHT JOIN'; - const RIGHT_OUTER_JOIN = 'RIGHT OUTER JOIN'; - const JOIN = 'JOIN'; - - - /** - * Class constructor - * @param bool $createObject - */ - public function __construct($createObject = true) - { - $this->_db = CDatabase::init(); - - if ($createObject && !empty($this->_table)) { - $this->_createObjectFromTable(); - $this->_pkValue = 0; - } - - $this->_dbDriver = CConfig::get('db.driver'); - $this->_dbPrefix = CConfig::get('db.prefix'); - - $this->_error = CDatabase::getError(); - $this->_errorMessage = CDatabase::getErrorMessage(); - - // Set back quote according to database driver - if (preg_match('/mssql|sqlsrv/i', $this->_dbDriver)) { - $this->_backQuote = ''; - } - } - - /** - * Setter - * @param string $index - * @param mixed $value - * @return void - */ - public function __set($index, $value) - { - $this->_columns[$index] = $value; - } - - /** - * Getter - * @param string $index - * @return string - */ - public function __get($index) - { - if (array_key_exists($index, $this->_columns)) { - return $this->_columns[$index]; - } else { - CDebug::AddMessage('errors', 'wrong_column' . $index, A::t('core', 'Wrong column name: {index} in table {table}', array('{index}' => $index, '{table}' => $this->_table))); - return ''; - } - } + /** @var object */ + private static $_instance; + /** @var string */ + private static $_className; + /** @var Database */ + protected $_db; + /** @var */ + protected $_dbDriver = ''; + /** @var */ + protected $_dbPrefix = ''; + /** @var boolean */ + protected $_error; + /** @var string */ + protected $_errorMessage; + + /** @var string */ + protected $_table = ''; + /** @var string */ + protected $_tableTranslation = ''; + /** @var */ + protected $_columns = []; + /** @var used to store fields from $_POST or another tables */ + protected $_specialFields = []; + /** @var allowed fields */ + protected $_fillable = []; + /** @var guarded fields */ + protected $_guarded = []; + /** @var char */ + private $_backQuote = '`'; + + /* class name => model */ + private static $_models = []; + + /** @var */ + private $_columnTypes = []; + /** @var */ + private $_pkValue = 0; + /** @var */ + private $_primaryKey; + /** @var */ + private $_isNewRecord = false; + + /** @var */ + private static $_joinTypes + = [ + 'INNER JOIN', + 'OUTER JOIN', + 'LEFT JOIN', + 'LEFT OUTER JOIN', + 'RIGHT JOIN', + 'RIGHT OUTER JOIN', + 'JOIN', + ]; + + const BELONGS_TO = 1; /* many-to-one */ + const HAS_ONE = 2; /* one-to-one */ + const HAS_MANY = 3; /* one-to-many */ + const MANY_MANY = 4; /* many-to-many */ + + const INNER_JOIN = 'INNER JOIN'; + const OUTER_JOIN = 'OUTER JOIN'; + const LEFT_JOIN = 'LEFT JOIN'; + const LEFT_OUTER_JOIN = 'LEFT OUTER JOIN'; + const RIGHT_JOIN = 'RIGHT JOIN'; + const RIGHT_OUTER_JOIN = 'RIGHT OUTER JOIN'; + const JOIN = 'JOIN'; + + + /** + * Class constructor + * + * @param bool $createObject + */ + public function __construct($createObject = true) + { + $this->_db = CDatabase::init(); + + if ($createObject && ! empty($this->_table)) { + $this->_createObjectFromTable(); + $this->_pkValue = 0; + } + + $this->_dbDriver = CConfig::get('db.driver'); + $this->_dbPrefix = CConfig::get('db.prefix'); + + $this->_error = CDatabase::getError(); + $this->_errorMessage = CDatabase::getErrorMessage(); + + // Set back quote according to database driver + if (preg_match('/mssql|sqlsrv/i', $this->_dbDriver)) { + $this->_backQuote = ''; + } + } + + /** + * Setter + * + * @param string $index + * @param mixed $value + * + * @return void + */ + public function __set($index, $value) + { + $this->_columns[$index] = $value; + } + + /** + * Getter + * + * @param string $index + * + * @return string + */ + public function __get($index) + { + if (array_key_exists($index, $this->_columns)) { + return $this->_columns[$index]; + } else { + CDebug::AddMessage( + 'errors', + 'wrong_column'.$index, + A::t( + 'core', + 'Wrong column name: {index} in table {table}', + ['{index}' => $index, '{table}' => $this->_table] + ) + ); + + return ''; + } + } /** * Checks if active record property exists - * @param string $index + * + * @param string $index + * * @return bool */ public function __isset($index) @@ -205,384 +222,444 @@ public function __isset($index) return array_key_exists($index, $this->_columns) ? true : false; } - /** - * Sets a active record property to be null - * @param string $index - * @return void - */ - public function __unset($index) - { - if (array_key_exists($index, $this->_columns)) { - unset($this->_columns[$index]); - } - } - - /** - * Triggered when invoking inaccessible methods in an object context - * We use this method to avoid calling model($className = __CLASS__) in derived class - * @param string $method - * @param array $args - * @return mixed - */ - public static function __callStatic($method, $args) - { - if (strtolower($method) == 'model') { - if (count($args) == 1) { - return self::_parentModel($args[0]); - } - } - } - - /** - * Initializes the database class - * @param array $params - */ - public static function init($params = array()) - { - if (self::$_instance == null) self::$_instance = new self($params); - return self::$_instance; - } - - /** - * Setter - * @param string $index - * @param mixed $value - * @return void - */ - public function set($index, $value) - { - $this->_columns[$index] = $value; - } - - /** - * Getter - * @param string $index - * @return string - */ - public function get($index) - { - if (array_key_exists($index, $this->_columns)) { - return $this->_columns[$index]; - } else { - CDebug::AddMessage('errors', 'wrong_column' . $index, A::t('core', 'Wrong column name: {index} in table {table}', array('{index}' => $index, '{table}' => $this->_table))); - return ''; - } - } - - /** - * Convert current object to array - * @param bool $allowFilters Return only allowed fields - * @return array - */ - public function resultArray($allowFilters = false) - { - if (is_object($this)) { - $columns = $this->_columns; - - if ($allowFilters) { - // Validate fillable fields, left only allowed fields - if (is_array($this->_fillable) && !empty($this->_fillable)) { - $columns = array_intersect_key($columns, array_flip($this->_fillable)); - } - - // Validate guarded fields, exclude guarded fields - if (is_array($this->_guarded) && !empty($this->_guarded)) { - $columns = array_diff_key($columns, array_flip($this->_guarded)); - } - } - - return $columns; - } - } - - /** - * Return all allowed columns - * @return array - */ - public function allowedColumns() - { - return $this->resultArray(true); - } - - /** - * Checks if a given column exists - * @param string $index - * @return bool - */ - public function isColumnExists($index) - { - return (array_key_exists($index, $this->_columns)) ? true : false; - } - - /** - * Setter for special fields - * @param string $index - * @param mixed $value - */ - public function setSpecialField($index, $value) - { - $this->_specialFields[$index] = $value; - } - - /** - * Getter - * @param string $index - */ - public function getSpecialField($index) - { - return isset($this->_specialFields[$index]) ? $this->_specialFields[$index] : ''; - } - - /** - * Get error status - * @return boolean - */ - public function getError() - { - return $this->_error; - } - - /** - * Get error message - * @return string - */ - public function getErrorMessage() - { - return $this->_errorMessage; - } - - /** - * Returns last query - * @return string - */ - public function lastQuery() - { - return $this->_db->lastQuery(); - } - - /** - * Returns the primary key of the associated database table - * @return string - */ - public function primaryKey() - { - return $this->_primaryKey; - } - - /** - * Returns the primary key value - * @return mixed - */ - public function getPrimaryKey() - { - return $this->_pkValue; - } - - /** - * Returns the table name value - * @param bool $usePrefix - * @return string - */ - public function getTableName($usePrefix = false) - { - return ($usePrefix ? $this->_dbPrefix : '') . $this->_table; - } - - /** - * Returns fields as array - * @return array - */ - public function getFieldsAsArray() - { - return $this->_columns; - } - - /** - * Returns if current operation is on new record or not - * @return bool - */ - public function isNewRecord() - { - return $this->_isNewRecord; - } - - /** - * Returns array of translation fields - * @param array $params - * @return array - */ - public function getTranslations($params = array()) - { - $key = isset($params['key']) ? $params['key'] : ''; - $value = isset($params['value']) ? $params['value'] : ''; - $fields = isset($params['fields']) ? $params['fields'] : array(); - $resultArray = array(); - - if ($this->_tableTranslation == '') { - CDebug::AddMessage('errors', 'get-translations', A::t('core', 'Property "{class}.{name}" is not defined.', array('{class}' => self::$_className, '{name}' => '_tableTranslation'))); - } - - $result = $this->_db->select( - 'SELECT * FROM ' . $this->_tableName($this->_tableTranslation) . ' WHERE ' . $key . ' = :' . $key, - array(':' . $key => $value) - ); - foreach ($result as $res) { - foreach ($fields as $field) { - $resultArray[$res['language_code']][$field] = $res[$field]; - } - } - - return $resultArray; - } - - /** - * Saves array of translation fields - * @param array $params - * @return array - */ - public function saveTranslations($params = array()) - { - $key = isset($params['key']) ? $params['key'] : ''; - $value = isset($params['value']) ? $params['value'] : ''; - $fields = isset($params['fields']) ? $params['fields'] : array(); - $paramsTranslation = array(); - - foreach ($fields as $lang => $langInfo) { - foreach ($langInfo as $langField => $langFieldValue) { - $paramsTranslation[$langField] = $langFieldValue; - } - if ($this->isNewRecord()) { - $paramsTranslation[$key] = $value; - $paramsTranslation['language_code'] = $lang; - $this->_db->insert($this->_tableTranslation, $paramsTranslation); - } else { - $this->_db->update($this->_tableTranslation, $paramsTranslation, $key . '=:key AND language_code=:language_code', array(':key' => $value, ':language_code' => $lang)); - } - } - } - - - /***************************************************************** - * ACTIVE RECORD METHODS - *****************************************************************/ - /** - * Returns the static model of the specified AR class - * @param string $className - * - * EVERY derived AR class must define model() method in the following way, - *
    -	 * public static function model()
    -	 * {
    -	 *     return parent::model(__CLASS__);
    -	 * }
    -	 * 
    - */ - private static function _parentModel($className = __CLASS__) - { - self::$_className = $className; - - if (isset(self::$_models[$className])) { - return self::$_models[$className]; - } else { - return self::$_models[$className] = new $className(null); - } - } - - /** - * Create empty object from table - * @return bool - */ - private function _createObjectFromTable() - { - if (is_null($this->_table)) { - return false; - } - - $cols = $this->_db->showColumns($this->_table); - if (!is_array($cols)) return false; - - switch ($this->_dbDriver) { - case 'mssql': - case 'sqlsrv': - // Handle MSSQL or SQLSRV drivers - $constraintStatement = "SELECT KU.TABLE_NAME, KU.COLUMN_NAME, KU.ORDINAL_POSITION, KU.CONSTRAINT_NAME + /** + * Sets a active record property to be null + * + * @param string $index + * + * @return void + */ + public function __unset($index) + { + if (array_key_exists($index, $this->_columns)) { + unset($this->_columns[$index]); + } + } + + /** + * Triggered when invoking inaccessible methods in an object context + * We use this method to avoid calling model($className = __CLASS__) in derived class + * + * @param string $method + * @param array $args + * + * @return mixed + */ + public static function __callStatic($method, $args) + { + if (strtolower($method) == 'model') { + if (count($args) == 1) { + return self::_parentModel($args[0]); + } + } + } + + /** + * Initializes the database class + * + * @param array $params + */ + public static function init($params = []) + { + if (self::$_instance == null) { + self::$_instance = new self($params); + } + + return self::$_instance; + } + + /** + * Setter + * + * @param string $index + * @param mixed $value + * + * @return void + */ + public function set($index, $value) + { + $this->_columns[$index] = $value; + } + + /** + * Getter + * + * @param string $index + * + * @return string + */ + public function get($index) + { + if (array_key_exists($index, $this->_columns)) { + return $this->_columns[$index]; + } else { + CDebug::AddMessage( + 'errors', + 'wrong_column'.$index, + A::t( + 'core', + 'Wrong column name: {index} in table {table}', + ['{index}' => $index, '{table}' => $this->_table] + ) + ); + + return ''; + } + } + + /** + * Convert current object to array + * + * @param bool $allowFilters Return only allowed fields + * + * @return array + */ + public function resultArray($allowFilters = false) + { + if (is_object($this)) { + $columns = $this->_columns; + + if ($allowFilters) { + // Validate fillable fields, left only allowed fields + if (is_array($this->_fillable) && ! empty($this->_fillable)) { + $columns = array_intersect_key($columns, array_flip($this->_fillable)); + } + + // Validate guarded fields, exclude guarded fields + if (is_array($this->_guarded) && ! empty($this->_guarded)) { + $columns = array_diff_key($columns, array_flip($this->_guarded)); + } + } + + return $columns; + } + } + + /** + * Return all allowed columns + * + * @return array + */ + public function allowedColumns() + { + return $this->resultArray(true); + } + + /** + * Checks if a given column exists + * + * @param string $index + * + * @return bool + */ + public function isColumnExists($index) + { + return (array_key_exists($index, $this->_columns)) ? true : false; + } + + /** + * Setter for special fields + * + * @param string $index + * @param mixed $value + */ + public function setSpecialField($index, $value) + { + $this->_specialFields[$index] = $value; + } + + /** + * Getter + * + * @param string $index + */ + public function getSpecialField($index) + { + return isset($this->_specialFields[$index]) ? $this->_specialFields[$index] : ''; + } + + /** + * Get error status + * + * @return boolean + */ + public function getError() + { + return $this->_error; + } + + /** + * Get error message + * + * @return string + */ + public function getErrorMessage() + { + return $this->_errorMessage; + } + + /** + * Returns last query + * + * @return string + */ + public function lastQuery() + { + return $this->_db->lastQuery(); + } + + /** + * Returns the primary key of the associated database table + * + * @return string + */ + public function primaryKey() + { + return $this->_primaryKey; + } + + /** + * Returns the primary key value + * + * @return mixed + */ + public function getPrimaryKey() + { + return $this->_pkValue; + } + + /** + * Returns the table name value + * + * @param bool $usePrefix + * + * @return string + */ + public function getTableName($usePrefix = false) + { + return ($usePrefix ? $this->_dbPrefix : '').$this->_table; + } + + /** + * Returns fields as array + * + * @return array + */ + public function getFieldsAsArray() + { + return $this->_columns; + } + + /** + * Returns if current operation is on new record or not + * + * @return bool + */ + public function isNewRecord() + { + return $this->_isNewRecord; + } + + /** + * Returns array of translation fields + * + * @param array $params + * + * @return array + */ + public function getTranslations($params = []) + { + $key = isset($params['key']) ? $params['key'] : ''; + $value = isset($params['value']) ? $params['value'] : ''; + $fields = isset($params['fields']) ? $params['fields'] : []; + $resultArray = []; + + if ($this->_tableTranslation == '') { + CDebug::AddMessage( + 'errors', + 'get-translations', + A::t( + 'core', + 'Property "{class}.{name}" is not defined.', + ['{class}' => self::$_className, '{name}' => '_tableTranslation'] + ) + ); + } + + $result = $this->_db->select( + 'SELECT * FROM '.$this->_tableName($this->_tableTranslation).' WHERE '.$key.' = :'.$key, + [':'.$key => $value] + ); + foreach ($result as $res) { + foreach ($fields as $field) { + $resultArray[$res['language_code']][$field] = $res[$field]; + } + } + + return $resultArray; + } + + /** + * Saves array of translation fields + * + * @param array $params + * + * @return array + */ + public function saveTranslations($params = []) + { + $key = isset($params['key']) ? $params['key'] : ''; + $value = isset($params['value']) ? $params['value'] : ''; + $fields = isset($params['fields']) ? $params['fields'] : []; + $paramsTranslation = []; + + foreach ($fields as $lang => $langInfo) { + foreach ($langInfo as $langField => $langFieldValue) { + $paramsTranslation[$langField] = $langFieldValue; + } + if ($this->isNewRecord()) { + $paramsTranslation[$key] = $value; + $paramsTranslation['language_code'] = $lang; + $this->_db->insert($this->_tableTranslation, $paramsTranslation); + } else { + $this->_db->update( + $this->_tableTranslation, + $paramsTranslation, + $key.'=:key AND language_code=:language_code', + [':key' => $value, ':language_code' => $lang] + ); + } + } + } + + + /***************************************************************** + * ACTIVE RECORD METHODS + *****************************************************************/ + /** + * Returns the static model of the specified AR class + * + * @param string $className + * + * EVERY derived AR class must define model() method in the following way, + *
    +     * public static function model()
    +     * {
    +     *     return parent::model(__CLASS__);
    +     * }
    +     * 
    + */ + private static function _parentModel($className = __CLASS__) + { + self::$_className = $className; + + if (isset(self::$_models[$className])) { + return self::$_models[$className]; + } else { + return self::$_models[$className] = new $className(null); + } + } + + /** + * Create empty object from table + * + * @return bool + */ + private function _createObjectFromTable() + { + if (is_null($this->_table)) { + return false; + } + + $cols = $this->_db->showColumns($this->_table); + if ( ! is_array($cols)) { + return false; + } + + switch ($this->_dbDriver) { + case 'mssql': + case 'sqlsrv': + // Handle MSSQL or SQLSRV drivers + $constraintStatement = "SELECT KU.TABLE_NAME, KU.COLUMN_NAME, KU.ORDINAL_POSITION, KU.CONSTRAINT_NAME FROM [INFORMATION_SCHEMA].[TABLE_CONSTRAINTS] TC, [INFORMATION_SCHEMA].[KEY_COLUMN_USAGE] KU WHERE TC.TABLE_CATALOG = KU.TABLE_CATALOG AND TC.CONSTRAINT_SCHEMA = KU.CONSTRAINT_SCHEMA AND TC.CONSTRAINT_NAME = KU.CONSTRAINT_NAME AND TC.CONSTRAINT_TYPE='PRIMARY KEY' AND - LOWER(KU.TABLE_NAME)='" . strtolower($this->_table) . "' "; - - $primaryInfos = $this->_db->select($constraintStatement); - - $isPrimaryKey = false; - foreach ($cols as $array) { - // If NULL is allowed and NULL is default value, use null otherwise insert default value $array[4] - // In mssql, sqlsrv the results contain are COLUMN_NAME, data_type, character_maximum_length - - $columnField = $array[0]; - $columnType = $array[1]; - $columnNullable = $array[2]; - $columnKey = $array[3]; - $columnDefault = $array[4]; - $columnExtra = $array[5]; - - $isPrimaryKey = ($columnKey == 'PRI') ? true : false; - if (!empty($primaryInfos)) { - $found = false; - foreach ($primaryInfos as $info) { - if ((!$found) && (strcasecmp($info['COLUMN_NAME'], $columnField) == 0)) { - $found = true; - $isPrimaryKey = true; - } - } - } - - if ($columnNullable === 'YES') { - $this->_columns[$columnField] = null; - } else { - $this->_columns[$columnField] = ($columnDefault != '') ? $columnDefault : ''; - } - - $arrayParts = explode('(', $columnType); - $this->_columnTypes[$columnField] = array_shift($arrayParts); - if ($isPrimaryKey) { - $this->_primaryKey = $columnField; - } - } - break; - - default: - // Handle all other db drivers - // In mysql the results are Field, Type, Null, Key, Default, Extra - foreach ($cols as $array) { - // If NULL is allowed and NULL is default value, use null - // otherwise insert default value $array[4] - if ($array[2] === 'YES') { - $this->_columns[$array[0]] = null; - } else { - $this->_columns[$array[0]] = ($array[4] != '') ? $array[4] : ''; - } - - $arrayParts = explode('(', $array[1]); - $this->_columnTypes[$array[0]] = array_shift($arrayParts); - if ($array[3] == 'PRI') { - $this->_primaryKey = $array[0]; - } - } - break; - } - - $this->_addCustomFields(); - if ($this->_primaryKey == '') $this->_primaryKey = 'id'; - - return true; - } + LOWER(KU.TABLE_NAME)='".strtolower($this->_table)."' "; + + $primaryInfos = $this->_db->select($constraintStatement); + + $isPrimaryKey = false; + foreach ($cols as $array) { + // If NULL is allowed and NULL is default value, use null otherwise insert default value $array[4] + // In mssql, sqlsrv the results contain are COLUMN_NAME, data_type, character_maximum_length + + $columnField = $array[0]; + $columnType = $array[1]; + $columnNullable = $array[2]; + $columnKey = $array[3]; + $columnDefault = $array[4]; + $columnExtra = $array[5]; + + $isPrimaryKey = ($columnKey == 'PRI') ? true : false; + if ( ! empty($primaryInfos)) { + $found = false; + foreach ($primaryInfos as $info) { + if (( ! $found) && (strcasecmp($info['COLUMN_NAME'], $columnField) == 0)) { + $found = true; + $isPrimaryKey = true; + } + } + } + + if ($columnNullable === 'YES') { + $this->_columns[$columnField] = null; + } else { + $this->_columns[$columnField] = ($columnDefault != '') ? $columnDefault : ''; + } + + $arrayParts = explode('(', $columnType); + $this->_columnTypes[$columnField] = array_shift($arrayParts); + if ($isPrimaryKey) { + $this->_primaryKey = $columnField; + } + } + break; + + default: + // Handle all other db drivers + // In mysql the results are Field, Type, Null, Key, Default, Extra + foreach ($cols as $array) { + // If NULL is allowed and NULL is default value, use null + // otherwise insert default value $array[4] + if ($array[2] === 'YES') { + $this->_columns[$array[0]] = null; + } else { + $this->_columns[$array[0]] = ($array[4] != '') ? $array[4] : ''; + } + + $arrayParts = explode('(', $array[1]); + $this->_columnTypes[$array[0]] = array_shift($arrayParts); + if ($array[3] == 'PRI') { + $this->_primaryKey = $array[0]; + } + } + break; + } + + $this->_addCustomFields(); + if ($this->_primaryKey == '') { + $this->_primaryKey = 'id'; + } + + return true; + } /** * Split AR result into parts (chunks) - * Ex.: chunk(array('condition'=>'post_id = :postID AND is_active = :isActive', 'select'=>'', 'group|groupBy'=>'', 'order|orderBy'=>'id DESC', 'limit'=>'0, 10'), array(':postID'=>10, ':isActive'=>1)); - * Ex.: chunk(CConfig::get('db.prefix').$this->_tableTranslation.'.news_text LIKE :keywords', array(':keywords'=>'%'.$keywords.'%')); + * Ex.: chunk(['condition'=>'post_id = :postID AND is_active = :isActive', 'select'=>'', 'group|groupBy'=>'', 'order|orderBy'=>'id DESC', 'limit'=>'0, 10'), [':postID'=>10, ':isActive'=>1]]; + * Ex.: chunk(CConfig::get('db.prefix').$this->_tableTranslation.'.news_text LIKE :keywords', [':keywords'=>'%'.$keywords.'%']); * * @param array $conditions * @param array $params @@ -593,25 +670,25 @@ private function _createObjectFromTable() */ public function chunk(array $conditions = [], array $params = [], int $size = 0, callable $callback = null) { - if (is_int($size) && $size > 0 && !empty($callback)) { - if (!isset($conditions['limit'])) { - $from = 0; + if (is_int($size) && $size > 0 && ! empty($callback)) { + if ( ! isset($conditions['limit'])) { + $from = 0; $limitSize = $size; } else { $limitParts = explode(',', $conditions['limit']); - $from = isset($limitParts[0]) ? $limitParts[0] : 0; - $limitSize = isset($limitParts[1]) ? $limitParts[1] : $size; + $from = isset($limitParts[0]) ? $limitParts[0] : 0; + $limitSize = isset($limitParts[1]) ? $limitParts[1] : $size; if ($size >= $limitSize) { $size = $limitSize; } } $conditions['limit'] = "$from, $size"; - $count = 0; + $count = 0; - while ($result = $this->findAll($conditions, $params)){ + while ($result = $this->findAll($conditions, $params)) { $callback($result); - $from += $size; + $from += $size; $conditions['limit'] = "$from, $size"; $count += $size; @@ -620,1023 +697,1167 @@ public function chunk(array $conditions = [], array $params = [], int $size = 0, } } } else { - CDebug::AddMessage('errors', 'chunk', A::t('core', 'Wrong params for chunk size: {size} or callback method is callable.', array('{size}' => $size))); + CDebug::AddMessage( + 'errors', + 'chunk', + A::t( + 'core', + 'Wrong params for chunk size: {size} or callback method is callable.', + ['{size}' => $size] + ) + ); } return null; } - - /** - * This method queries your database to find first related object - * Ex.: find('postID = :postID AND isActive = :isActive', array(':postID'=>10, ':isActive'=>1)); - * Ex.: find(array('condition'=>'postID = :postID AND isActive = :isActive', 'order|orderBy'=>'id DESC'), 'params'=>array(':postID'=>10, ':isActive'=>1)); - * @param mixed $conditions - * @param array $params - * @param bool|string $cacheId - * @return object - */ - public function find($conditions = '', $params = array(), $cacheId = false) - { - if (is_array($conditions)) { - $where = isset($conditions['condition']) ? $conditions['condition'] : ''; - if (isset($conditions['order'])) { - $order = isset($conditions['order']) ? $conditions['order'] : ''; - } elseif (isset($conditions['orderBy'])) { - $order = isset($conditions['orderBy']) ? $conditions['orderBy'] : ''; - } - } else { - $where = $conditions; - $order = ''; - } - - $whereClause = !empty($where) ? ' WHERE ' . $where : ''; - $orderBy = !empty($order) ? ' ORDER BY ' . $order : ''; - $relations = $this->_getRelations(); - $customFields = $this->_getCustomFields(); - $encryptedField = $this->_getEncryptedFields(); - $limits = $this->_prepareLimit('1'); - - $sql = 'SELECT - ' . $limits['before'] . ' - ' . $this->_tableName() . '.* - ' . $relations['fields'] . ' - ' . $customFields . ' - ' . $encryptedField . ' - FROM ' . $this->_tableName() . ' - ' . $relations['tables'] . ' - ' . $whereClause . ' - ' . $orderBy . ' - ' . $limits['after']; - - $result = $this->_db->select($sql, $params, 'fetchAll', PDO::FETCH_ASSOC, $cacheId); - if (isset($result[0]) && is_array($result[0])) { - foreach ($result[0] as $key => $val) { - $this->$key = $val; - if ($key == $this->_primaryKey) $this->_pkValue = $val; - } - return $this; - } else { - return null; - } - } - - /** - * This method queries your database to find related objects by PK - * Ex.: findByPk($pk, 'postID = :postID AND isActive = :isActive', array(':postID'=>10, ':isActive'=>1)); - * Ex.: findByPk($pk, array('condition'=>'postID = :postID AND isActive = :isActive', 'order|orderBy'=>'id DESC'), 'params'=>array(':postID'=>10, ':isActive'=>1)); - * @param string $pk - * @param mixed $conditions - * @param array $params - * @param bool|string $cacheId - * @return object - */ - public function findByPk($pk, $conditions = '', $params = array(), $cacheId = false) - { - if (is_array($conditions)) { - $where = isset($conditions['condition']) ? $conditions['condition'] : ''; - if (isset($conditions['order'])) { - $order = isset($conditions['order']) ? $conditions['order'] : ''; - } elseif (isset($conditions['orderBy'])) { - $order = isset($conditions['orderBy']) ? $conditions['orderBy'] : ''; - } - } else { - $where = $conditions; - $order = ''; - } - - $whereClause = !empty($where) ? ' AND (' . $where . ')' : ''; - $orderBy = !empty($order) ? ' ORDER BY ' . $order : ''; - $relations = $this->_getRelations(); - $customFields = $this->_getCustomFields(); - $encryptedField = $this->_getEncryptedFields(); - $limits = $this->_prepareLimit('1'); - - $sql = 'SELECT - ' . $limits['before'] . ' - ' . $this->_tableName() . '.* - ' . $relations['fields'] . ' - ' . $customFields . ' - ' . $encryptedField . ' - FROM ' . $this->_tableName() . ' - ' . $relations['tables'] . ' - WHERE ' . $this->_tableName() . '.' . $this->_primaryKey . ' = ' . (int)$pk . ' - ' . $whereClause . ' - ' . $orderBy . ' - ' . $limits['after']; - - $result = $this->_db->select($sql, $params, 'fetchAll', PDO::FETCH_ASSOC, $cacheId); - if (isset($result[0]) && is_array($result[0])) { - foreach ($result[0] as $key => $val) { - $this->$key = $val; - } - $this->_pkValue = $pk; - return $this; - } else { - return null; - } - } /** - * This method queries your database to find related objects by attributes - * Ex.: findByAttributes($attributes, 'postID = :postID AND isActive = :isActive', array(':postID'=>10, ':isActive'=>1)); - * Ex.: findByAttributes($attributes, array('condition'=>'postID = :postID AND isActive = :isActive', 'order|orderBy'=>'id DESC', 'limit'=>'0, 10'), 'params'=>array(':postID'=>10, ':isActive'=>1)); - * Ex.: $attributes = array('first_name'=>$firstName, 'last_name'=>$lastName); + * This method queries your database to find first related object + * Ex.: find('postID = :postID AND isActive = :isActive', [':postID'=>10, ':isActive'=>1]); + * Ex.: find(['condition'=>'postID = :postID AND isActive = :isActive', 'order|orderBy'=>'id DESC'], 'params'=>[':postID'=>10, ':isActive'=>1]); * - * @param array $attributes * @param mixed $conditions * @param array $params + * @param bool|string $cacheId * - * @return mixed + * @return object */ - public function findByAttributes($attributes, $conditions = '', $params = array()) - { - if (is_array($conditions)) { - $where = isset($conditions['condition']) ? $conditions['condition'] : ''; - if (isset($conditions['order'])) { - $order = isset($conditions['order']) ? $conditions['order'] : ''; - } elseif (isset($conditions['orderBy'])) { - $order = isset($conditions['orderBy']) ? $conditions['orderBy'] : ''; - } - $limit = isset($conditions['limit']) ? $conditions['limit'] : ''; - } else { - $where = $conditions; - $order = ''; - $limit = ''; - } - - $whereClause = !empty($where) ? ' AND ' . $where : ''; - $orderBy = !empty($order) ? ' ORDER BY ' . $order : ''; - $limits = $this->_prepareLimit($limit); - - $relations = $this->_getRelations(); - $customFields = $this->_getCustomFields(); - $encryptedField = $this->_getEncryptedFields(); - - $attributes_clause = ''; - foreach ($attributes as $key => $value) { - $attributes_clause .= ' AND ' . $key . " = '" . $value . "'"; - } - - $sql = 'SELECT - ' . $limits['before'] . ' - ' . $this->_tableName() . '.* - ' . $relations['fields'] . ' - ' . $customFields . ' - FROM ' . $this->_tableName() . ' - ' . $relations['tables'] . ' - ' . $encryptedField . ' - WHERE 1 = 1 - ' . $attributes_clause . ' - ' . $whereClause . ' - ' . $orderBy . ' - ' . $limits['after']; - - return $this->_db->select($sql, $params); - } - - /** - * This method queries your database to find all related objects - * Ex.: findAll('post_id = :postID AND is_active = :isActive', array(':postID'=>10, ':isActive'=>1)); - * Ex.: findAll(array('condition'=>'post_id = :postID AND is_active = :isActive', 'select'=>'', 'group|groupBy'=>'', 'order|orderBy'=>'id DESC', 'limit'=>'0, 10'), array(':postID'=>10, ':isActive'=>1)); - * Ex.: findAll(CConfig::get('db.prefix').$this->_tableTranslation.'.news_text LIKE :keywords', array(':keywords'=>'%'.$keywords.'%')); - * @param mixed $conditions - * @param array $params 'select': MAX(date), name or CConfig::get('db.prefix').table.field_name etc. - actually for ONLY_FULL_GROUP_BY mode - * 'groupBy': table.field_name or field_name - * @param bool|string $cacheId - * @param int $fetchMode - * @return array - */ - public function findAll($conditions = '', $params = array(), $cacheId = false, $fetchMode = PDO::FETCH_ASSOC) - { - if (is_array($conditions)) { - $where = isset($conditions['condition']) ? $conditions['condition'] : ''; - if (isset($conditions['group'])) { - $group = isset($conditions['group']) ? $conditions['group'] : ''; - } elseif (isset($conditions['groupBy'])) { - $group = isset($conditions['groupBy']) ? $conditions['groupBy'] : ''; - } - if (isset($conditions['order'])) { - $order = isset($conditions['order']) ? $conditions['order'] : ''; - } elseif (isset($conditions['orderBy'])) { - $order = isset($conditions['orderBy']) ? $conditions['orderBy'] : ''; - } - $limit = isset($conditions['limit']) ? $conditions['limit'] : ''; - $select = isset($conditions['select']) ? $conditions['select'] : ''; - } else { - $where = $conditions; - $group = ''; - $order = ''; - $limit = ''; - $select = ''; - } - - $whereClause = !empty($where) ? ' WHERE ' . $where : ''; - $groupBy = !empty($group) ? ' GROUP BY ' . $group : ''; - $orderBy = !empty($order) ? ' ORDER BY ' . $order : ''; - $limits = $this->_prepareLimit($limit); - $selectList = !empty($select) ? $select : $this->_tableName() . '.*'; - - $relations = $this->_getRelations(); - $customFields = $this->_getCustomFields(); - $encryptedField = $this->_getEncryptedFields(); - - $sql = 'SELECT - ' . $limits['before'] . ' - ' . $selectList . ' - ' . $relations['fields'] . ' - ' . $customFields . ' - ' . $encryptedField . ' - FROM ' . $this->_tableName() . ' - ' . $relations['tables'] . ' - ' . $whereClause . ' - ' . $groupBy . ' - ' . $orderBy . ' - ' . $limits['after']; - - return $this->_db->select($sql, $params, 'fetchAll', $fetchMode, $cacheId); - } - - /** - * This method queries your database to find first related record primary key - * Ex.: findPk('postID = :postID AND isActive = :isActive', array(':postID'=>10, ':isActive'=>1)); - * @param mixed $conditions - * @param array $params - * @return int - */ - public function findPk($conditions = '', $params = array()) - { - if ($result = $this->find($conditions, $params)) { - $key = $this->_primaryKey; - return $result->$key; - } - - return ''; - } - - /** - * Create new record - * @param array $data - * @param bool $preOperations - * @return bool - */ - public function create($data = array(), $preOperations = true) - { - $allowOperation = true; - if ($preOperations) { - if (!$this->_beforeSave($this->_pkValue)) { - $allowOperation = false; - CDebug::AddMessage('errors', 'before-save', A::t('core', 'AR before operation on table: {table}', array('{table}' => $this->_table))); - } - } - - if ($allowOperation) { - $result = $this->_db->insert($this->_table, $data); - $this->_isNewRecord = true; - // Save last inset ID - $this->_pkValue = (int)$result; - - if ($result) { - if ($preOperations) { - $this->_afterSave($this->_pkValue); - } - return true; - } - } - - return false; - } - - /** - * Update existing record - * @param int $id - * @param array $data - * @param bool $preOperations - * @param bool $forceSave - * @return boolean - */ - public function update($id, $data = array(), $preOperations = true, $forceSave = false) - { - $allowOperation = true; - if ($preOperations) { - if (!$this->_beforeSave($id)) { - $allowOperation = false; - CDebug::AddMessage('errors', 'before-save', A::t('core', 'AR before operation on table: {table}', array('{table}' => $this->_table))); - } - } - - if ($allowOperation) { - $result = $this->_db->update($this->_table, $data, $this->_primaryKey . ' = :primary_key', array(':primary_key' => (int)$id), $forceSave); - $this->_isNewRecord = false; - - if ($result) { - if ($preOperations) { - $this->_afterSave($id); - } - return true; - } - } - - return false; - } - - /** - * Save data - * @param CRecordEntity $entity - * @param bool $forceSave - * @return boolean - */ - public function save($entity = null, $forceSave = false) - { - $data = array(); - $this->_removeCustomFields(); - - if (!is_null($entity) && ($entity instanceof CRecordEntity)) { - // --------------------------------------- - // Handle Entity - // --------------------------------------- - $columns = $entity->allowedColumns(); - $primaryKey = $entity->primaryKey(); - $pkValue = $entity->getPrimaryKey(); - - foreach ($columns as $column => $val) { - if ($column != 'id' && $column != $primaryKey) { - $data[$column] = $entity->$column; - } - } - - if ($pkValue > 0) { - $result = $this->_db->update($this->_table, $data, $primaryKey . ' = :primary_key', array(':primary_key' => (int)$pkValue), $forceSave); - } else { - $result = $this->_db->insert($this->_table, $data, $forceSave); - // Save last inset ID - $pkValue = (int)$result; - } - - if ($result) { - $this->_afterSave($pkValue); - return true; - } - } else { - // --------------------------------------- - // Handle Model - // --------------------------------------- - if ($this->_beforeSave($this->_pkValue)) { - $columns = $this->allowedColumns(); - foreach ($columns as $column => $val) { - $relations = $this->_getRelations(); - if ($column != 'id' && $column != $this->_primaryKey && !in_array($column, $relations['fieldsArray'])) { // && ($column != 'created_at') && !$NEW) - //$value = $this->$column; - //if(array_search($this->_columnTypes[$column], array('int', 'float', 'decimal'))){ - // $value = filter_var($value, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); - //} - if ($this->_isEncryptedField($column)) { - $encryptedField = $this->_getEncryptedField($column); - $data[$column] = array('param_key' => $encryptedField['encrypt'] . '(' . $column . ',"' . $encryptedField['key'] . '")', 'param_value' => $this->$column); - } else { - $data[$column] = $this->$column; - } - } - } - - if ($this->_pkValue > 0) { - $result = $this->_db->update($this->_table, $data, $this->_primaryKey . ' = :primary_key', array(':primary_key' => (int)$this->_pkValue), $forceSave); - $this->_isNewRecord = false; - } else { - $result = $this->_db->insert($this->_table, $data, $forceSave); - $this->_isNewRecord = true; - // Save last inset ID - $this->_pkValue = (int)$result; - } - - if ($result) { - $this->_afterSave($this->_pkValue); - return true; - } - } else { - CDebug::AddMessage('errors', 'before-save', A::t('core', 'AR before operation on table: {table}', array('{table}' => $this->_table))); - } - } - - return false; - } - - /** - * Clear primary key - * @return boolean - */ - public function clearPkValue() - { - $this->_pkValue = 0; - - return true; - } - - /** - * Reset the object with fields - * @return boolean - */ - public function reset() - { - $this->_columns = array(); - $this->_specialFields = array(); - - if (!empty($this->_table)) { - $this->_createObjectFromTable(); - $this->_pkValue = 0; - } - - return true; - } - - /** - * Updates records with the specified primary key - * See {@link find()} for detailed explanation about $conditions - * Ex.: updateByPk($pk, array('name'=>$value), 'postID = 10 AND isActive = 1'); - * @param string $pk - * @param array $data - * @param mixed $conditions - * @param array $params - * @return bool - */ - public function updateByPk($pk, $data = array(), $conditions = '', $params = array()) - { - if ($this->_beforeSave($pk)) { - if (is_array($conditions)) { - $where = isset($conditions['condition']) ? $conditions['condition'] : ''; - } else { - $where = $conditions; - } - $whereClause = !empty($where) ? ' AND ' . $where : ''; - $params[':primary_key'] = (int)$pk; - - $result = $this->_db->update($this->_table, $data, $this->_primaryKey . ' = :primary_key' . $whereClause, $params); - if ($result) { - $this->_afterSave($pk); - return true; - } else { - return false; - } - } else { - CDebug::AddMessage('errors', 'before-update', A::t('core', 'AR before operation on table: {table}', array('{table}' => $this->_table))); - } - } - - /** - * Updates the rows matching the specified condition - * Ex.: updateAll(array('name'=>$value), 'postID = 10 AND isActive = 1'); - * Ex.: updateAll(array('name'=>$value), 'postID = 10 AND isActive = :isActive', array(':isActiv'=>1)); - * @param array $data - * @param mixed $conditions - * @param array $params - * @return bool - */ - public function updateAll($data = array(), $conditions = '', $params = array()) - { - if (is_array($conditions)) { - $where = isset($conditions['condition']) ? $conditions['condition'] : ''; - } else { - $where = $conditions; - } - $whereClause = !empty($where) ? $where : '1'; - - $result = $this->_db->update($this->_table, $data, $whereClause, $params); - if ($result) { - return true; - } else { - return false; - } - } - - /** - * Remove the row from database if AR instance has been populated with this row - * Ex.: $post = PostModel::model()->findByPk(10); - * $post->delete(); - * @return boolean - */ - public function delete() - { - if (!empty($this->_pkValue) && $this->deleteByPk($this->_pkValue)) { - return true; - } - - return false; - } - - /** - * Remove the rows matching the specified condition and primary key(s) - * Ex.: deleteByPk(10, 'postID = :postID AND isActive = :isActive', array(':postID'=>10, ':isActive'=>1)); - * @param string $pk - * @param mixed $conditions - * @param array $params - * @return boolean - */ - public function deleteByPk($pk, $conditions = '', $params = array()) - { - if ($this->_beforeDelete($pk)) { - if (is_array($conditions)) { - $where = isset($conditions['condition']) ? $conditions['condition'] : ''; - } else { - $where = $conditions; - } - $whereClause = !empty($where) ? ' WHERE ' . $where : ''; - $params[':primary_key'] = (int)$pk; - - $result = $this->_db->delete($this->_table, $this->_primaryKey . ' = :primary_key' . $whereClause, $params); - if ($result) { - $this->_afterDelete($pk); - return true; - } - } else { - CDebug::AddMessage('errors', 'before-delete', A::t('core', 'AR before delete operation on table: {table}', array('{table}' => $this->_table))); - } - - return false; - } - - /** - * Remove the rows matching the specified condition - * Ex.: deleteAll('postID = :postID AND isActive = :isActive', array(':postID'=>10, ':isActive'=>1)); - * Ex.: deleteAll(array('condition'=>'postID = :postID AND isActive = :isActive'), array(':postID'=>10, ':isActive'=>1)); - * @param mixed $conditions - * @param array $params - * @return boolean - */ - public function deleteAll($conditions = '', $params = array()) - { - if ($this->_beforeDelete()) { - if (is_array($conditions)) { - $where = isset($conditions['condition']) ? $conditions['condition'] : ''; - } else { - $where = $conditions; - } - $whereClause = !empty($where) ? ' WHERE ' . $where : ''; - - $result = $this->_db->delete($this->_table, $whereClause, $params); - if ($result) { - $this->_afterDelete(); - return true; - } - } else { - CDebug::AddMessage('errors', 'before-delete', A::t('core', 'AR before delete operation on table: {table}', array('{table}' => $this->_table))); - } - - return false; - } - - /** - * This method selects distinct value - * @param string $field - * @return array - */ - public function distinct($field = '') - { - return $this->findAll(array('group' => $this->_tableName() . '.' . $field)); - } - - /** - * This method reloads model data according to the current primary key - * @return object - */ - public function refresh() - { - return $this->findByPk($this->_pkValue); - } - - /** - * This method check if there is at least one row satisfying the specified condition - * Ex.: exists('postID = :postID AND isActive = :isActive', array(':postID'=>10, ':isActive'=>1)); - * @param mixed $conditions - * @param array $params - * @return bolean - */ - public function exists($conditions = '', $params = array()) - { - if (is_array($conditions)) { - $where = isset($conditions['condition']) ? $conditions['condition'] : ''; - } else { - $where = $conditions; - } - - $whereClause = !empty($where) ? ' WHERE ' . $where : ''; - $limits = $this->_prepareLimit('1'); - - $sql = 'SELECT - ' . $limits['before'] . ' - ' . $this->_tableName() . '.* - FROM ' . $this->_tableName() . ' - ' . $whereClause . ' - ' . $limits['after']; - - $result = $this->_db->select($sql, $params); - - return ($result) ? true : false; - } - - /** - * Finds the number of rows satisfying the specified query condition - * Ex.: count('postID = :postID AND isActive = :isActive', array(':postID'=>10, ':isActive'=>1)); - * Ex.: count(array('condition'=>'post_id = :postID AND is_active = :isActive', 'select'=>'', 'count'=>'*', 'group|groupBy'=>'', 'order|orderBy'=>'', 'allRows'=>false), array(':postID'=>10, ':isActive'=>1)); - * @param mixed $conditions - * @param array $params - * @return integer - */ - public function count($conditions = '', $params = array()) - { - if (is_array($conditions)) { - $where = isset($conditions['condition']) ? $conditions['condition'] : ''; - if (isset($conditions['group'])) { - $group = isset($conditions['group']) ? $conditions['group'] : ''; - } elseif (isset($conditions['groupBy'])) { - $group = isset($conditions['groupBy']) ? $conditions['groupBy'] : ''; - } - if (!empty($group)) { - if (isset($conditions['order'])) { - $order = isset($conditions['order']) ? $conditions['order'] : ''; - } elseif (isset($conditions['orderBy'])) { - $order = isset($conditions['orderBy']) ? $conditions['orderBy'] : ''; - } - } - $count = isset($conditions['count']) ? $conditions['count'] : '*'; - $select = isset($conditions['select']) ? $conditions['select'] : ''; - $allRows = isset($conditions['allRows']) ? (bool)$conditions['allRows'] : false; - } else { - $where = $conditions; - $group = ''; - $order = ''; - $count = '*'; - $select = ''; - $allRows = false; - } - - $whereClause = !empty($where) ? ' WHERE ' . $where : ''; - $groupBy = !empty($group) ? ' GROUP BY ' . $group : ''; - $orderBy = !empty($order) ? ' ORDER BY ' . $order : ''; - $limits = $this->_prepareLimit(($allRows ? '' : '1')); - $relations = $this->_getRelations(); - - $sql = 'SELECT - ' . $limits['before'] . ' - COUNT(' . $count . ') as cnt - ' . ($select ? ', ' . $select : '') . ' - FROM ' . $this->_tableName() . ' - ' . $relations['tables'] . ' - ' . $whereClause . ' - ' . $groupBy . ' - ' . $orderBy . ' - ' . $limits['after']; - - $result = $this->_db->select($sql, $params); - - if ($allRows) { - return (isset($result)) ? $result : null; - } else { - return (isset($result[0]['cnt'])) ? $result[0]['cnt'] : 0; - } - } - - /** - * Finds a maximum value of the specified column - * Ex.: max('id', 'postID = :postID AND isActive = :isActive', array(':postID'=>10, ':isActive'=>1)); - * @param string $column - * @param mixed $conditions - * @param array $params - * @return integer - */ - public function max($column = '', $conditions = '', $params = array()) - { - if (is_array($conditions)) { - $where = isset($conditions['condition']) ? $conditions['condition'] : ''; - } else { - $where = $conditions; - } - - $whereClause = !empty($where) ? ' WHERE ' . $where : ''; - $column = !empty($column) ? $this->_tableName() . '.' . $column : $this->_primaryKey; - $relations = $this->_getRelations(); - $limits = $this->_prepareLimit('1'); - - $sql = 'SELECT - ' . $limits['before'] . ' - MAX(' . $column . ') as column_max - FROM ' . $this->_tableName() . ' - ' . $relations['tables'] . ' - ' . $whereClause . ' - ' . $limits['after']; - - $result = $this->_db->select($sql, $params); - - return (isset($result[0]['column_max'])) ? $result[0]['column_max'] : 0; - } - - /** - * Finds a minimum value of the specified column - * Ex.: min('id', 'postID = :postID AND isActive = :isActive', array(':postID'=>10, 'isActive'=>1)); - * @param string $column - * @param mixed $conditions - * @param array $params - * @return integer - */ - public function min($column = '', $conditions = '', $params = array()) - { - if (is_array($conditions)) { - $where = isset($conditions['condition']) ? $conditions['condition'] : ''; - } else { - $where = $conditions; - } - - $whereClause = !empty($where) ? ' WHERE ' . $where : ''; - $column = !empty($column) ? $this->_tableName() . '.' . $column : $this->_primaryKey; - $relations = $this->_getRelations(); - $limits = $this->_prepareLimit('1'); - - $sql = 'SELECT - ' . $limits['before'] . ' - MIN(' . $column . ') as column_min - FROM ' . $this->_tableName() . ' - ' . $relations['tables'] . ' - ' . $whereClause . ' - ' . $limits['after']; - - $result = $this->_db->select($sql, $params); - - return (isset($result[0]['column_min'])) ? $result[0]['column_min'] : 0; - } - - /** - * Finds a sum value of the specified column - * Ex.: sum('id', 'postID = :postID AND isActive = :isActive', array(':postID'=>10, ':isActive'=>1)); - * @param string $column - * @param mixed $conditions - * @param array $params - * @return integer - */ - public function sum($column = '', $conditions = '', $params = array()) - { - if (is_array($conditions)) { - $where = isset($conditions['condition']) ? $conditions['condition'] : ''; - } else { - $where = $conditions; - } - - $whereClause = !empty($where) ? ' WHERE ' . $where : ''; - $column = !empty($column) ? $column : ''; - $relations = $this->_getRelations(); - $limits = $this->_prepareLimit('1'); - - $sql = 'SELECT - ' . $limits['before'] . ' - SUM(' . $column . ') as column_sum - FROM ' . $this->_tableName() . ' - ' . $relations['tables'] . ' - ' . $whereClause . ' - ' . $limits['after']; - - $result = $this->_db->select($sql, $params); - - return (isset($result[0]['column_sum'])) ? $result[0]['column_sum'] : 0; - } - - /** - * Used to define relations between different tables in database and current $_table - * This method should be overridden - */ - protected function _relations() - { - return array(); - } - - /** - * Used to define custom fields - * This method should be overridden - * Usage: 'CONCAT('.CConfig::get('db.prefix').$this->_table.'.last_name, " ", '.CConfig::get('db.prefix').$this->_table.'.first_name)' => 'fullname' - * '(SELECT COUNT(*) FROM '.CConfig::get('db.prefix').$this->_tableTranslation.')' => 'records_count' - */ - protected function _customFields() - { - return array(); - } - - /** - * Used to define encrypted fields - * This method should be overridden - * Usage: 'field_name_1' => array('encrypt'=>'AES_ENCRYPT', 'decrypt'=>'AES_DECRYPT', 'key'=>'encryptKey') - * 'field_name_2' => array('encrypt'=>'AES_ENCRYPT', 'decrypt'=>'AES_DECRYPT', 'key'=>CConfig::get('text.encryptKey')) - */ - protected function _encryptedFields() - { - return array(); - } - - /** - * This method is invoked before saving a record (after validation, if any) - * You may override this method - * @param int $pk - * @return boolean - */ - protected function _beforeSave($pk = 0) - { - // $pk - key used for saving operation - return true; - } - - /** - * This method is invoked after saving a record successfully - * @param int $pk - * You may override this method - */ - protected function _afterSave($pk = 0) - { - // $pk - key used for saving operation - // $this->_columns - array of columns, e.g. $this->_columns['is_active'] - // code here - } - - /** - * This method is invoked before deleting a record (after validation, if any) - * You may override this method - * @param int $pk - * @return boolean - */ - protected function _beforeDelete($pk = 0) - { - // $pk - key used for deleting operation - return true; - } - - /** - * This method is invoked after deleting a record successfully - * @param int $pk - * You may override this method - */ - protected function _afterDelete($pk = 0) - { - // $pk - key used for deleting operation - // code here - } - - /** - * Prepares custom fields for query - * @return string - */ - private function _getCustomFields() - { - $result = ''; - $fields = $this->_customFields(); - if (is_array($fields)) { - foreach ($fields as $key => $val) { - $result .= ', ' . $key . ' as ' . $val; - } - } - - return $result; - } - - /** - * Add custom fields for query - */ - private function _addCustomFields() - { - $fields = $this->_customFields(); - if (is_array($fields)) { - foreach ($fields as $key => $val) { - $this->_columns[$val] = ''; - $this->_columnTypes[$val] = 'varchar'; - } - } - } - - /** - * Remove custom fields for query - */ - private function _removeCustomFields() - { - $fields = $this->_customFields(); - if (is_array($fields)) { - foreach ($fields as $key => $val) { - unset($this->_columns[$val]); - unset($this->_columnTypes[$val]); - } - } - } - - /** - * Prepares relations for query - * @return string - */ - private function _getRelations() - { - $result = array('fields' => '', 'tables' => '', 'fieldsArray' => array()); - $rel = $this->_relations(); - if (!is_array($rel)) return $result; - $defaultJoinType = self::LEFT_OUTER_JOIN; - $nl = "\n"; - - foreach ($rel as $key => $val) { - $key = isset($val['parent_key']) ? $val['parent_key'] : $key; - $relationType = isset($val[0]) ? $val[0] : ''; - $relatedTable = isset($val[1]) ? $val[1] : ''; - $relatedTableKey = isset($val[2]) ? $val[2] : ''; - $joinType = (isset($val['joinType']) && in_array($val['joinType'], self::$_joinTypes)) ? $val['joinType'] : $defaultJoinType; - $condition = isset($val['condition']) ? $val['condition'] : ''; - - if ( - $relationType == self::HAS_ONE || - $relationType == self::BELONGS_TO || - $relationType == self::HAS_MANY || - $relationType == self::MANY_MANY - ) { - if (isset($val['fields']) && is_array($val['fields'])) { - foreach ($val['fields'] as $field => $fieldAlias) { - if (is_numeric($field)) { - $field = $fieldAlias; - $fieldAlias = ''; - } - $result['fields'] .= ', ' . $this->_tableName($relatedTable) . '.' . $field . (!empty($fieldAlias) ? ' as ' . $fieldAlias : ''); - $result['fieldsArray'][] = (!empty($fieldAlias) ? $fieldAlias : $field); - } - } else { - $result['fields'] .= ', ' . $this->_tableName($relatedTable) . '.*'; - } - $result['tables'] .= $joinType . ' ' . $this->_tableName($relatedTable) . ' ON ' . $this->_tableName() . '.' . $key . ' = ' . $this->_tableName($relatedTable) . '.' . $relatedTableKey; - $result['tables'] .= (($condition != '') ? ' AND ' . $condition : '') . $nl; - } - } - - return $result; - } - - /** - * Prepare LIMIT clause for SQL statement - * @param string $limit - * @retun array - */ - private function _prepareLimit($limit = '') - { - $limits = array('before' => '', 'after' => ''); - - if (!empty($limit)) { - if (preg_match('/mssql|sqlsrv/i', $this->_dbDriver)) { - $limits['before'] = !empty($limit) ? ' TOP ' . $limit : ''; - } else { - $limits['after'] = !empty($limit) ? ' LIMIT ' . $limit : ''; - } - } - - return $limits; - } - - /** - * Escapes table name with backquotes and adds db prefix - * Prepares table name for using in SQL statements - * @param string $table - * @return string - */ - private function _tableName($table = '') - { - if (empty($table)) { - $table = $this->_table; - } - - return $this->_backQuote . $this->_dbPrefix . $table . $this->_backQuote; - } - - /** - * Checks if a given field is encrypted field - * @param string $column - * @return bool - */ - private function _isEncryptedField($column = '') - { - $encryptedFields = $this->_encryptedFields(); - return isset($encryptedFields[$column]) ? true : false; - } - - /** - * Prepares encrypted fields for query - * @return string - */ - private function _getEncryptedFields() - { - $result = ''; - $fields = $this->_encryptedFields(); - if (is_array($fields)) { - foreach ($fields as $key => $val) { - $encryptedField = $this->_getEncryptedField($key); - $result .= ', ' . $encryptedField['decrypt'] . '(' . $key . ',"' . $encryptedField['key'] . '") as ' . $key; - } - } - - return $result; - } - - /** - * Returns encrypted field info - * @param string $column - * @return array - */ - private function _getEncryptedField($column = '') - { - $encryptedFields = $this->_encryptedFields(); - return isset($encryptedFields[$column]) ? $encryptedFields[$column] : array(); - } + public function find($conditions = '', $params = [], $cacheId = false) + { + if (is_array($conditions)) { + $where = isset($conditions['condition']) ? $conditions['condition'] : ''; + if (isset($conditions['order'])) { + $order = isset($conditions['order']) ? $conditions['order'] : ''; + } elseif (isset($conditions['orderBy'])) { + $order = isset($conditions['orderBy']) ? $conditions['orderBy'] : ''; + } + } else { + $where = $conditions; + $order = ''; + } + + $whereClause = ! empty($where) ? ' WHERE '.$where : ''; + $orderBy = ! empty($order) ? ' ORDER BY '.$order : ''; + $relations = $this->_getRelations(); + $customFields = $this->_getCustomFields(); + $encryptedField = $this->_getEncryptedFields(); + $limits = $this->_prepareLimit('1'); + + $sql = 'SELECT + '.$limits['before'].' + '.$this->_tableName().'.* + '.$relations['fields'].' + '.$customFields.' + '.$encryptedField.' + FROM '.$this->_tableName().' + '.$relations['tables'].' + '.$whereClause.' + '.$orderBy.' + '.$limits['after']; + + $result = $this->_db->select($sql, $params, 'fetchAll', PDO::FETCH_ASSOC, $cacheId); + if (isset($result[0]) && is_array($result[0])) { + foreach ($result[0] as $key => $val) { + $this->$key = $val; + if ($key == $this->_primaryKey) { + $this->_pkValue = $val; + } + } + + return $this; + } else { + return null; + } + } + + /** + * This method queries your database to find related objects by PK + * Ex.: findByPk($pk, 'postID = :postID AND isActive = :isActive', array(':postID'=>10, ':isActive'=>1)); + * Ex.: findByPk($pk, array('condition'=>'postID = :postID AND isActive = :isActive', 'order|orderBy'=>'id DESC'), 'params'=>array(':postID'=>10, ':isActive'=>1)); + * + * @param string $pk + * @param mixed $conditions + * @param array $params + * @param bool|string $cacheId + * + * @return object + */ + public function findByPk($pk, $conditions = '', $params = [], $cacheId = false) + { + if (is_array($conditions)) { + $where = isset($conditions['condition']) ? $conditions['condition'] : ''; + if (isset($conditions['order'])) { + $order = isset($conditions['order']) ? $conditions['order'] : ''; + } elseif (isset($conditions['orderBy'])) { + $order = isset($conditions['orderBy']) ? $conditions['orderBy'] : ''; + } + } else { + $where = $conditions; + $order = ''; + } + + $whereClause = ! empty($where) ? ' AND ('.$where.')' : ''; + $orderBy = ! empty($order) ? ' ORDER BY '.$order : ''; + $relations = $this->_getRelations(); + $customFields = $this->_getCustomFields(); + $encryptedField = $this->_getEncryptedFields(); + $limits = $this->_prepareLimit('1'); + + $sql = 'SELECT + '.$limits['before'].' + '.$this->_tableName().'.* + '.$relations['fields'].' + '.$customFields.' + '.$encryptedField.' + FROM '.$this->_tableName().' + '.$relations['tables'].' + WHERE '.$this->_tableName().'.'.$this->_primaryKey.' = '.(int)$pk.' + '.$whereClause.' + '.$orderBy.' + '.$limits['after']; + + $result = $this->_db->select($sql, $params, 'fetchAll', PDO::FETCH_ASSOC, $cacheId); + if (isset($result[0]) && is_array($result[0])) { + foreach ($result[0] as $key => $val) { + $this->$key = $val; + } + $this->_pkValue = $pk; + + return $this; + } else { + return null; + } + } + + /** + * This method queries your database to find related objects by attributes + * Ex.: findByAttributes($attributes, 'postID = :postID AND isActive = :isActive', array(':postID'=>10, ':isActive'=>1)); + * Ex.: findByAttributes($attributes, array('condition'=>'postID = :postID AND isActive = :isActive', 'order|orderBy'=>'id DESC', 'limit'=>'0, 10'), 'params'=>array(':postID'=>10, ':isActive'=>1)); + * Ex.: $attributes = array('first_name'=>$firstName, 'last_name'=>$lastName); + * + * @param array $attributes + * @param mixed $conditions + * @param array $params + * + * @return mixed + */ + public function findByAttributes($attributes, $conditions = '', $params = []) + { + if (is_array($conditions)) { + $where = isset($conditions['condition']) ? $conditions['condition'] : ''; + if (isset($conditions['order'])) { + $order = isset($conditions['order']) ? $conditions['order'] : ''; + } elseif (isset($conditions['orderBy'])) { + $order = isset($conditions['orderBy']) ? $conditions['orderBy'] : ''; + } + $limit = isset($conditions['limit']) ? $conditions['limit'] : ''; + } else { + $where = $conditions; + $order = ''; + $limit = ''; + } + + $whereClause = ! empty($where) ? ' AND '.$where : ''; + $orderBy = ! empty($order) ? ' ORDER BY '.$order : ''; + $limits = $this->_prepareLimit($limit); + + $relations = $this->_getRelations(); + $customFields = $this->_getCustomFields(); + $encryptedField = $this->_getEncryptedFields(); + + $attributes_clause = ''; + foreach ($attributes as $key => $value) { + $attributes_clause .= ' AND '.$key." = '".$value."'"; + } + + $sql = 'SELECT + '.$limits['before'].' + '.$this->_tableName().'.* + '.$relations['fields'].' + '.$customFields.' + FROM '.$this->_tableName().' + '.$relations['tables'].' + '.$encryptedField.' + WHERE 1 = 1 + '.$attributes_clause.' + '.$whereClause.' + '.$orderBy.' + '.$limits['after']; + + return $this->_db->select($sql, $params); + } + + /** + * This method queries your database to find all related objects + * Ex.: findAll('post_id = :postID AND is_active = :isActive', array(':postID'=>10, ':isActive'=>1)); + * Ex.: findAll(array('condition'=>'post_id = :postID AND is_active = :isActive', 'select'=>'', 'group|groupBy'=>'', 'order|orderBy'=>'id DESC', 'limit'=>'0, 10'), array(':postID'=>10, ':isActive'=>1)); + * Ex.: findAll(CConfig::get('db.prefix').$this->_tableTranslation.'.news_text LIKE :keywords', array(':keywords'=>'%'.$keywords.'%')); + * + * @param mixed $conditions + * @param array $params 'select': MAX(date), name or CConfig::get('db.prefix').table.field_name etc. - actually for ONLY_FULL_GROUP_BY mode + * 'groupBy': table.field_name or field_name + * @param bool|string $cacheId + * @param int $fetchMode + * + * @return array + */ + public function findAll($conditions = '', $params = [], $cacheId = false, $fetchMode = PDO::FETCH_ASSOC) + { + if (is_array($conditions)) { + $where = isset($conditions['condition']) ? $conditions['condition'] : ''; + if (isset($conditions['group'])) { + $group = isset($conditions['group']) ? $conditions['group'] : ''; + } elseif (isset($conditions['groupBy'])) { + $group = isset($conditions['groupBy']) ? $conditions['groupBy'] : ''; + } + if (isset($conditions['order'])) { + $order = isset($conditions['order']) ? $conditions['order'] : ''; + } elseif (isset($conditions['orderBy'])) { + $order = isset($conditions['orderBy']) ? $conditions['orderBy'] : ''; + } + $limit = isset($conditions['limit']) ? $conditions['limit'] : ''; + $select = isset($conditions['select']) ? $conditions['select'] : ''; + } else { + $where = $conditions; + $group = ''; + $order = ''; + $limit = ''; + $select = ''; + } + + $whereClause = ! empty($where) ? ' WHERE '.$where : ''; + $groupBy = ! empty($group) ? ' GROUP BY '.$group : ''; + $orderBy = ! empty($order) ? ' ORDER BY '.$order : ''; + $limits = $this->_prepareLimit($limit); + $selectList = ! empty($select) ? $select : $this->_tableName().'.*'; + + $relations = $this->_getRelations(); + $customFields = $this->_getCustomFields(); + $encryptedField = $this->_getEncryptedFields(); + + $sql = 'SELECT + '.$limits['before'].' + '.$selectList.' + '.$relations['fields'].' + '.$customFields.' + '.$encryptedField.' + FROM '.$this->_tableName().' + '.$relations['tables'].' + '.$whereClause.' + '.$groupBy.' + '.$orderBy.' + '.$limits['after']; + + return $this->_db->select($sql, $params, 'fetchAll', $fetchMode, $cacheId); + } + + /** + * This method queries your database to find first related record primary key + * Ex.: findPk('postID = :postID AND isActive = :isActive', array(':postID'=>10, ':isActive'=>1)); + * + * @param mixed $conditions + * @param array $params + * + * @return int + */ + public function findPk($conditions = '', $params = []) + { + if ($result = $this->find($conditions, $params)) { + $key = $this->_primaryKey; + + return $result->$key; + } + + return ''; + } + + /** + * Create new record + * + * @param array $data + * @param bool $preOperations + * + * @return bool + */ + public function create($data = [], $preOperations = true) + { + $allowOperation = true; + if ($preOperations) { + if ( ! $this->_beforeSave($this->_pkValue)) { + $allowOperation = false; + CDebug::AddMessage( + 'errors', + 'before-save', + A::t('core', 'AR before operation on table: {table}', ['{table}' => $this->_table]) + ); + } + } + + if ($allowOperation) { + $result = $this->_db->insert($this->_table, $data); + $this->_isNewRecord = true; + // Save last inset ID + $this->_pkValue = (int)$result; + + if ($result) { + if ($preOperations) { + $this->_afterSave($this->_pkValue); + } + + return true; + } + } + + return false; + } + + /** + * Update existing record + * + * @param int $id + * @param array $data + * @param bool $preOperations + * @param bool $forceSave + * + * @return boolean + */ + public function update($id, $data = [], $preOperations = true, $forceSave = false) + { + $allowOperation = true; + if ($preOperations) { + if ( ! $this->_beforeSave($id)) { + $allowOperation = false; + CDebug::AddMessage( + 'errors', + 'before-save', + A::t('core', 'AR before operation on table: {table}', ['{table}' => $this->_table]) + ); + } + } + + if ($allowOperation) { + $result = $this->_db->update( + $this->_table, + $data, + $this->_primaryKey.' = :primary_key', + [':primary_key' => (int)$id], + $forceSave + ); + $this->_isNewRecord = false; + + if ($result) { + if ($preOperations) { + $this->_afterSave($id); + } + + return true; + } + } + + return false; + } + + /** + * Save data + * + * @param CRecordEntity $entity + * @param bool $forceSave + * + * @return boolean + */ + public function save($entity = null, $forceSave = false) + { + $data = []; + $this->_removeCustomFields(); + + if ( ! is_null($entity) && ($entity instanceof CRecordEntity)) { + // --------------------------------------- + // Handle Entity + // --------------------------------------- + $columns = $entity->allowedColumns(); + $primaryKey = $entity->primaryKey(); + $pkValue = $entity->getPrimaryKey(); + + foreach ($columns as $column => $val) { + if ($column != 'id' && $column != $primaryKey) { + $data[$column] = $entity->$column; + } + } + + if ($pkValue > 0) { + $result = $this->_db->update( + $this->_table, + $data, + $primaryKey.' = :primary_key', + [':primary_key' => (int)$pkValue], + $forceSave + ); + } else { + $result = $this->_db->insert($this->_table, $data, $forceSave); + // Save last inset ID + $pkValue = (int)$result; + } + + if ($result) { + $this->_afterSave($pkValue); + + return true; + } + } else { + // --------------------------------------- + // Handle Model + // --------------------------------------- + if ($this->_beforeSave($this->_pkValue)) { + $columns = $this->allowedColumns(); + foreach ($columns as $column => $val) { + $relations = $this->_getRelations(); + if ($column != 'id' && $column != $this->_primaryKey + && ! in_array( + $column, + $relations['fieldsArray'] + ) + ) { // && ($column != 'created_at') && !$NEW) + //$value = $this->$column; + //if(array_search($this->_columnTypes[$column], array('int', 'float', 'decimal'))){ + // $value = filter_var($value, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); + //} + if ($this->_isEncryptedField($column)) { + $encryptedField = $this->_getEncryptedField($column); + $data[$column] = [ + 'param_key' => $encryptedField['encrypt'].'('.$column.',"'.$encryptedField['key'] + .'")', + 'param_value' => $this->$column + ]; + } else { + $data[$column] = $this->$column; + } + } + } + + if ($this->_pkValue > 0) { + $result = $this->_db->update( + $this->_table, + $data, + $this->_primaryKey.' = :primary_key', + [':primary_key' => (int)$this->_pkValue], + $forceSave + ); + $this->_isNewRecord = false; + } else { + $result = $this->_db->insert($this->_table, $data, $forceSave); + $this->_isNewRecord = true; + // Save last inset ID + $this->_pkValue = (int)$result; + } + + if ($result) { + $this->_afterSave($this->_pkValue); + + return true; + } + } else { + CDebug::AddMessage( + 'errors', + 'before-save', + A::t('core', 'AR before operation on table: {table}', ['{table}' => $this->_table]) + ); + } + } + + return false; + } + + /** + * Clear primary key + * + * @return boolean + */ + public function clearPkValue() + { + $this->_pkValue = 0; + + return true; + } + + /** + * Reset the object with fields + * + * @return boolean + */ + public function reset() + { + $this->_columns = []; + $this->_specialFields = []; + + if ( ! empty($this->_table)) { + $this->_createObjectFromTable(); + $this->_pkValue = 0; + } + + return true; + } + + /** + * Updates records with the specified primary key + * See {@link find()} for detailed explanation about $conditions + * Ex.: updateByPk($pk, array('name'=>$value), 'postID = 10 AND isActive = 1'); + * + * @param string $pk + * @param array $data + * @param mixed $conditions + * @param array $params + * + * @return bool + */ + public function updateByPk($pk, $data = [], $conditions = '', $params = []) + { + if ($this->_beforeSave($pk)) { + if (is_array($conditions)) { + $where = isset($conditions['condition']) ? $conditions['condition'] : ''; + } else { + $where = $conditions; + } + $whereClause = ! empty($where) ? ' AND '.$where : ''; + $params[':primary_key'] = (int)$pk; + + $result = $this->_db->update( + $this->_table, + $data, + $this->_primaryKey.' = :primary_key'.$whereClause, + $params + ); + if ($result) { + $this->_afterSave($pk); + + return true; + } else { + return false; + } + } else { + CDebug::AddMessage( + 'errors', + 'before-update', + A::t('core', 'AR before operation on table: {table}', ['{table}' => $this->_table]) + ); + } + } + + /** + * Updates the rows matching the specified condition + * Ex.: updateAll(array('name'=>$value), 'postID = 10 AND isActive = 1'); + * Ex.: updateAll(array('name'=>$value), 'postID = 10 AND isActive = :isActive', array(':isActiv'=>1)); + * + * @param array $data + * @param mixed $conditions + * @param array $params + * + * @return bool + */ + public function updateAll($data = [], $conditions = '', $params = []) + { + if (is_array($conditions)) { + $where = isset($conditions['condition']) ? $conditions['condition'] : ''; + } else { + $where = $conditions; + } + $whereClause = ! empty($where) ? $where : '1'; + + $result = $this->_db->update($this->_table, $data, $whereClause, $params); + if ($result) { + return true; + } else { + return false; + } + } + + /** + * Remove the row from database if AR instance has been populated with this row + * Ex.: $post = PostModel::model()->findByPk(10); + * $post->delete(); + * + * @return boolean + */ + public function delete() + { + if ( ! empty($this->_pkValue) && $this->deleteByPk($this->_pkValue)) { + return true; + } + + return false; + } + + /** + * Remove the rows matching the specified condition and primary key(s) + * Ex.: deleteByPk(10, 'postID = :postID AND isActive = :isActive', array(':postID'=>10, ':isActive'=>1)); + * + * @param string $pk + * @param mixed $conditions + * @param array $params + * + * @return boolean + */ + public function deleteByPk($pk, $conditions = '', $params = []) + { + if ($this->_beforeDelete($pk)) { + if (is_array($conditions)) { + $where = isset($conditions['condition']) ? $conditions['condition'] : ''; + } else { + $where = $conditions; + } + $whereClause = ! empty($where) ? ' WHERE '.$where : ''; + $params[':primary_key'] = (int)$pk; + + $result = $this->_db->delete($this->_table, $this->_primaryKey.' = :primary_key'.$whereClause, $params); + if ($result) { + $this->_afterDelete($pk); + + return true; + } + } else { + CDebug::AddMessage( + 'errors', + 'before-delete', + A::t( + 'core', + 'AR before delete operation on table: {table}', + ['{table}' => $this->_table] + ) + ); + } + + return false; + } + + /** + * Remove the rows matching the specified condition + * Ex.: deleteAll('postID = :postID AND isActive = :isActive', array(':postID'=>10, ':isActive'=>1)); + * Ex.: deleteAll(array('condition'=>'postID = :postID AND isActive = :isActive'), array(':postID'=>10, ':isActive'=>1)); + * + * @param mixed $conditions + * @param array $params + * + * @return boolean + */ + public function deleteAll($conditions = '', $params = []) + { + if ($this->_beforeDelete()) { + if (is_array($conditions)) { + $where = isset($conditions['condition']) ? $conditions['condition'] : ''; + } else { + $where = $conditions; + } + $whereClause = ! empty($where) ? ' WHERE '.$where : ''; + + $result = $this->_db->delete($this->_table, $whereClause, $params); + if ($result) { + $this->_afterDelete(); + + return true; + } + } else { + CDebug::AddMessage( + 'errors', + 'before-delete', + A::t( + 'core', + 'AR before delete operation on table: {table}', + ['{table}' => $this->_table] + ) + ); + } + + return false; + } + + /** + * This method selects distinct value + * + * @param string $field + * + * @return array + */ + public function distinct($field = '') + { + return $this->findAll(['group' => $this->_tableName().'.'.$field]); + } + + /** + * This method reloads model data according to the current primary key + * + * @return object + */ + public function refresh() + { + return $this->findByPk($this->_pkValue); + } + + /** + * This method check if there is at least one row satisfying the specified condition + * Ex.: exists('postID = :postID AND isActive = :isActive', array(':postID'=>10, ':isActive'=>1)); + * + * @param mixed $conditions + * @param array $params + * + * @return bolean + */ + public function exists($conditions = '', $params = []) + { + if (is_array($conditions)) { + $where = isset($conditions['condition']) ? $conditions['condition'] : ''; + } else { + $where = $conditions; + } + + $whereClause = ! empty($where) ? ' WHERE '.$where : ''; + $limits = $this->_prepareLimit('1'); + + $sql = 'SELECT + '.$limits['before'].' + '.$this->_tableName().'.* + FROM '.$this->_tableName().' + '.$whereClause.' + '.$limits['after']; + + $result = $this->_db->select($sql, $params); + + return ($result) ? true : false; + } + + /** + * Finds the number of rows satisfying the specified query condition + * Ex.: count('postID = :postID AND isActive = :isActive', array(':postID'=>10, ':isActive'=>1)); + * Ex.: count(array('condition'=>'post_id = :postID AND is_active = :isActive', 'select'=>'', 'count'=>'*', 'group|groupBy'=>'', 'order|orderBy'=>'', 'allRows'=>false), array(':postID'=>10, ':isActive'=>1)); + * + * @param mixed $conditions + * @param array $params + * + * @return integer + */ + public function count($conditions = '', $params = []) + { + if (is_array($conditions)) { + $where = isset($conditions['condition']) ? $conditions['condition'] : ''; + if (isset($conditions['group'])) { + $group = isset($conditions['group']) ? $conditions['group'] : ''; + } elseif (isset($conditions['groupBy'])) { + $group = isset($conditions['groupBy']) ? $conditions['groupBy'] : ''; + } + if ( ! empty($group)) { + if (isset($conditions['order'])) { + $order = isset($conditions['order']) ? $conditions['order'] : ''; + } elseif (isset($conditions['orderBy'])) { + $order = isset($conditions['orderBy']) ? $conditions['orderBy'] : ''; + } + } + $count = isset($conditions['count']) ? $conditions['count'] : '*'; + $select = isset($conditions['select']) ? $conditions['select'] : ''; + $allRows = isset($conditions['allRows']) ? (bool)$conditions['allRows'] : false; + } else { + $where = $conditions; + $group = ''; + $order = ''; + $count = '*'; + $select = ''; + $allRows = false; + } + + $whereClause = ! empty($where) ? ' WHERE '.$where : ''; + $groupBy = ! empty($group) ? ' GROUP BY '.$group : ''; + $orderBy = ! empty($order) ? ' ORDER BY '.$order : ''; + $limits = $this->_prepareLimit(($allRows ? '' : '1')); + $relations = $this->_getRelations(); + + $sql = 'SELECT + '.$limits['before'].' + COUNT('.$count.') as cnt + '.($select ? ', '.$select : '').' + FROM '.$this->_tableName().' + '.$relations['tables'].' + '.$whereClause.' + '.$groupBy.' + '.$orderBy.' + '.$limits['after']; + + $result = $this->_db->select($sql, $params); + + if ($allRows) { + return (isset($result)) ? $result : null; + } else { + return (isset($result[0]['cnt'])) ? $result[0]['cnt'] : 0; + } + } + + /** + * Finds a maximum value of the specified column + * Ex.: max('id', 'postID = :postID AND isActive = :isActive', array(':postID'=>10, ':isActive'=>1)); + * + * @param string $column + * @param mixed $conditions + * @param array $params + * + * @return integer + */ + public function max($column = '', $conditions = '', $params = []) + { + if (is_array($conditions)) { + $where = isset($conditions['condition']) ? $conditions['condition'] : ''; + } else { + $where = $conditions; + } + + $whereClause = ! empty($where) ? ' WHERE '.$where : ''; + $column = ! empty($column) ? $this->_tableName().'.'.$column : $this->_primaryKey; + $relations = $this->_getRelations(); + $limits = $this->_prepareLimit('1'); + + $sql = 'SELECT + '.$limits['before'].' + MAX('.$column.') as column_max + FROM '.$this->_tableName().' + '.$relations['tables'].' + '.$whereClause.' + '.$limits['after']; + + $result = $this->_db->select($sql, $params); + + return (isset($result[0]['column_max'])) ? $result[0]['column_max'] : 0; + } + + /** + * Finds a minimum value of the specified column + * Ex.: min('id', 'postID = :postID AND isActive = :isActive', array(':postID'=>10, 'isActive'=>1)); + * + * @param string $column + * @param mixed $conditions + * @param array $params + * + * @return integer + */ + public function min($column = '', $conditions = '', $params = []) + { + if (is_array($conditions)) { + $where = isset($conditions['condition']) ? $conditions['condition'] : ''; + } else { + $where = $conditions; + } + + $whereClause = ! empty($where) ? ' WHERE '.$where : ''; + $column = ! empty($column) ? $this->_tableName().'.'.$column : $this->_primaryKey; + $relations = $this->_getRelations(); + $limits = $this->_prepareLimit('1'); + + $sql = 'SELECT + '.$limits['before'].' + MIN('.$column.') as column_min + FROM '.$this->_tableName().' + '.$relations['tables'].' + '.$whereClause.' + '.$limits['after']; + + $result = $this->_db->select($sql, $params); + + return (isset($result[0]['column_min'])) ? $result[0]['column_min'] : 0; + } + + /** + * Finds a sum value of the specified column + * Ex.: sum('id', 'postID = :postID AND isActive = :isActive', array(':postID'=>10, ':isActive'=>1)); + * + * @param string $column + * @param mixed $conditions + * @param array $params + * + * @return integer + */ + public function sum($column = '', $conditions = '', $params = []) + { + if (is_array($conditions)) { + $where = isset($conditions['condition']) ? $conditions['condition'] : ''; + } else { + $where = $conditions; + } + + $whereClause = ! empty($where) ? ' WHERE '.$where : ''; + $column = ! empty($column) ? $column : ''; + $relations = $this->_getRelations(); + $limits = $this->_prepareLimit('1'); + + $sql = 'SELECT + '.$limits['before'].' + SUM('.$column.') as column_sum + FROM '.$this->_tableName().' + '.$relations['tables'].' + '.$whereClause.' + '.$limits['after']; + + $result = $this->_db->select($sql, $params); + + return (isset($result[0]['column_sum'])) ? $result[0]['column_sum'] : 0; + } + + /** + * Used to define relations between different tables in database and current $_table + * This method should be overridden + */ + protected function _relations() + { + return []; + } + + /** + * Used to define custom fields + * This method should be overridden + * Usage: 'CONCAT('.CConfig::get('db.prefix').$this->_table.'.last_name, " ", '.CConfig::get('db.prefix').$this->_table.'.first_name)' => 'fullname' + * '(SELECT COUNT(*) FROM '.CConfig::get('db.prefix').$this->_tableTranslation.')' => 'records_count' + */ + protected function _customFields() + { + return []; + } + + /** + * Used to define encrypted fields + * This method should be overridden + * Usage: 'field_name_1' => array('encrypt'=>'AES_ENCRYPT', 'decrypt'=>'AES_DECRYPT', 'key'=>'encryptKey') + * 'field_name_2' => array('encrypt'=>'AES_ENCRYPT', 'decrypt'=>'AES_DECRYPT', 'key'=>CConfig::get('text.encryptKey')) + */ + protected function _encryptedFields() + { + return []; + } + + /** + * This method is invoked before saving a record (after validation, if any) + * You may override this method + * + * @param int $pk + * + * @return boolean + */ + protected function _beforeSave($pk = 0) + { + // $pk - key used for saving operation + return true; + } + + /** + * This method is invoked after saving a record successfully + * + * @param int $pk + * You may override this method + */ + protected function _afterSave($pk = 0) + { + // $pk - key used for saving operation + // $this->_columns - array of columns, e.g. $this->_columns['is_active'] + // code here + } + + /** + * This method is invoked before deleting a record (after validation, if any) + * You may override this method + * + * @param int $pk + * + * @return boolean + */ + protected function _beforeDelete($pk = 0) + { + // $pk - key used for deleting operation + return true; + } + + /** + * This method is invoked after deleting a record successfully + * + * @param int $pk + * You may override this method + */ + protected function _afterDelete($pk = 0) + { + // $pk - key used for deleting operation + // code here + } + + /** + * Prepares custom fields for query + * + * @return string + */ + private function _getCustomFields() + { + $result = ''; + $fields = $this->_customFields(); + if (is_array($fields)) { + foreach ($fields as $key => $val) { + $result .= ', '.$key.' as '.$val; + } + } + + return $result; + } + + /** + * Add custom fields for query + */ + private function _addCustomFields() + { + $fields = $this->_customFields(); + if (is_array($fields)) { + foreach ($fields as $key => $val) { + $this->_columns[$val] = ''; + $this->_columnTypes[$val] = 'varchar'; + } + } + } + + /** + * Remove custom fields for query + */ + private function _removeCustomFields() + { + $fields = $this->_customFields(); + if (is_array($fields)) { + foreach ($fields as $key => $val) { + unset($this->_columns[$val]); + unset($this->_columnTypes[$val]); + } + } + } + + /** + * Prepares relations for query + * + * @return string + */ + private function _getRelations() + { + $result = ['fields' => '', 'tables' => '', 'fieldsArray' => []]; + $rel = $this->_relations(); + if ( ! is_array($rel)) { + return $result; + } + $defaultJoinType = self::LEFT_OUTER_JOIN; + $nl = "\n"; + + foreach ($rel as $key => $val) { + $key = isset($val['parent_key']) ? $val['parent_key'] : $key; + $relationType = isset($val[0]) ? $val[0] : ''; + $relatedTable = isset($val[1]) ? $val[1] : ''; + $relatedTableKey = isset($val[2]) ? $val[2] : ''; + $joinType = (isset($val['joinType']) && in_array($val['joinType'], self::$_joinTypes)) + ? $val['joinType'] : $defaultJoinType; + $condition = isset($val['condition']) ? $val['condition'] : ''; + + if ( + $relationType == self::HAS_ONE || $relationType == self::BELONGS_TO || $relationType == self::HAS_MANY + || $relationType == self::MANY_MANY + ) { + if (isset($val['fields']) && is_array($val['fields'])) { + foreach ($val['fields'] as $field => $fieldAlias) { + if (is_numeric($field)) { + $field = $fieldAlias; + $fieldAlias = ''; + } + $result['fields'] .= ', '.$this->_tableName($relatedTable).'.'.$field + .(! empty($fieldAlias) ? ' as '.$fieldAlias : ''); + $result['fieldsArray'][] = (! empty($fieldAlias) ? $fieldAlias : $field); + } + } else { + $result['fields'] .= ', '.$this->_tableName($relatedTable).'.*'; + } + $result['tables'] .= $joinType.' '.$this->_tableName($relatedTable).' ON '.$this->_tableName().'.'.$key + .' = '.$this->_tableName($relatedTable).'.'.$relatedTableKey; + $result['tables'] .= (($condition != '') ? ' AND '.$condition : '').$nl; + } + } + + return $result; + } + + /** + * Prepare LIMIT clause for SQL statement + * + * @param string $limit + * + * @retun array + */ + private function _prepareLimit($limit = '') + { + $limits = ['before' => '', 'after' => '']; + + if ( ! empty($limit)) { + if (preg_match('/mssql|sqlsrv/i', $this->_dbDriver)) { + $limits['before'] = ! empty($limit) ? ' TOP '.$limit : ''; + } else { + $limits['after'] = ! empty($limit) ? ' LIMIT '.$limit : ''; + } + } + + return $limits; + } + + /** + * Escapes table name with backquotes and adds db prefix + * Prepares table name for using in SQL statements + * + * @param string $table + * + * @return string + */ + private function _tableName($table = '') + { + if (empty($table)) { + $table = $this->_table; + } + + return $this->_backQuote.$this->_dbPrefix.$table.$this->_backQuote; + } + + /** + * Checks if a given field is encrypted field + * + * @param string $column + * + * @return bool + */ + private function _isEncryptedField($column = '') + { + $encryptedFields = $this->_encryptedFields(); + + return isset($encryptedFields[$column]) ? true : false; + } + + /** + * Prepares encrypted fields for query + * + * @return string + */ + private function _getEncryptedFields() + { + $result = ''; + $fields = $this->_encryptedFields(); + if (is_array($fields)) { + foreach ($fields as $key => $val) { + $encryptedField = $this->_getEncryptedField($key); + $result .= ', '.$encryptedField['decrypt'].'('.$key.',"'.$encryptedField['key'].'") as '.$key; + } + } + + return $result; + } + + /** + * Returns encrypted field info + * + * @param string $column + * + * @return array + */ + private function _getEncryptedField($column = '') + { + $encryptedFields = $this->_encryptedFields(); + + return isset($encryptedFields[$column]) ? $encryptedFields[$column] : []; + } } diff --git a/framework/db/CDatabase.php b/framework/db/CDatabase.php index 367a310..dac23e9 100644 --- a/framework/db/CDatabase.php +++ b/framework/db/CDatabase.php @@ -39,796 +39,966 @@ class CDatabase extends PDO { - - /** @var string */ - public static $count = 0; - - /** @var object */ - private static $_instance; - /** @var string */ - private $_dbPrefix; - /** @var string */ - private $_dbDriver; - /** @var string */ - private $_dbName; - /** @var bool */ - private $_cache; - /** @var string */ - private $_cacheType; - /** @var int */ - private $_cacheLifetime; - /** @var string */ - private $_cacheDir; - /** @var string */ - private $_query; - /** @var char */ - private $_backQuote = '`'; - /** @var boolean */ - private static $_error; - /** @var string */ - private static $_errorMessage; - - /** - * Class default constructor - * @param array $params - */ - public function __construct($params = array()) - { - // For direct use (e.g. setup module) - if (!empty($params)) { - $dbDriver = isset($params['dbDriver']) ? $params['dbDriver'] : ''; - $dbSocket = isset($params['dbSocket']) ? $params['dbSocket'] : ''; - $dbHost = isset($params['dbHost']) ? $params['dbHost'] : ''; - $dbPort = isset($params['dbPort']) ? $params['dbPort'] : ''; - $dbName = isset($params['dbName']) ? $params['dbName'] : ''; - $dbUser = isset($params['dbUser']) ? $params['dbUser'] : ''; - $dbPassword = isset($params['dbPassword']) ? $params['dbPassword'] : ''; - $dbCharset = isset($params['dbCharset']) ? $params['dbCharset'] : 'utf8'; - - try { - $this->_init($dbDriver, $dbSocket, $dbHost, $dbPort, $dbName, $dbUser, $dbPassword, $dbCharset); - $this->_dbDriver = $dbDriver; - $this->_dbName = $dbName; - $this->_dbPrefix = ''; - } catch (Exception $e) { - self::$_error = true; - self::$_errorMessage = $e->getMessage(); - } - } else { - if (!A::app()->isSetup()) { - if (APPHP_MODE == 'debug') { - $startTime = CTime::getMicrotime(); - } - - try { - if (CConfig::get('db') != '') { - $this->_init(CConfig::get('db.driver'), CConfig::get('db.socket'), CConfig::get('db.host'), CConfig::get('db.port'), CConfig::get('db.database'), CConfig::get('db.username'), CConfig::get('db.password'), CConfig::get('db.charset', 'utf8')); - } else { - throw new Exception('Missing database configuration file'); - } - } catch (Exception $e) { - header('HTTP/1.1 503 Service Temporarily Unavailable'); - header('Status: 503 Service Temporarily Unavailable'); - $output = self::_fatalErrorPageContent(); - if (APPHP_MODE == 'debug') { - $output = str_ireplace('{DESCRIPTION}', '

    ' . A::t('core', 'This application is currently experiencing some database difficulties') . '

    ', $output); - $output = str_ireplace( - '{CODE}', - 'Description: ' . $e->getMessage() . '
    - File: ' . $e->getFile() . '
    - Line: ' . $e->getLine(), - $output - ); - } else { - $output = str_ireplace('{DESCRIPTION}', '

    ' . A::t('core', 'This application is currently experiencing some database difficulties. Please check back again later') . '

    ', $output); - $output = str_ireplace('{CODE}', A::t('core', 'For more information turn on debug mode in your application'), $output); - } - echo $output; - exit(1); - } - - $this->_dbDriver = CConfig::get('db.driver'); - $this->_dbName = CConfig::get('db.database'); - $this->_dbPrefix = CConfig::get('db.prefix'); - - $this->_cache = CConfig::get('cache.db.enable') ? true : false; - $this->_cacheType = in_array(CConfig::get('cache.db.type'), array('auto', 'manual')) ? CConfig::get('cache.db.type') : 'auto'; - $this->_cacheLifetime = CConfig::get('cache.db.lifetime', 0); /* in minutes */ - $this->_cacheDir = CConfig::get('cache.db.path'); /* protected/tmp/cache/ */ - if ($this->_cache) CDebug::addMessage('general', 'cache', 'enabled (' . $this->_cacheType . ') '); - - // Save data for debug - if (APPHP_MODE == 'debug') { - $finishTime = CTime::getMicrotime(); - $sqlConnectionTime = round((float)$finishTime - (float)$startTime, 5); - CDebug::addSqlConnectionTime($sqlConnectionTime); - } - } - } - - // Set back quote according to database driver - if (!empty($this->_dbDriver) && preg_match('/mssql|sqlsrv/i', $this->_dbDriver)) { - $this->_backQuote = ''; - } - } - - /** - * Initializes the database class - * @param array $params - */ - public static function init($params = array()) - { - if (self::$_instance == null) self::$_instance = new self($params); - return self::$_instance; - } - - /** - * Sets cache off - */ - public function cacheOn() - { - $this->_setCaching(true); - } - - /** - * Sets cache off - */ - public function cacheOff() - { - $this->_setCaching(false); - } - - /** - * Performs select query - * @param string $sql SQL string - * @param array $params parameters to bind - * @param string $method (e.g 'fetch' or 'fetchAll') - * @param constant $fetchMode PDO fetch mode - * @param bool|string $cacheId cache identification - * @return mixed - an array containing all of the result set rows - * Ex.: Array([0] => Array([id] => 11, [name] => John), ...) - */ - public function select($sql, $params = array(), $method = 'fetchAll', $fetchMode = PDO::FETCH_ASSOC, $cacheId = '') - { - if (APPHP_MODE == 'debug') { - $startTime = CTime::getMicrotime(); - } - - $sth = $this->prepare($sql); - $cacheContent = null; - $error = false; - - try { - if ($this->_isCacheAllowed($cacheId)) { - $cacheFile = !empty($cacheId) ? $cacheId : $sql . (is_array($params) ? implode('|', $params) : ''); - $cacheContent = CCache::getContent( - $this->_cacheDir . md5($cacheFile) . '.cch', - $this->_cacheLifetime - ); - } - - if (!$cacheContent) { - if (is_array($params)) { - foreach ($params as $key => $value) { - if (is_array($value)) continue; - list($key, $param) = $this->_prepareParams($key); - $sth->bindValue($key, $value, $param); - } - } - $sth->execute(); - $result = $sth->$method($fetchMode); - - if ($this->_isCacheAllowed($cacheId)) CCache::setContent($result, $this->_cacheDir); - } else { - $result = $cacheContent; - } - } catch (PDOException $e) { - $this->_errorLog('select [database.php, ln.:' . $e->getLine() . ']', $e->getMessage() . ' => ' . $this->_interpolateQuery($sql, $params)); - $result = false; - $error = true; - } - - // Interpolate query and save it - $this->_query = $this->_interpolateQuery($sql, $params); - - // Save data for debug - if (APPHP_MODE == 'debug') { - $finishTime = CTime::getMicrotime(); - $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); - CDebug::addSqlTime($sqlTotalTime); - CDebug::addMessage('queries', ''.++self::$count . '. select | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ' . A::t('core', 'total') . ': ' . (($result) ? count($result) : '0 (' . ($error ? 'error' : 'empty') . ')') . ($cacheContent ? ' [cached]' : '') . '', $this->_query); - } - - return $result; - } - - /** - * Performs insert query - * @param string $table name of the table to insert into - * @param array $data associative array - * @param bool $forceUpdate used to force update on Demo mode - * @return int|boolean - */ - public function insert($table, $data, $forceUpdate = false) - { - if(APPHP_MODE == 'demo' && !$forceUpdate){ - self::$_errorMessage = A::t('core', 'This operation is blocked in Demo Mode!'); - return false; - } - - if (APPHP_MODE == 'debug') { - $startTime = CTime::getMicrotime(); - } - - ksort($data); - - $fieldNames = $this->_quotes(implode($this->_backQuote . ', ' . $this->_backQuote, array_keys($data))); - - $fieldValues = ''; - if (is_array($data)) { - foreach ($data as $key => $value) { - // Regular fields: :last_name, - // Encrypted fields: AES_ENCRYPT(:last_name, "key"), - // Use str_replace('('.$key.',', '(:'.$key.',', ... for encrypted fields - $fieldValues .= (is_array($value) ? str_replace('(' . $key . ',', '(:' . $key . ',', $value['param_key']) : ':' . $key) . ','; - } - $fieldValues = rtrim($fieldValues, ','); - } - - $sql = 'INSERT INTO ' . $this->_quotes($this->_dbPrefix . $table) . ' (' . $fieldNames . ') VALUES (' . $fieldValues . ')'; - $sth = $this->prepare($sql); - - if (is_array($data)) { - foreach ($data as $key => $value) { - list($key, $param) = $this->_prepareParams($key); - $sth->bindValue(':' . $key, (is_array($value) ? $value['param_value'] : $value), $param); - } - } - - try { - $sth->execute(); - $result = $this->lastInsertId(); - } catch (PDOException $e) { - $this->_errorLog('insert [database.php, ln.:' . $e->getLine() . ']', $e->getMessage() . ' => ' . $this->_interpolateQuery($sql, $data)); - $result = false; - } - - // Interpolate query and save it - $this->_query = $this->_interpolateQuery($sql, $data); - - // Save data for debug - if (APPHP_MODE == 'debug') { - $finishTime = CTime::getMicrotime(); - $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); - CDebug::addSqlTime($sqlTotalTime); - CDebug::addMessage('queries', '' . ++self::$count . '. insert | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ID: ' . (($result) ? $result : '0 (error)') . '', $this->_query); - } - - return $result; - } - - /** - * Performs update query - * @param string $table name of table to update - * @param array $data an associative array - * @param string $where the WHERE clause of query - * @param array $params , ex.: array('is_default'=>0, 'rate'=>array('expression'=>'ROUND(rate/1.2,4)')) - * @param bool $forceUpdate used to force update on Demo mode - * @param boolean - */ - public function update($table, $data, $where = '1', $params = array(), $forceUpdate = false) - { - if (APPHP_MODE == 'demo' && !$forceUpdate) { - self::$_errorMessage = A::t('core', 'This operation is blocked in Demo Mode!'); - return false; - } - - if (APPHP_MODE == 'debug') { - $startTime = CTime::getMicrotime(); - } - - ksort($data); - - $fieldDetails = NULL; - if (is_array($data)) { - foreach ($data as $key => $value) { - // Regular fields: `last_name` = :last_name, : 'last_name'=>'John', - // Expression: 'rate'=>'ROUND(rate/'.$this->rate.')' : 'rate'=>array('expression'=>'ROUND(rate/'.$this->rate.',4)', - // Encrypted fields: 'last_name'=>'AES_ENCRYPT(:last_name, "key")' : `last_name` = AES_ENCRYPT(:last_name, "key"), - // Use str_replace('('.$key.',', '(:'.$key.',', ... for encrypted fields - if (isset($value['expression'])) { - $fieldDetails .= $this->_quotes($key) . ' = ' . $value['expression'] . ','; - } else { - $fieldDetails .= $this->_quotes($key) . ' = ' . (is_array($value) ? str_replace('(' . $key . ',', '(:' . $key . ',', $value['param_key']) : ':' . $key) . ','; - } - } - } - $fieldDetails = rtrim($fieldDetails, ','); - $sql = 'UPDATE ' . $this->_quotes($this->_dbPrefix . $table) . ' SET ' . $fieldDetails . ' WHERE ' . $where; - - $sth = $this->prepare($sql); - if (is_array($data)) { - foreach ($data as $key => $value) { - if (!isset($value['expression'])) { - list($key, $param) = $this->_prepareParams($key); - $sth->bindValue(':' . $key, (is_array($value) ? $value['param_value'] : $value), $param); - } - } - } - if (is_array($params)) { - foreach ($params as $key => $value) { - list($key, $param) = $this->_prepareParams($key); - $sth->bindValue($key, $value, $param); - } - } - - try { - $sth->execute(); - // $result = $sth->rowCount(); - $result = true; - } catch (PDOException $e) { - // Get trace from parent level - // $trace = $e->getTrace(); - // echo '
    ';
    -			// echo $trace[1]['file'];
    -			// echo $trace[1]['line'];
    -			// echo '
    '; - $this->_errorLog('update [database.php, ln.:' . $e->getLine() . ']', $e->getMessage() . ' => ' . $this->_interpolateQuery($sql, $data)); - $result = false; - } - - // Interpolate query and save it - $this->_query = $this->_interpolateQuery($sql, $data); - - // Save data for debug - if (APPHP_MODE == 'debug') { - $finishTime = CTime::getMicrotime(); - $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); - CDebug::addSqlTime($sqlTotalTime); - CDebug::addMessage('queries', ''.++self::$count . '. update | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ' . A::t('core', 'total') . ': ' . (($result) ? $sth->rowCount() : '0 (error)') . '', $this->_query); - } - - return $result; - } - - /** - * Performs delete query - * @param string $table - * @param string $where the WHERE clause of query - * @param array $params - * @return bool|int affected rows or false - */ - public function delete($table, $where = '', $params = array()) - { - if (APPHP_MODE == 'demo') { - self::$_errorMessage = A::t('core', 'This operation is blocked in Demo Mode!'); - return false; - } - - if (APPHP_MODE == 'debug') { - $startTime = CTime::getMicrotime(); - } - - $where_clause = (!empty($where) && !preg_match('/\bwhere\b/i', $where)) ? ' WHERE ' . $where : $where; - $sql = 'DELETE FROM ' . $this->_quotes($this->_dbPrefix . $table) . ' ' . $where_clause; - - $sth = $this->prepare($sql); - if (is_array($params)) { - foreach ($params as $key => $value) { - list($key, $param) = $this->_prepareParams($key); - $sth->bindValue($key, $value, $param); - } - } - - try { - $sth->execute(); - $result = $sth->rowCount(); - } catch (PDOException $e) { - $this->_errorLog('delete [database.php, ln.:' . $e->getLine() . ']', $e->getMessage() . ' => ' . $this->_interpolateQuery($sql, $params)); - $result = false; - } - - // Interpolate query and save it - $this->_query = $this->_interpolateQuery($sql, $params); - - // Save data for debug - if (APPHP_MODE == 'debug') { - $finishTime = CTime::getMicrotime(); - $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); - CDebug::addSqlTime($sqlTotalTime); - CDebug::addMessage('queries', ''.++self::$count . '. delete | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ' . A::t('core', 'total') . ': ' . (($result) ? $result : '0 (warning)') . '', $this->_query); - } - - return $result; - } - - /** - * Builds and executes a SQL statement for truncating a DB table - * @param string $table the table to be truncated - * @return bool|int affected rows or false - * @since 1.1.0 - */ - public function truncate($table) - { - if (APPHP_MODE == 'demo') { - self::$_errorMessage = A::t('core', 'This operation is blocked in Demo Mode!'); - return false; - } - - if (APPHP_MODE == 'debug') { - $startTime = CTime::getMicrotime(); - } - - $sql = ' TRUNCATE TABLE ' . $this->_quotes($this->_dbPrefix . $table); - $sth = $this->prepare($sql); - - try { - $sth->execute(); - $result = $sth->rowCount(); - } catch (PDOException $e) { - $this->_errorLog('delete [database.php, ln.:' . $e->getLine() . ']', $e->getMessage() . ' => ' . $sql); - $result = false; - } - - // Save query - $this->_query = $sql; - - // Save data for debug - if (APPHP_MODE == 'debug') { - $finishTime = CTime::getMicrotime(); - $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); - CDebug::addSqlTime($sqlTotalTime); - CDebug::addMessage('queries', ''.++self::$count . '. truncate | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ' . A::t('core', 'total') . ': ' . (($result) ? $result : '0 (warning)') . '', $this->_query); - } - - return $result; - } - - /** - * Returns ID of the last inserted record - * @return int - */ - public function lastId() - { - return (!empty($this)) ? $this->lastInsertId() : 0; - } - - /** - * Returns last query - * @return string - */ - public function lastQuery() - { - return $this->_query; - } - - /** - * Performs a standard query - * @param string $sql - * @param array $params - * @param constant $fetchMode PDO fetch mode - * @return mixed - an array containing all of the result set rows - */ - public function customQuery($sql, $params = array(), $fetchMode = PDO::FETCH_ASSOC) - { - if (APPHP_MODE == 'demo') { - self::$_errorMessage = A::t('core', 'This operation is blocked in Demo Mode!'); - return false; - } - - if (APPHP_MODE == 'debug') { - $startTime = CTime::getMicrotime(); - } - - try { - if (is_array($params) && !empty($params)) { - $sth = $this->prepare($sql); - foreach ($params as $key => $value) { - list($key, $param) = $this->_prepareParams($key); - $sth->bindValue($key, $value, $param); - } - $sth->execute(); - } else { - $sth = $this->query($sql); - } - $result = $sth->fetchAll($fetchMode); - } catch (PDOException $e) { - $this->_errorLog('customQuery [database.php, ln.:' . $e->getLine() . ']', $e->getMessage() . ' => ' . $sql); - $result = false; - } - - // Interpolate query and save it - $this->_query = $this->_interpolateQuery($sql, $params); - - // Save data for debug - if (APPHP_MODE == 'debug') { - $finishTime = CTime::getMicrotime(); - $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); - CDebug::addSqlTime($sqlTotalTime); - CDebug::addMessage('queries', ''.++self::$count . '. query | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ' . A::t('core', 'total') . ': ' . (($result) ? count($result) : '0 (error)') . '', $this->_query); - } - - return $result; - } - - /** - * Performs a standard exec - * @param string $sql - * @param array $params - * @param bool $forceUpdate used to force update on Demo mode - * @return boolean - */ - public function customExec($sql, $params = array(), $forceUpdate = false) - { - if(APPHP_MODE == 'demo' && !$forceUpdate){ - self::$_errorMessage = A::t('core', 'This operation is blocked in Demo Mode!'); - return false; - } - - if (APPHP_MODE == 'debug') { - $startTime = CTime::getMicrotime(); - } - - try { - if (is_array($params) && !empty($params)) { - $sth = $this->prepare($sql); - foreach ($params as $key => $value) { - list($key, $param) = $this->_prepareParams($key); - $sth->bindValue($key, $value, $param); - } - $sth->execute(); - $result = $sth->rowCount(); - } else { - $result = $this->exec($sql); - } - } catch (PDOException $e) { - $this->_errorLog('customExec [database.php, ln.:' . $e->getLine() . ']', $e->getMessage() . ' => ' . $sql); - $result = false; - } - - // Interpolate query and save it - $this->_query = $this->_interpolateQuery($sql, $params); - - // Save data for debug - if (APPHP_MODE == 'debug') { - $finishTime = CTime::getMicrotime(); - $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); - CDebug::addSqlTime($sqlTotalTime); - CDebug::addMessage('queries', ''.++self::$count . '. query | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ' . A::t('core', 'total') . ': ' . (($result) ? $result : '0 (error)') . '', $this->_query); - } - - return $result; - } - - /** - * Creates a DB command for execution - * @param mixed $query - * @return CDbCommand - */ - public function createCommand($query = null) - { - return new CDbCommand($this, $query); - } - - /** - * Performs a show tables query - * @return mixed - */ - public function showTables() - { - if (APPHP_MODE == 'debug') { - $startTime = CTime::getMicrotime(); - } - - switch ($this->_dbDriver) { - case 'mssql'; - case 'sqlsrv': - $sql = "SELECT * FROM sys.all_objects WHERE type = 'U'"; - break; - case 'pgsql': - $sql = 'SELECT tablename FROM pg_tables WHERE tableowner = current_user'; - break; - case 'sqlite': - $sql = "SELECT * FROM sqlite_master WHERE type='table'"; - break; - case 'oci': - $sql = 'SELECT * FROM system.tab'; - break; - case 'ibm': - $sql = "SELECT TABLE_NAME FROM qsys2.systables" . ((CConfig::get('db.schema') != '') ? " WHERE TABLE_SCHEMA = '" . CConfig::get('db.schema') . "'" : ''); - break; - case 'mysql': - default: - $sql = 'SHOW TABLES IN ' . $this->_quotes($this->_dbName); - break; - } - - try { - $sth = $this->query($sql); - $result = $sth->fetchAll(); - } catch (PDOException $e) { - $this->_errorLog('showTables [database.php, ln.:' . $e->getLine() . ']', $e->getMessage()); - $result = false; - } - - // Save query - $this->_query = $sql; - - // Save data for debug - if (APPHP_MODE == 'debug') { - $finishTime = CTime::getMicrotime(); - $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); - CDebug::addSqlTime($sqlTotalTime); - CDebug::addMessage('queries', ''.++self::$count . '. query | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ' . A::t('core', 'total') . ': ' . (($result) ? count($result) : '0 (error)') . '', $this->_query); - } - - return $result; - } - - /** - * Performs a show column query - * @param string $table - * @return mixed - */ - public function showColumns($table = '') - { - if (APPHP_MODE == 'debug') { - $startTime = CTime::getMicrotime(); - } - - $cacheContent = ''; - - switch ($this->_dbDriver) { - case 'ibm': - $sql = "SELECT COLUMN_NAME FROM qsys2.syscolumns WHERE TABLE_NAME = '" . $this->_dbPrefix . $table . "'" . ((CConfig::get('db.schema') != '') ? " AND TABLE_SCHEMA = '" . CConfig::get('db.schema') . "'" : ''); - break; - case 'mssql': - case 'sqlsrv': - /// old version - /// $sql = "SELECT COLUMN_NAME, data_type, character_maximum_length FROM ".$this->_dbName.".information_schema.columns WHERE table_name = '".$this->_dbPrefix.$table."'"; - $sql = "SELECT COLUMN_NAME, data_type, IS_NULLABLE, '', COLUMN_DEFAULT, character_maximum_length as extra FROM " . $this->_dbName . ".information_schema.columns WHERE table_name = '" . $this->_dbPrefix . $table . "'"; - break; - default: - $sql = 'SHOW COLUMNS FROM ' . $this->_quotes($this->_dbPrefix . $table); - break; - } - - try { - if ($this->_isCacheAllowed(true)) { - $cacheContent = CCache::getContent( - $this->_cacheDir . md5($sql) . '.cch', - $this->_cacheLifetime - ); - } - - if (!$cacheContent) { - $sth = $this->query($sql); - $result = $sth->fetchAll(); - - if ($this->_isCacheAllowed(true)) CCache::setContent($result, $this->_cacheDir); - } else { - $result = $cacheContent; - } - } catch (PDOException $e) { - $this->_errorLog('showColumns [database.php, ln.:' . $e->getLine() . ']', $e->getMessage()); - $result = false; - } - - // Save query - $this->_query = $sql; - - // Save data for debug - if (APPHP_MODE == 'debug') { - $finishTime = CTime::getMicrotime(); - $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); - CDebug::addSqlTime($sqlTotalTime); - CDebug::addMessage('queries', ''.++self::$count . ' show | ' . $sqlTotalTime . ' ' . A::t('core', 'sec') . '. | ' . A::t('core', 'total') . ': ' . (($result) ? count($result) : '0 (error)') . ($cacheContent ? ' [cached]' : '') . '', $this->_query); - } - - return $result; - } - - /** - * Returns database engine version - */ - public function getVersion() - { - $version = A::t('core', 'Unknown'); - if (self::$_instance != null && !empty($this->_dbName)) { - $version = @self::getAttribute(PDO::ATTR_SERVER_VERSION); - if (empty($version) && empty(self::$_error)) { - $version = $this->query('select version()')->fetchColumn(); - } - // Clean version number from alphabetic characters - $version = preg_replace('/[^0-9,.]/', '', $version); - } - - return $version; - } - - /** - * Get error status - * @return boolean - */ - public static function getError() - { - return self::$_error; - } - - /** - * Get error message - * @return string - */ - public static function getErrorMessage() - { - return self::$_errorMessage; - } - - /** - * Initialize connection - * @param string $dbDriver - * @param string $dbSocket - * @param string $dbHost - * @param string $dbPort - * @param string $dbName - * @param string $dbUser - * @param string $dbPassword - * @param string $dbCharset - * @return void - */ - private function _init($dbDriver = '', $dbSocket = '', $dbHost = '', $dbPort = '', $dbName = '', $dbUser = '', $dbPassword = '', $dbCharset = '') - { - // Set db connection type, port and db name - if (strcasecmp($dbDriver, 'sqlsrv') == 0) { - $dsn = 'sqlsrv:Server=' . $dbHost; - $dsn .= !empty($dbPort) ? ',' . $dbPort : ''; - $dsn .= ';Database=' . $dbName; - - $this->exec("SET NAMES '" . $dbCharset . "'"); - - @parent::__construct($dsn, $dbUser, $dbPassword, array()); - - } else { - $dsn = (!empty($dbSocket)) ? $dbDriver . ':unix_socket=' . $dbSocket : $dbDriver . ':host=' . $dbHost; - $dsn .= !empty($dbPort) ? ';port=' . $dbPort : ''; - $dsn .= ';dbname=' . $dbName; - $options = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION); - - if (version_compare(phpversion(), '5.3.6', '<')) { - if (defined('PDO::MYSQL_ATTR_INIT_COMMAND')) { - $options[PDO::MYSQL_ATTR_INIT_COMMAND] = "SET NAMES '" . $dbCharset . "'"; - } - } else { - $dsn .= ';charset=' . $dbCharset; - } - - @parent::__construct($dsn, $dbUser, $dbPassword, $options); - - if (version_compare(phpversion(), '5.3.6', '<') && !defined('PDO::MYSQL_ATTR_INIT_COMMAND')) { - $this->exec("SET NAMES '" . $dbCharset . "'"); - } - } - } - - /** - * Writes error log - * @param string $debugMessage - * @param string $errorMessage - */ - private function _errorLog($debugMessage, $errorMessage) - { - self::$_error = true; - self::$_errorMessage = $errorMessage; - CDebug::addMessage('errors', $debugMessage, $errorMessage, 'session'); - } - - /** - * Returns fata error page content - * @return html code - */ - private static function _fatalErrorPageContent() - { - return ' + + /** @var string */ + public static $count = 0; + + /** @var object */ + private static $_instance; + /** @var string */ + private $_dbPrefix; + /** @var string */ + private $_dbDriver; + /** @var string */ + private $_dbName; + /** @var bool */ + private $_cache; + /** @var string */ + private $_cacheType; + /** @var int */ + private $_cacheLifetime; + /** @var string */ + private $_cacheDir; + /** @var string */ + private $_query; + /** @var char */ + private $_backQuote = '`'; + /** @var boolean */ + private static $_error; + /** @var string */ + private static $_errorMessage; + + /** + * Class default constructor + * + * @param array $params + */ + public function __construct($params = []) + { + // For direct use (e.g. setup module) + if ( ! empty($params)) { + $dbDriver = isset($params['dbDriver']) ? $params['dbDriver'] : ''; + $dbSocket = isset($params['dbSocket']) ? $params['dbSocket'] : ''; + $dbHost = isset($params['dbHost']) ? $params['dbHost'] : ''; + $dbPort = isset($params['dbPort']) ? $params['dbPort'] : ''; + $dbName = isset($params['dbName']) ? $params['dbName'] : ''; + $dbUser = isset($params['dbUser']) ? $params['dbUser'] : ''; + $dbPassword = isset($params['dbPassword']) ? $params['dbPassword'] : ''; + $dbCharset = isset($params['dbCharset']) ? $params['dbCharset'] : 'utf8'; + + try { + $this->_init($dbDriver, $dbSocket, $dbHost, $dbPort, $dbName, $dbUser, $dbPassword, $dbCharset); + $this->_dbDriver = $dbDriver; + $this->_dbName = $dbName; + $this->_dbPrefix = ''; + } catch (Exception $e) { + self::$_error = true; + self::$_errorMessage = $e->getMessage(); + } + } else { + if ( ! A::app()->isSetup()) { + if (APPHP_MODE == 'debug') { + $startTime = CTime::getMicrotime(); + } + + try { + if (CConfig::get('db') != '') { + $this->_init( + CConfig::get('db.driver'), + CConfig::get('db.socket'), + CConfig::get('db.host'), + CConfig::get('db.port'), + CConfig::get('db.database'), + CConfig::get('db.username'), + CConfig::get('db.password'), + CConfig::get('db.charset', 'utf8') + ); + } else { + throw new Exception('Missing database configuration file'); + } + } catch (Exception $e) { + header('HTTP/1.1 503 Service Temporarily Unavailable'); + header('Status: 503 Service Temporarily Unavailable'); + $output = self::_fatalErrorPageContent(); + if (APPHP_MODE == 'debug') { + $output = str_ireplace( + '{DESCRIPTION}', + '

    '.A::t( + 'core', + 'This application is currently experiencing some database difficulties' + ).'

    ', + $output + ); + $output = str_ireplace( + '{CODE}', + 'Description: '.$e->getMessage().'
    + File: '.$e->getFile().'
    + Line: '.$e->getLine(), + $output + ); + } else { + $output = str_ireplace( + '{DESCRIPTION}', + '

    '.A::t( + 'core', + 'This application is currently experiencing some database difficulties. Please check back again later' + ).'

    ', + $output + ); + $output = str_ireplace( + '{CODE}', + A::t( + 'core', + 'For more information turn on debug mode in your application' + ), + $output + ); + } + echo $output; + exit(1); + } + + $this->_dbDriver = CConfig::get('db.driver'); + $this->_dbName = CConfig::get('db.database'); + $this->_dbPrefix = CConfig::get('db.prefix'); + + $this->_cache = CConfig::get('cache.db.enable') ? true : false; + $this->_cacheType = in_array(CConfig::get('cache.db.type'), ['auto', 'manual']) ? CConfig::get( + 'cache.db.type' + ) : 'auto'; + $this->_cacheLifetime = CConfig::get('cache.db.lifetime', 0); /* in minutes */ + $this->_cacheDir = CConfig::get('cache.db.path'); /* protected/tmp/cache/ */ + if ($this->_cache) { + CDebug::addMessage('general', 'cache', 'enabled ('.$this->_cacheType.') '); + } + + // Save data for debug + if (APPHP_MODE == 'debug') { + $finishTime = CTime::getMicrotime(); + $sqlConnectionTime = round((float)$finishTime - (float)$startTime, 5); + CDebug::addSqlConnectionTime($sqlConnectionTime); + } + } + } + + // Set back quote according to database driver + if ( ! empty($this->_dbDriver) && preg_match('/mssql|sqlsrv/i', $this->_dbDriver)) { + $this->_backQuote = ''; + } + } + + /** + * Initializes the database class + * + * @param array $params + */ + public static function init($params = []) + { + if (self::$_instance == null) { + self::$_instance = new self($params); + } + + return self::$_instance; + } + + /** + * Sets cache off + */ + public function cacheOn() + { + $this->_setCaching(true); + } + + /** + * Sets cache off + */ + public function cacheOff() + { + $this->_setCaching(false); + } + + /** + * Performs select query + * + * @param string $sql SQL string + * @param array $params parameters to bind + * @param string $method (e.g 'fetch' or 'fetchAll') + * @param constant $fetchMode PDO fetch mode + * @param bool|string $cacheId cache identification + * + * @return mixed - an array containing all of the result set rows + * Ex.: Array([0] => Array([id] => 11, [name] => John), ...) + */ + public function select($sql, $params = [], $method = 'fetchAll', $fetchMode = PDO::FETCH_ASSOC, $cacheId = '') + { + if (APPHP_MODE == 'debug') { + $startTime = CTime::getMicrotime(); + } + + $sth = $this->prepare($sql); + $cacheContent = null; + $error = false; + + try { + if ($this->_isCacheAllowed($cacheId)) { + $cacheFile = ! empty($cacheId) ? $cacheId : $sql.(is_array($params) ? implode('|', $params) : ''); + $cacheContent = CCache::getContent( + $this->_cacheDir.md5($cacheFile).'.cch', + $this->_cacheLifetime + ); + } + + if ( ! $cacheContent) { + if (is_array($params)) { + foreach ($params as $key => $value) { + if (is_array($value)) { + continue; + } + [$key, $param] = $this->_prepareParams($key); + $sth->bindValue($key, $value, $param); + } + } + $sth->execute(); + $result = $sth->$method($fetchMode); + + if ($this->_isCacheAllowed($cacheId)) { + CCache::setContent($result, $this->_cacheDir); + } + } else { + $result = $cacheContent; + } + } catch (PDOException $e) { + $this->_errorLog( + 'select [database.php, ln.:'.$e->getLine().']', + $e->getMessage().' => '.$this->_interpolateQuery($sql, $params) + ); + $result = false; + $error = true; + } + + // Interpolate query and save it + $this->_query = $this->_interpolateQuery($sql, $params); + + // Save data for debug + if (APPHP_MODE == 'debug') { + $finishTime = CTime::getMicrotime(); + $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); + CDebug::addSqlTime($sqlTotalTime); + CDebug::addMessage( + 'queries', + ''.++self::$count.'. select | '.$sqlTotalTime.' '.A::t( + 'core', + 'sec' + ).'. | '.A::t('core', 'total').': '.(($result) ? count($result) + : '0 ('.($error ? 'error' : 'empty').')').($cacheContent ? ' [cached]' : '').'', + $this->_query + ); + } + + return $result; + } + + /** + * Performs insert query + * + * @param string $table name of the table to insert into + * @param array $data associative array + * @param bool $forceUpdate used to force update on Demo mode + * + * @return int|boolean + */ + public function insert($table, $data, $forceUpdate = false) + { + if (APPHP_MODE == 'demo' && ! $forceUpdate) { + self::$_errorMessage = A::t('core', 'This operation is blocked in Demo Mode!'); + + return false; + } + + if (APPHP_MODE == 'debug') { + $startTime = CTime::getMicrotime(); + } + + ksort($data); + + $fieldNames = $this->_quotes(implode($this->_backQuote.', '.$this->_backQuote, array_keys($data))); + + $fieldValues = ''; + if (is_array($data)) { + foreach ($data as $key => $value) { + // Regular fields: :last_name, + // Encrypted fields: AES_ENCRYPT(:last_name, "key"), + // Use str_replace('('.$key.',', '(:'.$key.',', ... for encrypted fields + $fieldValues .= (is_array($value) ? str_replace('('.$key.',', '(:'.$key.',', $value['param_key']) + : ':'.$key).','; + } + $fieldValues = rtrim($fieldValues, ','); + } + + $sql = 'INSERT INTO '.$this->_quotes($this->_dbPrefix.$table).' ('.$fieldNames.') VALUES ('.$fieldValues.')'; + $sth = $this->prepare($sql); + + if (is_array($data)) { + foreach ($data as $key => $value) { + [$key, $param] = $this->_prepareParams($key); + $sth->bindValue(':'.$key, (is_array($value) ? $value['param_value'] : $value), $param); + } + } + + try { + $sth->execute(); + $result = $this->lastInsertId(); + } catch (PDOException $e) { + $this->_errorLog( + 'insert [database.php, ln.:'.$e->getLine().']', + $e->getMessage().' => '.$this->_interpolateQuery($sql, $data) + ); + $result = false; + } + + // Interpolate query and save it + $this->_query = $this->_interpolateQuery($sql, $data); + + // Save data for debug + if (APPHP_MODE == 'debug') { + $finishTime = CTime::getMicrotime(); + $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); + CDebug::addSqlTime($sqlTotalTime); + CDebug::addMessage( + 'queries', + ''.++self::$count.'. insert | '.$sqlTotalTime.' '.A::t( + 'core', + 'sec' + ).'. | ID: '.(($result) ? $result : '0 (error)').'', + $this->_query + ); + } + + return $result; + } + + /** + * Performs update query + * + * @param string $table name of table to update + * @param array $data an associative array + * @param string $where the WHERE clause of query + * @param array $params , ex.: array('is_default'=>0, 'rate'=>array('expression'=>'ROUND(rate/1.2,4)')) + * @param bool $forceUpdate used to force update on Demo mode + * @param boolean + */ + public function update($table, $data, $where = '1', $params = [], $forceUpdate = false) + { + if (APPHP_MODE == 'demo' && ! $forceUpdate) { + self::$_errorMessage = A::t('core', 'This operation is blocked in Demo Mode!'); + + return false; + } + + if (APPHP_MODE == 'debug') { + $startTime = CTime::getMicrotime(); + } + + ksort($data); + + $fieldDetails = null; + if (is_array($data)) { + foreach ($data as $key => $value) { + // Regular fields: `last_name` = :last_name, : 'last_name'=>'John', + // Expression: 'rate'=>'ROUND(rate/'.$this->rate.')' : 'rate'=>array('expression'=>'ROUND(rate/'.$this->rate.',4)', + // Encrypted fields: 'last_name'=>'AES_ENCRYPT(:last_name, "key")' : `last_name` = AES_ENCRYPT(:last_name, "key"), + // Use str_replace('('.$key.',', '(:'.$key.',', ... for encrypted fields + if (isset($value['expression'])) { + $fieldDetails .= $this->_quotes($key).' = '.$value['expression'].','; + } else { + $fieldDetails .= $this->_quotes($key).' = '.(is_array($value) ? str_replace( + '('.$key.',', + '(:'.$key.',', + $value['param_key'] + ) : ':'.$key).','; + } + } + } + $fieldDetails = rtrim($fieldDetails, ','); + $sql = 'UPDATE '.$this->_quotes($this->_dbPrefix.$table).' SET '.$fieldDetails.' WHERE '.$where; + + $sth = $this->prepare($sql); + if (is_array($data)) { + foreach ($data as $key => $value) { + if ( ! isset($value['expression'])) { + [$key, $param] = $this->_prepareParams($key); + $sth->bindValue(':'.$key, (is_array($value) ? $value['param_value'] : $value), $param); + } + } + } + if (is_array($params)) { + foreach ($params as $key => $value) { + [$key, $param] = $this->_prepareParams($key); + $sth->bindValue($key, $value, $param); + } + } + + try { + $sth->execute(); + // $result = $sth->rowCount(); + $result = true; + } catch (PDOException $e) { + // Get trace from parent level + // $trace = $e->getTrace(); + // echo '
    ';
    +            // echo $trace[1]['file'];
    +            // echo $trace[1]['line'];
    +            // echo '
    '; + $this->_errorLog( + 'update [database.php, ln.:'.$e->getLine().']', + $e->getMessage().' => '.$this->_interpolateQuery($sql, $data) + ); + $result = false; + } + + // Interpolate query and save it + $this->_query = $this->_interpolateQuery($sql, $data); + + // Save data for debug + if (APPHP_MODE == 'debug') { + $finishTime = CTime::getMicrotime(); + $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); + CDebug::addSqlTime($sqlTotalTime); + CDebug::addMessage( + 'queries', + ''.++self::$count.'. update | '.$sqlTotalTime.' '.A::t( + 'core', + 'sec' + ).'. | '.A::t('core', 'total').': '.(($result) ? $sth->rowCount() : '0 (error)').'', + $this->_query + ); + } + + return $result; + } + + /** + * Performs delete query + * + * @param string $table + * @param string $where the WHERE clause of query + * @param array $params + * + * @return bool|int affected rows or false + */ + public function delete($table, $where = '', $params = []) + { + if (APPHP_MODE == 'demo') { + self::$_errorMessage = A::t('core', 'This operation is blocked in Demo Mode!'); + + return false; + } + + if (APPHP_MODE == 'debug') { + $startTime = CTime::getMicrotime(); + } + + $where_clause = ( ! empty($where) && ! preg_match('/\bwhere\b/i', $where)) ? ' WHERE '.$where : $where; + $sql = 'DELETE FROM '.$this->_quotes($this->_dbPrefix.$table).' '.$where_clause; + + $sth = $this->prepare($sql); + if (is_array($params)) { + foreach ($params as $key => $value) { + [$key, $param] = $this->_prepareParams($key); + $sth->bindValue($key, $value, $param); + } + } + + try { + $sth->execute(); + $result = $sth->rowCount(); + } catch (PDOException $e) { + $this->_errorLog( + 'delete [database.php, ln.:'.$e->getLine().']', + $e->getMessage().' => '.$this->_interpolateQuery($sql, $params) + ); + $result = false; + } + + // Interpolate query and save it + $this->_query = $this->_interpolateQuery($sql, $params); + + // Save data for debug + if (APPHP_MODE == 'debug') { + $finishTime = CTime::getMicrotime(); + $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); + CDebug::addSqlTime($sqlTotalTime); + CDebug::addMessage( + 'queries', + ''.++self::$count.'. delete | '.$sqlTotalTime.' '.A::t( + 'core', + 'sec' + ).'. | '.A::t('core', 'total').': '.(($result) ? $result : '0 (warning)').'', + $this->_query + ); + } + + return $result; + } + + /** + * Builds and executes a SQL statement for truncating a DB table + * + * @param string $table the table to be truncated + * + * @return bool|int affected rows or false + * @since 1.1.0 + */ + public function truncate($table) + { + if (APPHP_MODE == 'demo') { + self::$_errorMessage = A::t('core', 'This operation is blocked in Demo Mode!'); + + return false; + } + + if (APPHP_MODE == 'debug') { + $startTime = CTime::getMicrotime(); + } + + $sql = ' TRUNCATE TABLE '.$this->_quotes($this->_dbPrefix.$table); + $sth = $this->prepare($sql); + + try { + $sth->execute(); + $result = $sth->rowCount(); + } catch (PDOException $e) { + $this->_errorLog('delete [database.php, ln.:'.$e->getLine().']', $e->getMessage().' => '.$sql); + $result = false; + } + + // Save query + $this->_query = $sql; + + // Save data for debug + if (APPHP_MODE == 'debug') { + $finishTime = CTime::getMicrotime(); + $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); + CDebug::addSqlTime($sqlTotalTime); + CDebug::addMessage( + 'queries', + ''.++self::$count.'. truncate | '.$sqlTotalTime.' '.A::t( + 'core', + 'sec' + ).'. | '.A::t('core', 'total').': '.(($result) ? $result : '0 (warning)').'', + $this->_query + ); + } + + return $result; + } + + /** + * Returns ID of the last inserted record + * + * @return int + */ + public function lastId() + { + return ( ! empty($this)) ? $this->lastInsertId() : 0; + } + + /** + * Returns last query + * + * @return string + */ + public function lastQuery() + { + return $this->_query; + } + + /** + * Performs a standard query + * + * @param string $sql + * @param array $params + * @param constant $fetchMode PDO fetch mode + * + * @return mixed - an array containing all of the result set rows + */ + public function customQuery($sql, $params = [], $fetchMode = PDO::FETCH_ASSOC) + { + if (APPHP_MODE == 'demo') { + self::$_errorMessage = A::t('core', 'This operation is blocked in Demo Mode!'); + + return false; + } + + if (APPHP_MODE == 'debug') { + $startTime = CTime::getMicrotime(); + } + + try { + if (is_array($params) && ! empty($params)) { + $sth = $this->prepare($sql); + foreach ($params as $key => $value) { + [$key, $param] = $this->_prepareParams($key); + $sth->bindValue($key, $value, $param); + } + $sth->execute(); + } else { + $sth = $this->query($sql); + } + $result = $sth->fetchAll($fetchMode); + } catch (PDOException $e) { + $this->_errorLog('customQuery [database.php, ln.:'.$e->getLine().']', $e->getMessage().' => '.$sql); + $result = false; + } + + // Interpolate query and save it + $this->_query = $this->_interpolateQuery($sql, $params); + + // Save data for debug + if (APPHP_MODE == 'debug') { + $finishTime = CTime::getMicrotime(); + $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); + CDebug::addSqlTime($sqlTotalTime); + CDebug::addMessage( + 'queries', + ''.++self::$count.'. query | '.$sqlTotalTime.' '.A::t( + 'core', + 'sec' + ).'. | '.A::t('core', 'total').': '.(($result) ? count($result) : '0 (error)').'', + $this->_query + ); + } + + return $result; + } + + /** + * Performs a standard exec + * + * @param string $sql + * @param array $params + * @param bool $forceUpdate used to force update on Demo mode + * + * @return boolean + */ + public function customExec($sql, $params = [], $forceUpdate = false) + { + if (APPHP_MODE == 'demo' && ! $forceUpdate) { + self::$_errorMessage = A::t('core', 'This operation is blocked in Demo Mode!'); + + return false; + } + + if (APPHP_MODE == 'debug') { + $startTime = CTime::getMicrotime(); + } + + try { + if (is_array($params) && ! empty($params)) { + $sth = $this->prepare($sql); + foreach ($params as $key => $value) { + [$key, $param] = $this->_prepareParams($key); + $sth->bindValue($key, $value, $param); + } + $sth->execute(); + $result = $sth->rowCount(); + } else { + $result = $this->exec($sql); + } + } catch (PDOException $e) { + $this->_errorLog('customExec [database.php, ln.:'.$e->getLine().']', $e->getMessage().' => '.$sql); + $result = false; + } + + // Interpolate query and save it + $this->_query = $this->_interpolateQuery($sql, $params); + + // Save data for debug + if (APPHP_MODE == 'debug') { + $finishTime = CTime::getMicrotime(); + $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); + CDebug::addSqlTime($sqlTotalTime); + CDebug::addMessage( + 'queries', + ''.++self::$count.'. query | '.$sqlTotalTime.' '.A::t( + 'core', + 'sec' + ).'. | '.A::t('core', 'total').': '.(($result) ? $result : '0 (error)').'', + $this->_query + ); + } + + return $result; + } + + /** + * Creates a DB command for execution + * + * @param mixed $query + * + * @return CDbCommand + */ + public function createCommand($query = null) + { + return new CDbCommand($this, $query); + } + + /** + * Performs a show tables query + * + * @return mixed + */ + public function showTables() + { + if (APPHP_MODE == 'debug') { + $startTime = CTime::getMicrotime(); + } + + switch ($this->_dbDriver) { + case 'mssql'; + case 'sqlsrv': + $sql = "SELECT * FROM sys.all_objects WHERE type = 'U'"; + break; + case 'pgsql': + $sql = 'SELECT tablename FROM pg_tables WHERE tableowner = current_user'; + break; + case 'sqlite': + $sql = "SELECT * FROM sqlite_master WHERE type='table'"; + break; + case 'oci': + $sql = 'SELECT * FROM system.tab'; + break; + case 'ibm': + $sql = "SELECT TABLE_NAME FROM qsys2.systables".((CConfig::get('db.schema') != '') + ? " WHERE TABLE_SCHEMA = '".CConfig::get('db.schema')."'" : ''); + break; + case 'mysql': + default: + $sql = 'SHOW TABLES IN '.$this->_quotes($this->_dbName); + break; + } + + try { + $sth = $this->query($sql); + $result = $sth->fetchAll(); + } catch (PDOException $e) { + $this->_errorLog('showTables [database.php, ln.:'.$e->getLine().']', $e->getMessage()); + $result = false; + } + + // Save query + $this->_query = $sql; + + // Save data for debug + if (APPHP_MODE == 'debug') { + $finishTime = CTime::getMicrotime(); + $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); + CDebug::addSqlTime($sqlTotalTime); + CDebug::addMessage( + 'queries', + ''.++self::$count.'. query | '.$sqlTotalTime.' '.A::t( + 'core', + 'sec' + ).'. | '.A::t('core', 'total').': '.(($result) ? count($result) : '0 (error)').'', + $this->_query + ); + } + + return $result; + } + + /** + * Performs a show column query + * + * @param string $table + * + * @return mixed + */ + public function showColumns($table = '') + { + if (APPHP_MODE == 'debug') { + $startTime = CTime::getMicrotime(); + } + + $cacheContent = ''; + + switch ($this->_dbDriver) { + case 'ibm': + $sql = "SELECT COLUMN_NAME FROM qsys2.syscolumns WHERE TABLE_NAME = '".$this->_dbPrefix.$table."'" + .((CConfig::get('db.schema') != '') ? " AND TABLE_SCHEMA = '".CConfig::get('db.schema')."'" : ''); + break; + case 'mssql': + case 'sqlsrv': + /// old version + /// $sql = "SELECT COLUMN_NAME, data_type, character_maximum_length FROM ".$this->_dbName.".information_schema.columns WHERE table_name = '".$this->_dbPrefix.$table."'"; + $sql + = "SELECT COLUMN_NAME, data_type, IS_NULLABLE, '', COLUMN_DEFAULT, character_maximum_length as extra FROM " + .$this->_dbName.".information_schema.columns WHERE table_name = '".$this->_dbPrefix.$table."'"; + break; + default: + $sql = 'SHOW COLUMNS FROM '.$this->_quotes($this->_dbPrefix.$table); + break; + } + + try { + if ($this->_isCacheAllowed(true)) { + $cacheContent = CCache::getContent( + $this->_cacheDir.md5($sql).'.cch', + $this->_cacheLifetime + ); + } + + if ( ! $cacheContent) { + $sth = $this->query($sql); + $result = $sth->fetchAll(); + + if ($this->_isCacheAllowed(true)) { + CCache::setContent($result, $this->_cacheDir); + } + } else { + $result = $cacheContent; + } + } catch (PDOException $e) { + $this->_errorLog('showColumns [database.php, ln.:'.$e->getLine().']', $e->getMessage()); + $result = false; + } + + // Save query + $this->_query = $sql; + + // Save data for debug + if (APPHP_MODE == 'debug') { + $finishTime = CTime::getMicrotime(); + $sqlTotalTime = round((float)$finishTime - (float)$startTime, 5); + CDebug::addSqlTime($sqlTotalTime); + CDebug::addMessage( + 'queries', + ''.++self::$count.' show | '.$sqlTotalTime.' '.A::t( + 'core', + 'sec' + ).'. | '.A::t('core', 'total').': '.(($result) ? count($result) : '0 (error)').($cacheContent + ? ' [cached]' : '').'', + $this->_query + ); + } + + return $result; + } + + /** + * Returns database engine version + */ + public function getVersion() + { + $version = A::t('core', 'Unknown'); + if (self::$_instance != null && ! empty($this->_dbName)) { + $version = @self::getAttribute(PDO::ATTR_SERVER_VERSION); + if (empty($version) && empty(self::$_error)) { + $version = $this->query('select version()')->fetchColumn(); + } + // Clean version number from alphabetic characters + $version = preg_replace('/[^0-9,.]/', '', $version); + } + + return $version; + } + + /** + * Get error status + * + * @return boolean + */ + public static function getError() + { + return self::$_error; + } + + /** + * Get error message + * + * @return string + */ + public static function getErrorMessage() + { + return self::$_errorMessage; + } + + /** + * Initialize connection + * + * @param string $dbDriver + * @param string $dbSocket + * @param string $dbHost + * @param string $dbPort + * @param string $dbName + * @param string $dbUser + * @param string $dbPassword + * @param string $dbCharset + * + * @return void + */ + private function _init( + $dbDriver = '', + $dbSocket = '', + $dbHost = '', + $dbPort = '', + $dbName = '', + $dbUser = '', + $dbPassword = '', + $dbCharset = '' + ) { + // Set db connection type, port and db name + if (strcasecmp($dbDriver, 'sqlsrv') == 0) { + $dsn = 'sqlsrv:Server='.$dbHost; + $dsn .= ! empty($dbPort) ? ','.$dbPort : ''; + $dsn .= ';Database='.$dbName; + + $this->exec("SET NAMES '".$dbCharset."'"); + + @parent::__construct($dsn, $dbUser, $dbPassword, []); + } else { + $dsn = ( ! empty($dbSocket)) ? $dbDriver.':unix_socket='.$dbSocket : $dbDriver.':host='.$dbHost; + $dsn .= ! empty($dbPort) ? ';port='.$dbPort : ''; + $dsn .= ';dbname='.$dbName; + $options = [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]; + + if (version_compare(phpversion(), '5.3.6', '<')) { + if (defined('PDO::MYSQL_ATTR_INIT_COMMAND')) { + $options[PDO::MYSQL_ATTR_INIT_COMMAND] = "SET NAMES '".$dbCharset."'"; + } + } else { + $dsn .= ';charset='.$dbCharset; + } + + @parent::__construct($dsn, $dbUser, $dbPassword, $options); + + if (version_compare(phpversion(), '5.3.6', '<') && ! defined('PDO::MYSQL_ATTR_INIT_COMMAND')) { + $this->exec("SET NAMES '".$dbCharset."'"); + } + } + } + + /** + * Writes error log + * + * @param string $debugMessage + * @param string $errorMessage + */ + private function _errorLog($debugMessage, $errorMessage) + { + self::$_error = true; + self::$_errorMessage = $errorMessage; + CDebug::addMessage('errors', $debugMessage, $errorMessage, 'session'); + } + + /** + * Returns fata error page content + * + * @return html code + */ + private static function _fatalErrorPageContent() + { + return ' @@ -858,121 +1028,133 @@ private static function _fatalErrorPageContent()
    '; - } - - /** - * Replaces any parameter placeholders in a query with the value of that parameter - * @param string $sql - * @param array $params - * @return string - */ - private function _interpolateQuery($sql, $params = array()) - { - $keys = array(); - $count = 0; - if (!is_array($params)) return $sql; - - // Build regular expression for each parameter - foreach ($params as $key => $value) { - if (is_string($key)) { - $ind = strpos($key, ':'); - if ($ind == 1) { - // used param with prefix, like: i:param, f:param etc. - $newKey = substr($key, 2, strlen($key)); - $keys[] = '/:' . $newKey . '/'; - $params[$newKey] = $params[$key]; - unset($params[$key]); - } elseif ($ind !== false) { - $keys[] = '/' . $key . '/'; - } else { - $keys[] = '/:' . $key . '/'; - } - } else { - $keys[] = '/[?]/'; - } - - if (is_array($value)) { - if (isset($value['expression'])) { - $params[$key] = $value['expression']; - } elseif (isset($value['param_key'])) { - // Show encrypted fields - $params[$key] = str_replace($key, $value['param_value'], $value['param_key']); - } - } else { - // Show regular fields - $params[$key] = "'$value'"; - } - } - - return preg_replace($keys, $params, $sql, 1, $count); - } - - /** - * Prepares/changes keys and parameters - * @param $key - * @return array - */ - private function _prepareParams($key) - { - $param = 0; - $prefix = substr($key, 0, 2); - switch ($prefix) { - case 'i:': - $key = str_replace('i:', ':', $key); - $param = PDO::PARAM_INT; - break; - case 'b:': - $key = str_replace('b:', ':', $key); - $param = PDO::PARAM_BOOL; - break; - case 'f:': - $key = str_replace('f:', ':', $key); - $param = PDO::PARAM_STR; - break; - case 's:': - $key = str_replace('s:', ':', $key); - $param = PDO::PARAM_STR; - break; - case 'n:': - $key = str_replace('n:', ':', $key); - $param = PDO::PARAM_NULL; - break; - default: - $param = PDO::PARAM_STR; - break; - } - return array($key, $param); - } - - /** - * Sets cache state - * @param bool $enabled - */ - private function _setCaching($enabled) - { - $this->_cache = $this->_isCacheAllowed($enabled); - ///if(!$this->_cache) CDebug::addMessage('general', 'cache', 'disabled'); - } - - /** - * Check cache state - * @param $cacheId - * @return bool - */ - private function _isCacheAllowed($cacheId = false) - { - return ($this->_cache && ($this->_cacheType == 'auto' || ($this->_cacheType == 'manual' && !empty($cacheId)))); - } - - /** - * Escapes given string with backquotes - * Prepares table name for using in SQL statements - * @param string $string - * @return string - */ - private function _quotes($string = '') - { - return $this->_backQuote . $string . $this->_backQuote; - } - + } + + /** + * Replaces any parameter placeholders in a query with the value of that parameter + * + * @param string $sql + * @param array $params + * + * @return string + */ + private function _interpolateQuery($sql, $params = []) + { + $keys = []; + $count = 0; + if ( ! is_array($params)) { + return $sql; + } + + // Build regular expression for each parameter + foreach ($params as $key => $value) { + if (is_string($key)) { + $ind = strpos($key, ':'); + if ($ind == 1) { + // used param with prefix, like: i:param, f:param etc. + $newKey = substr($key, 2, strlen($key)); + $keys[] = '/:'.$newKey.'/'; + $params[$newKey] = $params[$key]; + unset($params[$key]); + } elseif ($ind !== false) { + $keys[] = '/'.$key.'/'; + } else { + $keys[] = '/:'.$key.'/'; + } + } else { + $keys[] = '/[?]/'; + } + + if (is_array($value)) { + if (isset($value['expression'])) { + $params[$key] = $value['expression']; + } elseif (isset($value['param_key'])) { + // Show encrypted fields + $params[$key] = str_replace($key, $value['param_value'], $value['param_key']); + } + } else { + // Show regular fields + $params[$key] = "'$value'"; + } + } + + return preg_replace($keys, $params, $sql, 1, $count); + } + + /** + * Prepares/changes keys and parameters + * + * @param $key + * + * @return array + */ + private function _prepareParams($key) + { + $param = 0; + $prefix = substr($key, 0, 2); + switch ($prefix) { + case 'i:': + $key = str_replace('i:', ':', $key); + $param = PDO::PARAM_INT; + break; + case 'b:': + $key = str_replace('b:', ':', $key); + $param = PDO::PARAM_BOOL; + break; + case 'f:': + $key = str_replace('f:', ':', $key); + $param = PDO::PARAM_STR; + break; + case 's:': + $key = str_replace('s:', ':', $key); + $param = PDO::PARAM_STR; + break; + case 'n:': + $key = str_replace('n:', ':', $key); + $param = PDO::PARAM_NULL; + break; + default: + $param = PDO::PARAM_STR; + break; + } + + return [$key, $param]; + } + + /** + * Sets cache state + * + * @param bool $enabled + */ + private function _setCaching($enabled) + { + $this->_cache = $this->_isCacheAllowed($enabled); + ///if(!$this->_cache) CDebug::addMessage('general', 'cache', 'disabled'); + } + + /** + * Check cache state + * + * @param $cacheId + * + * @return bool + */ + private function _isCacheAllowed($cacheId = false) + { + return ($this->_cache && ($this->_cacheType == 'auto' || ($this->_cacheType == 'manual' && ! empty($cacheId)))); + } + + /** + * Escapes given string with backquotes + * Prepares table name for using in SQL statements + * + * @param string $string + * + * @return string + */ + private function _quotes($string = '') + { + return $this->_backQuote.$string.$this->_backQuote; + } + } diff --git a/framework/db/CDbCommand.php b/framework/db/CDbCommand.php index 89ae81f..3b713d7 100644 --- a/framework/db/CDbCommand.php +++ b/framework/db/CDbCommand.php @@ -19,7 +19,7 @@ * $account = CDatabase::init()->createCommand() * ->select('id, username, password') * ->from(CConfig::get('db.prefix').'accounts') - * ->where('id=:id', array(':id'=>1)) + * ->where('id=:id', [':id'=>1]) * ->queryRow(); * * @@ -71,757 +71,843 @@ class CDbCommand { - /** @var CDatabase */ - protected $_db; - /** @var */ - protected $_dbDriver = ''; - /** @var array */ - public $_params = array(); - - /** @var string */ - private $_text; - /** @var string */ - private $_statement; - /** @var string */ - private $_query; - /** @var char */ - private $_backQuote = '`'; - /** @var int */ - private $_fetchMode = PDO::FETCH_ASSOC; - - - /** - * Class constructor - * @param CDatabase $dbConnection - */ - public function __construct($dbConnection = null) - { - $this->_db = $dbConnection; - $this->_dbDriver = CConfig::get('db.driver'); - - // Set back quote according to database driver - if (preg_match('/mssql|sqlsrv/i', CConfig::get('db.driver'))) { - $this->_backQuote = ''; - } - } - - /** - * Cleans up the command for building a new query - * @return CDbCommand command instance - */ - public function reset() - { - $this->_text = null; - $this->_query = null; - $this->_statement = null; - $this->_params = array(); - return $this; - } - - /** - * Cancels execution of the SQL statement - */ - public function cancel() - { - $this->_statement = null; - } - - /** - * Defines SQL statement to be executed - * @return CDbCommand command instance - */ - public function setText($value) - { - $this->_text = $value; - $this->cancel(); - return $this; - } - - /** - * Returns SQL to be executed - * @return string - */ - public function getText() - { - if ($this->_text == '' && !empty($this->_query)) { - $this->setText($this->buildQuery($this->_query)); - } - - return $this->_text; - } - - /** - * Executes the SQL statement and returns all rows - * @param boolean $fetchAssociative - * @param array $params - * @return array - */ - public function queryAll($fetchAssociative = true, $params = array()) - { - return $this->_queryInternal('fetchAll', $fetchAssociative ? $this->_fetchMode : PDO::FETCH_NUM, $params); - } - - /** - * Executes the SQL statement and returns the first row of the result. - * @param boolean $fetchAssociative - * @param array $params - * @return array - */ - public function queryRow($fetchAssociative = true, $params = array()) - { - return $this->_queryInternal('fetch', $fetchAssociative ? $this->_fetchMode : PDO::FETCH_NUM, $params); - } - - /** - * Executes the SQL statement and returns the value of the first column in the first row of data - * @param array $params - * @return array - */ - public function queryScalar($params = array()) - { - return $this->_queryInternal('fetchColumn', 0, $params); - - } - - /** - * Executes the SQL statement and returns the first column of the result - * @param array $params - * @return array - */ - public function queryColumn($params = array()) - { - return $this->_queryInternal('fetchAll', PDO::FETCH_COLUMN, $params); - } - - /** - * Executes the SQL statement - * @param string $method - * @param mixed $mode - * @param array $params - * @return mixed - */ - private function _queryInternal($method, $mode, $params = array()) - { - $params = array_merge($this->_params, $params); - return $this->_db->select($this->getText(), $params, $method, $mode); - } - - /** - * Builds a SQL SELECT statement from the given query specification - * @param array $query - * @return string the SQL statement - */ - public function buildQuery($query) - { - $sql = !empty($query['distinct']) ? 'SELECT DISTINCT' : 'SELECT'; - $sql .= ' ' . (!empty($query['select']) ? $query['select'] : '*'); - - $limit = isset($query['limit']) ? (int)$query['limit'] : ''; - $offset = isset($query['offset']) ? (int)$query['offset'] : ''; - $limits = $this->_applyLimit($limit, $offset); - - if (!empty($limits['before'])) { - $sql .= "\n " . $limits['before']; - } - if (!empty($query['from'])) { - $sql .= "\nFROM " . $query['from']; - } - if (!empty($query['join'])) { - $sql .= "\n" . (is_array($query['join']) ? implode("\n", $query['join']) : $query['join']); - } - if (!empty($query['where'])) { - $sql .= "\nWHERE " . $query['where']; - } - if (!empty($query['group'])) { - $sql .= "\nGROUP BY " . $query['group']; - } - if (!empty($query['having'])) { - $sql .= "\nHAVING " . $query['having']; - } - if (!empty($query['union'])) { - $sql .= "\nUNION (\n" . (is_array($query['union']) ? implode("\n) UNION (\n", $query['union']) : $query['union']) . ')'; - } - if (!empty($query['order'])) { - $sql .= "\nORDER BY " . $query['order']; - } - if (!empty($limits['after'])) { - $sql .= "\n " . $limits['after']; - } - - return $sql; - } - - /** - * Sets SELECT part of the query - * @param mixed $columns The columns to be selected (default '*' - all columns, or as array (e.g. array('id', 'name') ) - * @param string $option additional option that should be usaed, for example: SQL_CALC_FOUND_ROWS - * @return CDbCommand command instance - */ - public function select($columns = '*', $option = '') - { - if (is_string($columns) && strpos($columns, '(') !== false) { - $this->_query['select'] = $columns; - } else { - if (!is_array($columns)) { - $columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY); - } - - foreach ($columns as $key => $column) { - if (is_object($column)) { - $columns[$key] = (string)$column; - } elseif (strpos($column, '(') === false) { - // With alias - if (preg_match('/^(.*?)(?i:\s+as\s+|\s+)(.*)$/', $column, $matches)) { - $columns[$key] = $this->_quotes($matches[1]) . ' AS ' . $this->_quotes($matches[2]); - } else { - $columns[$key] = $column !== '*' ? $this->_quotes($column) : '*'; - } - } - } - - $this->_query['select'] = implode(', ', $columns); - } - - if ($option != '') { - $this->_query['select'] = $option . ' ' . $this->_query['select']; - } - - return $this; - } - - /** - * Returns the SELECT part of the query - * @return string - */ - public function getSelect() - { - return isset($this->_query['select']) ? $this->_query['select'] : ''; - } - - /** - * Sets a SELECT part of the query with the DISTINCT flag turned ON - * @param mixed $columns - * @return CDbCommand command instance - */ - public function selectDistinct($columns = '*') - { - $this->_query['distinct'] = true; - return $this->select($columns); - } - - /** - * Sets a FROM part of the query - * @param mixed string|array - * @return CDbCommand command instance - */ - public function from($tables) - { - if (is_string($tables) && strpos($tables, '(') !== false) { - $this->_query['from'] = $tables; - } else { - if (!is_array($tables)) { - $tables = preg_split('/\s*,\s*/', trim($tables), -1, PREG_SPLIT_NO_EMPTY); - } - - foreach ($tables as $key => $table) { - if (strpos($table, '(') === false) { - // With alias - if (preg_match('/^(.*?)(?i:\s+as|)\s+([^ ]+)$/', $table, $matches)) { - $tables[$key] = $this->_quotes($matches[1]) . ' ' . $this->_quotes($matches[2]); - } else { - $tables[$key] = $this->_quotes($table); - } - } - } - - $this->_query['from'] = implode(', ', $tables); - } - - return $this; - } - - /** - * Returns a FROM part in the query - * @return string - */ - public function getFrom() - { - return isset($this->_query['from']) ? $this->_query['from'] : ''; - } - - /** - * Sets the WHERE part of the query - * @param mixed $conditions Ex.: array('and', 'id=1', 'id=2') - * @param array $params - * @return CDbCommand the command object itself - */ - public function where($conditions, $params = array()) - { - $this->_query['where'] = $this->_processConditions($conditions); - foreach ($params as $name => $value) { - $this->_params[$name] = $value; - } - - return $this; - } - - /** - * Returns the WHERE part in the query - * @return string - */ - public function getWhere() - { - return isset($this->_query['where']) ? $this->_query['where'] : ''; - } - - /** - * Sets the WHERE part of the query with AND - * @param mixed $conditions Ex.: array('id=1', 'id=2') - * @param array $params - * @return CDbCommand the command object itself - */ - public function andWhere($conditions, $params = array()) - { - if (isset($this->_query['where'])) { - $this->_query['where'] = $this->_processConditions(array('AND', $this->_query['where'], $conditions)); - } else { - $this->_query['where'] = $this->_processConditions($conditions); - } - - foreach ($params as $name => $value) { - $this->_params[$name] = $value; - } - - return $this; - } - - /** - * Sets the WHERE part of the query with OR - * @param mixed $conditions Ex.: array('id=1', 'id=2') - * @param array $params - * @return CDbCommand the command object itself - */ - public function orWhere($conditions, $params = array()) - { - if (isset($this->_query['where'])) { - $this->_query['where'] = $this->_processConditions(array('OR', $this->_query['where'], $conditions)); - } else { - $this->_query['where'] = $this->_processConditions($conditions); - } - - foreach ($params as $name => $value) { - $this->_params[$name] = $value; - } - - return $this; - } - - /** - * Appends an INNER JOIN part to the query - * Ex.: join('table2', 'table1.id = table2.t_id') - * @param string $table - * @param mixed $conditions join condition that should appear in the ON part - * @param array $params format: (name=>value) to be bound to the query - * @return CDbCommand the command object itself - */ - public function join($table, $conditions, $params = array()) - { - return $this->_joinInternal('join', $table, $conditions, $params); - } - - /** - * Returns the join part in the query - * @return mixed - */ - public function getJoin() - { - return isset($this->_query['join']) ? $this->_query['join'] : ''; - } - - /** - * Appends a LEFT OUTER JOIN part to the query - * @param string $table - * @param mixed $conditions join condition that should appear in the ON part - * @param array $params format: (name=>value) to be bound to the query - * @return CDbCommand the command object itself - */ - public function leftJoin($table, $conditions, $params = array()) - { - return $this->_joinInternal('left join', $table, $conditions, $params); - } - - /** - * Appends a RIGHT OUTER JOIN part to the query - * @param string $table - * @param mixed $conditions join condition that should appear in the ON part - * @param array $params format: (name=>value) to be bound to the query - * @return CDbCommand the command object itself - */ - public function rightJoin($table, $conditions, $params = array()) - { - return $this->_joinInternal('right join', $table, $conditions, $params); - } - - /** - * Appends a CROSS (INNER) JOIN part to the query - * @param string $table - * @return CDbCommand the command object itself - */ - public function crossJoin($table) - { - return $this->_joinInternal('cross join', $table); - } - - /** - * Alias to crossJoin method - */ - public function innerJoin($table) - { - return $this->_joinInternal('inner join', $table); - } - - /** - * Appends a NATURAL JOIN part to the query - * @param string $table - * @return CDbCommand the command object itself - */ - public function naturalJoin($table) - { - return $this->_joinInternal('natural join', $table); - } - - /** - * Appends a NATURAL LEFT JOIN part to the query - * @param string $table - * @return CDbCommand the command object itself - */ - public function naturalLeftJoin($table) - { - return $this->_joinInternal('natural left join', $table); - } - - /** - * Appends a NATURAL RIGHT JOIN part to the query - * @param string $table - * @return CDbCommand the command object itself - */ - public function naturalRightJoin($table) - { - return $this->_joinInternal('natural right join', $table); - } - - /** - * Sets the GROUP BY part of the query - * Ex.: columns specified in either a string (e.g. 'id', 'name') or an array (e.g. array('id', 'name')) - * @return CDbCommand the command object itself - */ - public function group($columns) - { - if (is_string($columns) && strpos($columns, '(') !== false) { - $this->_query['group'] = $columns; - } else { - if (!is_array($columns)) { - $columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY); - } - - foreach ($columns as $i => $column) { - if (is_object($column)) { - $columns[$i] = (string)$column; - } elseif (strpos($column, '(') === false) { - $columns[$i] = $this->_quotes($column); - } - } - - $this->_query['group'] = implode(', ', $columns); - } - - return $this; - } - - /** - * Returns the GROUP BY part in the query - * @return string (without 'GROUP BY') - */ - public function getGroup() - { - return isset($this->_query['group']) ? $this->_query['group'] : ''; - } - - /** - * Sets the HAVING part of the query - * @param mixed $conditions - * @param array $params - * @return CDbCommand the command object itself - */ - public function having($conditions, $params = array()) - { - $this->_query['having'] = $this->_processConditions($conditions); - foreach ($params as $name => $value) { - $this->_params[$name] = $value; - } - - return $this; - } - - /** - * Returns the HAVING part in the query - * @return string (without 'HAVING') - */ - public function getHaving() - { - return isset($this->_query['having']) ? $this->_query['having'] : ''; - } - - /** - * Sets the ORDER BY part of the query. - * @param mixed $columns (e.g. order(array('id ASC', 'name DESC')) or order('(1)')) - * @return CDbCommand the command object itself - */ - public function order($columns) - { - if (is_string($columns) && strpos($columns, '(') !== false) { - $this->_query['order'] = $columns; - } else { - if (!is_array($columns)) { - $columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY); - } - - foreach ($columns as $i => $column) { - if (is_object($column)) { - $columns[$i] = (string)$column; - } elseif (strpos($column, '(') === false) { - if (preg_match('/^(.*?)\s+(asc|desc)$/i', $column, $matches)) { - $columns[$i] = $this->_quotes($matches[1]) . ' ' . strtoupper($matches[2]); - } else { - $columns[$i] = $this->_quotes($column); - } - } - } - - $this->_query['order'] = implode(', ', $columns); - } - - return $this; - } - - /** - * Returns the ORDER BY part in the query - * @return string (without 'ORDER BY') - */ - public function getOrder() - { - return isset($this->_query['order']) ? $this->_query['order'] : ''; - } - - /** - * Sets the LIMIT part of the query - * @param int $limit - * @param int $offset - * @return CDbCommand the command object itself - */ - public function limit($limit, $offset = null) - { - $this->_query['limit'] = (int)$limit; - if ($offset !== null) { - $this->offset($offset); - } - - return $this; - } - - /** - * Returns the LIMIT part in the query - * @return string (without 'LIMIT') - */ - public function getLimit() - { - return isset($this->_query['limit']) ? $this->_query['limit'] : -1; - } - - /** - * Sets the OFFSET part of the query - * @param int $offset - * @return CDbCommand the command object itself - */ - public function offset($offset) - { - $this->_query['offset'] = (int)$offset; - return $this; - } - - /** - * Returns the OFFSET part in the query - * @return string (without 'OFFSET') - */ - public function getOffset() - { - return isset($this->_query['offset']) ? $this->_query['offset'] : -1; - } - - /** - * Appends a SQL statement using UNION operator - * @param string $sql - * @return CDbCommand the command object itself - */ - public function union($sql) - { - if (isset($this->_query['union']) && is_string($this->_query['union'])) { - $this->_query['union'] = array($this->_query['union']); - } - - $this->_query['union'][] = $sql; - return $this; - } - - /** - * Returns the UNION part in the query - * @return mixed (without 'UNION') - */ - public function getUnion() - { - return isset($this->_query['union']) ? $this->_query['union'] : ''; - } - - /** - * Creates condition string that will be put in the WHERE part od the SQL statement - * @param mixed $conditions - * @return string - */ - private function _processConditions($conditions) - { - if (empty($conditions)) { - return ''; - } else if (!is_array($conditions)) { - return $conditions; - } - - $conditionsCount = count($conditions); - $operator = strtoupper($conditions[0]); - if (in_array($operator, array('OR', 'AND'))) { - $parts = array(); - for ($i = 1; $i < $conditionsCount; $i++) { - $condition = $this->_processConditions($conditions[$i]); - if ($condition !== '') { - $parts[] = '(' . $condition . ')'; - } - } - return !empty($parts) ? implode(' ' . $operator . ' ', $parts) : ''; - } - - if (!isset($conditions[1], $conditions[2])) { - return ''; - } - - $column = $conditions[1]; - if (strpos($column, '(') === false) { - $column = $this->_quotes($column); - } - - $values = $conditions[2]; - if (!is_array($values)) { - $values = array($values); - } - - if (in_array($operator, array('IN', 'NOT IN'))) { - if ($values === array()) { - return $operator === 'IN' ? '0=1' : ''; - } - - foreach ($values as $i => $value) { - $values[$i] = is_string($value) ? $this->_quotes($value) : (string)$value; - } - - return $column . ' ' . $operator . ' (' . implode(', ', $values) . ')'; - } - - if (in_array($operator, array('LIKE', 'NOT LIKE', 'OR LIKE', 'OR NOT LIKE'))) { - if (empty($values)) { - return $operator === 'LIKE' || $operator === 'OR LIKE' ? '0=1' : ''; - } - - if ($operator === 'LIKE' || $operator === 'NOT LIKE') { - $andor = ' AND '; - } else { - $andor = ' OR '; - $operator = $operator === 'OR LIKE' ? 'LIKE' : 'NOT LIKE'; - } - - $expressions = array(); - foreach ($values as $value) { - $expressions[] = $column . ' ' . $operator . ' ' . $this->_quotes($value); - } - - return implode($andor, $expressions); - } - - CDebug::addMessage('errors', 'wrong operator in condition ', A::t('core', 'Unknown operator "{operator}".', array('{operator}' => $operator))); - } - - /** - * Appends an JOIN part to the query - * @param string $type Ex.:('join', 'left join', 'right join', 'cross join', 'natural join') - * @param string $table - * @param mixed $conditions - * @param array $params - * @return CDbCommand the command object itself - */ - private function _joinInternal($type, $table, $conditions = '', $params = array()) - { - if (strpos($table, '(') === false) { - if (preg_match('/^(.*?)(?i:\s+as|)\s+([^ ]+)$/', $table, $matches)) { - // With alias - $table = $this->_connection->quoteTableName($matches[1]) . ' ' . $this->_connection->quoteTableName($matches[2]); - } else { - $table = $this->_connection->quoteTableName($table); - } - } - - $conditions = $this->_processConditions($conditions); - if ($conditions != '') { - $conditions = ' ON ' . $conditions; - } - - if (isset($this->_query['join']) && is_string($this->_query['join'])) { - $this->_query['join'] = array($this->_query['join']); - } - - $this->_query['join'][] = strtoupper($type) . ' ' . $table . $conditions; - foreach ($params as $name => $value) { - $this->_params[$name] = $value; - } - - return $this; - } - - /** - * Escapes given string with backquotes - * Prepares table name for using in SQL statements - * @param string $string - * @return string - */ - private function _quotes($string = '') - { - return $this->_backQuote . $string . $this->_backQuote; - } - - /** - * Prepare LIMIT clause for SQL statement - * @param string $limit - * @retun array - */ - private function _applyLimit($limit, $offset = '') - { - $limits = array('before' => '', 'after' => ''); - - if (!empty($limit)) { - if (preg_match('/mssql|sqlsrv/i', $this->_dbDriver)) { - $limits['before'] = !empty($limit) ? ' TOP ' . $limit : ''; - } else { - $limits['after'] = !empty($limit) ? ' LIMIT ' . (!empty($offset) ? ', ' : '') . ' ' . $limit : ''; - } - } - - return $limits; - } + /** @var CDatabase */ + protected $_db; + /** @var */ + protected $_dbDriver = ''; + /** @var array */ + public $_params = []; + + /** @var string */ + private $_text; + /** @var string */ + private $_statement; + /** @var string */ + private $_query; + /** @var char */ + private $_backQuote = '`'; + /** @var int */ + private $_fetchMode = PDO::FETCH_ASSOC; + + + /** + * Class constructor + * + * @param CDatabase $dbConnection + */ + public function __construct($dbConnection = null) + { + $this->_db = $dbConnection; + $this->_dbDriver = CConfig::get('db.driver'); + + // Set back quote according to database driver + if (preg_match('/mssql|sqlsrv/i', CConfig::get('db.driver'))) { + $this->_backQuote = ''; + } + } + + /** + * Cleans up the command for building a new query + * + * @return CDbCommand command instance + */ + public function reset() + { + $this->_text = null; + $this->_query = null; + $this->_statement = null; + $this->_params = []; + + return $this; + } + + /** + * Cancels execution of the SQL statement + */ + public function cancel() + { + $this->_statement = null; + } + + /** + * Defines SQL statement to be executed + * + * @return CDbCommand command instance + */ + public function setText($value) + { + $this->_text = $value; + $this->cancel(); + + return $this; + } + + /** + * Returns SQL to be executed + * + * @return string + */ + public function getText() + { + if ($this->_text == '' && ! empty($this->_query)) { + $this->setText($this->buildQuery($this->_query)); + } + + return $this->_text; + } + + /** + * Executes the SQL statement and returns all rows + * + * @param boolean $fetchAssociative + * @param array $params + * + * @return array + */ + public function queryAll($fetchAssociative = true, $params = []) + { + return $this->_queryInternal('fetchAll', $fetchAssociative ? $this->_fetchMode : PDO::FETCH_NUM, $params); + } + + /** + * Executes the SQL statement and returns the first row of the result. + * + * @param boolean $fetchAssociative + * @param array $params + * + * @return array + */ + public function queryRow($fetchAssociative = true, $params = []) + { + return $this->_queryInternal('fetch', $fetchAssociative ? $this->_fetchMode : PDO::FETCH_NUM, $params); + } + + /** + * Executes the SQL statement and returns the value of the first column in the first row of data + * + * @param array $params + * + * @return array + */ + public function queryScalar($params = []) + { + return $this->_queryInternal('fetchColumn', 0, $params); + } + + /** + * Executes the SQL statement and returns the first column of the result + * + * @param array $params + * + * @return array + */ + public function queryColumn($params = []) + { + return $this->_queryInternal('fetchAll', PDO::FETCH_COLUMN, $params); + } + + /** + * Executes the SQL statement + * + * @param string $method + * @param mixed $mode + * @param array $params + * + * @return mixed + */ + private function _queryInternal($method, $mode, $params = []) + { + $params = array_merge($this->_params, $params); + + return $this->_db->select($this->getText(), $params, $method, $mode); + } + + /** + * Builds a SQL SELECT statement from the given query specification + * + * @param array $query + * + * @return string the SQL statement + */ + public function buildQuery($query) + { + $sql = ! empty($query['distinct']) ? 'SELECT DISTINCT' : 'SELECT'; + $sql .= ' '.(! empty($query['select']) ? $query['select'] : '*'); + + $limit = isset($query['limit']) ? (int)$query['limit'] : ''; + $offset = isset($query['offset']) ? (int)$query['offset'] : ''; + $limits = $this->_applyLimit($limit, $offset); + + if ( ! empty($limits['before'])) { + $sql .= "\n ".$limits['before']; + } + if ( ! empty($query['from'])) { + $sql .= "\nFROM ".$query['from']; + } + if ( ! empty($query['join'])) { + $sql .= "\n".(is_array($query['join']) ? implode("\n", $query['join']) : $query['join']); + } + if ( ! empty($query['where'])) { + $sql .= "\nWHERE ".$query['where']; + } + if ( ! empty($query['group'])) { + $sql .= "\nGROUP BY ".$query['group']; + } + if ( ! empty($query['having'])) { + $sql .= "\nHAVING ".$query['having']; + } + if ( ! empty($query['union'])) { + $sql .= "\nUNION (\n".(is_array($query['union']) ? implode("\n) UNION (\n", $query['union']) + : $query['union']).')'; + } + if ( ! empty($query['order'])) { + $sql .= "\nORDER BY ".$query['order']; + } + if ( ! empty($limits['after'])) { + $sql .= "\n ".$limits['after']; + } + + return $sql; + } + + /** + * Sets SELECT part of the query + * + * @param mixed $columns The columns to be selected (default '*' - all columns, or as array (e.g. ['id', 'name'] ) + * @param string $option additional option that should be usaed, for example: SQL_CALC_FOUND_ROWS + * + * @return CDbCommand command instance + */ + public function select($columns = '*', $option = '') + { + if (is_string($columns) && strpos($columns, '(') !== false) { + $this->_query['select'] = $columns; + } else { + if ( ! is_array($columns)) { + $columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY); + } + + foreach ($columns as $key => $column) { + if (is_object($column)) { + $columns[$key] = (string)$column; + } elseif (strpos($column, '(') === false) { + // With alias + if (preg_match('/^(.*?)(?i:\s+as\s+|\s+)(.*)$/', $column, $matches)) { + $columns[$key] = $this->_quotes($matches[1]).' AS '.$this->_quotes($matches[2]); + } else { + $columns[$key] = $column !== '*' ? $this->_quotes($column) : '*'; + } + } + } + + $this->_query['select'] = implode(', ', $columns); + } + + if ($option != '') { + $this->_query['select'] = $option.' '.$this->_query['select']; + } + + return $this; + } + + /** + * Returns the SELECT part of the query + * + * @return string + */ + public function getSelect() + { + return isset($this->_query['select']) ? $this->_query['select'] : ''; + } + + /** + * Sets a SELECT part of the query with the DISTINCT flag turned ON + * + * @param mixed $columns + * + * @return CDbCommand command instance + */ + public function selectDistinct($columns = '*') + { + $this->_query['distinct'] = true; + + return $this->select($columns); + } + + /** + * Sets a FROM part of the query + * + * @param mixed string|array + * + * @return CDbCommand command instance + */ + public function from($tables) + { + if (is_string($tables) && strpos($tables, '(') !== false) { + $this->_query['from'] = $tables; + } else { + if ( ! is_array($tables)) { + $tables = preg_split('/\s*,\s*/', trim($tables), -1, PREG_SPLIT_NO_EMPTY); + } + + foreach ($tables as $key => $table) { + if (strpos($table, '(') === false) { + // With alias + if (preg_match('/^(.*?)(?i:\s+as|)\s+([^ ]+)$/', $table, $matches)) { + $tables[$key] = $this->_quotes($matches[1]).' '.$this->_quotes($matches[2]); + } else { + $tables[$key] = $this->_quotes($table); + } + } + } + + $this->_query['from'] = implode(', ', $tables); + } + + return $this; + } + + /** + * Returns a FROM part in the query + * + * @return string + */ + public function getFrom() + { + return isset($this->_query['from']) ? $this->_query['from'] : ''; + } + + /** + * Sets the WHERE part of the query + * + * @param mixed $conditions Ex.: ['and', 'id=1', 'id=2'] + * @param array $params + * + * @return CDbCommand the command object itself + */ + public function where($conditions, $params = []) + { + $this->_query['where'] = $this->_processConditions($conditions); + foreach ($params as $name => $value) { + $this->_params[$name] = $value; + } + + return $this; + } + + /** + * Returns the WHERE part in the query + * + * @return string + */ + public function getWhere() + { + return isset($this->_query['where']) ? $this->_query['where'] : ''; + } + + /** + * Sets the WHERE part of the query with AND + * + * @param mixed $conditions Ex.: ['id=1', 'id=2'] + * @param array $params + * + * @return CDbCommand the command object itself + */ + public function andWhere($conditions, $params = []) + { + if (isset($this->_query['where'])) { + $this->_query['where'] = $this->_processConditions(['AND', $this->_query['where'], $conditions]); + } else { + $this->_query['where'] = $this->_processConditions($conditions); + } + + foreach ($params as $name => $value) { + $this->_params[$name] = $value; + } + + return $this; + } + + /** + * Sets the WHERE part of the query with OR + * + * @param mixed $conditions Ex.: array('id=1', 'id=2') + * @param array $params + * + * @return CDbCommand the command object itself + */ + public function orWhere($conditions, $params = []) + { + if (isset($this->_query['where'])) { + $this->_query['where'] = $this->_processConditions(['OR', $this->_query['where'], $conditions]); + } else { + $this->_query['where'] = $this->_processConditions($conditions); + } + + foreach ($params as $name => $value) { + $this->_params[$name] = $value; + } + + return $this; + } + + /** + * Appends an INNER JOIN part to the query + * Ex.: join('table2', 'table1.id = table2.t_id') + * + * @param string $table + * @param mixed $conditions join condition that should appear in the ON part + * @param array $params format: (name=>value) to be bound to the query + * + * @return CDbCommand the command object itself + */ + public function join($table, $conditions, $params = []) + { + return $this->_joinInternal('join', $table, $conditions, $params); + } + + /** + * Returns the join part in the query + * + * @return mixed + */ + public function getJoin() + { + return isset($this->_query['join']) ? $this->_query['join'] : ''; + } + + /** + * Appends a LEFT OUTER JOIN part to the query + * + * @param string $table + * @param mixed $conditions join condition that should appear in the ON part + * @param array $params format: (name=>value) to be bound to the query + * + * @return CDbCommand the command object itself + */ + public function leftJoin($table, $conditions, $params = []) + { + return $this->_joinInternal('left join', $table, $conditions, $params); + } + + /** + * Appends a RIGHT OUTER JOIN part to the query + * + * @param string $table + * @param mixed $conditions join condition that should appear in the ON part + * @param array $params format: (name=>value) to be bound to the query + * + * @return CDbCommand the command object itself + */ + public function rightJoin($table, $conditions, $params = []) + { + return $this->_joinInternal('right join', $table, $conditions, $params); + } + + /** + * Appends a CROSS (INNER) JOIN part to the query + * + * @param string $table + * + * @return CDbCommand the command object itself + */ + public function crossJoin($table) + { + return $this->_joinInternal('cross join', $table); + } + + /** + * Alias to crossJoin method + */ + public function innerJoin($table) + { + return $this->_joinInternal('inner join', $table); + } + + /** + * Appends a NATURAL JOIN part to the query + * + * @param string $table + * + * @return CDbCommand the command object itself + */ + public function naturalJoin($table) + { + return $this->_joinInternal('natural join', $table); + } + + /** + * Appends a NATURAL LEFT JOIN part to the query + * + * @param string $table + * + * @return CDbCommand the command object itself + */ + public function naturalLeftJoin($table) + { + return $this->_joinInternal('natural left join', $table); + } + + /** + * Appends a NATURAL RIGHT JOIN part to the query + * + * @param string $table + * + * @return CDbCommand the command object itself + */ + public function naturalRightJoin($table) + { + return $this->_joinInternal('natural right join', $table); + } + + /** + * Sets the GROUP BY part of the query + * Ex.: columns specified in either a string (e.g. 'id', 'name') or an array (e.g. array('id', 'name')) + * + * @return CDbCommand the command object itself + */ + public function group($columns) + { + if (is_string($columns) && strpos($columns, '(') !== false) { + $this->_query['group'] = $columns; + } else { + if ( ! is_array($columns)) { + $columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY); + } + + foreach ($columns as $i => $column) { + if (is_object($column)) { + $columns[$i] = (string)$column; + } elseif (strpos($column, '(') === false) { + $columns[$i] = $this->_quotes($column); + } + } + + $this->_query['group'] = implode(', ', $columns); + } + + return $this; + } + + /** + * Returns the GROUP BY part in the query + * + * @return string (without 'GROUP BY') + */ + public function getGroup() + { + return isset($this->_query['group']) ? $this->_query['group'] : ''; + } + + /** + * Sets the HAVING part of the query + * + * @param mixed $conditions + * @param array $params + * + * @return CDbCommand the command object itself + */ + public function having($conditions, $params = []) + { + $this->_query['having'] = $this->_processConditions($conditions); + foreach ($params as $name => $value) { + $this->_params[$name] = $value; + } + + return $this; + } + + /** + * Returns the HAVING part in the query + * + * @return string (without 'HAVING') + */ + public function getHaving() + { + return isset($this->_query['having']) ? $this->_query['having'] : ''; + } + + /** + * Sets the ORDER BY part of the query. + * + * @param mixed $columns (e.g. order(array('id ASC', 'name DESC')) or order('(1)')) + * + * @return CDbCommand the command object itself + */ + public function order($columns) + { + if (is_string($columns) && strpos($columns, '(') !== false) { + $this->_query['order'] = $columns; + } else { + if ( ! is_array($columns)) { + $columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY); + } + + foreach ($columns as $i => $column) { + if (is_object($column)) { + $columns[$i] = (string)$column; + } elseif (strpos($column, '(') === false) { + if (preg_match('/^(.*?)\s+(asc|desc)$/i', $column, $matches)) { + $columns[$i] = $this->_quotes($matches[1]).' '.strtoupper($matches[2]); + } else { + $columns[$i] = $this->_quotes($column); + } + } + } + + $this->_query['order'] = implode(', ', $columns); + } + + return $this; + } + + /** + * Returns the ORDER BY part in the query + * + * @return string (without 'ORDER BY') + */ + public function getOrder() + { + return isset($this->_query['order']) ? $this->_query['order'] : ''; + } + + /** + * Sets the LIMIT part of the query + * + * @param int $limit + * @param int $offset + * + * @return CDbCommand the command object itself + */ + public function limit($limit, $offset = null) + { + $this->_query['limit'] = (int)$limit; + if ($offset !== null) { + $this->offset($offset); + } + + return $this; + } + + /** + * Returns the LIMIT part in the query + * + * @return string (without 'LIMIT') + */ + public function getLimit() + { + return isset($this->_query['limit']) ? $this->_query['limit'] : -1; + } + + /** + * Sets the OFFSET part of the query + * + * @param int $offset + * + * @return CDbCommand the command object itself + */ + public function offset($offset) + { + $this->_query['offset'] = (int)$offset; + + return $this; + } + + /** + * Returns the OFFSET part in the query + * + * @return string (without 'OFFSET') + */ + public function getOffset() + { + return isset($this->_query['offset']) ? $this->_query['offset'] : -1; + } + + /** + * Appends a SQL statement using UNION operator + * + * @param string $sql + * + * @return CDbCommand the command object itself + */ + public function union($sql) + { + if (isset($this->_query['union']) && is_string($this->_query['union'])) { + $this->_query['union'] = [$this->_query['union']]; + } + + $this->_query['union'][] = $sql; + + return $this; + } + + /** + * Returns the UNION part in the query + * + * @return mixed (without 'UNION') + */ + public function getUnion() + { + return isset($this->_query['union']) ? $this->_query['union'] : ''; + } + + /** + * Creates condition string that will be put in the WHERE part od the SQL statement + * + * @param mixed $conditions + * + * @return string + */ + private function _processConditions($conditions) + { + if (empty($conditions)) { + return ''; + } elseif ( ! is_array($conditions)) { + return $conditions; + } + + $conditionsCount = count($conditions); + $operator = strtoupper($conditions[0]); + if (in_array($operator, ['OR', 'AND'])) { + $parts = []; + for ($i = 1; $i < $conditionsCount; $i++) { + $condition = $this->_processConditions($conditions[$i]); + if ($condition !== '') { + $parts[] = '('.$condition.')'; + } + } + + return ! empty($parts) ? implode(' '.$operator.' ', $parts) : ''; + } + + if ( ! isset($conditions[1], $conditions[2])) { + return ''; + } + + $column = $conditions[1]; + if (strpos($column, '(') === false) { + $column = $this->_quotes($column); + } + + $values = $conditions[2]; + if ( ! is_array($values)) { + $values = [$values]; + } + + if (in_array($operator, ['IN', 'NOT IN'])) { + if ($values === []) { + return $operator === 'IN' ? '0=1' : ''; + } + + foreach ($values as $i => $value) { + $values[$i] = is_string($value) ? $this->_quotes($value) : (string)$value; + } + + return $column.' '.$operator.' ('.implode(', ', $values).')'; + } + + if (in_array($operator, ['LIKE', 'NOT LIKE', 'OR LIKE', 'OR NOT LIKE'])) { + if (empty($values)) { + return $operator === 'LIKE' || $operator === 'OR LIKE' ? '0=1' : ''; + } + + if ($operator === 'LIKE' || $operator === 'NOT LIKE') { + $andor = ' AND '; + } else { + $andor = ' OR '; + $operator = $operator === 'OR LIKE' ? 'LIKE' : 'NOT LIKE'; + } + + $expressions = []; + foreach ($values as $value) { + $expressions[] = $column.' '.$operator.' '.$this->_quotes($value); + } + + return implode($andor, $expressions); + } + + CDebug::addMessage( + 'errors', + 'wrong operator in condition ', + A::t('core', 'Unknown operator "{operator}".', ['{operator}' => $operator]) + ); + } + + /** + * Appends an JOIN part to the query + * + * @param string $type Ex.:('join', 'left join', 'right join', 'cross join', 'natural join') + * @param string $table + * @param mixed $conditions + * @param array $params + * + * @return CDbCommand the command object itself + */ + private function _joinInternal($type, $table, $conditions = '', $params = []) + { + if (strpos($table, '(') === false) { + if (preg_match('/^(.*?)(?i:\s+as|)\s+([^ ]+)$/', $table, $matches)) { + // With alias + $table = $this->_connection->quoteTableName($matches[1]).' '.$this->_connection->quoteTableName( + $matches[2] + ); + } else { + $table = $this->_connection->quoteTableName($table); + } + } + + $conditions = $this->_processConditions($conditions); + if ($conditions != '') { + $conditions = ' ON '.$conditions; + } + + if (isset($this->_query['join']) && is_string($this->_query['join'])) { + $this->_query['join'] = [$this->_query['join']]; + } + + $this->_query['join'][] = strtoupper($type).' '.$table.$conditions; + foreach ($params as $name => $value) { + $this->_params[$name] = $value; + } + + return $this; + } + + /** + * Escapes given string with backquotes + * Prepares table name for using in SQL statements + * + * @param string $string + * + * @return string + */ + private function _quotes($string = '') + { + return $this->_backQuote.$string.$this->_backQuote; + } + + /** + * Prepare LIMIT clause for SQL statement + * + * @param string $limit + * @param string $offset + * + * @return array + * @retun array + */ + private function _applyLimit($limit, $offset = '') + { + $limits = ['before' => '', 'after' => '']; + + if ( ! empty($limit)) { + if (preg_match('/mssql|sqlsrv/i', $this->_dbDriver)) { + $limits['before'] = ! empty($limit) ? ' TOP '.$limit : ''; + } else { + $limits['after'] = ! empty($limit) ? ' LIMIT '.(! empty($offset) ? ', ' : '').' '.$limit : ''; + } + } + + return $limits; + } } diff --git a/framework/db/CRecordEntity.php b/framework/db/CRecordEntity.php index f2a1c15..04ccb4f 100644 --- a/framework/db/CRecordEntity.php +++ b/framework/db/CRecordEntity.php @@ -32,58 +32,74 @@ abstract class CRecordEntity { - /** @var */ - protected $_columns = array(); - /** @var */ - protected $_primaryKey = ''; - /** @var */ - protected $_pkValue = 0; - - /** @var fillable fields */ - protected $_fillable = array(); - /** @var guarded fields */ - protected $_guarded = array(); - - /** - * Class constructor - * @param int $pkVal - */ - public function __construct($pkVal = 0) - { - if (!empty($pkVal)) { - $this->_pkValue = $pkVal; - } - } - - /** - * Setter - * @param string $index - * @param mixed $value - * @return void - */ - public function __set($index, $value) - { - $this->_columns[$index] = $value; - } - - /** - * Getter - * @param string $index - * @return string - */ - public function __get($index) - { - if (array_key_exists($index, $this->_columns)) { - return $this->_columns[$index]; - } else { - CDebug::AddMessage('errors', 'wrong_column' . $index, A::t('core', 'Wrong column name: {index} in table {table}', array('{index}' => $index, '{table}' => __CLASS__))); - return ''; - } - } + /** @var */ + protected $_columns = []; + /** @var */ + protected $_primaryKey = ''; + /** @var */ + protected $_pkValue = 0; + + /** @var fillable fields */ + protected $_fillable = []; + /** @var guarded fields */ + protected $_guarded = []; + + /** + * Class constructor + * + * @param int $pkVal + */ + public function __construct($pkVal = 0) + { + if ( ! empty($pkVal)) { + $this->_pkValue = $pkVal; + } + } + + /** + * Setter + * + * @param string $index + * @param mixed $value + * + * @return void + */ + public function __set($index, $value) + { + $this->_columns[$index] = $value; + } + + /** + * Getter + * + * @param string $index + * + * @return string + */ + public function __get($index) + { + if (array_key_exists($index, $this->_columns)) { + return $this->_columns[$index]; + } else { + CDebug::AddMessage( + 'errors', + 'wrong_column'.$index, + A::t( + 'core', + 'Wrong column name: {index} in table {table}', + ['{index}' => $index, '{table}' => __CLASS__] + ) + ); + + return ''; + } + } /** * Checks if record entity property exists - * @param string $index + * + * @param string $index + * * @return bool */ public function __isset($index) @@ -91,150 +107,177 @@ public function __isset($index) return array_key_exists($index, $this->_columns) ? true : false; } - /** - * Sets a record entity property to be null - * @param string $index - * @return void - */ - public function __unset($index) - { - if (array_key_exists($index, $this->_columns)) { - unset($this->_columns[$index]); - } - } - - /** - * Setter - * @param string $index - * @param mixed $value - * @return void - */ - public function set($index, $value) - { - $this->_columns[$index] = $value; - } - - /** - * Getter - * @param string $index - * @return string - */ - public function get($index) - { - if (array_key_exists($index, $this->_columns)) { - return $this->_columns[$index]; - } else { - CDebug::AddMessage('errors', 'wrong_column' . $index, A::t('core', 'Wrong column name: {index} in table {table}', array('{index}' => $index, '{table}' => $this->_table))); - return ''; - } - } - - /** - * Returns the primary key of the associated database table - * @return string - */ - public function primaryKey() - { - return $this->_primaryKey; - } - - /** - * Returns the primary key value - * @return mixed - */ - public function getPrimaryKey() - { - return $this->_pkValue; - } - - /** - * Returns the primary key value - * @param int $pkVal - */ - protected function setPrimaryKey($pkVal = 0) - { - if (!empty($pkVal)) { - $this->_pkValue = $pkVal; - } - } - - /** - * Return all columns - * @param bool $allowFilters Return only allowed fields - * @return array - */ - public function columns($allowFilters = false) - { - $columns = $this->_columns; - - if ($allowFilters) { - // Validate fillable fields, left only allowed fields - if (is_array($this->_fillable) && !empty($this->_fillable)) { - $columns = array_intersect_key($columns, array_flip($this->_fillable)); - } - - // Validate guarded fields, exclude guarded fields - if (is_array($this->_guarded) && !empty($this->_guarded)) { - $columns = array_diff_key($columns, array_flip($this->_guarded)); - } - } - - return $columns; - } - - /** - * Return all allowed columns - * @return array - */ - public function allowedColumns() - { - return $this->columns(true); - } - - /** - * Set fillable fields - * @param array $fields - * @return void - */ - public function setFillable($fields = array()) - { - if (is_array($fields)) { - $this->_fillable = array(); - foreach ($fields as $field) { - $this->_fillable[] = $field; - } - } - } - - /** - * Set guarded fields - * @param array $fields - * @return void - */ - public function setGuarded($fields = array()) - { - if (is_array($fields)) { - $this->_guarded= array(); - foreach ($fields as $field) { - $this->_guarded[] = $field; - } - } - } - - /** - * Fills data from array - * @param array|null $record - * @return bool - */ - public function fillFromArray($record = null) - { - // Copy data to CRecordEntity - if (!is_null($record) && is_array($record)) { - foreach ($record as $key => $val) { - $this->$key = $val; - } - } - - return true; - } + /** + * Sets a record entity property to be null + * + * @param string $index + * + * @return void + */ + public function __unset($index) + { + if (array_key_exists($index, $this->_columns)) { + unset($this->_columns[$index]); + } + } + + /** + * Setter + * + * @param string $index + * @param mixed $value + * + * @return void + */ + public function set($index, $value) + { + $this->_columns[$index] = $value; + } + + /** + * Getter + * + * @param string $index + * + * @return string + */ + public function get($index) + { + if (array_key_exists($index, $this->_columns)) { + return $this->_columns[$index]; + } else { + CDebug::AddMessage( + 'errors', + 'wrong_column'.$index, + A::t( + 'core', + 'Wrong column name: {index} in table {table}', + ['{index}' => $index, '{table}' => $this->_table] + ) + ); + + return ''; + } + } + + /** + * Returns the primary key of the associated database table + * + * @return string + */ + public function primaryKey() + { + return $this->_primaryKey; + } + + /** + * Returns the primary key value + * + * @return mixed + */ + public function getPrimaryKey() + { + return $this->_pkValue; + } + + /** + * Returns the primary key value + * + * @param int $pkVal + */ + protected function setPrimaryKey($pkVal = 0) + { + if ( ! empty($pkVal)) { + $this->_pkValue = $pkVal; + } + } + + /** + * Return all columns + * + * @param bool $allowFilters Return only allowed fields + * + * @return array + */ + public function columns($allowFilters = false) + { + $columns = $this->_columns; + + if ($allowFilters) { + // Validate fillable fields, left only allowed fields + if (is_array($this->_fillable) && ! empty($this->_fillable)) { + $columns = array_intersect_key($columns, array_flip($this->_fillable)); + } + + // Validate guarded fields, exclude guarded fields + if (is_array($this->_guarded) && ! empty($this->_guarded)) { + $columns = array_diff_key($columns, array_flip($this->_guarded)); + } + } + + return $columns; + } + + /** + * Return all allowed columns + * + * @return array + */ + public function allowedColumns() + { + return $this->columns(true); + } + + /** + * Set fillable fields + * + * @param array $fields + * + * @return void + */ + public function setFillable($fields = []) + { + if (is_array($fields)) { + $this->_fillable = []; + foreach ($fields as $field) { + $this->_fillable[] = $field; + } + } + } + + /** + * Set guarded fields + * + * @param array $fields + * + * @return void + */ + public function setGuarded($fields = []) + { + if (is_array($fields)) { + $this->_guarded = []; + foreach ($fields as $field) { + $this->_guarded[] = $field; + } + } + } + + /** + * Fills data from array + * + * @param array|null $record + * + * @return bool + */ + public function fillFromArray($record = null) + { + // Copy data to CRecordEntity + if ( ! is_null($record) && is_array($record)) { + foreach ($record as $key => $val) { + $this->$key = $val; + } + } + + return true; + } } \ No newline at end of file diff --git a/framework/helpers/widgets/CBreadCrumbs.php b/framework/helpers/widgets/CBreadCrumbs.php index 09d1a4d..aa3667e 100644 --- a/framework/helpers/widgets/CBreadCrumbs.php +++ b/framework/helpers/widgets/CBreadCrumbs.php @@ -16,62 +16,79 @@ class CBreadCrumbs extends CWidgs { - - const NL = "\n"; - - /** - * Draws breadcrumbs - * @param array $params - * - * Usage: - * CWidget::create('CBreadCrumbs', array( - * 'links' => array( - * array('label'=>'Label A', 'url'=>'url1/'), - * array('label'=>'Label B', 'url'=>'url2/'), - * ), - * 'wrapperClass' => '', - * 'wrapperTag' => '', - * 'linkWrapperTag' => '', - * 'separator' => ' / ', - * 'return' => true - * )); - */ - public static function init($params = array()) - { - parent::init($params); - - $output = ''; - $wrapperTag = self::params('wrapperTag', 'div'); - $links = self::params('links', ''); - $linkWrapperTag = self::params('linkWrapperTag', ''); - $separator = self::params('separator', '»'); - $return = (bool)self::params('return', true); - $wrapperClass = self::params('wrapperClass', 'breadcrumbs'); - $htmlOptions = array('class' => $wrapperClass); - - if (is_array($links)) { - if (!empty($wrapperTag)) $output .= CHtml::openTag($wrapperTag, $htmlOptions) . self::NL; - $counter = 0; - foreach ($params['links'] as $item => $val) { - $url = self::keyAt('url', $val, ''); - $label = self::keyAt('label', $val, ''); - - if (!empty($linkWrapperTag)) $output .= CHtml::openTag($linkWrapperTag, array()) . self::NL; - - if ($counter) $output .= ' ' . $separator . ' '; - if (!empty($url)) $output .= CHtml::link($label, $url); - else $output .= CHtml::tag('span', array(), $label) . self::NL; - - if (!empty($linkWrapperTag)) $output .= CHtml::closeTag($linkWrapperTag) . self::NL; - - $counter++; - } - - if (!empty($wrapperTag)) $output .= CHtml::closeTag($wrapperTag) . self::NL; - } - - if ($return) return $output; - else echo $output; - } - + + const NL = "\n"; + + /** + * Draws breadcrumbs + * + * @param array $params + * + * Usage: + * CWidget::create('CBreadCrumbs', [ + * 'links' => array( + * ['label'=>'Label A', 'url'=>'url1/'], + * ['label'=>'Label B', 'url'=>'url2/'], + * ), + * 'wrapperClass' => '', + * 'wrapperTag' => '', + * 'linkWrapperTag' => '', + * 'separator' => ' / ', + * 'return' => true + * ]); + */ + public static function init($params = []) + { + parent::init($params); + + $output = ''; + $wrapperTag = self::params('wrapperTag', 'div'); + $links = self::params('links', ''); + $linkWrapperTag = self::params('linkWrapperTag', ''); + $separator = self::params('separator', '»'); + $return = (bool)self::params('return', true); + $wrapperClass = self::params('wrapperClass', 'breadcrumbs'); + $htmlOptions = ['class' => $wrapperClass]; + + if (is_array($links)) { + if ( ! empty($wrapperTag)) { + $output .= CHtml::openTag($wrapperTag, $htmlOptions).self::NL; + } + $counter = 0; + foreach ($params['links'] as $item => $val) { + $url = self::keyAt('url', $val, ''); + $label = self::keyAt('label', $val, ''); + + if ( ! empty($linkWrapperTag)) { + $output .= CHtml::openTag($linkWrapperTag, []).self::NL; + } + + if ($counter) { + $output .= ' '.$separator.' '; + } + if ( ! empty($url)) { + $output .= CHtml::link($label, $url); + } else { + $output .= CHtml::tag('span', [], $label).self::NL; + } + + if ( ! empty($linkWrapperTag)) { + $output .= CHtml::closeTag($linkWrapperTag).self::NL; + } + + $counter++; + } + + if ( ! empty($wrapperTag)) { + $output .= CHtml::closeTag($wrapperTag).self::NL; + } + } + + if ($return) { + return $output; + } else { + echo $output; + } + } + } \ No newline at end of file diff --git a/framework/helpers/widgets/CLanguageSelector.php b/framework/helpers/widgets/CLanguageSelector.php index 8f7fc48..0bbe429 100644 --- a/framework/helpers/widgets/CLanguageSelector.php +++ b/framework/helpers/widgets/CLanguageSelector.php @@ -16,108 +16,119 @@ class CLanguageSelector extends CWidgs { - - /** - * @const string new line - */ - const NL = "\n"; - - - /** - * Draws language selector - * @param array $params - * - * Usage: - * echo CWidget::create('CLanguageSelector', array( - * 'languages' => array('en'=>array('name'=>'English', 'icon'=>''), 'es'=>array('name'=>'Espanol', 'icon'=>''), 'fr'=>array('name'=>'Francias', 'icon'=>'')), - * 'display' => 'names|keys|icons|dropdown|list', - * 'imagesPath' => 'images/langs/', - * 'forceDrawing' => false, - * 'currentLanguage' => A::app()->getLanguage(), - * 'return' => true - * )); - */ - public static function init($params = array()) - { - parent::init($params); - - $output = ''; - $tagName = 'div'; - $languages = self::params('languages', array()); - $display = self::params('display', 'names'); - $imagesPath = self::params('imagesPath', ''); - $currentLang = self::params('currentLanguage', ''); - $forceDrawing = self::params('forceDrawing', false); - $class = self::params('class', ''); - $return = (bool)self::params('return', true); - - $totalLangs = count($languages); - if ($totalLangs == 1 && !$forceDrawing) { - return ''; - } elseif ($totalLangs < 6 && in_array($display, array('names', 'keys', 'icons'))) { - // Render options - $totalLanguages = count($languages); - $count = 0; - foreach ($languages as $key => $lang) { - $langName = isset($lang['name']) ? $lang['name'] : ''; - $langIcon = (isset($lang['icon']) && !empty($lang['icon']) && file_exists($imagesPath . $lang['icon'])) ? $lang['icon'] : 'no_image.png'; - - if ($display == 'names') { - $displayValue = $langName; - } elseif ($display == 'icons') { - $displayValue = '' . $langName . ''; - } elseif ($display == 'keys') { - $displayValue = strtoupper($key); - } else { - $displayValue = $key; - } - - if ($key == $currentLang) { - $output .= CHtml::tag('span', array('class' => 'current', 'title' => $langName), $displayValue) . self::NL; - } else { - $output .= CHtml::link($displayValue, 'languages/change/lang/' . $key, array('title' => $langName)) . self::NL; - } - if (++$count < $totalLanguages) { - $output .= ($display == 'icons') ? ' ' : ' | '; - } - } - - $output = trim($output, ' | '); - } elseif ($display == 'list') { - $output .= CHtml::openTag('ul', array('class' => $class)) . self::NL; - foreach ($languages as $key => $lang) { - $langName = isset($lang['name']) ? $lang['name'] : ''; - $langIcon = (isset($lang['icon']) && !empty($lang['icon']) && file_exists($imagesPath . $lang['icon'])) ? $lang['icon'] : 'no_image.png'; - - $output .= '' . CHtml::link('' . $langName . '    ' . $langName, 'languages/change/lang/' . $key, array('title' => $langName)) . '' . self::NL; - } - $output .= CHtml::closeTag('ul') . self::NL; - } else { - // Render options as dropdown list - $output .= CHtml::openForm('languages/change/', 'get', array('name' => 'frmLangSelector')) . self::NL; - $arrLanguages = array(); - foreach ($languages as $key => $val) { - $arrLanguages[$key] = $val['name']; - } - $output .= CHtml::dropDownList( - 'lang', - $currentLang, - $arrLanguages, - array( - 'id' => 'selLanguages', - 'submit' => '', - 'class' => $class, - ) - ); - $output .= CHtml::closeForm() . self::NL; - } - - //$final_output = CHtml::openTag($tagName, array('id'=>'language-selector')); - //$final_output .= $output; - //$final_output .= CHtml::closeTag($tagName).self::NL; - - if ($return) return $output; - else echo $output; - } - + + /** + * @const string new line + */ + const NL = "\n"; + + + /** + * Draws language selector + * + * @param array $params + * + * Usage: + * echo CWidget::create('CLanguageSelector', [ + * 'languages' => ['en'=>['name'=>'English', 'icon'=>''], 'es'=>['name'=>'Espanol', 'icon'=>''], 'fr'=>['name'=>'Francias', 'icon'=>'']], + * 'display' => 'names|keys|icons|dropdown|list', + * 'imagesPath' => 'images/langs/', + * 'forceDrawing' => false, + * 'currentLanguage' => A::app()->getLanguage(), + * 'return' => true + * ]); + */ + public static function init($params = []) + { + parent::init($params); + + $output = ''; + $tagName = 'div'; + $languages = self::params('languages', []); + $display = self::params('display', 'names'); + $imagesPath = self::params('imagesPath', ''); + $currentLang = self::params('currentLanguage', ''); + $forceDrawing = self::params('forceDrawing', false); + $class = self::params('class', ''); + $return = (bool)self::params('return', true); + + $totalLangs = count($languages); + if ($totalLangs == 1 && ! $forceDrawing) { + return ''; + } elseif ($totalLangs < 6 && in_array($display, ['names', 'keys', 'icons'])) { + // Render options + $totalLanguages = count($languages); + $count = 0; + foreach ($languages as $key => $lang) { + $langName = isset($lang['name']) ? $lang['name'] : ''; + $langIcon = (isset($lang['icon']) && ! empty($lang['icon']) && file_exists($imagesPath.$lang['icon'])) + ? $lang['icon'] : 'no_image.png'; + + if ($display == 'names') { + $displayValue = $langName; + } elseif ($display == 'icons') { + $displayValue = ''.$langName.''; + } elseif ($display == 'keys') { + $displayValue = strtoupper($key); + } else { + $displayValue = $key; + } + + if ($key == $currentLang) { + $output .= CHtml::tag('span', ['class' => 'current', 'title' => $langName], $displayValue).self::NL; + } else { + $output .= CHtml::link($displayValue, 'languages/change/lang/'.$key, ['title' => $langName]) + .self::NL; + } + if (++$count < $totalLanguages) { + $output .= ($display == 'icons') ? ' ' : ' | '; + } + } + + $output = trim($output, ' | '); + } elseif ($display == 'list') { + $output .= CHtml::openTag('ul', ['class' => $class]).self::NL; + foreach ($languages as $key => $lang) { + $langName = isset($lang['name']) ? $lang['name'] : ''; + $langIcon = (isset($lang['icon']) && ! empty($lang['icon']) && file_exists($imagesPath.$lang['icon'])) + ? $lang['icon'] : 'no_image.png'; + + $output .= ''.CHtml::link( + ''.$langName.'    '.$langName, + 'languages/change/lang/'.$key, + ['title' => $langName] + ).''.self::NL; + } + $output .= CHtml::closeTag('ul').self::NL; + } else { + // Render options as dropdown list + $output .= CHtml::openForm('languages/change/', 'get', ['name' => 'frmLangSelector']).self::NL; + $arrLanguages = []; + foreach ($languages as $key => $val) { + $arrLanguages[$key] = $val['name']; + } + $output .= CHtml::dropDownList( + 'lang', + $currentLang, + $arrLanguages, + [ + 'id' => 'selLanguages', + 'submit' => '', + 'class' => $class, + ] + ); + $output .= CHtml::closeForm().self::NL; + } + + //$final_output = CHtml::openTag($tagName, ['id'=>'language-selector']); + //$final_output .= $output; + //$final_output .= CHtml::closeTag($tagName).self::NL; + + if ($return) { + return $output; + } else { + echo $output; + } + } + } \ No newline at end of file diff --git a/framework/helpers/widgets/CPagination.php b/framework/helpers/widgets/CPagination.php index 1bcf12e..ba6e583 100644 --- a/framework/helpers/widgets/CPagination.php +++ b/framework/helpers/widgets/CPagination.php @@ -16,183 +16,239 @@ class CPagination extends CWidgs { - - /** - * @const string new line - */ + + /** + * @const string new line + */ const NL = "\n"; - + /** * Draws pagination - * @param array $params + * + * @param array $params * * Usage: (in View file) - * echo CWidget::create('CPagination', array( - * 'actionPath' => $actionPath, - * 'currentPage' => $currentPage, - * 'pageSize' => $pageSize, - * 'totalRecords' => $totalRecords, - * 'linkType' => 0, - * 'paginationType' => 'prevNext|olderNewer|fullNumbers|justNumbers' - * 'linkNames' => array('previous'=>'', 'next'=>''), - * 'showEmptyLinks' => true, - * 'showResultsOfTotal' => true, - * 'htmlOptions' => array('linksWrapperTag' => 'div', 'linksWrapperClass' => 'links-part') + * echo CWidget::create('CPagination', [ + * 'actionPath' => $actionPath, + * 'currentPage' => $currentPage, + * 'pageSize' => $pageSize, + * 'totalRecords' => $totalRecords, + * 'linkType' => 0, + * 'paginationType' => 'prevNext|olderNewer|fullNumbers|justNumbers' + * 'linkNames' => ['previous'=>'', 'next'=>''], + * 'showEmptyLinks' => true, + * 'showResultsOfTotal'=> true, + * 'htmlOptions' => ['linksWrapperTag' => 'div', 'linksWrapperClass' => 'links-part'] * 'return' => true - * )); + * ]); + * + * @return string */ - public static function init($params = array()) - { - parent::init($params); - - // How many adjacent pages should be shown on each side? - $adjacents = 4; - $actionPath = self::params('actionPath', ''); - $paramsSign = preg_match('/\?/', $actionPath) ? '&' : '?'; - $page = (int)self::params('currentPage', 1); - $pageSize = (int)self::params('pageSize', 1); - $totalRecords = (int)self::params('totalRecords', 0); - // Link type: 0 - standard, 1 - SEO - $linkType = (int)self::params('linkType', 1); - // justNumbers - 1 2 3 - // fullNumbers - previous 1 2 3 next - // olderNewer - newer older - // prevNext - previous next - $paginationType = self::params('paginationType'); - $paginationType = (in_array(strtolower($paginationType), array('prevnext', 'oldernewer', 'fullnumbers', 'justnumbers'))) ? strtolower($paginationType) : 'fullnumbers'; - $showEmptyLinks = (bool)self::params('showEmptyLinks', true); - $showResultsOfTotal = (bool)self::params('showResultsOfTotal', true); - $linkNames = self::params('linkNames', array()); - - $linksWrapperTag = self::params('htmlOptions.linksWrapperTag', 'div'); - $linksWrapperClass = self::params('htmlOptions.linksWrapperClass', 'links-part'); - - $return = (bool)self::params('return', true); - - if ($page) { - $start = ($page - 1) * $pageSize; /* first item to display on this page */ - } else { - $start = 0; /* if no page var is given, set start to 0 */ - } - - // Setup page vars for display - if ($page == 0) $page = 1; /* if no page var is given, default to 1. */ - $prev = $page - 1; /* previous page is page - 1 */ - $next = $page + 1; /* next page is page + 1 */ - $lastpage = !empty($pageSize) ? ceil($totalRecords / $pageSize) : 1; /* lastpage is = total pages / items per page, rounded up. */ - $lpm1 = $lastpage - 1; /* last page minus 1 */ - $output = ''; - $middlePart = ''; - $counter = 0; - - $wPrevious = ($paginationType == 'oldernewer') ? A::t('core', 'newer') : A::t('core', 'previous'); - $wNext = ($paginationType == 'oldernewer') ? A::t('core', 'older') : A::t('core', 'next'); - if (isset($linkNames['previous'])) { - $wPrevious = $linkNames['previous']; - } - if (isset($linkNames['next'])) { - $wNext = $linkNames['next']; - } - - if ($lastpage > 0) { - $output .= CHtml::openTag('div', array('class' => 'pagination-wrapper')) . self::NL; - - if ($showResultsOfTotal) { - $output .= CHtml::openTag('div', array('class' => 'results-part')); - $numFrom = ($start + 1); - $numTo = (($totalRecords > ($start + $pageSize)) ? ($start + $pageSize) : $totalRecords); - $output .= CHtml::tag('span', array(), A::t('core', 'Results: {from} - {to} of {total}', array('{from}' => $numFrom, '{to}' => $numTo, '{total}' => $totalRecords))); - $output .= CHtml::closeTag('div') . self::NL; - } - - if ($lastpage > 1) { - $output .= CHtml::openTag($linksWrapperTag, array('class' => $linksWrapperClass)); - // Draw previous button - if (in_array($paginationType, array('fullnumbers', 'prevnext', 'oldernewer'))) { - if ($page > 1) { - $output .= CHtml::link('« ' . $wPrevious, $actionPath . (($linkType) ? '/page/' . $prev : $paramsSign . 'page=' . $prev), array('class' => 'first-link')); - } else { - if ($showEmptyLinks) $output .= CHtml::tag('span', array('class' => 'disabled'), '« ' . $wPrevious); - } - } - - // Pages - if ($lastpage < 7 + ($adjacents * 2)) { - // Not enough pages to bother breaking it up - for ($counter = 1; $counter <= $lastpage; $counter++) { - if ($counter == $page) { - $middlePart .= CHtml::tag('span', array('class' => 'current'), $counter); - } else { - $middlePart .= CHtml::link($counter, $actionPath . (($linkType) ? '/page/' . $counter : $paramsSign . 'page=' . $counter)); - } - } - // Enough pages to hide some - } elseif ($lastpage > 5 + ($adjacents * 2)) { - // Close to beginning, only hide later pages - if ($page < 1 + ($adjacents * 2)) { - for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++) { - if ($counter == $page) { - $middlePart .= CHtml::tag('span', array('class' => 'current'), $counter); - } else { - $middlePart .= CHtml::link($counter, $actionPath . (($linkType) ? '/page/' . $counter : $paramsSign . 'page=' . $counter)); - } - } - $middlePart .= '...'; - $middlePart .= CHtml::link($lpm1, $actionPath . (($linkType) ? '/page/' . $lpm1 : $paramsSign . 'page=' . $lpm1)); - $middlePart .= CHtml::link($lastpage, $actionPath . (($linkType) ? '/page/' . $lastpage : $paramsSign . 'page=' . $lastpage)); - } // In middle, hide some front and some back - elseif ($lastpage - ($adjacents * 2) > $page && $page > ($adjacents * 2)) { - $middlePart .= CHtml::link('1', $actionPath . (($linkType) ? '/page/1' : $paramsSign . 'page=1')); - $middlePart .= CHtml::link('2', $actionPath . (($linkType) ? '/page/2' : $paramsSign . 'page=2')); - $middlePart .= '...'; - for ($counter = $page - $adjacents; $counter <= $page + $adjacents; $counter++) { - if ($counter == $page) { - $middlePart .= CHtml::tag('span', array('class' => 'current'), $counter); - } else { - $middlePart .= CHtml::link($counter, $actionPath . (($linkType) ? '/page/' . $counter : $paramsSign . 'page=' . $counter)); - } - } - $middlePart .= '...'; - $middlePart .= CHtml::link($lpm1, $actionPath . (($linkType) ? '/page/' . $lpm1 : $paramsSign . 'page=' . $lpm1)); - $middlePart .= CHtml::link($lastpage, $actionPath . (($linkType) ? '/page/' . $lastpage : $paramsSign . 'page=' . $lastpage)); - } // Close to end, just hide early pages - else { - $middlePart .= CHtml::link('1', $actionPath . (($linkType) ? '/page/1' : $paramsSign . 'page=1')); - $middlePart .= CHtml::link('2', $actionPath . (($linkType) ? '/page/2' : $paramsSign . 'page=2')); - $middlePart .= '...'; - for ($counter = $lastpage - (2 + ($adjacents * 2)); $counter <= $lastpage; $counter++) { - if ($counter == $page) { - $middlePart .= CHtml::tag('span', array('class' => 'current'), $counter); - } else { - $middlePart .= CHtml::link($counter, $actionPath . (($linkType) ? '/page/' . $counter : $paramsSign . 'page=' . $counter)); - } - } - } - } - - // Draw middle part - if ($paginationType == 'fullnumbers' || $paginationType == 'justnumbers') { - $output .= $middlePart; - } - - // Draw next button - if (in_array($paginationType, array('fullnumbers', 'prevnext', 'oldernewer'))) { - if ($page < $counter - 1) { - $output .= CHtml::link($wNext . ' »', $actionPath . (($linkType) ? '/page/' . $next : $paramsSign . 'page=' . $next), array('class' => 'last-link')); - } else { - if ($showEmptyLinks) $output .= CHtml::tag('span', array('class' => 'disabled'), $wNext . ' »'); - } - } - - $output .= CHtml::closeTag($linksWrapperTag) . self::NL; - } - - $output .= CHtml::closeTag('div') . self::NL; - } - - if ($return) return $output; - else echo $output; - } - + public static function init($params = []) + { + parent::init($params); + + // How many adjacent pages should be shown on each side? + $adjacents = 4; + $actionPath = self::params('actionPath', ''); + $paramsSign = preg_match('/\?/', $actionPath) ? '&' : '?'; + $page = (int)self::params('currentPage', 1); + $pageSize = (int)self::params('pageSize', 1); + $totalRecords = (int)self::params('totalRecords', 0); + // Link type: 0 - standard, 1 - SEO + $linkType = (int)self::params('linkType', 1); + // justNumbers - 1 2 3 + // fullNumbers - previous 1 2 3 next + // olderNewer - newer older + // prevNext - previous next + $paginationType = self::params('paginationType'); + $paginationType = (in_array( + strtolower($paginationType), + ['prevnext', 'oldernewer', 'fullnumbers', 'justnumbers'] + )) ? strtolower($paginationType) : 'fullnumbers'; + $showEmptyLinks = (bool)self::params('showEmptyLinks', true); + $showResultsOfTotal = (bool)self::params('showResultsOfTotal', true); + $linkNames = self::params('linkNames', []); + + $linksWrapperTag = self::params('htmlOptions.linksWrapperTag', 'div'); + $linksWrapperClass = self::params('htmlOptions.linksWrapperClass', 'links-part'); + + $return = (bool)self::params('return', true); + + if ($page) { + $start = ($page - 1) * $pageSize; /* first item to display on this page */ + } else { + $start = 0; /* if no page var is given, set start to 0 */ + } + + // Setup page vars for display + if ($page == 0) { + $page = 1; + } /* if no page var is given, default to 1. */ + $prev = $page - 1; /* previous page is page - 1 */ + $next = $page + 1; /* next page is page + 1 */ + $lastpage = ! empty($pageSize) ? ceil($totalRecords / $pageSize) + : 1; /* lastpage is = total pages / items per page, rounded up. */ + $lpm1 = $lastpage - 1; /* last page minus 1 */ + $output = ''; + $middlePart = ''; + $counter = 0; + + $wPrevious = ($paginationType == 'oldernewer') ? A::t('core', 'newer') : A::t('core', 'previous'); + $wNext = ($paginationType == 'oldernewer') ? A::t('core', 'older') : A::t('core', 'next'); + if (isset($linkNames['previous'])) { + $wPrevious = $linkNames['previous']; + } + if (isset($linkNames['next'])) { + $wNext = $linkNames['next']; + } + + if ($lastpage > 0) { + $output .= CHtml::openTag('div', ['class' => 'pagination-wrapper']).self::NL; + + if ($showResultsOfTotal) { + $output .= CHtml::openTag('div', ['class' => 'results-part']); + $numFrom = ($start + 1); + $numTo = (($totalRecords > ($start + $pageSize)) ? ($start + $pageSize) : $totalRecords); + $output .= CHtml::tag( + 'span', + [], + A::t( + 'core', + 'Results: {from} - {to} of {total}', + ['{from}' => $numFrom, '{to}' => $numTo, '{total}' => $totalRecords] + ) + ); + $output .= CHtml::closeTag('div').self::NL; + } + + if ($lastpage > 1) { + $output .= CHtml::openTag($linksWrapperTag, ['class' => $linksWrapperClass]); + // Draw previous button + if (in_array($paginationType, ['fullnumbers', 'prevnext', 'oldernewer'])) { + if ($page > 1) { + $output .= CHtml::link( + '« '.$wPrevious, + $actionPath.(($linkType) ? '/page/'.$prev : $paramsSign.'page='.$prev), + ['class' => 'first-link'] + ); + } else { + if ($showEmptyLinks) { + $output .= CHtml::tag('span', ['class' => 'disabled'], '« '.$wPrevious); + } + } + } + + // Pages + if ($lastpage < 7 + ($adjacents * 2)) { + // Not enough pages to bother breaking it up + for ($counter = 1; $counter <= $lastpage; $counter++) { + if ($counter == $page) { + $middlePart .= CHtml::tag('span', ['class' => 'current'], $counter); + } else { + $middlePart .= CHtml::link( + $counter, + $actionPath.(($linkType) ? '/page/'.$counter : $paramsSign.'page='.$counter) + ); + } + } + // Enough pages to hide some + } elseif ($lastpage > 5 + ($adjacents * 2)) { + // Close to beginning, only hide later pages + if ($page < 1 + ($adjacents * 2)) { + for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++) { + if ($counter == $page) { + $middlePart .= CHtml::tag('span', ['class' => 'current'], $counter); + } else { + $middlePart .= CHtml::link( + $counter, + $actionPath.(($linkType) ? '/page/'.$counter : $paramsSign.'page='.$counter) + ); + } + } + $middlePart .= '...'; + $middlePart .= CHtml::link( + $lpm1, + $actionPath.(($linkType) ? '/page/'.$lpm1 : $paramsSign.'page='.$lpm1) + ); + $middlePart .= CHtml::link( + $lastpage, + $actionPath.(($linkType) ? '/page/'.$lastpage : $paramsSign.'page='.$lastpage) + ); + } // In middle, hide some front and some back + elseif ($lastpage - ($adjacents * 2) > $page && $page > ($adjacents * 2)) { + $middlePart .= CHtml::link('1', $actionPath.(($linkType) ? '/page/1' : $paramsSign.'page=1')); + $middlePart .= CHtml::link('2', $actionPath.(($linkType) ? '/page/2' : $paramsSign.'page=2')); + $middlePart .= '...'; + for ($counter = $page - $adjacents; $counter <= $page + $adjacents; $counter++) { + if ($counter == $page) { + $middlePart .= CHtml::tag('span', ['class' => 'current'], $counter); + } else { + $middlePart .= CHtml::link( + $counter, + $actionPath.(($linkType) ? '/page/'.$counter : $paramsSign.'page='.$counter) + ); + } + } + $middlePart .= '...'; + $middlePart .= CHtml::link( + $lpm1, + $actionPath.(($linkType) ? '/page/'.$lpm1 : $paramsSign.'page='.$lpm1) + ); + $middlePart .= CHtml::link( + $lastpage, + $actionPath.(($linkType) ? '/page/'.$lastpage : $paramsSign.'page='.$lastpage) + ); + } // Close to end, just hide early pages + else { + $middlePart .= CHtml::link('1', $actionPath.(($linkType) ? '/page/1' : $paramsSign.'page=1')); + $middlePart .= CHtml::link('2', $actionPath.(($linkType) ? '/page/2' : $paramsSign.'page=2')); + $middlePart .= '...'; + for ($counter = $lastpage - (2 + ($adjacents * 2)); $counter <= $lastpage; $counter++) { + if ($counter == $page) { + $middlePart .= CHtml::tag('span', ['class' => 'current'], $counter); + } else { + $middlePart .= CHtml::link( + $counter, + $actionPath.(($linkType) ? '/page/'.$counter : $paramsSign.'page='.$counter) + ); + } + } + } + } + + // Draw middle part + if ($paginationType == 'fullnumbers' || $paginationType == 'justnumbers') { + $output .= $middlePart; + } + + // Draw next button + if (in_array($paginationType, ['fullnumbers', 'prevnext', 'oldernewer'])) { + if ($page < $counter - 1) { + $output .= CHtml::link( + $wNext.' »', + $actionPath.(($linkType) ? '/page/'.$next : $paramsSign.'page='.$next), + ['class' => 'last-link'] + ); + } else { + if ($showEmptyLinks) { + $output .= CHtml::tag('span', ['class' => 'disabled'], $wNext.' »'); + } + } + } + + $output .= CHtml::closeTag($linksWrapperTag).self::NL; + } + + $output .= CHtml::closeTag('div').self::NL; + } + + if ($return) { + return $output; + } else { + echo $output; + } + } + } diff --git a/framework/helpers/widgets/CTabs.php b/framework/helpers/widgets/CTabs.php index e7e3641..4f1d3ea 100644 --- a/framework/helpers/widgets/CTabs.php +++ b/framework/helpers/widgets/CTabs.php @@ -45,128 +45,146 @@ class CTabs extends CWidgs * * * - * echo CWidget::create('CTabs', array( - * 'tabsWrapper'=>array('tag'=>'div', 'class'=>'title', 'id'=>''), - * 'tabsWrapperInner'=>array('tag'=>'div', 'class'=>'tabs', 'id'=>''), -- optional - - * 'tabsWrapperInnerItem'=>array('tag'=>'a', 'class'=>'', 'id'=>''), -- optional - - * 'contentWrapper'=>array('tag'=>'div', 'class'=>'content', 'id'=>''), - * 'contentWrapperItem'=>array('tag'=>'div', 'class'=>'', 'id'=>''), + * echo CWidget::create('CTabs', [ + * 'tabsWrapper'=>['tag'=>'div', 'class'=>'title', 'id'=>''], + * 'tabsWrapperInner'=>['tag'=>'div', 'class'=>'tabs', 'id'=>''], -- optional - + * 'tabsWrapperInnerItem'=>['tag'=>'a', 'class'=>'', 'id'=>''], -- optional - + * 'contentWrapper'=>['tag'=>'div', 'class'=>'content', 'id'=>''], + * 'contentWrapperItem'=>['tag'=>'div', 'class'=>'', 'id'=>''], * 'contentMessage'=>$actionMessage, * 'contentAdditional'=>'', * 'firstTabActive'=>true, - * 'tabs'=>array( - * 'General Settings' =>array('href'=>'#tab1', 'id'=>'tab1', 'content'=>$tab1, 'active'=>true, 'htmlOptions'=>array()), - * 'Visual Settings' =>array('href'=>'#tab2', 'id'=>'tab2', 'content'=>'Content for tab 2', 'htmlOptions'=>array()), - * 'Local Settings' =>array('href'=>'#tab3', 'id'=>'tab3', 'content'=>'Content for tab 3', 'htmlOptions'=>array()), - * 'Email Settings' =>array('href'=>'#tab4', 'id'=>'tab4', 'content'=>'Content for tab 4', 'htmlOptions'=>array()), - * 'Templates & Styles' =>array('href'=>'#tab5', 'id'=>'tab5', 'content'=>'Content for tab 5', 'htmlOptions'=>array()), - * 'Server Info' =>array('href'=>'#tab6', 'id'=>'tab6', 'content'=>'Content for tab 6', 'htmlOptions'=>array()), - * 'Site Info' =>array('href'=>'#tab7', 'id'=>'tab7', 'content'=>'Content for tab 7', 'htmlOptions'=>array()), - * 'Cron Jobs' =>array('href'=>'#tab8', 'id'=>'tab8', 'content'=>'Content for tab 8', 'htmlOptions'=>array()), - * ), + * 'tabs'=>[ + * 'General Settings' =>['href'=>'#tab1', 'id'=>'tab1', 'content'=>$tab1, 'active'=>true, 'htmlOptions'=>[]], + * 'Visual Settings' =>['href'=>'#tab2', 'id'=>'tab2', 'content'=>'Content for tab 2', 'htmlOptions'=>[]], + * 'Local Settings' =>['href'=>'#tab3', 'id'=>'tab3', 'content'=>'Content for tab 3', 'htmlOptions'=>[]], + * 'Email Settings' =>['href'=>'#tab4', 'id'=>'tab4', 'content'=>'Content for tab 4', 'htmlOptions'=>[]], + * 'Templates & Styles' =>['href'=>'#tab5', 'id'=>'tab5', 'content'=>'Content for tab 5', 'htmlOptions'=>[]], + * 'Server Info' =>['href'=>'#tab6', 'id'=>'tab6', 'content'=>'Content for tab 6', 'htmlOptions'=>[]], + * 'Site Info' =>['href'=>'#tab7', 'id'=>'tab7', 'content'=>'Content for tab 7', 'htmlOptions'=>[]], + * 'Cron Jobs' =>['href'=>'#tab8', 'id'=>'tab8', 'content'=>'Content for tab 8', 'htmlOptions'=>[]], + * ], * 'events'=>array( - * //'click'=>array('field'=>$errorField) + * //'click'=>['field'=>$errorField] * ), * 'return'=>true, - * )); + * ]); */ - public static function init($params = array()) - { - parent::init($params); - - // Get param variables - $tabs = self::params('tabs', array()); - $tabsWrapper = self::params('tabsWrapper', array()); - $tabsWrapperInner = self::params('tabsWrapperInner', array()); - $tabsWrapperInnerItem = self::params('tabsWrapperInnerItem', array()); - $contentWrapper = self::params('contentWrapper', array()); - $contentWrapperItem = self::params('contentWrapperItem', array()); - $contentMessage = self::params('contentMessage', ''); - $contentAdditional = self::params('contentAdditional', ''); - $firstTabActive = self::params('firstTabActive', false); - $return = self::params('return', true); - - $output = ''; - $tagName = 'div'; - - $output .= CHtml::openTag($tabsWrapper['tag'], array('class' => $tabsWrapper['class'])) . self::NL; - if (!empty($tabsWrapperInner)) { - $twiTag = isset($tabsWrapperInner['tag']) ? $tabsWrapperInner['tag'] : 'div'; - $twiClass = isset($tabsWrapperInner['class']) ? $tabsWrapperInner['class'] : ''; - $twiId = isset($tabsWrapperInner['id']) ? $tabsWrapperInner['id'] : ''; - $output .= CHtml::openTag($twiTag, array('class' => $twiClass, 'id' => $twiId)) . self::NL; - } - - // Set the first tab to be "active" if nothing defined - $activeTabExists = false; - foreach ($tabs as $tab => $tabInfo) { - if (isset($tabInfo['active']) && $tabInfo['active']) { - $activeTabExists = true; - break; - } - } - if (!$activeTabExists && $firstTabActive) { - $firstKey = key($tabs); - $tabs[$firstKey]['active'] = true; - } - - foreach ($tabs as $tab => $tabInfo) { - if (empty($tabInfo)) continue; - if (isset($tabInfo['disabled']) && (bool)$tabInfo['disabled'] === true) continue; - - $htmlOptions = (isset($tabInfo['htmlOptions']) && is_array($tabInfo['htmlOptions'])) ? $tabInfo['htmlOptions'] : array(); - if (isset($tabInfo['active']) && $tabInfo['active']) { - if (!isset($htmlOptions['class'])) $htmlOptions['class'] = 'active'; - else $htmlOptions['class'] .= ' active'; - } - if (isset($tabInfo['id'])) $htmlOptions['id'] = $tabInfo['id'] . '_link'; - $href = isset($tabInfo['href']) ? $tabInfo['href'] : ''; - - if (!empty($tabsWrapperInnerItem)) { - $htmlOptions['role'] = 'tab'; - $htmlOptions['data-toggle'] = 'tab'; - $htmlOptions['aria-controls'] = trim($href, '#'); - $cssClass = ''; - if (isset($htmlOptions['class'])) { - $cssClass = $htmlOptions['class']; - unset($htmlOptions['class']); - } - - $twiiTag = isset($tabsWrapperInnerItem['tag']) ? $tabsWrapperInnerItem['tag'] : 'a'; - $output .= CHtml::openTag($twiiTag, array('class' => $cssClass, 'id' => false)); - $output .= CHtml::link($tab, $href, $htmlOptions); - $output .= CHtml::closeTag($twiiTag) . self::NL; - } else { - $output .= CHtml::link($tab, $href, $htmlOptions) . self::NL; - } - } - if (!empty($tabsWrapperInner)) $output .= CHtml::closeTag($tabsWrapperInner['tag']) . self::NL; - $output .= $contentAdditional; - $output .= CHtml::closeTag($tabsWrapper['tag']) . self::NL; - - $output .= $contentMessage; - - // Show content only if contentWrapper defined as non-empty - if (!empty($contentWrapper)) { - $output .= CHtml::openTag($contentWrapper['tag'], array('class' => $contentWrapper['class'])) . self::NL; - foreach ($tabs as $tab => $tabInfo) { - $id = isset($tabInfo['id']) ? $tabInfo['id'] : ''; - $content = isset($tabInfo['content']) ? $tabInfo['content'] : ''; - $style = isset($contentWrapperItem['style']) ? $contentWrapperItem['style'] : 'display:block;'; - $class = isset($contentWrapperItem['class']) ? $contentWrapperItem['class'] : ''; - - if (isset($tabInfo['active']) && $tabInfo['active']) { - if (empty($class)) $class = 'active in'; - else $class .= ' active in'; - } - - $output .= CHtml::tag('div', array('id' => $id, 'class' => $class, 'style' => $style), $content) . self::NL; - } - $output .= CHtml::closeTag($contentWrapper['tag']) . self::NL; - } - - if ($return) return $output; - else echo $output; - } - + public static function init($params = []) + { + parent::init($params); + + // Get param variables + $tabs = self::params('tabs', []); + $tabsWrapper = self::params('tabsWrapper', []); + $tabsWrapperInner = self::params('tabsWrapperInner', []); + $tabsWrapperInnerItem = self::params('tabsWrapperInnerItem', []); + $contentWrapper = self::params('contentWrapper', []); + $contentWrapperItem = self::params('contentWrapperItem', []); + $contentMessage = self::params('contentMessage', ''); + $contentAdditional = self::params('contentAdditional', ''); + $firstTabActive = self::params('firstTabActive', false); + $return = self::params('return', true); + + $output = ''; + $tagName = 'div'; + + $output .= CHtml::openTag($tabsWrapper['tag'], ['class' => $tabsWrapper['class']]).self::NL; + if ( ! empty($tabsWrapperInner)) { + $twiTag = isset($tabsWrapperInner['tag']) ? $tabsWrapperInner['tag'] : 'div'; + $twiClass = isset($tabsWrapperInner['class']) ? $tabsWrapperInner['class'] : ''; + $twiId = isset($tabsWrapperInner['id']) ? $tabsWrapperInner['id'] : ''; + $output .= CHtml::openTag($twiTag, ['class' => $twiClass, 'id' => $twiId]).self::NL; + } + + // Set the first tab to be "active" if nothing defined + $activeTabExists = false; + foreach ($tabs as $tab => $tabInfo) { + if (isset($tabInfo['active']) && $tabInfo['active']) { + $activeTabExists = true; + break; + } + } + if ( ! $activeTabExists && $firstTabActive) { + $firstKey = key($tabs); + $tabs[$firstKey]['active'] = true; + } + + foreach ($tabs as $tab => $tabInfo) { + if (empty($tabInfo)) { + continue; + } + if (isset($tabInfo['disabled']) && (bool)$tabInfo['disabled'] === true) { + continue; + } + + $htmlOptions = (isset($tabInfo['htmlOptions']) && is_array($tabInfo['htmlOptions'])) + ? $tabInfo['htmlOptions'] : []; + if (isset($tabInfo['active']) && $tabInfo['active']) { + if ( ! isset($htmlOptions['class'])) { + $htmlOptions['class'] = 'active'; + } else { + $htmlOptions['class'] .= ' active'; + } + } + if (isset($tabInfo['id'])) { + $htmlOptions['id'] = $tabInfo['id'].'_link'; + } + $href = isset($tabInfo['href']) ? $tabInfo['href'] : ''; + + if ( ! empty($tabsWrapperInnerItem)) { + $htmlOptions['role'] = 'tab'; + $htmlOptions['data-toggle'] = 'tab'; + $htmlOptions['aria-controls'] = trim($href, '#'); + $cssClass = ''; + if (isset($htmlOptions['class'])) { + $cssClass = $htmlOptions['class']; + unset($htmlOptions['class']); + } + + $twiiTag = isset($tabsWrapperInnerItem['tag']) ? $tabsWrapperInnerItem['tag'] : 'a'; + $output .= CHtml::openTag($twiiTag, ['class' => $cssClass, 'id' => false]); + $output .= CHtml::link($tab, $href, $htmlOptions); + $output .= CHtml::closeTag($twiiTag).self::NL; + } else { + $output .= CHtml::link($tab, $href, $htmlOptions).self::NL; + } + } + if ( ! empty($tabsWrapperInner)) { + $output .= CHtml::closeTag($tabsWrapperInner['tag']).self::NL; + } + $output .= $contentAdditional; + $output .= CHtml::closeTag($tabsWrapper['tag']).self::NL; + + $output .= $contentMessage; + + // Show content only if contentWrapper defined as non-empty + if ( ! empty($contentWrapper)) { + $output .= CHtml::openTag($contentWrapper['tag'], ['class' => $contentWrapper['class']]).self::NL; + foreach ($tabs as $tab => $tabInfo) { + $id = isset($tabInfo['id']) ? $tabInfo['id'] : ''; + $content = isset($tabInfo['content']) ? $tabInfo['content'] : ''; + $style = isset($contentWrapperItem['style']) ? $contentWrapperItem['style'] : 'display:block;'; + $class = isset($contentWrapperItem['class']) ? $contentWrapperItem['class'] : ''; + + if (isset($tabInfo['active']) && $tabInfo['active']) { + if (empty($class)) { + $class = 'active in'; + } else { + $class .= ' active in'; + } + } + + $output .= CHtml::tag('div', ['id' => $id, 'class' => $class, 'style' => $style], $content).self::NL; + } + $output .= CHtml::closeTag($contentWrapper['tag']).self::NL; + } + + if ($return) { + return $output; + } else { + echo $output; + } + } + } diff --git a/tests/framework/helpers/CArrayTest.php b/tests/framework/helpers/CArrayTest.php index e106d04..1c824b4 100644 --- a/tests/framework/helpers/CArrayTest.php +++ b/tests/framework/helpers/CArrayTest.php @@ -10,100 +10,100 @@ class CArrayTest extends TestCase { - protected function setUp(): void - { - parent::setUp(); - } - - /** - * Test for CArray::flipByField - */ - public function testFlipByField(): void - { - $array1 = array( - '0' => array('field1' => '11', 'field2' => '12', 'field3' => '13'), - '1' => array('field1' => '21', 'field2' => '22', 'field3' => '23'), - ); - - $array2 = array( - '11' => array('field1' => '11', 'field2' => '12', 'field3' => '13'), - '21' => array('field1' => '21', 'field2' => '22', 'field3' => '23'), - ); - - self::assertEquals(array(), CArray::flipByField($array1)); - self::assertEquals($array2, CArray::flipByField($array1, 'field1')); - } - - /** - * Test for CArray::uniqueByField - */ - public function testUniqueByField(): void - { - $arrayTest = array( - '0' => array('field1' => '11', 'field2' => '12', 'field3' => '13'), - '1' => array('field1' => '21', 'field2' => '22', 'field3' => '23'), - '2' => array('field1' => '31', 'field2' => '32', 'field3' => '33'), - ); - - $arrayResult = array( - '0' => '11', - '1' => '21', - '2' => '31', - ); - - $arrayTest2 = array( - '0' => array('field1' => '11', 'field2' => '12', 'field3' => '13'), - '1' => array('field1' => '21', 'field2' => '22', 'field3' => '23'), - '2' => array('field1' => '31', 'field2' => '32', 'field3' => '33'), - '3' => array('field1' => '11', 'field2' => '12', 'field3' => '12'), - ); - - $arrayResult2 = array( - '0' => '11', - '1' => '21', - '2' => '31', - '3' => '11', - ); - - self::assertEquals(array(), CArray::uniqueByField($arrayTest)); - self::assertEquals($arrayResult, CArray::uniqueByField($arrayTest, 'field1')); - self::assertEquals($arrayResult2, CArray::uniqueByField($arrayTest2, 'field1', false)); - self::assertEquals($arrayResult, CArray::uniqueByField($arrayTest2, 'field1', true)); - } - - /** - * Test for CArray::changeKeysCase - */ - public function testChangeKeysCase(): void - { - $arrTest = array('Key1'=>1, 'kEy2'=>2); - $arrTestLower = array('key1'=>1, 'key2'=>2); - $arrTestUpper = array('KEY1'=>1, 'KEY2'=>2); - - self::assertEquals($arrTestLower, CArray::changeKeysCase($arrTest)); - self::assertEquals($arrTestLower, CArray::changeKeysCase($arrTest, CASE_LOWER)); - self::assertEquals($arrTestUpper, CArray::changeKeysCase($arrTest, CASE_UPPER)); - } - - /** - * Test for CArray::toArray - */ - public function testTtoArray() - { - $obj = new stdClass(); - $obj->fieldA = 'A'; - $obj->fieldB = 2; - $obj->fieldC = array(1, 2, 3); - $obj->fieldD = array('1'=>1, '2'=>2, '3'=>3); - - $array = array( - 'fieldA' => 'A', - 'fieldB' => 2, - 'fieldC' => array(0 => 1, 1 => 2, 2 => 3), - 'fieldD' => array(1 => 1, 2 => 2, 3 => 3), - ); - - self::assertEquals(array(), CArray::toArray(new stdClass())); - self::assertEquals($array, CArray::toArray($obj)); - } + protected function setUp(): void + { + parent::setUp(); + } + + /** + * Test for CArray::flipByField + */ + public function testFlipByField(): void + { + $array1 = [ + '0' => ['field1' => '11', 'field2' => '12', 'field3' => '13'], + '1' => ['field1' => '21', 'field2' => '22', 'field3' => '23'], + ]; + + $array2 = [ + '11' => ['field1' => '11', 'field2' => '12', 'field3' => '13'], + '21' => ['field1' => '21', 'field2' => '22', 'field3' => '23'], + ]; + + self::assertEquals([], CArray::flipByField($array1)); + self::assertEquals($array2, CArray::flipByField($array1, 'field1')); + } + + /** + * Test for CArray::uniqueByField + */ + public function testUniqueByField(): void + { + $arrayTest = [ + '0' => ['field1' => '11', 'field2' => '12', 'field3' => '13'], + '1' => ['field1' => '21', 'field2' => '22', 'field3' => '23'], + '2' => ['field1' => '31', 'field2' => '32', 'field3' => '33'], + ]; + + $arrayResult = [ + '0' => '11', + '1' => '21', + '2' => '31', + ]; + + $arrayTest2 = [ + '0' => ['field1' => '11', 'field2' => '12', 'field3' => '13'], + '1' => ['field1' => '21', 'field2' => '22', 'field3' => '23'], + '2' => ['field1' => '31', 'field2' => '32', 'field3' => '33'], + '3' => ['field1' => '11', 'field2' => '12', 'field3' => '12'], + ]; + + $arrayResult2 = [ + '0' => '11', + '1' => '21', + '2' => '31', + '3' => '11', + ]; + + self::assertEquals([], CArray::uniqueByField($arrayTest)); + self::assertEquals($arrayResult, CArray::uniqueByField($arrayTest, 'field1')); + self::assertEquals($arrayResult2, CArray::uniqueByField($arrayTest2, 'field1', false)); + self::assertEquals($arrayResult, CArray::uniqueByField($arrayTest2, 'field1', true)); + } + + /** + * Test for CArray::changeKeysCase + */ + public function testChangeKeysCase(): void + { + $arrTest = ['Key1' => 1, 'kEy2' => 2]; + $arrTestLower = ['key1' => 1, 'key2' => 2]; + $arrTestUpper = ['KEY1' => 1, 'KEY2' => 2]; + + self::assertEquals($arrTestLower, CArray::changeKeysCase($arrTest)); + self::assertEquals($arrTestLower, CArray::changeKeysCase($arrTest, CASE_LOWER)); + self::assertEquals($arrTestUpper, CArray::changeKeysCase($arrTest, CASE_UPPER)); + } + + /** + * Test for CArray::toArray + */ + public function testTtoArray() + { + $obj = new stdClass(); + $obj->fieldA = 'A'; + $obj->fieldB = 2; + $obj->fieldC = [1, 2, 3]; + $obj->fieldD = ['1' => 1, '2' => 2, '3' => 3]; + + $array = [ + 'fieldA' => 'A', + 'fieldB' => 2, + 'fieldC' => [0 => 1, 1 => 2, 2 => 3], + 'fieldD' => [1 => 1, 2 => 2, 3 => 3], + ]; + + self::assertEquals([], CArray::toArray(new stdClass())); + self::assertEquals($array, CArray::toArray($obj)); + } } diff --git a/tests/framework/helpers/CAuthTest.php b/tests/framework/helpers/CAuthTest.php index bf8e572..fb98fe6 100644 --- a/tests/framework/helpers/CAuthTest.php +++ b/tests/framework/helpers/CAuthTest.php @@ -65,10 +65,10 @@ public function testIsLoggedInAsAdmin(): void A::app()->getSession()->set('loggedRole', 'super-admin'); self::assertEquals(false, CAuth::isLoggedInAsAdmin()); - self::assertEquals(true, CAuth::isLoggedInAsAdmin(array('super-admin'))); - } + self::assertEquals(true, CAuth::isLoggedInAsAdmin(['super-admin'])); + } - // + // //isGuest() // handleLogin // handleLoggedIn diff --git a/tests/framework/helpers/CValidatorTest.php b/tests/framework/helpers/CValidatorTest.php index dd35e0b..5730d11 100644 --- a/tests/framework/helpers/CValidatorTest.php +++ b/tests/framework/helpers/CValidatorTest.php @@ -9,41 +9,41 @@ class CValidatorTest extends TestCase { - protected function setUp(): void - { - parent::setUp(); - } - - /** - * Test for CValidator::isEmpty - */ - public function testIsEmpty(): void - { - self::assertEquals(true, CValidator::isEmpty(null)); - self::assertEquals(true, CValidator::isEmpty(array())); - self::assertEquals(true, CValidator::isEmpty('')); - self::assertEquals(true, CValidator::isEmpty(' ', true)); - - self::assertNotEquals(true, CValidator::isEmpty(0)); - self::assertNotEquals(true, CValidator::isEmpty('text')); - } - - /** - * Test for CValidator::isAlpha - */ - public function testIsAlpha(): void - { - self::assertEquals(true, CValidator::isAlpha('abcde')); - self::assertEquals(true, CValidator::isAlpha('ABCDE')); - self::assertEquals(true, CValidator::isAlpha('ABcde')); - self::assertEquals(true, CValidator::isAlpha('ABcde#', array('#'))); - self::assertEquals(true, CValidator::isAlpha('ABc de#', array(' ', '#'))); - - self::assertNotEquals(true, CValidator::isAlpha('ABcde3')); - self::assertNotEquals(true, CValidator::isAlpha('ABcde#')); - self::assertNotEquals(true, CValidator::isAlpha('ABc de')); - self::assertNotEquals(true, CValidator::isAlpha('ABc de#', array('#'))); - } + protected function setUp(): void + { + parent::setUp(); + } + + /** + * Test for CValidator::isEmpty + */ + public function testIsEmpty(): void + { + self::assertEquals(true, CValidator::isEmpty(null)); + self::assertEquals(true, CValidator::isEmpty([])); + self::assertEquals(true, CValidator::isEmpty('')); + self::assertEquals(true, CValidator::isEmpty(' ', true)); + + self::assertNotEquals(true, CValidator::isEmpty(0)); + self::assertNotEquals(true, CValidator::isEmpty('text')); + } + + /** + * Test for CValidator::isAlpha + */ + public function testIsAlpha(): void + { + self::assertEquals(true, CValidator::isAlpha('abcde')); + self::assertEquals(true, CValidator::isAlpha('ABCDE')); + self::assertEquals(true, CValidator::isAlpha('ABcde')); + self::assertEquals(true, CValidator::isAlpha('ABcde#', ['#'])); + self::assertEquals(true, CValidator::isAlpha('ABc de#', [' ', '#'])); + + self::assertNotEquals(true, CValidator::isAlpha('ABcde3')); + self::assertNotEquals(true, CValidator::isAlpha('ABcde#')); + self::assertNotEquals(true, CValidator::isAlpha('ABc de')); + self::assertNotEquals(true, CValidator::isAlpha('ABc de#', ['#'])); + } } \ No newline at end of file From 98ad58ee5efd271aab9d1c6c9db4c51fd46267b9 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 22 Aug 2020 16:07:13 +0300 Subject: [PATCH 28/45] Added chuck method for Active Records, code array => [] changes --- CHANGELOG | 1 + .../setup/views/setup/requirements.php | 40 +- demos/simple-blog/protected/config/db.php | 12 - demos/simple-blog/protected/config/main.php | 193 --- .../protected/controllers/PostsController.php | 6 +- .../protected/views/categories/add.php | 34 +- .../protected/views/categories/edit.php | 18 +- .../protected/views/settings/edit.php | 46 +- .../modules/setup/templates/default.php | 31 +- .../setup/templates/views/setup/ready.php | 36 +- docs/pages/coding-standards.html | 8 +- framework/Apphp.php | 100 +- framework/helpers/CConvert.php | 50 +- framework/helpers/widgets/CGridView.php | 86 +- framework/i18n/en.php | 1140 ++++++++--------- framework/messages/ar/core.php | 2 +- framework/messages/de/core.php | 2 +- framework/messages/en/core.php | 2 +- framework/messages/es/core.php | 2 +- framework/messages/fr/core.php | 2 +- framework/messages/he/core.php | 2 +- framework/messages/it/core.php | 2 +- framework/messages/nl/core.php | 2 +- framework/messages/pl/core.php | 2 +- framework/messages/ru/core.php | 2 +- utils/tests/inc/filter/test.php | 8 +- utils/tests/index.php | 48 +- 27 files changed, 847 insertions(+), 1030 deletions(-) delete mode 100644 demos/simple-blog/protected/config/db.php delete mode 100644 demos/simple-blog/protected/config/main.php diff --git a/CHANGELOG b/CHANGELOG index 97820c3..aa2d71b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,7 @@ Version 1.4.x - ---------------------------- - Enh: added possibility to hide system queries in debug panel - Enh: added possibility to close debug panel to minimum size +- Enh: added possibility to get records by chunks with chuck() method of Active Record - Bug: fixed wrong assignment of _isRendered in CView diff --git a/demos/login-system/protected/modules/setup/views/setup/requirements.php b/demos/login-system/protected/modules/setup/views/setup/requirements.php index 56e7f5b..7369bd5 100644 --- a/demos/login-system/protected/modules/setup/views/setup/requirements.php +++ b/demos/login-system/protected/modules/setup/views/setup/requirements.php @@ -50,22 +50,30 @@ 'setup/requirements', - 'method' => 'post', - 'htmlOptions' => array( - 'name' => 'frmSetup', - ), - 'fields' => array( - 'act' => array('type' => 'hidden', 'value' => 'send'), - ), - 'buttons' => array( - 'back' => array('type' => 'button', 'value' => A::t('setup', 'Previous'), 'htmlOptions' => array('name' => '', 'onclick' => "$(location).attr('href','setup/index');")), - 'submit' => array('type' => 'submit', 'value' => A::t('setup', 'Next'), 'htmlOptions' => array('name' => '')) - ), - 'return' => true, - )); + +if ( ! $isCriticalError) { + echo CWidget::create( + 'CFormView', + [ + 'action' => 'setup/requirements', + 'method' => 'post', + 'htmlOptions' => [ + 'name' => 'frmSetup', + ], + 'fields' => [ + 'act' => ['type' => 'hidden', 'value' => 'send'], + ], + 'buttons' => [ + 'back' => [ + 'type' => 'button', + 'value' => A::t('setup', 'Previous'), + 'htmlOptions' => ['name' => '', 'onclick' => "$(location).attr('href','setup/index');"] + ], + 'submit' => ['type' => 'submit', 'value' => A::t('setup', 'Next'), 'htmlOptions' => ['name' => '']] + ], + 'return' => true, + ] + ); } ?>
    diff --git a/demos/simple-blog/protected/config/db.php b/demos/simple-blog/protected/config/db.php deleted file mode 100644 index f0681cd..0000000 --- a/demos/simple-blog/protected/config/db.php +++ /dev/null @@ -1,12 +0,0 @@ - array( - 'driver' => 'mysql', - 'host' => 'localhost', - 'database' => 'test', - 'username' => 'root', - 'password' => '', - 'prefix' => 'mb_', - ) -); \ No newline at end of file diff --git a/demos/simple-blog/protected/config/main.php b/demos/simple-blog/protected/config/main.php deleted file mode 100644 index 7af26d2..0000000 --- a/demos/simple-blog/protected/config/main.php +++ /dev/null @@ -1,193 +0,0 @@ - 'Simple Blog', - 'version' => '1.0.2', - - // Directy CMF data - 'directy_cmf_version' => '', - - // installation settings - 'installationKey' => '2x4686fpyk', - - // Password keys settings (for database passwords only) - // Remember: changing these settings after installation may lead to unstable work of application - // encryptAlgorithm - md5, sha1 (not recommended), sha256, whirlpool, etc - 'password' => array( - 'encryption' => true, - 'encryptAlgorithm' => 'sha256', - 'encryptSalt' => true, - 'hashKey' => 'apphp_directy_login_system', - ), - - // Text encryption settings (for database text fields only) - // Remember: changing these settings after installation may lead to unstable work of application - // Encryption level - PHP or DB - // encryptAlgorithm - PHP: aes-256-cbc DB: AES - 'text' => array( - 'encryption' => true, - 'encryptAlgorithm' => 'aes-256-cbc', - 'encryptKey' => 'apphp_directy_cmf', - ), - - // Default email settings - 'email' => array( - 'mailer' => 'smtpMailer', /* phpMail | phpMailer | smtpMailer */ - 'from' => 'info@email.me', - 'fromName' => '', /* John Smith */ - 'isHtml' => true, - 'smtp' => array( - 'auth' => true, /* true or false */ - 'secure' => 'ssl', /* 'ssl', 'tls' or '' */ - 'host' => 'smtp.gmail.com', - 'port' => '465', - 'username' => '', - 'password' => '', - ), - ), - - // Validations - // Define array of 'excluded' controllers, ex.: array('PaymentProviders', 'Checkout') - // Token type: 'session', 'cookie' or 'multipages' - 'validation' => array( - 'csrf' => array('enable' => false, 'exclude' => array('PaymentProviders'), 'tokenType' => 'session'), - 'bruteforce' => array('enable' => true, 'badLogins' => 5, 'badRestores' => 5, 'redirectDelay' => 3) - ), - - // Exception handling - // Define exceptions exceptions in application - 'exceptionHandling' => array( - 'enable' => true, - 'level' => 'global' - ), - - // Output compression - 'compression' => array( - 'gzip' => array('enable' => false), - 'html' => array('enable' => false), - 'css' => array('enable' => false, 'path' => 'assets/minified/css/', 'minify' => true), - 'js' => array('enable' => false, 'path' => 'assets/minified/js/', 'minify' => true), - ), - - // Session settings - 'session' => array( - 'customStorage' => false, /* true value means use a custom storage (database), false - standard storage */ - 'cacheLimiter' => '', /* to prevent 'Web Page expired' message for POST request use "private,must-revalidate" */ - 'lifetime' => 24, /* session timeout in minutes, default: 24 min = 1440 sec */ - ), - - // Cookies settings - 'cookies' => array( - 'domain' => '', - 'path' => '/' - ), - - // Cache settings - 'cache' => array( - 'enable' => false, - 'type' => 'auto', /* 'auto' or 'manual' */ - 'lifetime' => 20, /* in minutes */ - 'path' => 'protected/tmp/cache/' - ), - - // Logger settings - 'log' => array( - 'enable' => false, - 'path' => 'protected/tmp/logs/', - 'fileExtension' => 'php', - 'dateFormat' => 'Y-m-d H:i:s', - 'threshold' => 1, - 'filePermissions' => 0644, - 'lifetime' => 30 /* in days */ - ), - - // RSS Feed settings - 'rss' => array( - 'path' => 'feeds/' - ), - - // Datetime settings - 'defaultTimeZone' => 'UTC', - - // Template default settings - 'template' => array( - 'default' => 'default' - ), - - // Layout default settings - 'layouts' => array( - 'enable' => false, - 'default' => 'default' - ), - - // Layout default settings - 'layouts' => array( - 'enable' => array('frontend' => false, 'backend' => false), - 'default' => 'default' - ), - - // Application default settings - 'defaultBackendDirectory' => 'backoffice', /* default backoffice directory */ - 'defaultErrorController' => 'Error', /* may be overridden by module settings */ - 'defaultController' => 'Index', /* may be overridden by module settings */ - 'defaultAction' => 'index', /* may be overridden by module settings */ - - // Application Backend settings - 'restoreAdminPassword' => array( - 'enable' => true, - 'recoveryType' => 'direct' /* 'direct' - send new password directly, 'recovery' - send link to recovery page */ - ), - - // Application components - 'components' => array( - 'Bootstrap' => array('enable' => true, 'class' => 'Bootstrap'), - 'BlogMenu' => array('enable' => true, 'class' => 'BlogMenu'), - ), - - // Logger settings - 'log' => array( - 'enable' => false, - 'path' => 'protected/tmp/logs/', - 'fileExtension' => 'php', - 'dateFormat' => 'Y-m-d H:i:s', - 'threshold' => 1, - 'filePermissions' => 0644, - 'lifetime' => 30 /* in days */ - ), - - // Widget settings - 'widgets' => array( - 'paramKeysSensitive' => true - ), - - // Application helpers - 'helpers' => array( - //'helper' => array('enable' => true, 'class' => 'Helper'), - ), - - // Application modules - 'modules' => array( - 'setup' => array('enable' => true, 'removable' => false, 'backendDefaultUrl' => ''), - ), - - // Url manager - 'urlManager' => array( - 'urlFormat' => 'shortPath', /* get | path | shortPath */ - 'rules' => array( - // Required by payments module. If you remove these rules - make sure you define full path URL for pyment providers - //'paymentProviders/handlePayment/provider/([a-zA-Z0-9\_]+)/handler/([a-zA-Z0-9\_]+)/module/([a-zA-Z0-9\_]+)[\/]?$' => 'paymentProviders/handlePayment/provider/{$0}/handler/{$1}/module/{$2}', - 'paymentProviders/handlePayment/([a-zA-Z0-9\_]+)/([a-zA-Z0-9\_]+)/([a-zA-Z0-9\_]+)[\/]?$' => 'paymentProviders/handlePayment/provider/{$0}/handler/{$1}/module/{$2}', - //'paymentProviders/handlePayment/provider/([a-zA-Z0-9\_]+)/handler/([a-zA-Z0-9\_]+)[\/]?$' => 'paymentProviders/handlePayment/provider/{$0}/handler/{$1}', - 'paymentProviders/handlePayment/([a-zA-Z0-9\_]+)/([a-zA-Z0-9\_]+)[\/]?$' => 'paymentProviders/handlePayment/provider/{$0}/handler/{$1}', - //'paymentProviders/handlePayment/provider/([a-zA-Z0-9\_]+)[\/]?$' => 'paymentProviders/handlePayment/provider/{$0}', - 'paymentProviders/handlePayment/([a-zA-Z0-9\_]+)[\/]?$' => 'paymentProviders/handlePayment/provider/{$0}', - // Required by dynamic pages, if you want to use user-friendly URLs - //'controller/action/value1/value2' => 'controllerName/action/param1/value1/param2/value2', - //'sitepages/show/example-page-1' => 'sitePages/show/name/about-us', - //'value1' => 'controllerName/action/param1/value1', - //'about-us' => 'sitePages/show/name/about-us', - ), - ), - -); diff --git a/demos/simple-blog/protected/controllers/PostsController.php b/demos/simple-blog/protected/controllers/PostsController.php index b6e00c0..34299ba 100644 --- a/demos/simple-blog/protected/controllers/PostsController.php +++ b/demos/simple-blog/protected/controllers/PostsController.php @@ -129,7 +129,7 @@ public function indexAction($msg = '') // prepare pagination vars $this->_view->targetPage = 'posts/index'; $this->_view->currentPage = A::app()->getRequest()->getQuery('page', 'integer', 1); - $this->_view->pageSize = '15'; + $this->_view->pageSize = 15; $this->_view->totalRecords = Posts::model()->count(); if (!$this->_view->currentPage) { @@ -147,13 +147,11 @@ public function indexAction($msg = '') )); }else{ $posts = null; - Posts::model()->chunk($conditions, [], 2, function ($records) use(&$posts){ + Posts::model()->chunk($conditions, [], 10, function ($records) use(&$posts){ foreach ($records as $key => $record) { $posts[] = $record; } - //CDebug::d($record); }); - //CDebug::dd($posts); $this->_view->posts = $posts; } } diff --git a/demos/simple-blog/protected/views/categories/add.php b/demos/simple-blog/protected/views/categories/add.php index 7c34af8..816a9ee 100644 --- a/demos/simple-blog/protected/views/categories/add.php +++ b/demos/simple-blog/protected/views/categories/add.php @@ -4,27 +4,27 @@
    - 'categories/insert', 'method' => 'post', - 'htmlOptions' => array( + 'htmlOptions' => [ 'name' => 'frmAddCategory', - ), - 'fields' => array( - 'act' => array('type' => 'hidden', 'value' => 'send'), - 'categoryName' => array('type' => 'textbox', 'title' => 'Category Name', 'mandatoryStar' => true, 'htmlOptions' => array('maxlength' => '50', 'class' => 'text_header')), - ), - 'buttons' => array( - 'cancel' => array('type' => 'button', 'value' => 'Cancel', 'htmlOptions' => array('name' => '', 'onclick' => "$(location).attr('href','categories/index');")), - 'submit' => array('type' => 'submit', 'value' => 'Create'), - ), - 'events' => array( - 'focus' => array('field' => $errorField), - ), + ], + 'fields' => [ + 'act' => ['type' => 'hidden', 'value' => 'send'], + 'categoryName' => ['type' => 'textbox', 'title' => 'Category Name', 'mandatoryStar' => true, 'htmlOptions' => ['maxlength' => '50', 'class' => 'text_header']], + ], + 'buttons' => [ + 'cancel' => ['type' => 'button', 'value' => 'Cancel', 'htmlOptions' => ['name' => '', 'onclick' => "$(location).attr('href','categories/index');"]], + 'submit' => ['type' => 'submit', 'value' => 'Create'], + ], + 'events' => [ + 'focus' => ['field' => $errorField], + ], 'return' => true, - )); - ?> + ]); + ?>
    This page provides you possibility to add new category. diff --git a/demos/simple-blog/protected/views/categories/edit.php b/demos/simple-blog/protected/views/categories/edit.php index 3b6688e..dc407ec 100644 --- a/demos/simple-blog/protected/views/categories/edit.php +++ b/demos/simple-blog/protected/views/categories/edit.php @@ -9,9 +9,9 @@ echo CWidget::create('CFormView', array( 'action' => 'categories/update', 'method' => 'post', - 'htmlOptions' => array( - 'name' => 'frmEditCategory', - ), + 'htmlOptions' => [ + 'name' => 'frmEditCategory', + ], 'fields' => array( 'act' => array('type' => 'hidden', 'value' => 'send'), 'categoryId' => array('type' => 'hidden', 'value' => $categoryId), @@ -20,12 +20,12 @@ ), 'buttons' => array( 'cancel' => array('type' => 'button', 'value' => 'Cancel', 'htmlOptions' => array('name' => '', 'onclick' => "$(location).attr('href','categories/index');")), - 'submit' => array('type' => 'submit', 'value' => 'Update'), - ), - 'events' => array( - 'focus' => array('field' => $errorField), - ), - 'return' => true, + 'submit' => ['type' => 'submit', 'value' => 'Update'], + ), + 'events' => array( + 'focus' => ['field' => $errorField], + ), + 'return' => true, )); ?>
    diff --git a/demos/simple-blog/protected/views/settings/edit.php b/demos/simple-blog/protected/views/settings/edit.php index 6c865a5..0d82997 100644 --- a/demos/simple-blog/protected/views/settings/edit.php +++ b/demos/simple-blog/protected/views/settings/edit.php @@ -4,33 +4,33 @@
    - 'settings/update', 'method' => 'post', - 'htmlOptions' => array( + 'htmlOptions' => [ 'name' => 'frmSettings', - ), - 'fields' => array( - 'act' => array('type' => 'hidden', 'value' => 'send'), - 'blogName' => array('type' => 'textbox', 'value' => $blogName, 'title' => 'Blog Name', 'mandatoryStar' => true, 'htmlOptions' => array('maxlength' => '100', 'class' => 'text_header')), - 'slogan' => array('type' => 'textarea', 'value' => $slogan, 'title' => 'Slogan', 'mandatoryStar' => false, 'htmlOptions' => array('maxlength' => '250', 'class' => 'small')), - 'footer' => array('type' => 'textarea', 'value' => $footer, 'title' => 'Footer', 'mandatoryStar' => false, 'htmlOptions' => array('maxlength' => '250', 'class' => 'middle')), - 'postMaxChars' => array('type' => 'textbox', 'value' => $postMaxChars, 'title' => 'Maximum Post Length', 'mandatoryStar' => true, 'htmlOptions' => array('maxlength' => '5', 'class' => 'numeric')), - 'metaTagTitle' => array('type' => 'textarea', 'value' => $metaTagTitle, 'title' => CHtml::encode('Tag '), 'mandatoryStar' => true, 'htmlOptions' => array('maxlength' => '250', 'class' => 'small')), - 'metaTagKeywords' => array('type' => 'textarea', 'value' => $metaTagKeywords, 'title' => CHtml::encode('Meta Tag <KEYWORDS>'), 'mandatoryStar' => false, 'htmlOptions' => array('maxlength' => '250', 'class' => 'middle')), - 'metaTagDescription' => array('type' => 'textarea', 'value' => $metaTagDescription, 'title' => CHtml::encode('Meta Tag <DESCRIPTION>'), 'mandatoryStar' => false, 'htmlOptions' => array('maxlength' => '250', 'class' => 'middle')), - ), - 'buttons' => array( - 'reset' => array('type' => 'reset', 'value' => 'Reset', 'htmlOptions' => array('type' => 'reset')), - 'submit' => array('type' => 'submit', 'value' => 'Update'), - ), - 'events' => array( - 'focus' => array('field' => $errorField), - ), + ], + 'fields' => [ + 'act' => ['type' => 'hidden', 'value' => 'send'], + 'blogName' => ['type' => 'textbox', 'value' => $blogName, 'title' => 'Blog Name', 'mandatoryStar' => true, 'htmlOptions' => ['maxlength' => '100', 'class' => 'text_header']], + 'slogan' => ['type' => 'textarea', 'value' => $slogan, 'title' => 'Slogan', 'mandatoryStar' => false, 'htmlOptions' => ['maxlength' => '250', 'class' => 'small']], + 'footer' => ['type' => 'textarea', 'value' => $footer, 'title' => 'Footer', 'mandatoryStar' => false, 'htmlOptions' => ['maxlength' => '250', 'class' => 'middle']], + 'postMaxChars' => ['type' => 'textbox', 'value' => $postMaxChars, 'title' => 'Maximum Post Length', 'mandatoryStar' => true, 'htmlOptions' => ['maxlength' => '5', 'class' => 'numeric']], + 'metaTagTitle' => ['type' => 'textarea', 'value' => $metaTagTitle, 'title' => CHtml::encode('Tag <TITLE>'), 'mandatoryStar' => true, 'htmlOptions' => ['maxlength' => '250', 'class' => 'small']], + 'metaTagKeywords' => ['type' => 'textarea', 'value' => $metaTagKeywords, 'title' => CHtml::encode('Meta Tag <KEYWORDS>'), 'mandatoryStar' => false, 'htmlOptions' => ['maxlength' => '250', 'class' => 'middle']], + 'metaTagDescription' => ['type' => 'textarea', 'value' => $metaTagDescription, 'title' => CHtml::encode('Meta Tag <DESCRIPTION>'), 'mandatoryStar' => false, 'htmlOptions' => ['maxlength' => '250', 'class' => 'middle']], + ], + 'buttons' => [ + 'reset' => ['type' => 'reset', 'value' => 'Reset', 'htmlOptions' => ['type' => 'reset']], + 'submit' => ['type' => 'submit', 'value' => 'Update'], + ], + 'events' => [ + 'focus' => ['field' => $errorField], + ], 'return' => true, - )); - ?> + ]); + ?> </div> <div class="panel-settings"> This page provides you possibility to edit global site settings. diff --git a/demos/simple-cms/protected/modules/setup/templates/default.php b/demos/simple-cms/protected/modules/setup/templates/default.php index 1a3982a..a80be54 100644 --- a/demos/simple-cms/protected/modules/setup/templates/default.php +++ b/demos/simple-cms/protected/modules/setup/templates/default.php @@ -27,21 +27,24 @@ </div> <?php - CWidget::create('CMenu', array( - 'type'=>'vertical', - 'items'=>array( - array('label'=>'1. Server Requirements', 'url'=>'setup/index', 'readonly'=>true), - array('label'=>'2. Database Settings', 'url'=>'setup/database', 'readonly'=>true), - array('label'=>'3. Administrator Account', 'url'=>'setup/administrator', 'readonly'=>true), - array('label'=>'4. Ready to Install', 'url'=>'setup/ready', 'readonly'=>true), - array('label'=>'5. Completed', 'url'=>'setup/completed', 'readonly'=>true), - ), - 'selected'=>$this->_activeMenu, - 'return'=>false - )); + CWidget::create( + 'CMenu', + [ + 'type' => 'vertical', + 'items' => [ + ['label' => '1. Server Requirements', 'url' => 'setup/index', 'readonly' => true], + ['label' => '2. Database Settings', 'url' => 'setup/database', 'readonly' => true], + ['label' => '3. Administrator Account', 'url' => 'setup/administrator', 'readonly' => true], + ['label' => '4. Ready to Install', 'url' => 'setup/ready', 'readonly' => true], + ['label' => '5. Completed', 'url' => 'setup/completed', 'readonly' => true], + ], + 'selected' => $this->_activeMenu, + 'return' => false + ] + ); ?> - </aside> - <article> + </aside> + <article> <?php echo A::app()->view->getContent(); ?> </article> </section> diff --git a/demos/simple-cms/protected/modules/setup/templates/views/setup/ready.php b/demos/simple-cms/protected/modules/setup/templates/views/setup/ready.php index 540b390..dce0036 100644 --- a/demos/simple-cms/protected/modules/setup/templates/views/setup/ready.php +++ b/demos/simple-cms/protected/modules/setup/templates/views/setup/ready.php @@ -37,21 +37,27 @@ <?php echo ($actionMessage) ? $actionMessage.'<br>' : ''; ?> <?php - echo CWidget::create('CFormView', array( - 'action'=>'setup/ready', - 'method'=>'post', - 'htmlOptions'=>array( - 'name'=>'frmSetup' - ), - 'fields'=>array( - 'act'=>array('type'=>'hidden', 'value'=>'send'), - ), - 'buttons'=>array( - 'back'=>array('type'=>'button', 'value'=>'Previous', 'htmlOptions'=>array('name'=>'', 'onclick'=>"$(location).attr('href','setup/administrator');")), - 'submit'=>array('type'=>'submit', 'value'=>'Next', 'htmlOptions'=>array('name'=>'')) - ), - 'return'=>true, - )); + +echo CWidget::create( + 'CFormView', + [ + 'action' => 'setup/ready', + 'method' => 'post', + 'htmlOptions' => ['name' => 'frmSetup'], + 'fields' => [ + 'act' => ['type' => 'hidden', 'value' => 'send'], + ], + 'buttons' => [ + 'back' => [ + 'type' => 'button', + 'value' => 'Previous', + 'htmlOptions' => ['name' => '', 'onclick' => "$(location).attr('href','setup/administrator');"] + ], + 'submit' => ['type' => 'submit', 'value' => 'Next', 'htmlOptions' => ['name' => '']] + ], + 'return' => true, + ] +); ?> <br> diff --git a/docs/pages/coding-standards.html b/docs/pages/coding-standards.html index 287e831..4114385 100644 --- a/docs/pages/coding-standards.html +++ b/docs/pages/coding-standards.html @@ -119,16 +119,18 @@ <h3>Arrays <a class="hashlink" href="#arrays">¶</a></h3> <br><br> When declaring indexed arrays with the <code>array</code> function, a trailing space must be added after each comma delimiter to improve readability: -<pre name="dlhl" class="php">$sampleArray = array(1, 2, 3, 'ApPHP', 'People', 99);</pre> +<pre name="dlhl" class="php">$sampleArray = [1, 2, 3, 'ApPHP', 'People', 99];</pre> +<br><br> +We recommend to use square brackets [] for arrays. <br> <b>Associative Arrays</b><br> When declaring associative arrays with the array construct, breaking the statement into multiple lines is encouraged, for example: -<pre name="dlhl" class="php">$sampleArray = array( +<pre name="dlhl" class="php">$sampleArray = [ 'firstKey' => 'firstValue', 'secondKey' => 'secondValue', -);</pre> +];</pre> <br><br> diff --git a/framework/Apphp.php b/framework/Apphp.php index 27e0a87..0e94742 100644 --- a/framework/Apphp.php +++ b/framework/Apphp.php @@ -74,14 +74,14 @@ class A /** @var object */ private static $_instance; /** @var array */ - private static $_classMap = array( - 'Controller' => 'controllers', - 'Model' => 'models', - 'Entity' => 'entities', - '' => 'models', - ); - /** @var array */ - private static $_coreClasses = array( + private static $_classMap = [ + 'Controller' => 'controllers', + 'Model' => 'models', + 'Entity' => 'entities', + '' => 'models', + ]; + /** @var array */ + private static $_coreClasses = [ 'CConfig' => 'collections/CConfig.php', 'CController' => 'core/CController.php', @@ -94,35 +94,35 @@ class A 'CRecordEntity' => 'db/CRecordEntity.php', 'CDatabase' => 'db/CDatabase.php', 'CDbCommand' => 'db/CDbCommand.php', - ); + ]; /** @var array */ - private static $_coreConsoleClasses = array( + private static $_coreConsoleClasses = [ 'CConsole' => 'console/CConsole.php', 'CConsoleCommand' => 'console/CConsoleCommand.php', 'CHelpCommand' => 'console/CHelpCommand.php', 'CVersionCommand' => 'console/CVersionCommand.php', 'CCacheClearCommand' => 'console/CCacheClearCommand.php', 'CMakeControllerCommand' => 'console/CMakeControllerCommand.php', - ); + ]; /** @var array */ - private static $_coreComponents = array( + private static $_coreComponents = [ //'component' => array('class' => 'CComponent', 'path' => array('5.4.0' => 'components/CComponent.php')), - 'component' => array('class' => 'CComponent', 'path' => 'components/CComponent.php'), - 'clientScript' => array('class' => 'CClientScript', 'path' => 'components/CClientScript.php'), - 'dbSession' => array('class' => 'CDbHttpSession', 'path' => 'components/CDbHttpSession.php'), - 'request' => array('class' => 'CHttpRequest', 'path' => 'components/CHttpRequest.php'), - 'session' => array('class' => 'CHttpSession', 'path' => 'components/CHttpSession.php'), - 'cookie' => array('class' => 'CHttpCookie', 'path' => 'components/CHttpCookie.php'), - 'localTime' => array('class' => 'CLocalTime', 'path' => 'components/CLocalTime.php'), - 'logger' => array('class' => 'CLogger', 'path' => 'components/CLogger.php'), - 'coreMessages' => array('class' => 'CMessageSource', 'path' => 'components/CMessageSource.php', 'language' => 'en'), - 'messages' => array('class' => 'CMessageSource', 'path' => 'components/CMessageSource.php'), - 'mobileDetect' => array('class' => 'CMobileDetect', 'path' => 'components/CMobileDetect.php'), - 'shoppingCart' => array('class' => 'CShoppingCart', 'path' => 'components/CShoppingCart.php'), - 'uri' => array('class' => 'CUri', 'path' => 'components/CUri.php'), - ); - /** @var array */ - private static $_coreHelpers = array( + 'component' => ['class' => 'CComponent', 'path' => 'components/CComponent.php'], + 'clientScript' => ['class' => 'CClientScript', 'path' => 'components/CClientScript.php'], + 'dbSession' => ['class' => 'CDbHttpSession', 'path' => 'components/CDbHttpSession.php'], + 'request' => ['class' => 'CHttpRequest', 'path' => 'components/CHttpRequest.php'], + 'session' => ['class' => 'CHttpSession', 'path' => 'components/CHttpSession.php'], + 'cookie' => ['class' => 'CHttpCookie', 'path' => 'components/CHttpCookie.php'], + 'localTime' => ['class' => 'CLocalTime', 'path' => 'components/CLocalTime.php'], + 'logger' => ['class' => 'CLogger', 'path' => 'components/CLogger.php'], + 'coreMessages' => ['class' => 'CMessageSource', 'path' => 'components/CMessageSource.php', 'language' => 'en'], + 'messages' => ['class' => 'CMessageSource', 'path' => 'components/CMessageSource.php'], + 'mobileDetect' => ['class' => 'CMobileDetect', 'path' => 'components/CMobileDetect.php'], + 'shoppingCart' => ['class' => 'CShoppingCart', 'path' => 'components/CShoppingCart.php'], + 'uri' => ['class' => 'CUri', 'path' => 'components/CUri.php'], + ]; + /** @var array */ + private static $_coreHelpers = [ 'CArray' => 'helpers/CArray.php', 'CAuth' => 'helpers/CAuth.php', 'CCache' => 'helpers/CCache.php', @@ -150,35 +150,35 @@ class A 'CTime' => 'helpers/CTime.php', 'CValidator' => 'helpers/CValidator.php', 'CWidget' => 'helpers/CWidget.php', - ); - /** @var array */ - private static $_coreModules = array( - // 'General' => '/core/modules/General.php' - ); + ]; /** @var array */ - private static $_appClasses = array( + private static $_coreModules = [ + // 'General' => '/core/modules/General.php' + ]; + /** @var array */ + private static $_appClasses = [ // empty - ); + ]; /** @var array */ - private static $_appComponents = array( + private static $_appComponents = [ // empty - ); + ]; /** @var array */ - private static $_appHelpers = array( + private static $_appHelpers = [ // empty - ); + ]; /** @var array */ - private static $_appModules = array( - 'setup' => array('classes' => array('Modules\Setup\Controllers\Setup')), - ); + private static $_appModules = [ + 'setup' => ['classes' => ['Modules\Setup\Controllers\Setup']], + ]; /** @var bool */ private $_coreComponentsLazyLoading = true; /** @var array */ - private $_components = array(); - /** @var array */ - private $_events = array(); - /** @var boolean */ - private $_setup = false; + private $_components = []; + /** @var array */ + private $_events = []; + /** @var boolean */ + private $_setup = false; /** @var string */ private $_responseCode = ''; /** @var string */ @@ -195,9 +195,9 @@ class A public function __construct($configDir) { // Set autoload register method - spl_autoload_register(array($this, '_autoload')); - - // Include interfaces + spl_autoload_register([$this, '_autoload']); + + // Include interfaces require(dirname(__FILE__) . DS . 'core' . DS . 'interfaces.php'); self::$_phpVersion = phpversion(); diff --git a/framework/helpers/CConvert.php b/framework/helpers/CConvert.php index 7ed3ba9..ac02dd8 100644 --- a/framework/helpers/CConvert.php +++ b/framework/helpers/CConvert.php @@ -8,34 +8,36 @@ * @copyright Copyright (c) 2012 - 2020 ApPHP Framework * @license http://www.apphpframework.com/license/ * - * PUBLIC (static): PROTECTED: PRIVATE: + * PUBLIC (static): PROTECTED: PRIVATE: * ---------- ---------- ---------- * fileSize - * + * */ class CConvert { - - /** - * Converts a given size into mb Mb or Kb - * @param integer $size - * @param array $params - * @return float - */ - public static function fileSize($size, $params = array()) - { - $spaceBeforeUnit = isset($params['spaceBeforeUnit']) ? (bool)$params['spaceBeforeUnit'] : true; - $unitCase = isset($params['unitCase']) ? $params['unitCase'] : ''; - $unit = array('b', 'kb', 'mb', 'gb', 'tb', 'pb'); - - if ($unitCase == 'camel') { - $unit = array('b', 'Kb', 'Mb', 'Gb', 'Tb', 'Pb'); - } elseif ($unitCase == 'upper') { - $unit = array('B', 'KB', 'MB', 'GB', 'TB', 'PB'); - } - - return @round($size / pow(1024, ($i = floor(log($size, 1024)))), 2) . ($spaceBeforeUnit ? ' ' : '') . $unit[$i]; - } - + + /** + * Converts a given size into mb Mb or Kb + * + * @param integer $size + * @param array $params + * + * @return float + */ + public static function fileSize($size, $params = []) + { + $spaceBeforeUnit = isset($params['spaceBeforeUnit']) ? (bool)$params['spaceBeforeUnit'] : true; + $unitCase = isset($params['unitCase']) ? $params['unitCase'] : ''; + $unit = ['b', 'kb', 'mb', 'gb', 'tb', 'pb']; + + if ($unitCase == 'camel') { + $unit = ['b', 'Kb', 'Mb', 'Gb', 'Tb', 'Pb']; + } elseif ($unitCase == 'upper') { + $unit = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']; + } + + return @round($size / pow(1024, ($i = floor(log($size, 1024)))), 2).($spaceBeforeUnit ? ' ' : '').$unit[$i]; + } + } \ No newline at end of file diff --git a/framework/helpers/widgets/CGridView.php b/framework/helpers/widgets/CGridView.php index cefc290..f172c3c 100644 --- a/framework/helpers/widgets/CGridView.php +++ b/framework/helpers/widgets/CGridView.php @@ -41,7 +41,7 @@ class CGridView extends CWidgs * - 'case'=>'normal' - attribute for type 'label', allows to convert value to 'upper', 'lower', 'camel' or 'humanize' cases * - 'maxLength'=>'X' - attribute for type 'label', specifies to show maximum X characters of the string * 'showTooltip'=>true - specifies whether to show tooltip on field if it's length was reduced - * - 'aggregate'=>array('function'=>'sum|avg') - allow to run aggregate function on specific column + * - 'aggregate'=>['function'=>'sum|avg'] - allow to run aggregate function on specific column * - 'sourceField'=>'' - used to show data from another field * - 'callback'=>array('class'=>'className', 'function'=>'functionName', 'params'=>$functionParams) * callback of closure function that is called when item created (available for labels only), $record - all current record @@ -92,10 +92,10 @@ class CGridView extends CWidgs * 'gridTable' => array('class'=>''), * ), * 'filters' => array( - * 'field_1' => array('title'=>'Field 1', 'type'=>'textbox', 'table'=>'', 'operator'=>'=', 'default'=>'', 'width'=>'', 'maxLength'=>'', 'htmlOptions'=>array()), - * 'field_2' => array('title'=>'Field 2', 'type'=>'textbox', 'table'=>'', 'operator'=>'=', 'default'=>'', 'width'=>'', 'maxLength'=>'', 'autocomplete'=>array('enable'=>true, 'ajaxHandler'=>'path/to/handler/file', 'minLength'=>3, 'returnId'=>true), 'htmlOptions'=>array()), - * 'field_3' => array('title'=>'Field 3', 'type'=>'enum', 'table'=>'', 'operator'=>'=', 'default'=>'', 'width'=>'', 'source'=>array('0'=>'No', '1'=>'Yes'), 'emptyOption'=>true, 'emptyValue'=>'', 'htmlOptions'=>array('class'=>'chosen-select-filter')), - * 'field_4' => array('title'=>'Field 5', 'type'=>'datetime', 'table'=>'', 'operator'=>'=', 'default'=>'', 'width'=>'80px', 'maxLength'=>'', 'format'=>'', 'htmlOptions'=>array(), 'viewType'=>'datetime|date|time'), + * 'field_1' => ['title'=>'Field 1', 'type'=>'textbox', 'table'=>'', 'operator'=>'=', 'default'=>'', 'width'=>'', 'maxLength'=>'', 'htmlOptions'=>array()], + * 'field_2' => ['title'=>'Field 2', 'type'=>'textbox', 'table'=>'', 'operator'=>'=', 'default'=>'', 'width'=>'', 'maxLength'=>'', 'autocomplete'=>array('enable'=>true, 'ajaxHandler'=>'path/to/handler/file', 'minLength'=>3, 'returnId'=>true), 'htmlOptions'=>array()], + * 'field_3' => ['title'=>'Field 3', 'type'=>'enum', 'table'=>'', 'operator'=>'=', 'default'=>'', 'width'=>'', 'source'=>array('0'=>'No', '1'=>'Yes'), 'emptyOption'=>true, 'emptyValue'=>'', 'htmlOptions'=>array('class'=>'chosen-select-filter')], + * 'field_4' => ['title'=>'Field 5', 'type'=>'datetime', 'table'=>'', 'operator'=>'=', 'default'=>'', 'width'=>'80px', 'maxLength'=>'', 'format'=>'', 'htmlOptions'=>array(), 'viewType'=>'datetime|date|time'], * ), * 'fields' => array( * 'field_1' => array('title'=>'Field 1', 'type'=>'index', 'align'=>'', 'width'=>'', 'class'=>'left', 'headerTooltip'=>'', 'headerClass'=>'left', 'isSortable'=>false), @@ -597,11 +597,11 @@ public static function init($params = array()) // --------------------------------------- $totalRecords = $totalPageRecords = 0; $currentPage = ''; - $modelParams = !empty($relationType) ? array($relationType) : array(); - $objModel = call_user_func_array($model . '::model', $modelParams); + $modelParams = ! empty($relationType) ? [$relationType] : []; + $objModel = call_user_func_array($model . '::model', $modelParams); if (!$objModel) { - CDebug::addMessage('errors', 'missing-model', A::t('core', 'Unable to find class "{class}".', array('{class}' => $model)), 'session'); - return ''; + CDebug::addMessage('errors', 'missing-model', A::t('core', 'Unable to find class "{class}".', ['{class}' => $model]), 'session'); + return ''; } // Replacing rows @@ -623,9 +623,9 @@ public static function init($params = array()) $val2 = $record2->$replaceField; } if ($val1 != '' && $val2 != '') { - $objModel->updateByPk($id1, array($replaceField => $val2)); - $objModel->updateByPk($id2, array($replaceField => $val1)); - if (APPHP_MODE == 'demo') { + $objModel->updateByPk($id1, [$replaceField => $val2]); + $objModel->updateByPk($id2, [$replaceField => $val1]); + if (APPHP_MODE == 'demo') { A::app()->getSession()->setFlash('alert', A::t('core', 'This operation is blocked in Demo Mode!')); A::app()->getSession()->setFlash('alertType', 'warning'); } else { @@ -649,24 +649,24 @@ public static function init($params = array()) if ($pagination) { $currentPage = A::app()->getRequest()->getQuery('page', 'integer', 1); - $totalRecords = self::_countAllRecords($objModel, array('condition' => $whereClause, 'group' => $groupBy)); + $totalRecords = self::_countAllRecords($objModel, ['condition' => $whereClause, 'group' => $groupBy]); if ($currentPage) { $records = self::_getAllRecords($objModel, array('condition' => $whereClause, 'order' => $orderClause, 'group' => $groupBy, 'limit' => (($currentPage - 1) * $pageSize) . ', ' . $pageSize)); $totalPageRecords = is_array($records) ? count($records) : 0; } if (!$totalPageRecords || !$currentPage) { if (A::app()->getRequest()->getQuery('but_filter')) { - $output .= CWidget::create('CMessage', array('warning', A::t('core', 'No records found or incorrect parameters passed'))); - } else { - $output .= CWidget::create('CMessage', array('warning', A::t('core', 'No records found'))); - } - } + $output .= CWidget::create('CMessage', ['warning', A::t('core', 'No records found or incorrect parameters passed')]); + } else { + $output .= CWidget::create('CMessage', ['warning', A::t('core', 'No records found')]); + } + } } else { - $records = self::_getAllRecords($objModel, array('condition' => $whereClause, 'order' => $orderClause, 'group' => $groupBy, 'limit' => $limit)); + $records = self::_getAllRecords($objModel, ['condition' => $whereClause, 'order' => $orderClause, 'group' => $groupBy, 'limit' => $limit]); $totalPageRecords = is_array($records) ? count($records) : 0; if (!$totalPageRecords) { - $output .= CWidget::create('CMessage', array('warning', A::t('core', 'No records found'))); - } + $output .= CWidget::create('CMessage', ['warning', A::t('core', 'No records found')]); + } } // Draw table @@ -681,15 +681,15 @@ public static function init($params = array()) // Draw TABLE wrapper // ---------------------------------------------- if (!empty($gridWrapper['tag'])) { - $output .= CHtml::openTag($gridWrapper['tag'], array('class' => (!empty($gridWrapper['class']) ? $gridWrapper['class'] : null))) . self::NL; - } + $output .= CHtml::openTag($gridWrapper['tag'], ['class' => (! empty($gridWrapper['class']) ? $gridWrapper['class'] : null)]).self::NL; + } // ---------------------------------------------- // Draw <THEAD> rows // ---------------------------------------------- - $output .= CHtml::openTag('table', array('class' => 'grid-view-table' . (!empty($gridTable['class']) ? ' ' . $gridTable['class'] : ''))) . self::NL; - $output .= CHtml::openTag('thead') . self::NL; - $output .= CHtml::openTag('tr', array('id' => 'tr' . $modelName . '_' . self::$_rowCount++)) . self::NL; - foreach ($fields as $key => $val) { + $output .= CHtml::openTag('table', ['class' => 'grid-view-table'.(! empty($gridTable['class']) ? ' '.$gridTable['class'] : '')]).self::NL; + $output .= CHtml::openTag('thead') . self::NL; + $output .= CHtml::openTag('tr', ['id' => 'tr'.$modelName.'_'.self::$_rowCount++]).self::NL; + foreach ($fields as $key => $val) { // Check if we want to use another field as a "source field" $sourceField = self::keyAt('sourceField', $val, ''); @@ -714,7 +714,7 @@ public static function init($params = array()) if ($sortingEnabled && $isSortable && ($type != 'template' || ($type == 'template' && !empty($sortField)))) { $sortByField = !empty($sortField) ? $sortField : $key; $colSortDir = (($sortBy != $sortByField) ? 'asc' : (($sortDir == 'asc') ? 'desc' : 'asc')); - $sortImg = ($sortBy == $sortByField) ? ' ' . CHtml::tag('span', array('class' => 'sort-arrow'), (($colSortDir == 'asc') ? '▼' : '▲')) : ''; + $sortImg = ($sortBy == $sortByField) ? ' ' . CHtml::tag('span', ['class' => 'sort-arrow'], (($colSortDir == 'asc') ? '▼' : '▲')) : ''; if ($sortBy == $sortByField) $sortUrl = 'sort_by=' . $sortByField . '&sort_dir=' . $sortDir; $separateSymbol = preg_match('/\?/', $actionPath) ? '&' : '?'; @@ -724,25 +724,25 @@ public static function init($params = array()) $linkUrl .= self::_customParams($customParameters, $linkType, '&'); $title = CHtml::link($title . $sortImg, $linkUrl); } - - $title .= !empty($headerTooltip) ? ' ' . CHtml::link('', false, array('class' => 'tooltip-icon', 'title' => $headerTooltip)) : ''; - - $output .= CHtml::tag('th', array('class' => $headerClass, 'style' => $style), $title) . self::NL; - } + + $title .= ! empty($headerTooltip) ? ' '.CHtml::link('', false, ['class' => 'tooltip-icon', 'title' => $headerTooltip]) : ''; + + $output .= CHtml::tag('th', ['class' => $headerClass, 'style' => $style], $title).self::NL; + } if ($activeActions > 0) { - $output .= CHtml::tag('th', array('class' => 'actions'), A::t('core', 'Actions')) . self::NL; - } + $output .= CHtml::tag('th', ['class' => 'actions'], A::t('core', 'Actions')).self::NL; + } $output .= CHtml::closeTag('tr') . self::NL;; $output .= CHtml::closeTag('thead') . self::NL; // ---------------------------------------------- // Draw <TBODY> rows // ---------------------------------------------- - $aggregateRow = array(); - $output .= CHtml::openTag('tbody') . self::NL; + $aggregateRow = []; + $output .= CHtml::openTag('tbody') . self::NL; for ($i = 0; $i < $totalPageRecords; $i++) { - $output .= CHtml::openTag('tr', array('id' => 'tr' . $modelName . '_' . self::$_rowCount++)) . self::NL; - $id = (isset($records[$i]['id'])) ? $records[$i]['id'] : ''; + $output .= CHtml::openTag('tr', ['id' => 'tr'.$modelName.'_'.self::$_rowCount++]).self::NL; + $id = (isset($records[$i]['id'])) ? $records[$i]['id'] : ''; $prevId = (isset($records[$i - 1]['id'])) ? $records[$i - 1]['id'] : ''; $nextId = (isset($records[$i + 1]['id'])) ? $records[$i + 1]['id'] : ''; @@ -764,14 +764,14 @@ public static function init($params = array()) $title = self::keyAt('title', $val, ''); $format = self::keyAt('format', $val, ''); $definedValues = self::keyAt('definedValues', $val, ''); - $htmlOptions = (array)self::keyAt('htmlOptions', $val, array()); - $prependCode = self::keyAt('prependCode', $val, ''); + $htmlOptions = (array)self::keyAt('htmlOptions', $val, []); + $prependCode = self::keyAt('prependCode', $val, ''); $appendCode = self::keyAt('appendCode', $val, ''); $fieldValue = (isset($records[$i][$key])) ? $records[$i][$key] : ''; /* $key */ $fieldValueOriginal = $fieldValue; $aggregateFunction = self::keyAt('aggregate.function', $val, ''); - $aggregateFunction = in_array(strtolower($aggregateFunction), array('sum', 'avg')) ? strtolower($aggregateFunction) : ''; - $changeOrder = (bool)self::keyAt('changeOrder', $val, false); + $aggregateFunction = in_array(strtolower($aggregateFunction), ['sum', 'avg']) ? strtolower($aggregateFunction) : ''; + $changeOrder = (bool)self::keyAt('changeOrder', $val, false); $fieldOutput = ''; switch ($type) { diff --git a/framework/i18n/en.php b/framework/i18n/en.php index 9978f00..6317228 100644 --- a/framework/i18n/en.php +++ b/framework/i18n/en.php @@ -2,574 +2,574 @@ /** * Locale data for 'en' - English */ -return array( - 'monthNames' => array( - 'wide' => array( - 1 => 'January', - 2 => 'February', - 3 => 'March', - 4 => 'April', - 5 => 'May', - 6 => 'June', - 7 => 'July', - 8 => 'August', - 9 => 'September', - 10 => 'October', - 11 => 'November', - 12 => 'December', - ), - 'abbreviated' => array( - 1 => 'Jan', - 2 => 'Feb', - 3 => 'Mar', - 4 => 'Apr', - 5 => 'May', - 6 => 'Jun', - 7 => 'Jul', - 8 => 'Aug', - 9 => 'Sep', - 10 => 'Oct', - 11 => 'Nov', - 12 => 'Dec', - ), - 'narrow' => array( - 1 => 'J', - 2 => 'F', - 3 => 'M', - 4 => 'A', - 5 => 'M', - 6 => 'J', - 7 => 'J', - 8 => 'A', - 9 => 'S', - 10 => 'O', - 11 => 'N', - 12 => 'D', - ), - ), - 'amName' => 'AM', - 'pmName' => 'PM', - 'weekDayNames' => array( - 'wide' => array( - 1 => 'Sunday', - 2 => 'Monday', - 3 => 'Tuesday', - 4 => 'Wednesday', - 5 => 'Thursday', - 6 => 'Friday', - 7 => 'Saturday', - ), - 'abbreviated' => array( - 1 => 'Sun', - 2 => 'Mon', - 3 => 'Tue', - 4 => 'Wed', - 5 => 'Thu', - 6 => 'Fri', - 7 => 'Sat', - ), - 'narrow' => array( - 1 => 'S', - 2 => 'M', - 3 => 'T', - 4 => 'W', - 5 => 'T', - 6 => 'F', - 7 => 'S', - ), - ), - 'orientation' => 'ltr', - 'languages' => array( - 'aa' => 'Afar', - 'ab' => 'Abkhazian', - 'ae' => 'Avestan', - 'af' => 'Afrikaans', - 'ak' => 'Akan', - 'am' => 'Amharic', - 'an' => 'Aragonese', - 'ar' => 'Arabic', - 'as' => 'Assamese', - 'av' => 'Avaric', - 'ay' => 'Aymara', - 'az' => 'Azeri', - 'ba' => 'Bashkir', - 'be' => 'Belarusian', - 'bg' => 'Bulgarian', - 'bh' => 'Bihari', - 'bi' => 'Bislama', - 'bm' => 'Bambara', - 'bn' => 'Bengali', - 'bo' => 'Tibetan', - 'br' => 'Breton', - 'bs' => 'Bosnian', - 'ca' => 'Catalan', - 'ce' => 'Chechen', - 'ch' => 'Chamorro', - 'co' => 'Corsican', - 'cr' => 'Cree', - 'cs' => 'Czech', - 'cu' => 'Church Slavic', - 'cv' => 'Chuvash', - 'cy' => 'Welsh', - 'da' => 'Danish', - 'de' => 'German', - 'dv' => 'Divehi', - 'dz' => 'Dzongkha', - 'ee' => 'Ewe', - 'el' => 'Greek', - 'en' => 'English', - 'eo' => 'Esperanto', - 'es' => 'Spanish', - 'et' => 'Estonian', - 'eu' => 'Basque', - 'fa' => 'Persian', - 'ff' => 'Fulah', - 'fi' => 'Finnish', - 'fj' => 'Fijian', - 'fo' => 'Faroese', - 'fr' => 'French', - 'fy' => 'Western Frisian', - 'ga' => 'Irish', - 'gd' => 'Scottish Gaelic', - 'gl' => 'Galician', - 'gn' => 'Guarani', - 'gu' => 'Gujarati', - 'gv' => 'Manx', - 'ha' => 'Hausa', - 'he' => 'Hebrew', - 'hi' => 'Hindi', - 'ho' => 'Hiri Motu', - 'hr' => 'Croatian', - 'ht' => 'Haitian', - 'hu' => 'Hungarian', - 'hy' => 'Armenian', - 'hz' => 'Herero', - 'ia' => 'Interlingua', - 'id' => 'Indonesian', - 'ie' => 'Interlingue', - 'ig' => 'Igbo', - 'ii' => 'Sichuan Yi', - 'ik' => 'Inupiaq', - 'io' => 'Ido', - 'is' => 'Icelandic', - 'it' => 'Italian', - 'iu' => 'Inuktitut', - 'ja' => 'Japanese', - 'jv' => 'Javanese', - 'ka' => 'Georgian', - 'kg' => 'Kongo', - 'ki' => 'Kikuyu', - 'kj' => 'Kuanyama', - 'kk' => 'Kazakh', - 'kl' => 'Kalaallisut', - 'km' => 'Khmer', - 'kn' => 'Kannada', - 'ko' => 'Korean', - 'kr' => 'Kanuri', - 'ks' => 'Kashmiri', - 'ku' => 'Kurdish', - 'kv' => 'Komi', - 'kw' => 'Cornish', - 'ky' => 'Kirghiz', - 'la' => 'Latin', - 'lb' => 'Luxembourgish', - 'lg' => 'Ganda', - 'li' => 'Limburgish', - 'ln' => 'Lingala', - 'lo' => 'Lao', - 'lt' => 'Lithuanian', - 'lu' => 'Luba-Katanga', - 'lv' => 'Latvian', - 'mg' => 'Malagasy', - 'mh' => 'Marshallese', - 'mi' => 'Maori', - 'mk' => 'Macedonian', - 'ml' => 'Malayalam', - 'mn' => 'Mongolian', - 'mo' => 'Moldavian', - 'mr' => 'Marathi', - 'ms' => 'Malay', - 'mt' => 'Maltese', - 'my' => 'Burmese', - 'na' => 'Nauru', - 'nb' => 'Norwegian Bokmål', - 'nd' => 'North Ndebele', - 'ne' => 'Nepali', - 'ng' => 'Ndonga', - 'nl' => 'Dutch', - 'nn' => 'Norwegian Nynorsk', - 'no' => 'Norwegian', - 'nr' => 'South Ndebele', - 'nv' => 'Navajo', - 'ny' => 'Nyanja', - 'oc' => 'Occitan', - 'oj' => 'Ojibwa', - 'om' => 'Oromo', - 'or' => 'Oriya', - 'os' => 'Ossetic', - 'pa' => 'Punjabi', - 'pi' => 'Pali', - 'pl' => 'Polish', - 'ps' => 'Pushto', - 'pt' => 'Portuguese', - 'qu' => 'Quechua', - 'rm' => 'Romansh', - 'rn' => 'Rundi', - 'ro' => 'Romanian', - 'ru' => 'Russian', - 'rw' => 'Kinyarwanda', - 'sa' => 'Sanskrit', - 'sc' => 'Sardinian', - 'sd' => 'Sindhi', - 'se' => 'Northern Sami', - 'sg' => 'Sango', - 'sh' => 'Serbo-Croatian', - 'si' => 'Sinhala', - 'sk' => 'Slovak', - 'sl' => 'Slovenian', - 'sm' => 'Samoan', - 'sn' => 'Shona', - 'so' => 'Somali', - 'sq' => 'Albanian', - 'sr' => 'Serbian', - 'ss' => 'Swati', - 'st' => 'Southern Sotho', - 'su' => 'Sundanese', - 'sv' => 'Swedish', - 'sw' => 'Swahili', - 'ta' => 'Tamil', - 'te' => 'Telugu', - 'tg' => 'Tajik', - 'th' => 'Thai', - 'ti' => 'Tigrinya', - 'tk' => 'Turkmen', - 'tl' => 'Tagalog', - 'tn' => 'Tswana', - 'to' => 'Tongan', - 'tr' => 'Turkish', - 'ts' => 'Tsonga', - 'tt' => 'Tatar', - 'tw' => 'Twi', - 'ty' => 'Tahitian', - 'ug' => 'Uyghur', - 'uk' => 'Ukrainian', - 'ur' => 'Urdu', - 'uz' => 'Uzbek', - 've' => 'Venda', - 'vi' => 'Vietnamese', - 'vo' => 'Volapük', - 'wa' => 'Walloon', - 'wo' => 'Wolof', - 'xh' => 'Xhosa', - 'yi' => 'Yiddish', - 'yo' => 'Yoruba', - 'za' => 'Zhuang', - 'zh' => 'Chinese', - 'zu' => 'Zulu', - ), - 'continents' => array( - '001' => 'World', - '010' => 'Africa', - '011' => 'Western Africa', - '012' => 'Eastern Africa', - '013' => 'Northern Africa', - '014' => 'Middle Africa', - '015' => 'Southern Africa', - '020' => 'Americas', - '021' => 'North America', - '022' => 'South America', - '023' => 'Central America', - '024' => 'Latin America', - '025' => 'Caribbean', - '030' => 'Asia', - '031' => 'Central Asia', - '032' => 'Western Asia', - '033' => 'Eastern Asia', - '034' => 'Southern Asia', - '035' => 'South-Eastern Asia', - '036' => 'South-Central Asia', - '037' => 'Middle East', - '040' => 'Europe', - '041' => 'Eastern Europe', - '042' => 'Northern Europe', - '043' => 'Western Europe', - '044' => 'Southern Europe', - '050' => 'Australia and New Zealand', - '051' => 'Oceania', - '052' => 'Melanesia', - '053' => 'Micronesian Region', - '054' => 'Polynesia', - ), - 'countries' => array( - 'ac' => 'Ascension Island', - 'ad' => 'Andorra', - 'ae' => 'United Arab Emirates', - 'af' => 'Afghanistan', - 'ag' => 'Antigua and Barbuda', - 'ai' => 'Anguilla', - 'al' => 'Albania', - 'am' => 'Armenia', - 'an' => 'Netherlands Antilles', - 'ao' => 'Angola', - 'aq' => 'Antarctica', - 'ar' => 'Argentina', - 'as' => 'American Samoa', - 'at' => 'Austria', - 'au' => 'Australia', - 'aw' => 'Aruba', - 'ax' => 'Åland Islands', - 'az' => 'Azerbaijan', - 'ba' => 'Bosnia and Herzegovina', - 'bb' => 'Barbados', - 'bd' => 'Bangladesh', - 'be' => 'Belgium', - 'bf' => 'Burkina Faso', - 'bg' => 'Bulgaria', - 'bh' => 'Bahrain', - 'bi' => 'Burundi', - 'bj' => 'Benin', - 'bl' => 'Saint Barthélemy', - 'bm' => 'Bermuda', - 'bn' => 'Brunei', - 'bo' => 'Bolivia', - 'bq' => 'Bonaire, Saint Eustatius, and Saba', - 'br' => 'Brazil', - 'bs' => 'Bahamas', - 'bt' => 'Bhutan', - 'bv' => 'Bouvet Island', - 'bw' => 'Botswana', - 'by' => 'Belarus', - 'bz' => 'Belize', - 'ca' => 'Canada', - 'cc' => 'Cocos [Keeling] Islands', - 'cd' => 'Congo [DRC]', - 'cf' => 'Central African Republic', - 'cg' => 'Congo [Republic]', - 'ch' => 'Switzerland', - 'ci' => 'Ivory Coast', - 'ck' => 'Cook Islands', - 'cl' => 'Chile', - 'cm' => 'Cameroon', - 'cn' => 'China', - 'co' => 'Colombia', - 'cp' => 'Clipperton Island', - 'cr' => 'Costa Rica', - 'cs' => 'Serbia and Montenegro', - 'ct' => 'Canton and Enderbury Islands', - 'cu' => 'Cuba', - 'cv' => 'Cape Verde', - 'cw' => 'Curacao', - 'cx' => 'Christmas Island', - 'cy' => 'Cyprus', - 'cz' => 'Czech Republic', - 'de' => 'Germany', - 'dg' => 'Diego Garcia', - 'dj' => 'Djibouti', - 'dk' => 'Denmark', - 'dm' => 'Dominica', - 'do' => 'Dominican Republic', - 'dz' => 'Algeria', - 'ea' => 'Ceuta and Melilla', - 'ec' => 'Ecuador', - 'ee' => 'Estonia', - 'eg' => 'Egypt', - 'eh' => 'Western Sahara', - 'er' => 'Eritrea', - 'es' => 'Spain', - 'et' => 'Ethiopia', - 'eu' => 'European Union', - 'fi' => 'Finland', - 'fj' => 'Fiji', - 'fk' => 'Falkland Islands [Islas Malvinas]', - 'fm' => 'Micronesia', - 'fo' => 'Faroe Islands', - 'fq' => 'French Southern and Antarctic Territories', - 'fr' => 'France', - 'fx' => 'Metropolitan France', - 'ga' => 'Gabon', - 'gb' => 'United Kingdom', - 'gd' => 'Grenada', - 'ge' => 'Georgia', - 'gf' => 'French Guiana', - 'gg' => 'Guernsey', - 'gh' => 'Ghana', - 'gi' => 'Gibraltar', - 'gl' => 'Greenland', - 'gm' => 'Gambia', - 'gn' => 'Guinea', - 'gp' => 'Guadeloupe', - 'gq' => 'Equatorial Guinea', - 'gr' => 'Greece', - 'gs' => 'South Georgia and the South Sandwich Islands', - 'gt' => 'Guatemala', - 'gu' => 'Guam', - 'gw' => 'Guinea-Bissau', - 'gy' => 'Guyana', - 'hk' => 'Hong Kong', - 'hm' => 'Heard Island and McDonald Islands', - 'hn' => 'Honduras', - 'hr' => 'Croatia', - 'ht' => 'Haiti', - 'hu' => 'Hungary', - 'ic' => 'Canary Islands', - 'id' => 'Indonesia', - 'ie' => 'Ireland', - 'il' => 'Israel', - 'im' => 'Isle of Man', - 'in' => 'India', - 'io' => 'British Indian Ocean Territory', - 'iq' => 'Iraq', - 'ir' => 'Iran', - 'is' => 'Iceland', - 'it' => 'Italy', - 'je' => 'Jersey', - 'jm' => 'Jamaica', - 'jo' => 'Jordan', - 'jp' => 'Japan', - 'jt' => 'Johnston Island', - 'ke' => 'Kenya', - 'kg' => 'Kyrgyzstan', - 'kh' => 'Cambodia', - 'ki' => 'Kiribati', - 'km' => 'Comoros', - 'kn' => 'Saint Kitts and Nevis', - 'kp' => 'North Korea', - 'kr' => 'South Korea', - 'kw' => 'Kuwait', - 'ky' => 'Cayman Islands', - 'kz' => 'Kazakhstan', - 'la' => 'Laos', - 'lb' => 'Lebanon', - 'lc' => 'Saint Lucia', - 'li' => 'Liechtenstein', - 'lk' => 'Sri Lanka', - 'lr' => 'Liberia', - 'ls' => 'Lesotho', - 'lt' => 'Lithuania', - 'lu' => 'Luxembourg', - 'lv' => 'Latvia', - 'ly' => 'Libya', - 'ma' => 'Morocco', - 'mc' => 'Monaco', - 'md' => 'Moldova', - 'me' => 'Montenegro', - 'mf' => 'Saint Martin', - 'mg' => 'Madagascar', - 'mh' => 'Marshall Islands', - 'mi' => 'Midway Islands', - 'mk' => 'Macedonia [FYROM]', - 'ml' => 'Mali', - 'mm' => 'Myanmar [Burma]', - 'mn' => 'Mongolia', - 'mo' => 'Macau', - 'mp' => 'Northern Mariana Islands', - 'mq' => 'Martinique', - 'mr' => 'Mauritania', - 'ms' => 'Montserrat', - 'mt' => 'Malta', - 'mu' => 'Mauritius', - 'mv' => 'Maldives', - 'mw' => 'Malawi', - 'mx' => 'Mexico', - 'my' => 'Malaysia', - 'mz' => 'Mozambique', - 'na' => 'Namibia', - 'nc' => 'New Caledonia', - 'ne' => 'Niger', - 'nf' => 'Norfolk Island', - 'ng' => 'Nigeria', - 'ni' => 'Nicaragua', - 'nl' => 'Netherlands', - 'no' => 'Norway', - 'np' => 'Nepal', - 'nq' => 'Dronning Maud Land', - 'nr' => 'Nauru', - 'nu' => 'Niue', - 'nz' => 'New Zealand', - 'om' => 'Oman', - 'pa' => 'Panama', - 'pc' => 'Pacific Islands Trust Territory', - 'pe' => 'Peru', - 'pf' => 'French Polynesia', - 'pg' => 'Papua New Guinea', - 'ph' => 'Philippines', - 'pk' => 'Pakistan', - 'pl' => 'Poland', - 'pm' => 'Saint Pierre and Miquelon', - 'pn' => 'Pitcairn Islands', - 'pr' => 'Puerto Rico', - 'ps' => 'Palestinian Territories', - 'pt' => 'Portugal', - 'pu' => 'U.S. Miscellaneous Pacific Islands', - 'pw' => 'Palau', - 'py' => 'Paraguay', - 'pz' => 'Panama Canal Zone', - 'qa' => 'Qatar', - 'qo' => 'Outlying Oceania', - 're' => 'Réunion', - 'ro' => 'Romania', - 'rs' => 'Serbia', - 'ru' => 'Russia', - 'rw' => 'Rwanda', - 'sa' => 'Saudi Arabia', - 'sb' => 'Solomon Islands', - 'sc' => 'Seychelles', - 'sd' => 'Sudan', - 'se' => 'Sweden', - 'sg' => 'Singapore', - 'sh' => 'Saint Helena', - 'si' => 'Slovenia', - 'sj' => 'Svalbard and Jan Mayen', - 'sk' => 'Slovakia', - 'sl' => 'Sierra Leone', - 'sm' => 'San Marino', - 'sn' => 'Senegal', - 'so' => 'Somalia', - 'sr' => 'Suriname', - 'st' => 'São Tomé and Príncipe', - 'sv' => 'El Salvador', - 'sx' => 'St. Maarten', - 'sy' => 'Syria', - 'sz' => 'Swaziland', - 'ta' => 'Tristan da Cunha', - 'tc' => 'Turks and Caicos Islands', - 'td' => 'Chad', - 'tf' => 'French Southern Territories', - 'tg' => 'Togo', - 'th' => 'Thailand', - 'tj' => 'Tajikistan', - 'tk' => 'Tokelau', - 'tl' => 'East Timor', - 'tm' => 'Turkmenistan', - 'tn' => 'Tunisia', - 'to' => 'Tonga', - 'tr' => 'Turkey', - 'tt' => 'Trinidad and Tobago', - 'tv' => 'Tuvalu', - 'tw' => 'Taiwan', - 'tz' => 'Tanzania', - 'ua' => 'Ukraine', - 'ug' => 'Uganda', - 'um' => 'U.S. Minor Outlying Islands', - 'us' => 'United States', - 'uy' => 'Uruguay', - 'uz' => 'Uzbekistan', - 'va' => 'Vatican City', - 'vc' => 'Saint Vincent and the Grenadines', - 've' => 'Venezuela', - 'vg' => 'British Virgin Islands', - 'vi' => 'U.S. Virgin Islands', - 'vn' => 'Vietnam', - 'vu' => 'Vanuatu', - 'wf' => 'Wallis and Futuna', - 'wk' => 'Wake Island', - 'ws' => 'Samoa', - 'ye' => 'Yemen', - 'yt' => 'Mayotte', - 'za' => 'South Africa', - 'zm' => 'Zambia', - 'zw' => 'Zimbabwe', - 'zz' => 'Unknown Region', - ), +return [ + 'monthNames' => [ + 'wide' => [ + 1 => 'January', + 2 => 'February', + 3 => 'March', + 4 => 'April', + 5 => 'May', + 6 => 'June', + 7 => 'July', + 8 => 'August', + 9 => 'September', + 10 => 'October', + 11 => 'November', + 12 => 'December', + ], + 'abbreviated' => [ + 1 => 'Jan', + 2 => 'Feb', + 3 => 'Mar', + 4 => 'Apr', + 5 => 'May', + 6 => 'Jun', + 7 => 'Jul', + 8 => 'Aug', + 9 => 'Sep', + 10 => 'Oct', + 11 => 'Nov', + 12 => 'Dec', + ], + 'narrow' => [ + 1 => 'J', + 2 => 'F', + 3 => 'M', + 4 => 'A', + 5 => 'M', + 6 => 'J', + 7 => 'J', + 8 => 'A', + 9 => 'S', + 10 => 'O', + 11 => 'N', + 12 => 'D', + ], + ], + 'amName' => 'AM', + 'pmName' => 'PM', + 'weekDayNames' => [ + 'wide' => [ + 1 => 'Sunday', + 2 => 'Monday', + 3 => 'Tuesday', + 4 => 'Wednesday', + 5 => 'Thursday', + 6 => 'Friday', + 7 => 'Saturday', + ], + 'abbreviated' => [ + 1 => 'Sun', + 2 => 'Mon', + 3 => 'Tue', + 4 => 'Wed', + 5 => 'Thu', + 6 => 'Fri', + 7 => 'Sat', + ], + 'narrow' => [ + 1 => 'S', + 2 => 'M', + 3 => 'T', + 4 => 'W', + 5 => 'T', + 6 => 'F', + 7 => 'S', + ], + ], + 'orientation' => 'ltr', + 'languages' => [ + 'aa' => 'Afar', + 'ab' => 'Abkhazian', + 'ae' => 'Avestan', + 'af' => 'Afrikaans', + 'ak' => 'Akan', + 'am' => 'Amharic', + 'an' => 'Aragonese', + 'ar' => 'Arabic', + 'as' => 'Assamese', + 'av' => 'Avaric', + 'ay' => 'Aymara', + 'az' => 'Azeri', + 'ba' => 'Bashkir', + 'be' => 'Belarusian', + 'bg' => 'Bulgarian', + 'bh' => 'Bihari', + 'bi' => 'Bislama', + 'bm' => 'Bambara', + 'bn' => 'Bengali', + 'bo' => 'Tibetan', + 'br' => 'Breton', + 'bs' => 'Bosnian', + 'ca' => 'Catalan', + 'ce' => 'Chechen', + 'ch' => 'Chamorro', + 'co' => 'Corsican', + 'cr' => 'Cree', + 'cs' => 'Czech', + 'cu' => 'Church Slavic', + 'cv' => 'Chuvash', + 'cy' => 'Welsh', + 'da' => 'Danish', + 'de' => 'German', + 'dv' => 'Divehi', + 'dz' => 'Dzongkha', + 'ee' => 'Ewe', + 'el' => 'Greek', + 'en' => 'English', + 'eo' => 'Esperanto', + 'es' => 'Spanish', + 'et' => 'Estonian', + 'eu' => 'Basque', + 'fa' => 'Persian', + 'ff' => 'Fulah', + 'fi' => 'Finnish', + 'fj' => 'Fijian', + 'fo' => 'Faroese', + 'fr' => 'French', + 'fy' => 'Western Frisian', + 'ga' => 'Irish', + 'gd' => 'Scottish Gaelic', + 'gl' => 'Galician', + 'gn' => 'Guarani', + 'gu' => 'Gujarati', + 'gv' => 'Manx', + 'ha' => 'Hausa', + 'he' => 'Hebrew', + 'hi' => 'Hindi', + 'ho' => 'Hiri Motu', + 'hr' => 'Croatian', + 'ht' => 'Haitian', + 'hu' => 'Hungarian', + 'hy' => 'Armenian', + 'hz' => 'Herero', + 'ia' => 'Interlingua', + 'id' => 'Indonesian', + 'ie' => 'Interlingue', + 'ig' => 'Igbo', + 'ii' => 'Sichuan Yi', + 'ik' => 'Inupiaq', + 'io' => 'Ido', + 'is' => 'Icelandic', + 'it' => 'Italian', + 'iu' => 'Inuktitut', + 'ja' => 'Japanese', + 'jv' => 'Javanese', + 'ka' => 'Georgian', + 'kg' => 'Kongo', + 'ki' => 'Kikuyu', + 'kj' => 'Kuanyama', + 'kk' => 'Kazakh', + 'kl' => 'Kalaallisut', + 'km' => 'Khmer', + 'kn' => 'Kannada', + 'ko' => 'Korean', + 'kr' => 'Kanuri', + 'ks' => 'Kashmiri', + 'ku' => 'Kurdish', + 'kv' => 'Komi', + 'kw' => 'Cornish', + 'ky' => 'Kirghiz', + 'la' => 'Latin', + 'lb' => 'Luxembourgish', + 'lg' => 'Ganda', + 'li' => 'Limburgish', + 'ln' => 'Lingala', + 'lo' => 'Lao', + 'lt' => 'Lithuanian', + 'lu' => 'Luba-Katanga', + 'lv' => 'Latvian', + 'mg' => 'Malagasy', + 'mh' => 'Marshallese', + 'mi' => 'Maori', + 'mk' => 'Macedonian', + 'ml' => 'Malayalam', + 'mn' => 'Mongolian', + 'mo' => 'Moldavian', + 'mr' => 'Marathi', + 'ms' => 'Malay', + 'mt' => 'Maltese', + 'my' => 'Burmese', + 'na' => 'Nauru', + 'nb' => 'Norwegian Bokmål', + 'nd' => 'North Ndebele', + 'ne' => 'Nepali', + 'ng' => 'Ndonga', + 'nl' => 'Dutch', + 'nn' => 'Norwegian Nynorsk', + 'no' => 'Norwegian', + 'nr' => 'South Ndebele', + 'nv' => 'Navajo', + 'ny' => 'Nyanja', + 'oc' => 'Occitan', + 'oj' => 'Ojibwa', + 'om' => 'Oromo', + 'or' => 'Oriya', + 'os' => 'Ossetic', + 'pa' => 'Punjabi', + 'pi' => 'Pali', + 'pl' => 'Polish', + 'ps' => 'Pushto', + 'pt' => 'Portuguese', + 'qu' => 'Quechua', + 'rm' => 'Romansh', + 'rn' => 'Rundi', + 'ro' => 'Romanian', + 'ru' => 'Russian', + 'rw' => 'Kinyarwanda', + 'sa' => 'Sanskrit', + 'sc' => 'Sardinian', + 'sd' => 'Sindhi', + 'se' => 'Northern Sami', + 'sg' => 'Sango', + 'sh' => 'Serbo-Croatian', + 'si' => 'Sinhala', + 'sk' => 'Slovak', + 'sl' => 'Slovenian', + 'sm' => 'Samoan', + 'sn' => 'Shona', + 'so' => 'Somali', + 'sq' => 'Albanian', + 'sr' => 'Serbian', + 'ss' => 'Swati', + 'st' => 'Southern Sotho', + 'su' => 'Sundanese', + 'sv' => 'Swedish', + 'sw' => 'Swahili', + 'ta' => 'Tamil', + 'te' => 'Telugu', + 'tg' => 'Tajik', + 'th' => 'Thai', + 'ti' => 'Tigrinya', + 'tk' => 'Turkmen', + 'tl' => 'Tagalog', + 'tn' => 'Tswana', + 'to' => 'Tongan', + 'tr' => 'Turkish', + 'ts' => 'Tsonga', + 'tt' => 'Tatar', + 'tw' => 'Twi', + 'ty' => 'Tahitian', + 'ug' => 'Uyghur', + 'uk' => 'Ukrainian', + 'ur' => 'Urdu', + 'uz' => 'Uzbek', + 've' => 'Venda', + 'vi' => 'Vietnamese', + 'vo' => 'Volapük', + 'wa' => 'Walloon', + 'wo' => 'Wolof', + 'xh' => 'Xhosa', + 'yi' => 'Yiddish', + 'yo' => 'Yoruba', + 'za' => 'Zhuang', + 'zh' => 'Chinese', + 'zu' => 'Zulu', + ], + 'continents' => [ + '001' => 'World', + '010' => 'Africa', + '011' => 'Western Africa', + '012' => 'Eastern Africa', + '013' => 'Northern Africa', + '014' => 'Middle Africa', + '015' => 'Southern Africa', + '020' => 'Americas', + '021' => 'North America', + '022' => 'South America', + '023' => 'Central America', + '024' => 'Latin America', + '025' => 'Caribbean', + '030' => 'Asia', + '031' => 'Central Asia', + '032' => 'Western Asia', + '033' => 'Eastern Asia', + '034' => 'Southern Asia', + '035' => 'South-Eastern Asia', + '036' => 'South-Central Asia', + '037' => 'Middle East', + '040' => 'Europe', + '041' => 'Eastern Europe', + '042' => 'Northern Europe', + '043' => 'Western Europe', + '044' => 'Southern Europe', + '050' => 'Australia and New Zealand', + '051' => 'Oceania', + '052' => 'Melanesia', + '053' => 'Micronesian Region', + '054' => 'Polynesia', + ], + 'countries' => [ + 'ac' => 'Ascension Island', + 'ad' => 'Andorra', + 'ae' => 'United Arab Emirates', + 'af' => 'Afghanistan', + 'ag' => 'Antigua and Barbuda', + 'ai' => 'Anguilla', + 'al' => 'Albania', + 'am' => 'Armenia', + 'an' => 'Netherlands Antilles', + 'ao' => 'Angola', + 'aq' => 'Antarctica', + 'ar' => 'Argentina', + 'as' => 'American Samoa', + 'at' => 'Austria', + 'au' => 'Australia', + 'aw' => 'Aruba', + 'ax' => 'Åland Islands', + 'az' => 'Azerbaijan', + 'ba' => 'Bosnia and Herzegovina', + 'bb' => 'Barbados', + 'bd' => 'Bangladesh', + 'be' => 'Belgium', + 'bf' => 'Burkina Faso', + 'bg' => 'Bulgaria', + 'bh' => 'Bahrain', + 'bi' => 'Burundi', + 'bj' => 'Benin', + 'bl' => 'Saint Barthélemy', + 'bm' => 'Bermuda', + 'bn' => 'Brunei', + 'bo' => 'Bolivia', + 'bq' => 'Bonaire, Saint Eustatius, and Saba', + 'br' => 'Brazil', + 'bs' => 'Bahamas', + 'bt' => 'Bhutan', + 'bv' => 'Bouvet Island', + 'bw' => 'Botswana', + 'by' => 'Belarus', + 'bz' => 'Belize', + 'ca' => 'Canada', + 'cc' => 'Cocos [Keeling] Islands', + 'cd' => 'Congo [DRC]', + 'cf' => 'Central African Republic', + 'cg' => 'Congo [Republic]', + 'ch' => 'Switzerland', + 'ci' => 'Ivory Coast', + 'ck' => 'Cook Islands', + 'cl' => 'Chile', + 'cm' => 'Cameroon', + 'cn' => 'China', + 'co' => 'Colombia', + 'cp' => 'Clipperton Island', + 'cr' => 'Costa Rica', + 'cs' => 'Serbia and Montenegro', + 'ct' => 'Canton and Enderbury Islands', + 'cu' => 'Cuba', + 'cv' => 'Cape Verde', + 'cw' => 'Curacao', + 'cx' => 'Christmas Island', + 'cy' => 'Cyprus', + 'cz' => 'Czech Republic', + 'de' => 'Germany', + 'dg' => 'Diego Garcia', + 'dj' => 'Djibouti', + 'dk' => 'Denmark', + 'dm' => 'Dominica', + 'do' => 'Dominican Republic', + 'dz' => 'Algeria', + 'ea' => 'Ceuta and Melilla', + 'ec' => 'Ecuador', + 'ee' => 'Estonia', + 'eg' => 'Egypt', + 'eh' => 'Western Sahara', + 'er' => 'Eritrea', + 'es' => 'Spain', + 'et' => 'Ethiopia', + 'eu' => 'European Union', + 'fi' => 'Finland', + 'fj' => 'Fiji', + 'fk' => 'Falkland Islands [Islas Malvinas]', + 'fm' => 'Micronesia', + 'fo' => 'Faroe Islands', + 'fq' => 'French Southern and Antarctic Territories', + 'fr' => 'France', + 'fx' => 'Metropolitan France', + 'ga' => 'Gabon', + 'gb' => 'United Kingdom', + 'gd' => 'Grenada', + 'ge' => 'Georgia', + 'gf' => 'French Guiana', + 'gg' => 'Guernsey', + 'gh' => 'Ghana', + 'gi' => 'Gibraltar', + 'gl' => 'Greenland', + 'gm' => 'Gambia', + 'gn' => 'Guinea', + 'gp' => 'Guadeloupe', + 'gq' => 'Equatorial Guinea', + 'gr' => 'Greece', + 'gs' => 'South Georgia and the South Sandwich Islands', + 'gt' => 'Guatemala', + 'gu' => 'Guam', + 'gw' => 'Guinea-Bissau', + 'gy' => 'Guyana', + 'hk' => 'Hong Kong', + 'hm' => 'Heard Island and McDonald Islands', + 'hn' => 'Honduras', + 'hr' => 'Croatia', + 'ht' => 'Haiti', + 'hu' => 'Hungary', + 'ic' => 'Canary Islands', + 'id' => 'Indonesia', + 'ie' => 'Ireland', + 'il' => 'Israel', + 'im' => 'Isle of Man', + 'in' => 'India', + 'io' => 'British Indian Ocean Territory', + 'iq' => 'Iraq', + 'ir' => 'Iran', + 'is' => 'Iceland', + 'it' => 'Italy', + 'je' => 'Jersey', + 'jm' => 'Jamaica', + 'jo' => 'Jordan', + 'jp' => 'Japan', + 'jt' => 'Johnston Island', + 'ke' => 'Kenya', + 'kg' => 'Kyrgyzstan', + 'kh' => 'Cambodia', + 'ki' => 'Kiribati', + 'km' => 'Comoros', + 'kn' => 'Saint Kitts and Nevis', + 'kp' => 'North Korea', + 'kr' => 'South Korea', + 'kw' => 'Kuwait', + 'ky' => 'Cayman Islands', + 'kz' => 'Kazakhstan', + 'la' => 'Laos', + 'lb' => 'Lebanon', + 'lc' => 'Saint Lucia', + 'li' => 'Liechtenstein', + 'lk' => 'Sri Lanka', + 'lr' => 'Liberia', + 'ls' => 'Lesotho', + 'lt' => 'Lithuania', + 'lu' => 'Luxembourg', + 'lv' => 'Latvia', + 'ly' => 'Libya', + 'ma' => 'Morocco', + 'mc' => 'Monaco', + 'md' => 'Moldova', + 'me' => 'Montenegro', + 'mf' => 'Saint Martin', + 'mg' => 'Madagascar', + 'mh' => 'Marshall Islands', + 'mi' => 'Midway Islands', + 'mk' => 'Macedonia [FYROM]', + 'ml' => 'Mali', + 'mm' => 'Myanmar [Burma]', + 'mn' => 'Mongolia', + 'mo' => 'Macau', + 'mp' => 'Northern Mariana Islands', + 'mq' => 'Martinique', + 'mr' => 'Mauritania', + 'ms' => 'Montserrat', + 'mt' => 'Malta', + 'mu' => 'Mauritius', + 'mv' => 'Maldives', + 'mw' => 'Malawi', + 'mx' => 'Mexico', + 'my' => 'Malaysia', + 'mz' => 'Mozambique', + 'na' => 'Namibia', + 'nc' => 'New Caledonia', + 'ne' => 'Niger', + 'nf' => 'Norfolk Island', + 'ng' => 'Nigeria', + 'ni' => 'Nicaragua', + 'nl' => 'Netherlands', + 'no' => 'Norway', + 'np' => 'Nepal', + 'nq' => 'Dronning Maud Land', + 'nr' => 'Nauru', + 'nu' => 'Niue', + 'nz' => 'New Zealand', + 'om' => 'Oman', + 'pa' => 'Panama', + 'pc' => 'Pacific Islands Trust Territory', + 'pe' => 'Peru', + 'pf' => 'French Polynesia', + 'pg' => 'Papua New Guinea', + 'ph' => 'Philippines', + 'pk' => 'Pakistan', + 'pl' => 'Poland', + 'pm' => 'Saint Pierre and Miquelon', + 'pn' => 'Pitcairn Islands', + 'pr' => 'Puerto Rico', + 'ps' => 'Palestinian Territories', + 'pt' => 'Portugal', + 'pu' => 'U.S. Miscellaneous Pacific Islands', + 'pw' => 'Palau', + 'py' => 'Paraguay', + 'pz' => 'Panama Canal Zone', + 'qa' => 'Qatar', + 'qo' => 'Outlying Oceania', + 're' => 'Réunion', + 'ro' => 'Romania', + 'rs' => 'Serbia', + 'ru' => 'Russia', + 'rw' => 'Rwanda', + 'sa' => 'Saudi Arabia', + 'sb' => 'Solomon Islands', + 'sc' => 'Seychelles', + 'sd' => 'Sudan', + 'se' => 'Sweden', + 'sg' => 'Singapore', + 'sh' => 'Saint Helena', + 'si' => 'Slovenia', + 'sj' => 'Svalbard and Jan Mayen', + 'sk' => 'Slovakia', + 'sl' => 'Sierra Leone', + 'sm' => 'San Marino', + 'sn' => 'Senegal', + 'so' => 'Somalia', + 'sr' => 'Suriname', + 'st' => 'São Tomé and Príncipe', + 'sv' => 'El Salvador', + 'sx' => 'St. Maarten', + 'sy' => 'Syria', + 'sz' => 'Swaziland', + 'ta' => 'Tristan da Cunha', + 'tc' => 'Turks and Caicos Islands', + 'td' => 'Chad', + 'tf' => 'French Southern Territories', + 'tg' => 'Togo', + 'th' => 'Thailand', + 'tj' => 'Tajikistan', + 'tk' => 'Tokelau', + 'tl' => 'East Timor', + 'tm' => 'Turkmenistan', + 'tn' => 'Tunisia', + 'to' => 'Tonga', + 'tr' => 'Turkey', + 'tt' => 'Trinidad and Tobago', + 'tv' => 'Tuvalu', + 'tw' => 'Taiwan', + 'tz' => 'Tanzania', + 'ua' => 'Ukraine', + 'ug' => 'Uganda', + 'um' => 'U.S. Minor Outlying Islands', + 'us' => 'United States', + 'uy' => 'Uruguay', + 'uz' => 'Uzbekistan', + 'va' => 'Vatican City', + 'vc' => 'Saint Vincent and the Grenadines', + 've' => 'Venezuela', + 'vg' => 'British Virgin Islands', + 'vi' => 'U.S. Virgin Islands', + 'vn' => 'Vietnam', + 'vu' => 'Vanuatu', + 'wf' => 'Wallis and Futuna', + 'wk' => 'Wake Island', + 'ws' => 'Samoa', + 'ye' => 'Yemen', + 'yt' => 'Mayotte', + 'za' => 'South Africa', + 'zm' => 'Zambia', + 'zw' => 'Zimbabwe', + 'zz' => 'Unknown Region', + ], -); \ No newline at end of file +]; \ No newline at end of file diff --git a/framework/messages/ar/core.php b/framework/messages/ar/core.php index fc4f20e..0b3ff80 100644 --- a/framework/messages/ar/core.php +++ b/framework/messages/ar/core.php @@ -186,5 +186,5 @@ 'You cannot delete the last remaining record in table {table}!' => 'لا يمكنك حذف السجل الأخير المتبقي في الجدول {table}!', 'Warnings' => 'تحذيرات', 'Wrong column name: {index} in table {table}' => 'اسم عمود غير صحيح: "{index}" في الجدول "{table}" - لا يمكن الوصول إلى خاصية غير موجودة لكائن AR', - 'Wrong params for chunk size: {size} or callback method is callable.' => 'Wrong params for chunk size: {size} or callback method is callable.', + 'Wrong params for chunk size: {size} or callback method is not callable.' => 'معلمات خاطئة لحجم القطعة: {size} أو طريقة رد الاتصال غير قابلة للاستدعاء.', ); \ No newline at end of file diff --git a/framework/messages/de/core.php b/framework/messages/de/core.php index d2939ca..db3e87b 100644 --- a/framework/messages/de/core.php +++ b/framework/messages/de/core.php @@ -184,5 +184,5 @@ 'You cannot delete the last remaining record in table {table}!' => 'Sie können die letzten verbliebenen Satz in der Tabelle {table} nicht löschen!', 'Warnings' => 'Warnungen', 'Wrong column name: {index} in table {table}' => 'Falsche Spalte name: {index} in Tabelle {table}', -'Wrong params for chunk size: {size} or callback method is callable.' => 'Wrong params for chunk size: {size} or callback method is callable.', +'Wrong params for chunk size: {size} or callback method is not callable.' => 'Falsche Parameter für Blockgröße: {size} oder Rückrufmethode können nicht aufgerufen werden.', ); \ No newline at end of file diff --git a/framework/messages/en/core.php b/framework/messages/en/core.php index 162f20d..d8075f2 100644 --- a/framework/messages/en/core.php +++ b/framework/messages/en/core.php @@ -186,5 +186,5 @@ 'You cannot delete the last remaining record in table {table}!' => 'You cannot delete the last remaining record in table {table}!', 'Warnings' => 'Warnings', 'Wrong column name: {index} in table {table}' => 'Wrong column name: "{index}" in table "{table}" - can\'t access non existent property of AR object', - 'Wrong params for chunk size: {size} or callback method is callable.' => 'Wrong params for chunk size: {size} or callback method is callable.', + 'Wrong params for chunk size: {size} or callback method is not callable.' => 'Wrong params for chunk size: {size} or callback method is not callable.', ); \ No newline at end of file diff --git a/framework/messages/es/core.php b/framework/messages/es/core.php index c0b51b9..9ce0e06 100644 --- a/framework/messages/es/core.php +++ b/framework/messages/es/core.php @@ -186,5 +186,5 @@ 'You cannot delete the last remaining record in table {table}!' => 'No se puede eliminar el único registro existente en la tabla {table}.', 'Warnings' => 'Advertencias', 'Wrong column name: {index} in table {table}' => 'Nombre de columna incorrecta: {index} en la tabla {table}.', - 'Wrong params for chunk size: {size} or callback method is callable.' => 'Wrong params for chunk size: {size} or callback method is callable.', + 'Wrong params for chunk size: {size} or callback method is not callable.' => 'Parámetros incorrectos para el tamaño del fragmento: {size} o el método de devolución de llamada no se puede llamar.', ); \ No newline at end of file diff --git a/framework/messages/fr/core.php b/framework/messages/fr/core.php index 721bcd3..f1b8f69 100644 --- a/framework/messages/fr/core.php +++ b/framework/messages/fr/core.php @@ -186,5 +186,5 @@ 'You cannot delete the last remaining record in table {table}!' => 'Vous ne pouvez pas supprimer le dernier enregistrement restante dans le tableau {table}!', 'Warnings' => 'Avertissements', 'Wrong column name: {index} in table {table}' => 'Nom de colonne incorrect: {index} dans la table {table}', - 'Wrong params for chunk size: {size} or callback method is callable.' => 'Wrong params for chunk size: {size} or callback method is callable.', + 'Wrong params for chunk size: {size} or callback method is not callable.' => 'Mauvais paramètres pour la taille du bloc: {size} ou la méthode de rappel ne peut pas être appelée.', ); \ No newline at end of file diff --git a/framework/messages/he/core.php b/framework/messages/he/core.php index 364e6b7..212e93a 100644 --- a/framework/messages/he/core.php +++ b/framework/messages/he/core.php @@ -186,5 +186,5 @@ 'You cannot delete the last remaining record in table {table}!' => 'לא ניתן למחוק את הרשומה האחרונה שנותרה בטבלה {table}!', 'Warnings' => 'אזהרות', 'Wrong column name: {index} in table {table}' => 'שם עמוד שגוי: {index} בטבלה {table}', - 'Wrong params for chunk size: {size} or callback method is callable.' => 'Wrong params for chunk size: {size} or callback method is callable.', + 'Wrong params for chunk size: {size} or callback method is not callable.' => 'פרמטרים שגויים בגודל נתח: {size} או מטודות התקשרות אינה תקינה.', ); \ No newline at end of file diff --git a/framework/messages/it/core.php b/framework/messages/it/core.php index a9b904e..7020d1d 100644 --- a/framework/messages/it/core.php +++ b/framework/messages/it/core.php @@ -186,5 +186,5 @@ 'You cannot delete the last remaining record in table {table}!' => 'Non è possibile eliminare l\'ultimo record rimasto nella tabella {table}!', 'Warnings' => 'Avvertenze', 'Wrong column name: {index} in table {table}' => 'Colonna sbagliato nome: {index} nella tabella {table}', - 'Wrong params for chunk size: {size} or callback method is callable.' => 'Wrong params for chunk size: {size} or callback method is callable.', + 'Wrong params for chunk size: {size} or callback method is not callable.' => 'Parametri errati per la dimensione del blocco: {size} o il metodo di callback non è richiamabile.', ); \ No newline at end of file diff --git a/framework/messages/nl/core.php b/framework/messages/nl/core.php index 1ce9f5a..14259d4 100644 --- a/framework/messages/nl/core.php +++ b/framework/messages/nl/core.php @@ -186,5 +186,5 @@ 'You cannot delete the last remaining record in table {table}!' => 'U kunt de laatst overgebleven record niet verwijderen in tabel {table}!', 'Warnings' => 'Waarschuwingen', 'Wrong column name: {index} in table {table}' => 'naam verkeerd column: {index} in tabel {table}', - 'Wrong params for chunk size: {size} or callback method is callable.' => 'Wrong params for chunk size: {size} or callback method is callable.', + 'Wrong params for chunk size: {size} or callback method is not callable.' => 'Verkeerde parameters voor chunkgrootte: {size} of callback-methode is niet opvraagbaar.', ); \ No newline at end of file diff --git a/framework/messages/pl/core.php b/framework/messages/pl/core.php index 0c14653..9e579da 100644 --- a/framework/messages/pl/core.php +++ b/framework/messages/pl/core.php @@ -186,5 +186,5 @@ 'You cannot delete the last remaining record in table {table}!' => 'Nie możesz skasować ostatniego rekordu który pozostał {table}!', 'Warnings' => 'Ostrzeżenia', 'Wrong column name: {index} in table {table}' => 'Zła nazwa kolumny: {index} w tablicy {table}', - 'Wrong params for chunk size: {size} or callback method is callable.' => 'Wrong params for chunk size: {size} or callback method is callable.', + 'Wrong params for chunk size: {size} or callback method is not callable.' => 'Nieprawidłowe parametry rozmiaru fragmentu: {size} lub metoda wywołania zwrotnego nie może zostać wywołana.', ); \ No newline at end of file diff --git a/framework/messages/ru/core.php b/framework/messages/ru/core.php index 0957afd..662a20b 100644 --- a/framework/messages/ru/core.php +++ b/framework/messages/ru/core.php @@ -186,5 +186,5 @@ 'You cannot delete the last remaining record in table {table}!' => 'Вы не можете удалить последнюю оставшуюся запись в таблице {table}!', 'Warnings' => 'Предупреждения', 'Wrong column name: {index} in table {table}' => 'Неверное имя колонки: {index} в таблице {table}', - 'Wrong params for chunk size: {size} or callback method is callable.' => 'Wrong params for chunk size: {size} or callback method is callable.', + 'Wrong params for chunk size: {size} or callback method is not callable.' => 'Неправильные параметры для размера блока: {size} или метод обратного вызова не доступен.', ); \ No newline at end of file diff --git a/utils/tests/inc/filter/test.php b/utils/tests/inc/filter/test.php index 2b84f8a..fd3b130 100644 --- a/utils/tests/inc/filter/test.php +++ b/utils/tests/inc/filter/test.php @@ -18,10 +18,10 @@ $count = 0; foreach($val as $v_key => $v_val){ if($count++ % $span == 0) $content .= '</tr><tr>'; - $parameters = (!is_array($v_val)) ? array($v_val) : $v_val; - $expected_result = isset($v_val[2]) ? $v_val[2]: true; - $result = call_user_func_array(array('CFilter', $key), $parameters); - $content .= '<td>'.$parameters[0].'</td> + $parameters = ( ! is_array($v_val)) ? [$v_val] : $v_val; + $expected_result = isset($v_val[2]) ? $v_val[2] : true; + $result = call_user_func_array(['CFilter', $key], $parameters); + $content .= '<td>'.$parameters[0].'</td> <td>'.$parameters[1].'</td> <td>'.$result.'</td> <td class="align-center">'.(($parameters[1] === $result) ? '<span class="true">not cleaned</span>' : '<span class="false">cleaned</span>').'</td> diff --git a/utils/tests/index.php b/utils/tests/index.php index 8d3df8e..a185c10 100644 --- a/utils/tests/index.php +++ b/utils/tests/index.php @@ -5,18 +5,18 @@ * This script will run tests on framework and existing applications */ -$arr_projects = array( - 'framework' => array('name'=>'Framework', 'path'=>''), - 'hello-world' => array('name'=>'Hello World', 'path'=>'../../demos/hello-world/protected/controllers/'), - 'static-site' => array('name'=>'Static Site', 'path'=>'../../demos/static-site/protected/controllers/'), - 'login-system' => array('name'=>'Simple Login System', 'path'=>'../../demos/login-system/protected/controllers/'), - 'simple-blog' => array('name'=>'Simple Blog Site', 'path'=>'../../demos/simple-blog/protected/controllers/'), - 'simple-cms' => array('name'=>'Simple CMS Site', 'path'=>'../../demos/simple-cms/protected/controllers/') -); -$arr_actions = array(); -$arr_operations = array(); +$arr_projects = [ + 'framework' => ['name' => 'Framework', 'path' => ''], + 'hello-world' => ['name' => 'Hello World', 'path' => '../../demos/hello-world/protected/controllers/'], + 'static-site' => ['name' => 'Static Site', 'path' => '../../demos/static-site/protected/controllers/'], + 'login-system' => ['name' => 'Simple Login System', 'path' => '../../demos/login-system/protected/controllers/'], + 'simple-blog' => ['name' => 'Simple Blog Site', 'path' => '../../demos/simple-blog/protected/controllers/'], + 'simple-cms' => ['name' => 'Simple CMS Site', 'path' => '../../demos/simple-cms/protected/controllers/'] +]; +$arr_actions = []; +$arr_operations = []; -$project = isset($_GET['project']) ? filter_var($_GET['project'], FILTER_SANITIZE_STRING) : ''; +$project = isset($_GET['project']) ? filter_var($_GET['project'], FILTER_SANITIZE_STRING) : ''; $action = isset($_GET['action']) ? filter_var($_GET['action'], FILTER_SANITIZE_STRING) : ''; $operation = isset($_GET['operation']) ? filter_var($_GET['operation'], FILTER_SANITIZE_STRING) : ''; $content = '<h2>Tester</h2>To run new test select a Project and then an appropriate Action from the left dropdown boxes.'; @@ -35,7 +35,7 @@ } if($project == 'framework'){ - $arr_actions = array('validator'=>'Validator', 'filter'=>'Filter'); + $arr_actions = ['validator' => 'Validator', 'filter' => 'Filter']; if(isset($arr_actions[$action])){ if(file_exists('inc/'.$action.'/data.php')){ include('inc/'.$action.'/data.php'); @@ -46,7 +46,7 @@ } } if($operation != ''){ - $test_data = array(); + $test_data = []; if($operation === 'all'){ $test_data = $prepare_data; }else{ @@ -61,7 +61,7 @@ $content = '<span class="failed">Wrong parameter passed! Cannot find "'.$action.'" action.</span>'; } }elseif(isset($arr_projects[$project])){ - $arr_actions = array('controller'=>'Controller'); + $arr_actions = ['controller' => 'Controller']; if(isset($arr_actions[$action])){ if(file_exists('inc/'.$action.'/data.php')){ include('inc/'.$action.'/data.php'); @@ -73,7 +73,7 @@ } } if($operation != ''){ - $test_data = array(); + $test_data = []; if($operation === 'all'){ $test_data = $prepare_data; }else{ @@ -99,11 +99,13 @@ //////////////////////////////////////////////////////////////////////////// -render_file(array( - 'arr_projects' => $arr_projects, - 'arr_actions' => $arr_actions, - 'arr_operations' => $arr_operations, - 'project' => $project, - 'action' => $action, - 'content' => $content -)); +render_file( + [ + 'arr_projects' => $arr_projects, + 'arr_actions' => $arr_actions, + 'arr_operations' => $arr_operations, + 'project' => $project, + 'action' => $action, + 'content' => $content + ] +); From b96368f78f8484106edf4bf4d3f58cd352ba1fcd Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 22 Aug 2020 20:44:15 +0300 Subject: [PATCH 29/45] Adding cache-clear command, preparing make:controller command --- framework/Apphp.php | 2 +- framework/components/CLogger.php | 8 +-- framework/console/CCacheClearCommand.php | 71 ++++++++++---------- framework/console/CMakeControllerCommand.php | 24 ++++++- 4 files changed, 63 insertions(+), 42 deletions(-) diff --git a/framework/Apphp.php b/framework/Apphp.php index 0e94742..a037185 100644 --- a/framework/Apphp.php +++ b/framework/Apphp.php @@ -292,7 +292,7 @@ public function run() { if ( ! in_array(APPHP_MODE, array('hidden', 'console')) ) { // Specify error settings - if (APPHP_MODE == 'debug' || APPHP_MODE == 'test') { + if (in_array(APPHP_MODE, ['debug', 'test'])) { error_reporting(E_ALL); ini_set('display_errors', 'On'); } else { diff --git a/framework/components/CLogger.php b/framework/components/CLogger.php index c975565..06e83ac 100644 --- a/framework/components/CLogger.php +++ b/framework/components/CLogger.php @@ -45,16 +45,14 @@ class CLogger extends CComponent function __construct() { $this->_enabled = CConfig::get('log.enable') !== '' ? CConfig::get('log.enable') : false; - $this->_logPath = APPHP_PATH.DS.(CConfig::get('log.path') !== '' ? CConfig::get('log.path') - : 'protected/tmp/logs/'); - $this->_fileExtension = CConfig::exists('log.fileExtension') && CConfig::get('log.fileExtension') !== '' - ? ltrim(CConfig::get('log.fileExtension'), '.') : 'php'; + $this->_logPath = APPHP_PATH.DS.(CConfig::get('log.path') !== '' ? CConfig::get('log.path') : 'protected/tmp/logs/'); + $this->_fileExtension = CConfig::exists('log.fileExtension') && CConfig::get('log.fileExtension') !== '' ? ltrim(CConfig::get('log.fileExtension'), '.') : 'php'; $this->_dateFormat = CConfig::get('log.dateFormat') !== '' ? CConfig::get('log.dateFormat') : ''; $this->_lifetime = CConfig::get('log.lifetime') !== '' ? CConfig::get('log.lifetime') : ''; $logThreshold = CConfig::get('log.threshold') !== '' ? CConfig::get('log.threshold') : ''; $logFilePermissions = CConfig::get('log.filePermissions') !== '' ? CConfig::get('log.filePermissions') : ''; - if ( ! file_exists($this->_logPath)) { + if ( APPHP_MODE !== 'console' && ! file_exists($this->_logPath)) { mkdir($this->_logPath, 0755, true); } diff --git a/framework/console/CCacheClearCommand.php b/framework/console/CCacheClearCommand.php index c571889..0deedcd 100644 --- a/framework/console/CCacheClearCommand.php +++ b/framework/console/CCacheClearCommand.php @@ -28,43 +28,44 @@ public static function handle($param = '') { $output = ''; - //var_dump($argv); - //var_dump($argc); - if (empty($param)) { - $output .= CConsole::redbg("No cache type for deleting is defined. Type cache:clear -help").PHP_EOL; -// } elseif ($param === '-h' || $param === '-help') { -// $output .= CConsole::yellow("Usage:") . PHP_EOL; -// $output .= " cache:clear-all\tFlush all application cache". PHP_EOL; -// $output .= " cache:clear [type]\tFlush specific application cache". PHP_EOL; -// $output .= " \t\t\t[type] - the type of cache to be removed: 'db', 'css', 'js' or 'all'". PHP_EOL; -// } elseif (in_array($param, ['db', 'css', 'js', 'all'])) { -// if($param == 'db' || $param == 'all'){ -// if (CConfig::get('cache.db.path') == '') { -// $output .= CConsole::redbg("Config value 'cache.db.path' is not defined. Check your configuration file.") . PHP_EOL; -// }else{ -// $result = CFile::emptyDirectory(CConfig::get('cache.db.path'), array('index.html')); -// $output .= 'DB cache ' . ($result ? 'successfully cleaned' : 'error'); -// } -// } -// if($param == 'css' || $param == 'all'){ -// if (CConfig::get('compression.css.path') == '') { -// $output .= CConsole::redbg("Config value 'compression.css.path' is not defined. Check your configuration file.") . PHP_EOL; -// }else{ -// $result = CFile::emptyDirectory(CConfig::get('compression.css.path'), array('index.html')); -// $output .= 'CSS cache ' . ($result ? 'successfully cleaned' : 'error'); -// } -// } -// if($param == 'js' || $param == 'all'){ -// if (CConfig::get('compression.js.path') == '') { -// $output .= CConsole::redbg("Config value 'compression.js.path' is not defined. Check your configuration file.") . PHP_EOL; -// }else{ -// $result = CFile::emptyDirectory(CConfig::get('compression.js.path'), array('index.html')); -// $output .= 'JS cache ' . ($result ? 'successfully cleaned' : 'error'); -// } -// } + $output .= CConsole::redbg("No cache type for deleting is defined. Type cache:clear -h or --help").PHP_EOL; + } + elseif ($param === '-h' || $param === '--help') { + $output .= CConsole::yellow("Usage:") . PHP_EOL; + $output .= " cache:clear-all\tFlush all application cache". PHP_EOL; + $output .= " cache:clear [type]\tFlush specific application cache". PHP_EOL; + $output .= " \t\t\t[type] - the type of cache to be removed: 'db', 'css', 'js' or 'all'". PHP_EOL; + } + elseif (in_array($param, ['db', 'css', 'js', 'all'])) { + if($param == 'db' || $param == 'all'){ + if (CConfig::get('cache.db.path') == '') { + $output .= CConsole::redbg("Config value 'cache.db.path' is not defined. Check your configuration file.") . PHP_EOL; + }else{ + $result = CFile::emptyDirectory(CConfig::get('cache.db.path'), array('index.html')); + $output .= 'DB cache ' . ($result ? 'successfully cleaned' : 'error'); + } + } + if($param == 'css' || $param == 'all'){ + if (CConfig::get('compression.css.path') == '') { + $output .= CConsole::redbg("Config value 'compression.css.path' is not defined. Check your configuration file.") . PHP_EOL; + }else{ + $result = CFile::emptyDirectory(CConfig::get('compression.css.path'), array('index.html')); + $output .= 'CSS cache ' . ($result ? 'successfully cleaned' : 'error'); + } + } + if($param == 'js' || $param == 'all'){ + if (CConfig::get('compression.js.path') == '') { + $output .= CConsole::redbg("Config value 'compression.js.path' is not defined. Check your configuration file.") . PHP_EOL; + }else{ + $result = CFile::emptyDirectory(CConfig::get('compression.js.path'), array('index.html')); + $output .= 'JS cache ' . ($result ? 'successfully cleaned' : 'error'); + } + } + } + else { + $output .= CConsole::redbg("No cache type for deleting is defined or wrong parameters. Type cache:clear -h or --help").PHP_EOL; } - return $output; } diff --git a/framework/console/CMakeControllerCommand.php b/framework/console/CMakeControllerCommand.php index f74f6b6..a545765 100644 --- a/framework/console/CMakeControllerCommand.php +++ b/framework/console/CMakeControllerCommand.php @@ -26,7 +26,29 @@ class CMakeControllerCommand implements IConsoleCommand */ public static function handle($param = '') { - $output = 'Controller created: '.$param; + $output = ''; + + if (empty($param)) { + $output .= CConsole::redbg("No model name is defined. Type make:controller -h or --help").PHP_EOL; + } + elseif ($param === '-h' || $param === '--help') { + $output .= CConsole::yellow("Usage:") . PHP_EOL; + $output .= " make:controller [model]\t Create a new controller class". PHP_EOL; + $output .= " \t\t\t\t[model] - Generate a resource controller for the given model.". PHP_EOL; + } + elseif (CValidator::isVariable($param)) { + // TODO: create controller + } + else { + if (!CValidator::isVariable($param)){ + $output .= CConsole::redbg("The model name must be a valid controller name (alphanumeric, starts with letter and can contain an underscore)! Please re-enter.").PHP_EOL; + } else { + $output .= CConsole::redbg("No model name is defined or wrong parameters. Type make:controller -h or --help").PHP_EOL; + } + } + + //echo $param; + //$output = 'Controller created: '.$param; return $output; } From 4892f05f44301c91b909c8ccdd573528bfdd049f Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 22 Aug 2020 23:01:24 +0300 Subject: [PATCH 30/45] added new helper CSecureHeaders --- CHANGELOG | 1 + composer.lock | 178 +++++++++--------- demos/static-site/protected/config/main.php | 8 +- .../static-site/protected/tmp/logs/error.log | 11 ++ framework/Apphp.php | 55 +++--- framework/core/CView.php | 17 +- framework/helpers/CSecureHeaders.php | 97 ++++++++++ 7 files changed, 243 insertions(+), 124 deletions(-) create mode 100644 framework/helpers/CSecureHeaders.php diff --git a/CHANGELOG b/CHANGELOG index aa2d71b..611d42b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,6 @@ Version 1.4.x - ---------------------------- +- New: added new helper CSecureHeaders - Enh: added possibility to hide system queries in debug panel - Enh: added possibility to close debug panel to minimum size - Enh: added possibility to get records by chunks with chuck() method of Active Record diff --git a/composer.lock b/composer.lock index 76c50b6..22c8d3f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,25 +4,25 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "a57272a03f835344d931c2917c41d6bd", + "content-hash": "e678da7134869beac197a8686ab32b43", "packages": [], "packages-dev": [ { "name": "doctrine/instantiator", - "version": "1.3.0", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "ae466f726242e637cebdd526a7d991b9433bacf1" + "reference": "f350df0268e904597e3bd9c4685c53e0e333feea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/ae466f726242e637cebdd526a7d991b9433bacf1", - "reference": "ae466f726242e637cebdd526a7d991b9433bacf1", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/f350df0268e904597e3bd9c4685c53e0e333feea", + "reference": "f350df0268e904597e3bd9c4685c53e0e333feea", "shasum": "" }, "require": { - "php": "^7.1" + "php": "^7.1 || ^8.0" }, "require-dev": { "doctrine/coding-standard": "^6.0", @@ -61,24 +61,24 @@ "constructor", "instantiate" ], - "time": "2019-10-21T16:45:58+00:00" + "time": "2020-05-29T17:27:14+00:00" }, { "name": "myclabs/deep-copy", - "version": "1.9.3", + "version": "1.10.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea" + "reference": "969b211f9a51aa1f6c01d1d2aef56d3bd91598e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/007c053ae6f31bba39dfa19a7726f56e9763bbea", - "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/969b211f9a51aa1f6c01d1d2aef56d3bd91598e5", + "reference": "969b211f9a51aa1f6c01d1d2aef56d3bd91598e5", "shasum": "" }, "require": { - "php": "^7.1" + "php": "^7.1 || ^8.0" }, "replace": { "myclabs/deep-copy": "self.version" @@ -109,7 +109,7 @@ "object", "object graph" ], - "time": "2019-08-09T12:45:53+00:00" + "time": "2020-06-29T13:22:24+00:00" }, { "name": "phar-io/manifest", @@ -215,28 +215,25 @@ }, { "name": "phpdocumentor/reflection-common", - "version": "2.0.0", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a" + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a", - "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", "shasum": "" }, "require": { - "php": ">=7.1" - }, - "require-dev": { - "phpunit/phpunit": "~6" + "php": "^7.2 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.x-dev" + "dev-2.x": "2.x-dev" } }, "autoload": { @@ -263,44 +260,41 @@ "reflection", "static analysis" ], - "time": "2018-08-07T13:53:10+00:00" + "time": "2020-06-27T09:03:43+00:00" }, { "name": "phpdocumentor/reflection-docblock", - "version": "4.3.2", + "version": "5.2.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e" + "reference": "d870572532cd70bc3fab58f2e23ad423c8404c44" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/b83ff7cfcfee7827e1e78b637a5904fe6a96698e", - "reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d870572532cd70bc3fab58f2e23ad423c8404c44", + "reference": "d870572532cd70bc3fab58f2e23ad423c8404c44", "shasum": "" }, "require": { - "php": "^7.0", - "phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0", - "phpdocumentor/type-resolver": "~0.4 || ^1.0.0", - "webmozart/assert": "^1.0" + "ext-filter": "*", + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^1.3", + "webmozart/assert": "^1.9.1" }, "require-dev": { - "doctrine/instantiator": "^1.0.5", - "mockery/mockery": "^1.0", - "phpunit/phpunit": "^6.4" + "mockery/mockery": "~1.3.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.x-dev" + "dev-master": "5.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] + "phpDocumentor\\Reflection\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -311,38 +305,40 @@ { "name": "Mike van Riel", "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "account@ijaap.nl" } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2019-09-12T14:27:41+00:00" + "time": "2020-08-15T11:14:08+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "1.0.1", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9" + "reference": "e878a14a65245fbe78f8080eba03b47c3b705651" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", - "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e878a14a65245fbe78f8080eba03b47c3b705651", + "reference": "e878a14a65245fbe78f8080eba03b47c3b705651", "shasum": "" }, "require": { - "php": "^7.1", + "php": "^7.2 || ^8.0", "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { - "ext-tokenizer": "^7.1", - "mockery/mockery": "~1", - "phpunit/phpunit": "^7.0" + "ext-tokenizer": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-1.x": "1.x-dev" } }, "autoload": { @@ -361,37 +357,37 @@ } ], "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "time": "2019-08-22T18:11:29+00:00" + "time": "2020-06-27T10:12:23+00:00" }, { "name": "phpspec/prophecy", - "version": "1.9.0", + "version": "1.11.1", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203" + "reference": "b20034be5efcdab4fb60ca3a29cba2949aead160" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/f6811d96d97bdf400077a0cc100ae56aa32b9203", - "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/b20034be5efcdab4fb60ca3a29cba2949aead160", + "reference": "b20034be5efcdab4fb60ca3a29cba2949aead160", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.0.2", - "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", - "sebastian/comparator": "^1.1|^2.0|^3.0", - "sebastian/recursion-context": "^1.0|^2.0|^3.0" + "doctrine/instantiator": "^1.2", + "php": "^7.2", + "phpdocumentor/reflection-docblock": "^5.0", + "sebastian/comparator": "^3.0 || ^4.0", + "sebastian/recursion-context": "^3.0 || ^4.0" }, "require-dev": { - "phpspec/phpspec": "^2.5|^3.2", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" + "phpspec/phpspec": "^6.0", + "phpunit/phpunit": "^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8.x-dev" + "dev-master": "1.11.x-dev" } }, "autoload": { @@ -424,7 +420,7 @@ "spy", "stub" ], - "time": "2019-10-03T11:07:50+00:00" + "time": "2020-07-08T12:44:21+00:00" }, { "name": "phpunit/php-code-coverage", @@ -676,20 +672,21 @@ "keywords": [ "tokenizer" ], + "abandoned": true, "time": "2019-09-17T06:23:10+00:00" }, { "name": "phpunit/phpunit", - "version": "7.5.18", + "version": "7.5.20", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "fcf6c4bfafaadc07785528b06385cce88935474d" + "reference": "9467db479d1b0487c99733bb1e7944d32deded2c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fcf6c4bfafaadc07785528b06385cce88935474d", - "reference": "fcf6c4bfafaadc07785528b06385cce88935474d", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9467db479d1b0487c99733bb1e7944d32deded2c", + "reference": "9467db479d1b0487c99733bb1e7944d32deded2c", "shasum": "" }, "require": { @@ -760,7 +757,7 @@ "testing", "xunit" ], - "time": "2019-12-06T05:14:37+00:00" + "time": "2020-01-08T08:45:45+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -1330,16 +1327,16 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.13.1", + "version": "v1.18.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3" + "reference": "1c302646f6efc070cd46856e600e5e0684d6b454" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", - "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/1c302646f6efc070cd46856e600e5e0684d6b454", + "reference": "1c302646f6efc070cd46856e600e5e0684d6b454", "shasum": "" }, "require": { @@ -1351,7 +1348,11 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.13-dev" + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { @@ -1384,27 +1385,27 @@ "polyfill", "portable" ], - "time": "2019-11-27T13:56:44+00:00" + "time": "2020-07-14T12:35:20+00:00" }, { "name": "theseer/tokenizer", - "version": "1.1.3", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9" + "reference": "75a63c33a8577608444246075ea0af0d052e452a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9", - "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/75a63c33a8577608444246075ea0af0d052e452a", + "reference": "75a63c33a8577608444246075ea0af0d052e452a", "shasum": "" }, "require": { "ext-dom": "*", "ext-tokenizer": "*", "ext-xmlwriter": "*", - "php": "^7.0" + "php": "^7.2 || ^8.0" }, "type": "library", "autoload": { @@ -1424,28 +1425,29 @@ } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "time": "2019-06-13T22:48:21+00:00" + "time": "2020-07-12T23:59:07+00:00" }, { "name": "webmozart/assert", - "version": "1.6.0", + "version": "1.9.1", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "573381c0a64f155a0d9a23f4b0c797194805b925" + "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/573381c0a64f155a0d9a23f4b0c797194805b925", - "reference": "573381c0a64f155a0d9a23f4b0c797194805b925", + "url": "https://api.github.com/repos/webmozart/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389", + "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0", + "php": "^5.3.3 || ^7.0 || ^8.0", "symfony/polyfill-ctype": "^1.8" }, "conflict": { - "vimeo/psalm": "<3.6.0" + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<3.9.1" }, "require-dev": { "phpunit/phpunit": "^4.8.36 || ^7.5.13" @@ -1472,13 +1474,13 @@ "check", "validate" ], - "time": "2019-11-24T13:36:37+00:00" + "time": "2020-07-08T17:02:28+00:00" } ], "aliases": [], - "minimum-stability": "stable", + "minimum-stability": "dev", "stability-flags": [], - "prefer-stable": false, + "prefer-stable": true, "prefer-lowest": false, "platform": { "php": ">=7.1.0" diff --git a/demos/static-site/protected/config/main.php b/demos/static-site/protected/config/main.php index 12dcbd0..37f25a8 100644 --- a/demos/static-site/protected/config/main.php +++ b/demos/static-site/protected/config/main.php @@ -146,13 +146,9 @@ 'recoveryType' => 'direct' /* 'direct' - send new password directly, 'recovery' - send link to recovery page */ ), - // Widget settings - 'widgets' => array( - 'paramKeysSensitive' => true, - ), - // Application helpers - 'helpers' => array(//'helper' => array('enable' => true, 'class' => 'Helper'), + 'helpers' => array( + //'helper' => array('enable' => true, 'class' => 'Helper'), ), // Application modules diff --git a/demos/static-site/protected/tmp/logs/error.log b/demos/static-site/protected/tmp/logs/error.log index e69de29..1d5734e 100644 --- a/demos/static-site/protected/tmp/logs/error.log +++ b/demos/static-site/protected/tmp/logs/error.log @@ -0,0 +1,11 @@ +[22-Aug-2020 19:45:03 UTC] PHP Fatal error: Uncaught Error: Class 'CSecureHeaders' not found in C:\xampp\htdocs\git\php-mvc-framework\framework\core\CView.php:655 +Stack trace: +#0 C:\xampp\htdocs\git\php-mvc-framework\framework\core\CView.php(346): CView->_renderHeaders() +#1 C:\xampp\htdocs\git\php-mvc-framework\demos\static-site\protected\controllers\IndexController.php(24): CView->render('index/index') +#2 C:\xampp\htdocs\git\php-mvc-framework\framework\core\CController.php(49): IndexController->indexAction() +#3 C:\xampp\htdocs\git\php-mvc-framework\framework\core\CRouter.php(232): CController->execute('indexAction', Array) +#4 C:\xampp\htdocs\git\php-mvc-framework\framework\Apphp.php(575): CRouter->route() +#5 C:\xampp\htdocs\git\php-mvc-framework\framework\Apphp.php(321): A->_runApp() +#6 C:\xampp\htdocs\git\php-mvc-framework\demos\static-site\index.php(24): A->run() +#7 {main} + thrown in C:\xampp\htdocs\git\php-mvc-framework\framework\core\CView.php on line 655 diff --git a/framework/Apphp.php b/framework/Apphp.php index a037185..5674174 100644 --- a/framework/Apphp.php +++ b/framework/Apphp.php @@ -123,33 +123,34 @@ class A ]; /** @var array */ private static $_coreHelpers = [ - 'CArray' => 'helpers/CArray.php', - 'CAuth' => 'helpers/CAuth.php', - 'CCache' => 'helpers/CCache.php', - 'CClass' => 'helpers/CClass.php', - 'CConvert' => 'helpers/CConvert.php', - 'CCurrency' => 'helpers/CCurrency.php', - 'CFile' => 'helpers/CFile.php', - 'CFilter' => 'helpers/CFilter.php', - 'CGeoLocation' => 'helpers/CGeoLocation.php', - 'CHash' => 'helpers/CHash.php', - 'CHtml' => 'helpers/CHtml.php', - 'CImage' => 'helpers/CImage.php', - 'CLoader' => 'helpers/CLoader.php', - 'CLocale' => 'helpers/CLocale.php', - 'CLog' => 'helpers/CLog.php', - 'CMailer' => 'helpers/CMailer.php', - 'CMinify' => 'helpers/CMinify.php', - 'CNumber' => 'helpers/CNumber.php', - 'COauth' => 'helpers/COauth.php', - 'CPdf' => 'helpers/CPdf.php', - 'CRss' => 'helpers/CRss.php', - 'CSessionCache' => 'helpers/CSessionCache.php', - 'CSoap' => 'helpers/CSoap.php', - 'CString' => 'helpers/CString.php', - 'CTime' => 'helpers/CTime.php', - 'CValidator' => 'helpers/CValidator.php', - 'CWidget' => 'helpers/CWidget.php', + 'CArray' => 'helpers/CArray.php', + 'CAuth' => 'helpers/CAuth.php', + 'CCache' => 'helpers/CCache.php', + 'CClass' => 'helpers/CClass.php', + 'CConvert' => 'helpers/CConvert.php', + 'CCurrency' => 'helpers/CCurrency.php', + 'CFile' => 'helpers/CFile.php', + 'CFilter' => 'helpers/CFilter.php', + 'CGeoLocation' => 'helpers/CGeoLocation.php', + 'CHash' => 'helpers/CHash.php', + 'CHtml' => 'helpers/CHtml.php', + 'CImage' => 'helpers/CImage.php', + 'CLoader' => 'helpers/CLoader.php', + 'CLocale' => 'helpers/CLocale.php', + 'CLog' => 'helpers/CLog.php', + 'CMailer' => 'helpers/CMailer.php', + 'CMinify' => 'helpers/CMinify.php', + 'CNumber' => 'helpers/CNumber.php', + 'COauth' => 'helpers/COauth.php', + 'CPdf' => 'helpers/CPdf.php', + 'CRss' => 'helpers/CRss.php', + 'CSecureHeaders' => 'helpers/CSecureHeaders.php', + 'CSessionCache' => 'helpers/CSessionCache.php', + 'CSoap' => 'helpers/CSoap.php', + 'CString' => 'helpers/CString.php', + 'CTime' => 'helpers/CTime.php', + 'CValidator' => 'helpers/CValidator.php', + 'CWidget' => 'helpers/CWidget.php', ]; /** @var array */ private static $_coreModules = [ diff --git a/framework/core/CView.php b/framework/core/CView.php index 4c8afc3..fa7542a 100644 --- a/framework/core/CView.php +++ b/framework/core/CView.php @@ -342,8 +342,9 @@ public function render($params, $isPartial = false, $return = false) if ($return) { return $output; } else { - $this->_isRendered = true; - echo $output; + $this->_isRendered = true; + $this->_renderHeaders(); + echo $output; } ///CDebug::addMessage('params', 'view', $this->__viewFile); @@ -644,5 +645,15 @@ public function isDefaultPage() true : false; } - + + /** + * Render headers + */ + private function _renderHeaders() + { + header('X-Author: ApPHP'); + //header('X-Framework-Name: ApPHP'); + //header('X-Framework-Version: '.A::version()); + //CSecureHeaders::renderHeaders(); + } } \ No newline at end of file diff --git a/framework/helpers/CSecureHeaders.php b/framework/helpers/CSecureHeaders.php new file mode 100644 index 0000000..17a7db9 --- /dev/null +++ b/framework/helpers/CSecureHeaders.php @@ -0,0 +1,97 @@ +<?php +/** + * CSecureHeaders is a helper class that provides basic secure headers + * + * @project ApPHP Framework + * @author ApPHP <info@apphp.com> + * @link http://www.apphpframework.com/ + * @copyright Copyright (c) 2012 - 2020 ApPHP Framework + * @license http://www.apphpframework.com/license/ + * + * PUBLIC (static): PROTECTED: PRIVATE: + * ---------- ---------- ---------- + * renderHeaders + * + */ + +class CSecureHeaders +{ + /** + * Render headers + * + * @return mixed + */ + public static function renderHeaders() + { + /* + |------------------------------------------------------------------------------- + | Prevent browsers from incorrectly detecting non-scripts as scripts + | SEE MORE: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options + |------------------------------------------------------------------------------- + */ + header('X-Content-Type-Options: nosniff'); + + /* + |------------------------------------------------------------------------------- + | Only allow my site to frame itself + | ------------------------ + | Other options: + | header('X-Frame-Options', 'ALLOW FROM https://example.com/') + | SEE MORE: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options + |------------------------------------------------------------------------------- + */ + header('X-Frame-Options: SAMEORIGIN'); + + /* + |------------------------------------------------------------------------------- + | Block pages from loading when they detect reflected XSS attacks + | SEE MORE: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection + |------------------------------------------------------------------------------- + */ + header('X-XSS-Protection: 1; mode=block'); + + /* + |------------------------------------------------------------------------------- + | Only connect to this site via HTTPS for the two years + | ------------------------ + | Other options: + | header('Strict-Transport-Security', 'max-age=63072000; includeSubDomains; preload') + | SEE MORE: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security + |------------------------------------------------------------------------------- + */ + header('Strict-Transport-Security: max-age=63072000'); + + /* + |------------------------------------------------------------------------------- + | Will not allow any information to be sent when a scheme downgrade happens (the user is navigating from HTTPS to HTTP) + | ------------------------ + | Other options: + | SEE MORE: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy + |------------------------------------------------------------------------------- + */ + header('Referrer-Policy: strict-origin-when-cross-origin'); + + /* + |------------------------------------------------------------------------------- + | Allow or deny the use of browser features in its own frame, and in content within any <iframe> + | ------------------------ + | Other options: + | SEE MORE: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy + |------------------------------------------------------------------------------- + */ + header("Feature-Policy: microphone 'none'; camera 'none'; geolocation 'none';"); + + /* + |------------------------------------------------------------------------------- + | Disable disable framing and disable plugins + | ------------------------ + | Other options: + | default-src 'none'; font-src https://fonts.gstatic.com; img-src 'self' https://i.imgur.com; object-src 'none'; script-src 'self'; style-src 'self' + | SEE MORE: https://infosec.mozilla.org/guidelines/web_security#content-security-policy + | SEE MORE: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/ + |------------------------------------------------------------------------------- + */ + header("Content-Security-Policy: default-src 'self' https:; font-src http://fonts.googleapis.com; img-src 'self' http://www.w3.org"); + header("Content-Security-Policy: frame-ancestors 'none'; object-src 'none'; img-src 'self' data:; script-src 'self' 'unsafe-eval' 'unsafe-inline'; form-action 'self'; base-uri 'self'; style-src https://fonts.googleapis.com 'self' 'unsafe-inline' 'unsafe-eval';"); + } +} \ No newline at end of file From c8f52c9c0ce993c2ae602a63392f23106e0d3fd7 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 29 Aug 2020 17:20:32 +0300 Subject: [PATCH 31/45] Added docs for new helper CSecureHeaders --- CHANGELOG | 2 +- docs/pages/configuration-files.html | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 611d42b..c2be854 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,6 @@ Version 1.4.x - ---------------------------- -- New: added new helper CSecureHeaders +- New: added new helper CSecureHeaders with possibility to define secure headers - Enh: added possibility to hide system queries in debug panel - Enh: added possibility to close debug panel to minimum size - Enh: added possibility to get records by chunks with chuck() method of Active Record diff --git a/docs/pages/configuration-files.html b/docs/pages/configuration-files.html index 52e0226..1ec9f22 100644 --- a/docs/pages/configuration-files.html +++ b/docs/pages/configuration-files.html @@ -73,7 +73,7 @@ <h3>File <code>main.php</code></h3> 'hashKey' => 'YOUR_HASH_PASSWORD_KEY', ), - // Password restore settings + // Password restore settings 'restoreAdminPassword' => array( 'enable' => true, 'recoveryType' => 'direct' /* 'direct' - send new password directly, 'recovery' - send a link to recovery page */ @@ -101,6 +101,12 @@ <h3>File <code>main.php</code></h3> 'bruteforce' => array('enable' => true, 'badLogins' => 5, 'redirectDelay' => 3), ), + // HTTP headers + 'httpHeaders' => array( + 'secure' => true, + 'framework' => true + ), + // Exception handling // Define exceptions exceptions in application 'exceptionHandling' => array( From bac1162f9430fddbc8f8b9d9316cdbb156715e5e Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 29 Aug 2020 17:37:42 +0300 Subject: [PATCH 32/45] Redo array() to [] --- .../protected/modules/setup/config/main.php | 12 +-- .../setup/controllers/SetupController.php | 8 +- .../protected/modules/setup/models/Setup.php | 2 +- .../modules/setup/views/setup/database.php | 39 +++++---- .../modules/setup/views/setup/index.php | 28 ++++--- .../protected/entities/PostEntity.php | 2 +- demos/simple-blog/protected/models/Posts.php | 4 +- .../setup/controllers/SetupController.php | 8 +- .../protected/modules/setup/models/Setup.php | 2 +- .../modules/setup/views/error/index.php | 2 +- .../setup/views/setup/administrator.php | 49 +++++++----- .../protected/views/authors/edit.php | 59 +++++++------- .../protected/views/posts/edit.php | 7 +- .../protected/views/posts/manage.php | 35 ++++---- .../protected/views/posts/view.php | 2 +- demos/simple-blog/templates/setup/default.php | 26 +++--- .../controllers/SettingsController.php | 21 ++--- .../protected/modules/setup/config/main.php | 12 +-- .../setup/controllers/SetupController.php | 8 +- .../protected/modules/setup/models/Setup.php | 2 +- .../protected/views/admins/edit.php | 6 +- .../simple-cms/protected/views/pages/add.php | 2 +- .../simple-cms/protected/views/pages/edit.php | 2 +- docs/search.php | 2 +- framework/Apphp.php | 50 ++++++------ framework/core/CController.php | 18 ++--- framework/core/CDebug.php | 28 +++---- framework/core/CModel.php | 4 +- framework/core/CRouter.php | 2 +- framework/core/CView.php | 20 +++-- framework/helpers/CGeoLocation.php | 2 +- framework/helpers/widgets/CFormValidation.php | 18 ++--- framework/helpers/widgets/CGridView.php | 34 ++++---- framework/helpers/widgets/CMessage.php | 24 +++--- framework/vendors/tcpdf/tcpdf_parser.php | 24 +++--- utils/generators/inc/functions.inc.php | 2 +- utils/generators/index.php | 16 ++-- utils/requirements/inc/functions.inc.php | 8 +- utils/requirements/index.php | 43 +++++----- utils/tests/inc/controller/data.php | 2 +- utils/tests/inc/filter/data.php | 52 ++++++------ utils/tests/inc/functions.inc.php | 2 +- utils/tests/inc/validator/data.php | 80 +++++++++---------- 43 files changed, 397 insertions(+), 372 deletions(-) diff --git a/demos/login-system/protected/modules/setup/config/main.php b/demos/login-system/protected/modules/setup/config/main.php index 5dd721b..bb35704 100644 --- a/demos/login-system/protected/modules/setup/config/main.php +++ b/demos/login-system/protected/modules/setup/config/main.php @@ -1,8 +1,8 @@ <?php -return array( - // Module classes - 'classes' => array( - 'Modules\Setup\Controllers\Setup' - ) -); +return [ + // Module classes + 'classes' => [ + 'Modules\Setup\Controllers\Setup' + ] +]; diff --git a/demos/login-system/protected/modules/setup/controllers/SetupController.php b/demos/login-system/protected/modules/setup/controllers/SetupController.php index b6d9500..51ef9e0 100644 --- a/demos/login-system/protected/modules/setup/controllers/SetupController.php +++ b/demos/login-system/protected/modules/setup/controllers/SetupController.php @@ -83,7 +83,7 @@ public function indexAction() $this->_view->formFields = array( 'act' => array('type' => 'hidden', 'value' => 'send'), - 'language' => array('type' => 'dropdownlist', 'value' => $language, 'title' => A::t('setup', 'Language'), 'mandatoryStar' => false, 'data' => $this->_languages, 'htmlOptions' => array(), 'validation' => array('required' => true, 'type' => 'set', 'source' => array_keys($this->_languages))), + 'language' => array('type' => 'dropdownlist', 'value' => $language, 'title' => A::t('setup', 'Language'), 'mandatoryStar' => false, 'data' => $this->_languages, 'htmlOptions' => [], 'validation' => array('required' => true, 'type' => 'set', 'source' => array_keys($this->_languages))), ); if ($this->_cRequest->getPost('act') == 'send') { @@ -254,7 +254,7 @@ public function databaseAction() $separatorGeneralFields = array( 'separatorInfo' => array('legend' => 'General Settings'), - 'setupType' => array('type' => 'dropdownlist', 'value' => $this->_view->setupType, 'title' => A::t('setup', 'Setup Type'), 'mandatoryStar' => false, 'data' => array('install' => A::t('setup', 'New Installation'), 'update' => A::t('setup', 'Update')), 'htmlOptions' => array(), 'validation' => array('required' => true, 'type' => 'text', 'source' => array('install'))), + 'setupType' => array('type' => 'dropdownlist', 'value' => $this->_view->setupType, 'title' => A::t('setup', 'Setup Type'), 'mandatoryStar' => false, 'data' => array('install' => A::t('setup', 'New Installation'), 'update' => A::t('setup', 'Update')), 'htmlOptions' => [], 'validation' => array('required' => true, 'type' => 'text', 'source' => array('install'))), 'dbDriver' => array('type' => 'dropdownlist', 'value' => $this->_view->dbDriver, 'title' => A::t('setup', 'Database Driver'), 'mandatoryStar' => true, 'data' => $dbDrivers, 'htmlOptions' => array('style' => 'width:85px'), 'validation' => array('required' => true, 'type' => 'text', 'source' => array_keys($dbDrivers))), 'dbPrefix' => array('type' => 'textbox', 'value' => $this->_view->dbPrefix, 'title' => A::t('setup', 'Database (tables) Prefix'), 'mandatoryStar' => false, 'htmlOptions' => array('maxLength' => '10', 'autocomplete' => 'off'), 'validation' => array('required' => false, 'type' => 'variable')), ); @@ -641,13 +641,13 @@ private function _getPhpInfo() { ob_start(); if (function_exists('phpinfo')) @phpinfo(-1); - $phpInfo = array('phpinfo' => array()); + $phpInfo = array('phpinfo' => []); if (preg_match_all('#(?:<h2>(?:<a name=".*?">)?(.*?)(?:</a>)?</h2>)|(?:<tr(?: class=".*?")?><t[hd](?: class=".*?")?>(.*?)\s*</t[hd]>(?:<t[hd](?: class=".*?")?>(.*?)\s*</t[hd]>(?:<t[hd](?: class=".*?")?>(.*?)\s*</t[hd]>)?)?</tr>)#s', ob_get_clean(), $matches, PREG_SET_ORDER)) foreach ($matches as $match) { $arrayKeys = array_keys($phpInfo); $endArrayKeys = end($arrayKeys); if (strlen($match[1])) { - $phpInfo[$match[1]] = array(); + $phpInfo[$match[1]] = []; } elseif (isset($match[3])) { $phpInfo[$endArrayKeys][$match[2]] = isset($match[4]) ? array($match[3], $match[4]) : $match[3]; } else { diff --git a/demos/login-system/protected/modules/setup/models/Setup.php b/demos/login-system/protected/modules/setup/models/Setup.php index e5cd06f..185589c 100644 --- a/demos/login-system/protected/modules/setup/models/Setup.php +++ b/demos/login-system/protected/modules/setup/models/Setup.php @@ -23,7 +23,7 @@ class Setup extends CModel { - public function __construct($params = array()) + public function __construct($params = []) { parent::__construct($params); } diff --git a/demos/login-system/protected/modules/setup/views/setup/database.php b/demos/login-system/protected/modules/setup/views/setup/database.php index 16a4ee4..a25e63b 100644 --- a/demos/login-system/protected/modules/setup/views/setup/database.php +++ b/demos/login-system/protected/modules/setup/views/setup/database.php @@ -12,22 +12,27 @@ <br> <?php -echo CWidget::create('CFormView', array( - 'action' => 'setup/database', - 'method' => 'post', - 'htmlOptions' => array( - 'name' => 'frmSetup', - 'id' => 'frmSetup' - ), - 'fields' => $formFields, - 'buttons' => array( - 'back' => array('type' => 'button', 'value' => A::t('setup', 'Previous'), 'htmlOptions' => array('name' => '', 'onclick' => "$(location).attr('href','setup/requirements');")), - 'submit' => array('type' => 'submit', 'value' => A::t('setup', 'Next'), 'htmlOptions' => array('name' => '')) - ), - 'events' => array( - 'focus' => array('field' => $errorField) - ), - 'return' => true, -)); +echo CWidget::create( + 'CFormView', [ + 'action' => 'setup/database', + 'method' => 'post', + 'htmlOptions' => [ + 'name' => 'frmSetup', + 'id' => 'frmSetup' + ], + 'fields' => $formFields, + 'buttons' => [ + 'back' => [ + 'type' => 'button', + 'value' => A::t('setup', 'Previous'), + 'htmlOptions' => ['name' => '', 'onclick' => "$(location).attr('href','setup/requirements');"] + ], + 'submit' => ['type' => 'submit', 'value' => A::t('setup', 'Next'), 'htmlOptions' => ['name' => '']] + ], + 'events' => [ + 'focus' => ['field' => $errorField] + ], + 'return' => true, + ]); ?> <br> diff --git a/demos/login-system/protected/modules/setup/views/setup/index.php b/demos/login-system/protected/modules/setup/views/setup/index.php index 53774cb..4d3640d 100644 --- a/demos/login-system/protected/modules/setup/views/setup/index.php +++ b/demos/login-system/protected/modules/setup/views/setup/index.php @@ -10,17 +10,21 @@ <?= $actionMessage; ?> <br> <?php -echo CWidget::create('CFormView', array( - 'action' => 'setup/index', - 'method' => 'post', - 'htmlOptions' => array( - 'name' => 'frmSetup', - ), - 'fields' => $formFields, - 'buttons' => array( - 'submit' => array('type' => 'submit', 'value' => A::t('setup', 'Next'), 'htmlOptions' => array('name' => '')) - ), - 'return' => true, -)); + +echo CWidget::create( + 'CFormView', + [ + 'action' => 'setup/index', + 'method' => 'post', + 'htmlOptions' => [ + 'name' => 'frmSetup', + ], + 'fields' => $formFields, + 'buttons' => [ + 'submit' => ['type' => 'submit', 'value' => A::t('setup', 'Next'), 'htmlOptions' => ['name' => '']] + ], + 'return' => true, + ] +); ?> <br> diff --git a/demos/simple-blog/protected/entities/PostEntity.php b/demos/simple-blog/protected/entities/PostEntity.php index d2b2e1f..03cab5a 100644 --- a/demos/simple-blog/protected/entities/PostEntity.php +++ b/demos/simple-blog/protected/entities/PostEntity.php @@ -15,7 +15,7 @@ class PostEntity extends CRecordEntity protected $_pkValue = 0; /** @var */ - protected $_fillable = array(); + protected $_fillable = []; /** @var */ protected $_guarded = array('post_datetime'); diff --git a/demos/simple-blog/protected/models/Posts.php b/demos/simple-blog/protected/models/Posts.php index 9d08728..0ab7b05 100644 --- a/demos/simple-blog/protected/models/Posts.php +++ b/demos/simple-blog/protected/models/Posts.php @@ -80,6 +80,6 @@ private function _updatePostsCount($pKey) { // update total count of posts in categories table $totalPosts = self::model()->count('category_id = :category_id', [':category_id' => $pKey]); - $this->_db->update('categories', array('posts_count' => $totalPosts), 'id = ' . (int)$pKey); - } + $this->_db->update('categories', ['posts_count' => $totalPosts], 'id = '.(int)$pKey); + } } diff --git a/demos/simple-blog/protected/modules/setup/controllers/SetupController.php b/demos/simple-blog/protected/modules/setup/controllers/SetupController.php index 7459e6a..beba331 100644 --- a/demos/simple-blog/protected/modules/setup/controllers/SetupController.php +++ b/demos/simple-blog/protected/modules/setup/controllers/SetupController.php @@ -83,7 +83,7 @@ public function indexAction() $this->_view->formFields = array( 'act' => array('type' => 'hidden', 'value' => 'send'), - 'language' => array('type' => 'dropdownlist', 'value' => $language, 'title' => A::t('setup', 'Language'), 'mandatoryStar' => false, 'data' => $this->_languages, 'htmlOptions' => array(), 'validation' => array('required' => true, 'type' => 'set', 'source' => array_keys($this->_languages))), + 'language' => array('type' => 'dropdownlist', 'value' => $language, 'title' => A::t('setup', 'Language'), 'mandatoryStar' => false, 'data' => $this->_languages, 'htmlOptions' => [], 'validation' => array('required' => true, 'type' => 'set', 'source' => array_keys($this->_languages))), ); if ($this->_cRequest->getPost('act') == 'send') { @@ -254,7 +254,7 @@ public function databaseAction() $separatorGeneralFields = array( 'separatorInfo' => array('legend' => 'General Settings'), - 'setupType' => array('type' => 'dropdownlist', 'value' => $this->_view->setupType, 'title' => A::t('setup', 'Setup Type'), 'mandatoryStar' => false, 'data' => array('install' => A::t('setup', 'New Installation'), 'update' => A::t('setup', 'Update')), 'htmlOptions' => array(), 'validation' => array('required' => true, 'type' => 'text', 'source' => array('install'))), + 'setupType' => array('type' => 'dropdownlist', 'value' => $this->_view->setupType, 'title' => A::t('setup', 'Setup Type'), 'mandatoryStar' => false, 'data' => array('install' => A::t('setup', 'New Installation'), 'update' => A::t('setup', 'Update')), 'htmlOptions' => [], 'validation' => array('required' => true, 'type' => 'text', 'source' => array('install'))), 'dbDriver' => array('type' => 'dropdownlist', 'value' => $this->_view->dbDriver, 'title' => A::t('setup', 'Database Driver'), 'mandatoryStar' => true, 'data' => $dbDrivers, 'htmlOptions' => array('style' => 'width:85px'), 'validation' => array('required' => true, 'type' => 'text', 'source' => array_keys($dbDrivers))), 'dbPrefix' => array('type' => 'textbox', 'value' => $this->_view->dbPrefix, 'title' => A::t('setup', 'Database (tables) Prefix'), 'mandatoryStar' => false, 'htmlOptions' => array('maxLength' => '10', 'autocomplete' => 'off'), 'validation' => array('required' => false, 'type' => 'variable')), ); @@ -641,13 +641,13 @@ private function _getPhpInfo() { ob_start(); if (function_exists('phpinfo')) @phpinfo(-1); - $phpInfo = array('phpinfo' => array()); + $phpInfo = array('phpinfo' => []); if (preg_match_all('#(?:<h2>(?:<a name=".*?">)?(.*?)(?:</a>)?</h2>)|(?:<tr(?: class=".*?")?><t[hd](?: class=".*?")?>(.*?)\s*</t[hd]>(?:<t[hd](?: class=".*?")?>(.*?)\s*</t[hd]>(?:<t[hd](?: class=".*?")?>(.*?)\s*</t[hd]>)?)?</tr>)#s', ob_get_clean(), $matches, PREG_SET_ORDER)) foreach ($matches as $match) { $arrayKeys = array_keys($phpInfo); $endArrayKeys = end($arrayKeys); if (strlen($match[1])) { - $phpInfo[$match[1]] = array(); + $phpInfo[$match[1]] = []; } elseif (isset($match[3])) { $phpInfo[$endArrayKeys][$match[2]] = isset($match[4]) ? array($match[3], $match[4]) : $match[3]; } else { diff --git a/demos/simple-blog/protected/modules/setup/models/Setup.php b/demos/simple-blog/protected/modules/setup/models/Setup.php index e5cd06f..185589c 100644 --- a/demos/simple-blog/protected/modules/setup/models/Setup.php +++ b/demos/simple-blog/protected/modules/setup/models/Setup.php @@ -23,7 +23,7 @@ class Setup extends CModel { - public function __construct($params = array()) + public function __construct($params = []) { parent::__construct($params); } diff --git a/demos/simple-blog/protected/modules/setup/views/error/index.php b/demos/simple-blog/protected/modules/setup/views/error/index.php index 7fe3db5..6c598e3 100644 --- a/demos/simple-blog/protected/modules/setup/views/error/index.php +++ b/demos/simple-blog/protected/modules/setup/views/error/index.php @@ -6,5 +6,5 @@ <h2><?= $header; ?></h2> <p> - <?= CWidget::create('CMessage', array('error', $text)) . '<br>'; ?> + <?= CWidget::create('CMessage', ['error', $text]).'<br>'; ?> </p> diff --git a/demos/simple-blog/protected/modules/setup/views/setup/administrator.php b/demos/simple-blog/protected/modules/setup/views/setup/administrator.php index 79f1205..8e77ffc 100644 --- a/demos/simple-blog/protected/modules/setup/views/setup/administrator.php +++ b/demos/simple-blog/protected/modules/setup/views/setup/administrator.php @@ -12,27 +12,34 @@ <br> <?php -echo CWidget::create('CFormView', array( - 'action' => 'setup/administrator', - 'method' => 'post', - 'htmlOptions' => array( - 'name' => 'frmSetup', - ), - 'fields' => array( - 'act' => array('type' => 'hidden', 'value' => 'send'), - 'username' => array('type' => 'textbox', 'value' => $username, 'title' => A::t('setup', 'Username'), 'mandatoryStar' => true, 'htmlOptions' => array('maxLength' => '32', 'autocomplete' => 'off')), - 'password' => array('type' => 'password', 'value' => $password, 'title' => A::t('setup', 'Password'), 'mandatoryStar' => true, 'htmlOptions' => array('maxLength' => '25', 'autocomplete' => 'off', 'id' => 'password'), 'appendCode' => '<div for="password" class="toggle_password" data-field="password"></div>'), - 'email' => array('type' => 'textbox', 'value' => $email, 'title' => A::t('setup', 'Email'), 'mandatoryStar' => false, 'htmlOptions' => array('maxLength' => '100', 'autocomplete' => 'off')), - ), - 'buttons' => array( - 'back' => array('type' => 'button', 'value' => A::t('setup', 'Previous'), 'htmlOptions' => array('name' => '', 'onclick' => "$(location).attr('href','setup/database');")), - 'submit' => array('type' => 'submit', 'value' => A::t('setup', 'Next'), 'htmlOptions' => array('name' => '')), - ), - 'events' => array( - 'focus' => array('field' => $errorField), - ), - 'return' => true, -)); +echo CWidget::create( + 'CFormView', + [ + 'action' => 'setup/administrator', + 'method' => 'post', + 'htmlOptions' => [ + 'name' => 'frmSetup', + ], + 'fields' => [ + 'act' => ['type' => 'hidden', 'value' => 'send'], + 'username' => ['type' => 'textbox', 'value' => $username, 'title' => A::t('setup', 'Username'), 'mandatoryStar' => true, 'htmlOptions' => ['maxLength' => '32', 'autocomplete' => 'off']], + 'password' => ['type' => 'password', 'value' => $password, 'title' => A::t('setup', 'Password'), 'mandatoryStar' => true, 'htmlOptions' => ['maxLength' => '25', 'autocomplete' => 'off', 'id' => 'password'], 'appendCode' => '<div for="password" class="toggle_password" data-field="password"></div>'], + 'email' => ['type' => 'textbox', 'value' => $email, 'title' => A::t('setup', 'Email'), 'mandatoryStar' => false, 'htmlOptions' => ['maxLength' => '100', 'autocomplete' => 'off']], + ], + 'buttons' => [ + 'back' => [ + 'type' => 'button', + 'value' => A::t('setup', 'Previous'), + 'htmlOptions' => ['name' => '', 'onclick' => "$(location).attr('href','setup/database');"] + ], + 'submit' => ['type' => 'submit', 'value' => A::t('setup', 'Next'), 'htmlOptions' => ['name' => '']], + ], + 'events' => [ + 'focus' => ['field' => $errorField], + ], + 'return' => true, + ] +); ?> <br> \ No newline at end of file diff --git a/demos/simple-blog/protected/views/authors/edit.php b/demos/simple-blog/protected/views/authors/edit.php index ed89f5e..e52cb13 100644 --- a/demos/simple-blog/protected/views/authors/edit.php +++ b/demos/simple-blog/protected/views/authors/edit.php @@ -5,35 +5,36 @@ <div class="panel-content"> <?php - echo CWidget::create('CFormView', array( - 'action' => 'authors/update', - 'method' => 'post', - 'htmlOptions' => array( - 'name' => 'frmAuthor', - 'enctype' => 'multipart/form-data', - ), - 'fields' => array( - 'act' => array('type' => 'hidden', 'value' => 'send'), - 'login' => array('type' => 'hidden', 'value' => $login), - 'loginLabel' => array('type' => 'label', 'value' => $login, 'title' => 'User Name'), - 'password' => array('type' => 'password', 'value' => $password, 'title' => 'Password', 'mandatoryStar' => true, 'htmlOptions' => array('maxlength' => '20', 'placeholder' => '●●●●●')), - 'passwordRetype' => array('type' => 'password', 'value' => $passwordRetype, 'title' => 'Repeat Password', 'mandatoryStar' => true, 'htmlOptions' => array('maxlength' => '20', 'placeholder' => '●●●●●')), - 'email' => array('type' => 'textbox', 'value' => $email, 'title' => 'Email', 'mandatoryStar' => true, 'htmlOptions' => array('maxlength' => '100', 'class' => 'email', 'autocomplete' => 'off')), - 'aboutText' => array('type' => 'textarea', 'value' => $aboutText, 'title' => 'About Me', 'mandatoryStar' => true, 'htmlOptions' => array('maxlength' => '300', 'class' => 'large')), - 'avatarImg' => array('type' => 'image', 'title' => 'Avatar Preview', 'src' => 'templates/default/images/authors/' . $avatarFile, 'alt' => 'Avatar Preview', 'htmlOptions' => array('class' => 'avatar')), - 'avatarLabel' => array('type' => 'label', 'value' => $avatarFile, 'title' => 'Avatar File', 'mandatoryStar' => false), - 'avatar' => array('type' => 'file', 'title' => ' ', 'mandatoryStar' => false, 'htmlOptions' => array('accept' => 'image/jpeg, image/png, image/gif, image/jpg', 'class' => 'file', 'size' => '25')), - ), - 'buttons' => array( - 'reset' => array('type' => 'reset', 'value' => 'Reset', 'htmlOptions' => array('type' => 'reset')), - 'submit' => array('type' => 'submit', 'value' => 'Update'), - ), - 'events' => array( - 'focus' => array('field' => $errorField), - ), - 'return' => true, - )); - ?> + + echo CWidget::create( + 'CFormView', + [ + 'action' => 'authors/update', + 'method' => 'post', + 'htmlOptions' => ['name' => 'frmAuthor', 'enctype' => 'multipart/form-data'], + 'fields' => [ + 'act' => ['type' => 'hidden', 'value' => 'send'], + 'login' => ['type' => 'hidden', 'value' => $login], + 'loginLabel' => ['type' => 'label', 'value' => $login, 'title' => 'User Name'], + 'password' => ['type' => 'password', 'value' => $password, 'title' => 'Password', 'mandatoryStar' => true, 'htmlOptions' => ['maxlength' => '20', 'placeholder' => '●●●●●']], + 'passwordRetype' => ['type' => 'password', 'value' => $passwordRetype, 'title' => 'Repeat Password', 'mandatoryStar' => true, 'htmlOptions' => ['maxlength' => '20', 'placeholder' => '●●●●●']], + 'email' => ['type' => 'textbox', 'value' => $email, 'title' => 'Email', 'mandatoryStar' => true, 'htmlOptions' => ['maxlength' => '100', 'class' => 'email', 'autocomplete' => 'off']], + 'aboutText' => ['type' => 'textarea', 'value' => $aboutText, 'title' => 'About Me', 'mandatoryStar' => true, 'htmlOptions' => ['maxlength' => '300', 'class' => 'large']], + 'avatarImg' => ['type' => 'image', 'title' => 'Avatar Preview', 'src' => 'templates/default/images/authors/'.$avatarFile, 'alt' => 'Avatar Preview', 'htmlOptions' => ['class' => 'avatar']], + 'avatarLabel' => ['type' => 'label', 'value' => $avatarFile, 'title' => 'Avatar File', 'mandatoryStar' => false], + 'avatar' => ['type' => 'file', 'title' => ' ', 'mandatoryStar' => false, 'htmlOptions' => ['accept' => 'image/jpeg, image/png, image/gif, image/jpg', 'class' => 'file', 'size' => '25']], + ], + 'buttons' => [ + 'reset' => ['type' => 'reset', 'value' => 'Reset', 'htmlOptions' => ['type' => 'reset']], + 'submit' => ['type' => 'submit', 'value' => 'Update'], + ], + 'events' => [ + 'focus' => ['field' => $errorField], + ], + 'return' => true, + ] + ); + ?> </div> <div class="panel-settings"> This page provides you possibility to edit profile information. diff --git a/demos/simple-blog/protected/views/posts/edit.php b/demos/simple-blog/protected/views/posts/edit.php index 3008c2d..fa46fe9 100644 --- a/demos/simple-blog/protected/views/posts/edit.php +++ b/demos/simple-blog/protected/views/posts/edit.php @@ -5,8 +5,9 @@ <div class="panel-content"> <?php - $listData = array('' => '-- select --'); - if (!empty($categories)) { + + $listData = ['' => '-- select --']; + if (!empty($categories)) { foreach ($categories as $cat) { $listData[$cat['id']] = $cat['name']; } @@ -19,7 +20,7 @@ 'name' => 'frmEditPost', ), 'fields' => array( - 'act' => array('type' => 'hidden', 'value' => 'send'), + 'act' => ['type' => 'hidden', 'value' => 'send'], 'postId' => array('type' => 'hidden', 'value' => $postId), 'postIdLabel' => array('type' => 'label', 'title' => 'Post ID', 'value' => $postId), 'header' => array('type' => 'textbox', 'title' => 'Header', 'value' => $header, 'mandatoryStar' => true, 'htmlOptions' => array('maxlength' => '100', 'class' => 'text_header', 'encode' => true)), diff --git a/demos/simple-blog/protected/views/posts/manage.php b/demos/simple-blog/protected/views/posts/manage.php index 2225b9b..128dd65 100644 --- a/demos/simple-blog/protected/views/posts/manage.php +++ b/demos/simple-blog/protected/views/posts/manage.php @@ -4,31 +4,24 @@ <div id="content"> <?php - echo CWidget::create('CDataGrid', array( + echo CWidget::create('CDataGrid', [ 'model' => 'Posts', 'actionPath' => 'posts/manage', - -// 'condition'=>'', -// 'defaultOrder'=>array('id'=>'DESC'), -// 'passParameters'=>true, - - 'pagination' => array('enable'=>true, 'pageSize'=>20), + 'pagination' => ['enable'=>true, 'pageSize'=>20], 'sorting' => true, - - 'filters'=>array( - 'header' => array('title'=>A::t('app', 'Post Header'), 'type'=>'textbox', 'operator'=>'%like%', 'width'=>'100px', 'maxLength'=>''), - 'post_datetime' => array('title'=>A::t('app', 'Date Created'), 'type'=>'datetime', 'operator'=>'like%', 'width'=>'80px', 'maxLength'=>'', 'format'=>''), - ), - 'fields' => array( - 'header' => array('title'=>A::t('app', 'Post Header'), 'type'=>'label', 'class'=>'left', 'headerClass'=>'left', 'stripTags'=>true, 'sortType'=>'string'), - 'category_name' => array('title'=>A::t('app', 'Category'), 'type'=>'label', 'class'=>'center', 'headerClass'=>'center', 'width'=>'120px'), - 'post_datetime' => array('title'=>A::t('app', 'Date Created'), 'type'=>'datetime', 'align'=>'center', 'width'=>'170px', 'class'=>'left', 'headerClass'=>'left', 'isSortable'=>true, 'definedValues'=>array(), 'format'=>'Y-m-d H:i:s'), - 'id' => array('title'=>'ID', 'type'=>'label', 'class'=>'center', 'headerClass'=>'center', 'width'=>'50px'), - ), - + 'filters'=>[ + 'header' => ['title'=>A::t('app', 'Post Header'), 'type'=>'textbox', 'operator'=>'%like%', 'width'=>'100px', 'maxLength'=>''], + 'post_datetime' => ['title'=>A::t('app', 'Date Created'), 'type'=>'datetime', 'operator'=>'like%', 'width'=>'80px', 'maxLength'=>'', 'format'=>''], + ], + 'fields' => [ + 'header' => ['title'=>A::t('app', 'Post Header'), 'type'=>'label', 'class'=>'left', 'headerClass'=>'left', 'stripTags'=>true, 'sortType'=>'string'], + 'category_name' => ['title'=>A::t('app', 'Category'), 'type'=>'label', 'class'=>'center', 'headerClass'=>'center', 'width'=>'120px'], + 'post_datetime' => ['title'=>A::t('app', 'Date Created'), 'type'=>'datetime', 'align'=>'center', 'width'=>'170px', 'class'=>'left', 'headerClass'=>'left', 'isSortable'=>true, 'definedValues'=>[], 'format'=>'Y-m-d H:i:s'], + 'id' => ['title'=>'ID', 'type'=>'label', 'class'=>'center', 'headerClass'=>'center', 'width'=>'50px'], + ], 'return'=>true, - )); + ]); ?> </div> - + </article> diff --git a/demos/simple-blog/protected/views/posts/view.php b/demos/simple-blog/protected/views/posts/view.php index 0b0decf..2015a0a 100644 --- a/demos/simple-blog/protected/views/posts/view.php +++ b/demos/simple-blog/protected/views/posts/view.php @@ -9,7 +9,7 @@ } if (is_object($posts)) { - $posts_new = array(); + $posts_new = []; $posts_new[0]['id'] = $posts->id; $posts_new[0]['header'] = $posts->header; $posts_new[0]['post_text'] = $posts->post_text; diff --git a/demos/simple-blog/templates/setup/default.php b/demos/simple-blog/templates/setup/default.php index 9a8091c..e7eca11 100644 --- a/demos/simple-blog/templates/setup/default.php +++ b/demos/simple-blog/templates/setup/default.php @@ -29,19 +29,19 @@ </div> <?php - CWidget::create('CMenu', array( - 'type' => 'vertical', - 'items' => array( - array('label' => '1. ' . A::t('setup', 'General'), 'url' => 'setup/index', 'readonly' => true), - array('label' => '2. ' . A::t('setup', 'Check Requirements'), 'url' => 'setup/requirements', 'readonly' => true), - array('label' => '3. ' . A::t('setup', 'Database Settings'), 'url' => 'setup/database', 'readonly' => true), - array('label' => '4. ' . A::t('setup', 'Administrator Account'), 'url' => 'setup/administrator', 'readonly' => true), - array('label' => '5. ' . A::t('setup', 'Ready to Install'), 'url' => 'setup/ready', 'readonly' => true), - array('label' => '6. ' . A::t('setup', 'Completed'), 'url' => 'setup/completed', 'readonly' => true), - ), - 'selected' => $this->_activeMenu, - 'return' => false, - )); + CWidget::create('CMenu', [ + 'type' => 'vertical', + 'items' => array( + ['label' => '1. ' . A::t('setup', 'General'), 'url' => 'setup/index', 'readonly' => true], + ['label' => '2. ' . A::t('setup', 'Check Requirements'), 'url' => 'setup/requirements', 'readonly' => true], + ['label' => '3. ' . A::t('setup', 'Database Settings'), 'url' => 'setup/database', 'readonly' => true], + ['label' => '4. ' . A::t('setup', 'Administrator Account'), 'url' => 'setup/administrator', 'readonly' => true], + ['label' => '5. ' . A::t('setup', 'Ready to Install'), 'url' => 'setup/ready', 'readonly' => true], + ['label' => '6. ' . A::t('setup', 'Completed'), 'url' => 'setup/completed', 'readonly' => true], + ), + 'selected' => $this->_activeMenu, + 'return' => false, + ]); ?> </aside> <article> diff --git a/demos/simple-cms/protected/controllers/SettingsController.php b/demos/simple-cms/protected/controllers/SettingsController.php index 9f2a7da..9af89cf 100644 --- a/demos/simple-cms/protected/controllers/SettingsController.php +++ b/demos/simple-cms/protected/controllers/SettingsController.php @@ -70,16 +70,17 @@ public function updateAction() $this->_view->metaTagDescription = $cRequest->getPost('metaTagDescription'); // perform settings form validation - $result = CWidget::create('CFormValidation', array( - 'fields' => array( - 'cmsName' => array('title' => 'Site Name', 'validation' => array('required' => true, 'type' => 'any', 'maxLength' => 100)), - 'slogan' => array('title' => 'Slogan', 'validation' => array('required' => false, 'type' => 'any', 'maxLength' => 250)), - 'footer' => array('title' => 'Footer', 'validation' => array('required' => false, 'type' => 'any', 'maxLength' => 250)), - 'metaTagTitle' => array('title' => CHtml::encode('Tag <TITLE>'), 'validation' => array('required' => true, 'type' => 'any', 'maxLength' => 250)), - 'metaTagKeywords' => array('title' => CHtml::encode('Meta tag <KEYWORDS>'), 'validation' => array('required' => false, 'type' => 'any', 'maxLength' => 250)), - 'metaTagDescription' => array('title' => CHtml::encode('Meta tag <DESCRIPTION>'), 'validation' => array('required' => false, 'type' => 'any', 'maxLength' => 250)), - ), - )); + $result = CWidget::create('CFormValidation', [ + 'fields' => [ + 'cmsName' => ['title' => 'Site Name', 'validation' => ['required' => true, 'type' => 'any', 'maxLength' => 100]], + 'slogan' => ['title' => 'Slogan', 'validation' => ['required' => false, 'type' => 'any', 'maxLength' => 250]], + 'footer' => ['title' => 'Footer', 'validation' => ['required' => false, 'type' => 'any', 'maxLength' => 250]], + 'metaTagTitle' => ['title' => CHtml::encode('Tag <TITLE>'), 'validation' => ['required' => true, 'type' => 'any', 'maxLength' => 250]], + 'metaTagKeywords' => ['title' => CHtml::encode('Meta tag <KEYWORDS>'), 'validation' => ['required' => false, 'type' => 'any', 'maxLength' => 250]], + 'metaTagDescription' => ['title' => CHtml::encode('Meta tag <DESCRIPTION>'), 'validation' => ['required' => false, 'type' => 'any', 'maxLength' => 250]], + ], + ]); + if ($result['error']) { $msg = $result['errorMessage']; $msgType = 'validation'; diff --git a/demos/simple-cms/protected/modules/setup/config/main.php b/demos/simple-cms/protected/modules/setup/config/main.php index 05d143e..de6d505 100644 --- a/demos/simple-cms/protected/modules/setup/config/main.php +++ b/demos/simple-cms/protected/modules/setup/config/main.php @@ -1,8 +1,8 @@ <?php -return array( - // Module classes - 'classes' => array( - 'Modules\Setup\Controllers\Setup', - ), -); +return [ + // Module classes + 'classes' => [ + 'Modules\Setup\Controllers\Setup', + ], +]; diff --git a/demos/simple-cms/protected/modules/setup/controllers/SetupController.php b/demos/simple-cms/protected/modules/setup/controllers/SetupController.php index 7459e6a..beba331 100644 --- a/demos/simple-cms/protected/modules/setup/controllers/SetupController.php +++ b/demos/simple-cms/protected/modules/setup/controllers/SetupController.php @@ -83,7 +83,7 @@ public function indexAction() $this->_view->formFields = array( 'act' => array('type' => 'hidden', 'value' => 'send'), - 'language' => array('type' => 'dropdownlist', 'value' => $language, 'title' => A::t('setup', 'Language'), 'mandatoryStar' => false, 'data' => $this->_languages, 'htmlOptions' => array(), 'validation' => array('required' => true, 'type' => 'set', 'source' => array_keys($this->_languages))), + 'language' => array('type' => 'dropdownlist', 'value' => $language, 'title' => A::t('setup', 'Language'), 'mandatoryStar' => false, 'data' => $this->_languages, 'htmlOptions' => [], 'validation' => array('required' => true, 'type' => 'set', 'source' => array_keys($this->_languages))), ); if ($this->_cRequest->getPost('act') == 'send') { @@ -254,7 +254,7 @@ public function databaseAction() $separatorGeneralFields = array( 'separatorInfo' => array('legend' => 'General Settings'), - 'setupType' => array('type' => 'dropdownlist', 'value' => $this->_view->setupType, 'title' => A::t('setup', 'Setup Type'), 'mandatoryStar' => false, 'data' => array('install' => A::t('setup', 'New Installation'), 'update' => A::t('setup', 'Update')), 'htmlOptions' => array(), 'validation' => array('required' => true, 'type' => 'text', 'source' => array('install'))), + 'setupType' => array('type' => 'dropdownlist', 'value' => $this->_view->setupType, 'title' => A::t('setup', 'Setup Type'), 'mandatoryStar' => false, 'data' => array('install' => A::t('setup', 'New Installation'), 'update' => A::t('setup', 'Update')), 'htmlOptions' => [], 'validation' => array('required' => true, 'type' => 'text', 'source' => array('install'))), 'dbDriver' => array('type' => 'dropdownlist', 'value' => $this->_view->dbDriver, 'title' => A::t('setup', 'Database Driver'), 'mandatoryStar' => true, 'data' => $dbDrivers, 'htmlOptions' => array('style' => 'width:85px'), 'validation' => array('required' => true, 'type' => 'text', 'source' => array_keys($dbDrivers))), 'dbPrefix' => array('type' => 'textbox', 'value' => $this->_view->dbPrefix, 'title' => A::t('setup', 'Database (tables) Prefix'), 'mandatoryStar' => false, 'htmlOptions' => array('maxLength' => '10', 'autocomplete' => 'off'), 'validation' => array('required' => false, 'type' => 'variable')), ); @@ -641,13 +641,13 @@ private function _getPhpInfo() { ob_start(); if (function_exists('phpinfo')) @phpinfo(-1); - $phpInfo = array('phpinfo' => array()); + $phpInfo = array('phpinfo' => []); if (preg_match_all('#(?:<h2>(?:<a name=".*?">)?(.*?)(?:</a>)?</h2>)|(?:<tr(?: class=".*?")?><t[hd](?: class=".*?")?>(.*?)\s*</t[hd]>(?:<t[hd](?: class=".*?")?>(.*?)\s*</t[hd]>(?:<t[hd](?: class=".*?")?>(.*?)\s*</t[hd]>)?)?</tr>)#s', ob_get_clean(), $matches, PREG_SET_ORDER)) foreach ($matches as $match) { $arrayKeys = array_keys($phpInfo); $endArrayKeys = end($arrayKeys); if (strlen($match[1])) { - $phpInfo[$match[1]] = array(); + $phpInfo[$match[1]] = []; } elseif (isset($match[3])) { $phpInfo[$endArrayKeys][$match[2]] = isset($match[4]) ? array($match[3], $match[4]) : $match[3]; } else { diff --git a/demos/simple-cms/protected/modules/setup/models/Setup.php b/demos/simple-cms/protected/modules/setup/models/Setup.php index e5cd06f..185589c 100644 --- a/demos/simple-cms/protected/modules/setup/models/Setup.php +++ b/demos/simple-cms/protected/modules/setup/models/Setup.php @@ -23,7 +23,7 @@ class Setup extends CModel { - public function __construct($params = array()) + public function __construct($params = []) { parent::__construct($params); } diff --git a/demos/simple-cms/protected/views/admins/edit.php b/demos/simple-cms/protected/views/admins/edit.php index 9a0404e..5c93420 100644 --- a/demos/simple-cms/protected/views/admins/edit.php +++ b/demos/simple-cms/protected/views/admins/edit.php @@ -39,11 +39,11 @@ ), 'separatorAccount' => array( 'separatorInfo' => array('legend' => A::t('app', 'Account Information')), - 'role' => array('type' => 'select', 'title' => A::t('app', 'Account Type'), 'data' => ($isMyAccount ? $allRolesList : $rolesList), 'mandatoryStar' => true, 'htmlOptions' => ($isMyAccount ? array('disabled' => 'disabled') : array()), 'validation' => array('required' => false, 'type' => 'set', 'source' => ($isMyAccount ? array('owner') : array_keys($rolesList)))), - 'username' => array('type' => 'label', 'title' => A::t('app', 'Username'), 'tooltip' => '', 'htmlOptions' => array()), + 'role' => array('type' => 'select', 'title' => A::t('app', 'Account Type'), 'data' => ($isMyAccount ? $allRolesList : $rolesList), 'mandatoryStar' => true, 'htmlOptions' => ($isMyAccount ? array('disabled' => 'disabled') : []), 'validation' => array('required' => false, 'type' => 'set', 'source' => ($isMyAccount ? array('owner') : array_keys($rolesList)))), + 'username' => array('type' => 'label', 'title' => A::t('app', 'Username'), 'tooltip' => '', 'htmlOptions' => []), 'password' => array('type' => 'password', 'title' => A::t('app', 'Password'), 'validation' => array('required' => false, 'type' => 'password', 'minLength' => 4, 'maxlength' => 20), 'encryption' => array('enabled' => CConfig::get('password.encryption'), 'encryptAlgorithm' => CConfig::get('password.encryptAlgorithm'), 'hashKey' => CConfig::get('password.hashKey')), 'htmlOptions' => array('maxlength' => '20', 'placeholder' => '●●●●●')), 'passwordRetype' => array('type' => 'password', 'title' => A::t('app', 'Retype Password'), 'validation' => array('required' => false, 'type' => 'confirm', 'confirmField' => 'password', 'minLength' => 4, 'maxlength' => 20), 'htmlOptions' => array('maxlength' => '20', 'placeholder' => '●●●●●')), - 'is_active' => array('type' => 'checkbox', 'title' => A::t('app', 'Active'), 'validation' => array('type' => 'set', 'source' => array(0, 1)), 'htmlOptions' => ($isMyAccount ? array('disabled' => 'disabled', 'uncheckValue' => 1) : array())), + 'is_active' => array('type' => 'checkbox', 'title' => A::t('app', 'Active'), 'validation' => array('type' => 'set', 'source' => array(0, 1)), 'htmlOptions' => ($isMyAccount ? array('disabled' => 'disabled', 'uncheckValue' => 1) : [])), ), 'separatorOther' => array( 'separatorInfo' => array('legend' => A::t('app', 'Other')), diff --git a/demos/simple-cms/protected/views/pages/add.php b/demos/simple-cms/protected/views/pages/add.php index 2be7f1b..035e9f6 100644 --- a/demos/simple-cms/protected/views/pages/add.php +++ b/demos/simple-cms/protected/views/pages/add.php @@ -23,7 +23,7 @@ 'link_text' => array('type' => 'textbox', 'title' => 'Link', 'value' => $linkText, 'mandatoryStar' => true, 'htmlOptions' => array('maxlength' => '255', 'class' => 'text_header')), 'header_text' => array('type' => 'textbox', 'title' => 'Header', 'value' => $headerText, 'mandatoryStar' => true, 'htmlOptions' => array('maxlength' => '255', 'class' => 'text_header')), 'menuId' => array('type' => 'dropdown', 'title' => 'Menu', 'data' => $listData, 'value' => $menuId), - 'is_homepage' => array('type' => 'checkbox', 'title' => 'Homepage', 'tooltip' => '', 'value' => '1', 'checked' => ($isHomePage ? true : false), 'htmlOptions' => array()), + 'is_homepage' => array('type' => 'checkbox', 'title' => 'Homepage', 'tooltip' => '', 'value' => '1', 'checked' => ($isHomePage ? true : false), 'htmlOptions' => []), 'metaTagTitle' => array('type' => 'textbox', 'title' => CHtml::encode('Page <TITLE>'), 'value' => $metaTagTitle, 'htmlOptions' => array('maxlength' => '250', 'class' => 'text_header')), 'metaTagKeywords' => array('type' => 'textbox', 'title' => CHtml::encode('Page <KEYWORDS>'), 'value' => $metaTagKeywords, 'htmlOptions' => array('maxlength' => '250', 'class' => 'text_header')), 'metaTagDescription' => array('type' => 'textbox', 'title' => CHtml::encode('Page <DESCRIPTION>'), 'value' => $metaTagDescription, 'htmlOptions' => array('maxlength' => '250', 'class' => 'text_header')), diff --git a/demos/simple-cms/protected/views/pages/edit.php b/demos/simple-cms/protected/views/pages/edit.php index ae56d70..6611d95 100644 --- a/demos/simple-cms/protected/views/pages/edit.php +++ b/demos/simple-cms/protected/views/pages/edit.php @@ -24,7 +24,7 @@ 'link_text' => array('type' => 'textbox', 'title' => 'Link', 'value' => $linkText, 'mandatoryStar' => true, 'htmlOptions' => array('maxlength' => '255', 'class' => 'text_header')), 'header_text' => array('type' => 'textbox', 'title' => 'Header', 'value' => $headerText, 'mandatoryStar' => true, 'htmlOptions' => array('maxlength' => '255', 'class' => 'text_header')), 'menuId' => array('type' => 'dropdown', 'title' => 'Menu', 'data' => $listData, 'value' => $menuId), - 'is_homepage' => array('type' => 'checkbox', 'title' => 'Homepage', 'tooltip' => '', 'value' => '1', 'checked' => ($isHomePage ? true : false), 'htmlOptions' => array()), + 'is_homepage' => array('type' => 'checkbox', 'title' => 'Homepage', 'tooltip' => '', 'value' => '1', 'checked' => ($isHomePage ? true : false), 'htmlOptions' => []), 'metaTagTitle' => array('type' => 'textbox', 'title' => CHtml::encode('Page <TITLE>'), 'value' => $metaTagTitle, 'htmlOptions' => array('maxlength' => '250', 'class' => 'text_header')), 'metaTagKeywords' => array('type' => 'textbox', 'title' => CHtml::encode('Page <KEYWORDS>'), 'value' => $metaTagKeywords, 'htmlOptions' => array('maxlength' => '250', 'class' => 'text_header')), 'metaTagDescription' => array('type' => 'textbox', 'title' => CHtml::encode('Page <DESCRIPTION>'), 'value' => $metaTagDescription, 'htmlOptions' => array('maxlength' => '250', 'class' => 'text_header')), diff --git a/docs/search.php b/docs/search.php index 918c2d8..7028743 100644 --- a/docs/search.php +++ b/docs/search.php @@ -53,7 +53,7 @@ function listFiles($dir, $keyword, &$array){ } - $array = array(); + $array = []; $keyword = isset($_GET['keyword']) ? trim($_GET['keyword']) : ''; $keyword = str_ireplace(array('\\', ':', '../', '%00'), '', $keyword); $keyword = str_ireplace(array('(', ')', '[', ']'), array('\(', '\)', '\[', '\]'), $keyword); diff --git a/framework/Apphp.php b/framework/Apphp.php index 5674174..251e38a 100644 --- a/framework/Apphp.php +++ b/framework/Apphp.php @@ -90,7 +90,7 @@ class A 'CRouter' => 'core/CRouter.php', 'CView' => 'core/CView.php', - 'CActiveRecord' => array('5.4.0' => 'db/CActiveRecord.php'), + 'CActiveRecord' => ['5.4.0' => 'db/CActiveRecord.php'], 'CRecordEntity' => 'db/CRecordEntity.php', 'CDatabase' => 'db/CDatabase.php', 'CDbCommand' => 'db/CDbCommand.php', @@ -106,7 +106,7 @@ class A ]; /** @var array */ private static $_coreComponents = [ - //'component' => array('class' => 'CComponent', 'path' => array('5.4.0' => 'components/CComponent.php')), + //'component' => ['class' => 'CComponent', 'path' => ['5.4.0' => 'components/CComponent.php']], 'component' => ['class' => 'CComponent', 'path' => 'components/CComponent.php'], 'clientScript' => ['class' => 'CClientScript', 'path' => 'components/CClientScript.php'], 'dbSession' => ['class' => 'CDbHttpSession', 'path' => 'components/CDbHttpSession.php'], @@ -209,12 +209,12 @@ public function __construct($configDir) if (is_string($configMain) && is_string($configDb)) { // Check if main configuration file exists if (!file_exists($configMain)) { - $arrConfig = array( - 'template' => array('default' => 'setup'), - 'defaultController' => 'Setup', - 'defaultAction' => 'index', - ); - // Block access to regular files when application is not properly installed + $arrConfig = [ + 'template' => ['default' => 'setup'], + 'defaultController' => 'Setup', + 'defaultAction' => 'index', + ]; + // Block access to regular files when application is not properly installed $url = isset($_GET['url']) ? $_GET['url'] : ''; if (!preg_match('/setup\//i', $url)) { $_GET['url'] = 'setup/index'; @@ -282,16 +282,16 @@ public function __construct($configDir) // Set error handler method if (CConfig::get('exceptionHandling.enable') && CConfig::get('exceptionHandling.level') === 'global') { - set_error_handler(array($this, 'errorHandler')); - } - } + set_error_handler([$this, 'errorHandler']); + } + } /** * Runs application */ public function run() { - if ( ! in_array(APPHP_MODE, array('hidden', 'console')) ) { + if ( ! in_array(APPHP_MODE, ['hidden', 'console'])) { // Specify error settings if (in_array(APPHP_MODE, ['debug', 'test'])) { error_reporting(E_ALL); @@ -334,9 +334,9 @@ public function run() * @param array $config * @return object Apphp */ - public static function init($config = array()) - { - if (self::$_instance == null) self::$_instance = new self($config); + public static function init($config = []) + { + if (self::$_instance == null) self::$_instance = new self($config); return self::$_instance; } @@ -388,7 +388,7 @@ public static function powered() * @param string $language * @return string */ - public static function t($category = 'app', $message = '', $params = array(), $source = null, $language = null) + public static function t($category = 'app', $message = '', $params = [], $source = null, $language = null) { if (self::$_instance !== null && $message !== '') { if ($source === null) $source = ($category === 'core') ? 'coreMessages' : 'messages'; @@ -397,11 +397,11 @@ public static function t($category = 'app', $message = '', $params = array(), $s } } - if ($params === array()) { + if ($params === []) { return $message; } else { if (!is_array($params)) $params = array($params); - return $params !== array() ? strtr($message, $params) : $message; + return $params !== [] ? strtr($message, $params) : $message; } } @@ -414,7 +414,7 @@ public static function t($category = 'app', $message = '', $params = array(), $s * @param string $language * @return string */ - public static function te($category = 'app', $message = '', $params = array(), $source = null, $language = null) + public static function te($category = 'app', $message = '', $params = [], $source = null, $language = null) { return CHtml::encode(self::t($category, $message, $params, $source, $language)); } @@ -593,7 +593,7 @@ protected function _setComponent($id, $component) unset($this->_components[$id]); } else { // For PHP_VERSION | phpversion() < 5.4.0 you may use - /// if($callback = call_user_func_array($component.'::init', array())){ + /// if($callback = call_user_func_array($component.'::init', [])){ if ($callback = $component::init()) { $this->_components[$id] = $callback; CDebug::addMessage('general', 'components', ucfirst($id)); @@ -821,7 +821,7 @@ public function attachEventHandler($name, $handler) if ($this->_hasEvent($name)) { $name = strtolower($name); if (!isset($this->_events[$name])) { - $this->_events[$name] = array(); + $this->_events[$name] = []; } if (!in_array($handler, $this->_events[$name])) { $this->_events[$name][] = $handler; @@ -882,7 +882,7 @@ protected function _raiseEvent($name) $object = $handler[0]; $method = $handler[1]; if (is_string($object)) { - @call_user_func_array(array($object, $method), array()); + @call_user_func_array(array($object, $method), []); } elseif (CClass::isMethodExists($object, $method)) { $object->$method(); } @@ -993,7 +993,7 @@ public function getResponseCode() * @param string $language (code) * @param array $params */ - public function setLanguage($language = '', $params = array()) + public function setLanguage($language = '', $params = []) { $this->_language = $language; $this->getSession()->set('language', $this->_language); @@ -1042,7 +1042,7 @@ public function supportedLanguages() * @param string $currency (code) * @param array $params */ - public function setCurrency($currency = '', $params = array()) + public function setCurrency($currency = '', $params = []) { $this->_currency = $currency; $this->getSession()->set('currency_code', $this->_currency); @@ -1169,7 +1169,7 @@ protected function _registerAppComponents() $components = CConfig::get('components'); if (!is_array($components)) return false; - $arrSetComponents = array(); + $arrSetComponents = []; foreach ($components as $id => $component) { $enable = isset($component['enable']) ? (bool)$component['enable'] : false; $class = isset($component['class']) ? $component['class'] : ''; diff --git a/framework/core/CController.php b/framework/core/CController.php index 74bc02e..0eac1d4 100644 --- a/framework/core/CController.php +++ b/framework/core/CController.php @@ -40,7 +40,7 @@ function __construct() * @param array $params * @return void */ - final public function execute($action = '', $params = array()) + final public function execute($action = '', $params = []) { if (!empty($action)) { $this->_action = $action; @@ -176,7 +176,7 @@ public function redirect($path, $isDirectUrl = false, $code = '') */ protected function _accessRules() { - return array(); + return []; } /** @@ -185,10 +185,10 @@ protected function _accessRules() * @param array $rules * @return bool */ - protected function _filtersAccessControl($rules = array()) + protected function _filtersAccessControl($rules = []) { - $allowed = !empty($rules[0]) ? $rules[0] : array(); - $denied = !empty($rules[1]) ? $rules[1] : array(); + $allowed = !empty($rules[0]) ? $rules[0] : []; + $denied = !empty($rules[1]) ? $rules[1] : []; $current_ip = A::app()->getRequest()->getUserHostAddress(); $return = true; @@ -197,8 +197,8 @@ protected function _filtersAccessControl($rules = array()) } if ($allowed) { - $actions = !empty($allowed['actions']) ? (array)$allowed['actions'] : array(); - $ips = !empty($allowed['ips']) ? (array)$allowed['ips'] : array(); + $actions = !empty($allowed['actions']) ? (array)$allowed['actions'] : []; + $ips = !empty($allowed['ips']) ? (array)$allowed['ips'] : []; $access = $this->_filterAccessControl('allowed', $actions, $ips, $current_ip); if ($access !== null) { @@ -207,8 +207,8 @@ protected function _filtersAccessControl($rules = array()) } if ($denied) { - $actions = !empty($denied['actions']) ? (array)$denied['actions'] : array(); - $ips = !empty($denied['ips']) ? (array)$denied['ips'] : array(); + $actions = !empty($denied['actions']) ? (array)$denied['actions'] : []; + $ips = !empty($denied['ips']) ? (array)$denied['ips'] : []; $access = $this->_filterAccessControl('denied', $actions, $ips, $current_ip); if ($access !== null) { diff --git a/framework/core/CDebug.php b/framework/core/CDebug.php index 5f47cbf..c892f73 100644 --- a/framework/core/CDebug.php +++ b/framework/core/CDebug.php @@ -34,17 +34,17 @@ class CDebug /** @var string */ private static $_endMemoryUsage; /** @var array */ - private static $_arrGeneral = array(); + private static $_arrGeneral = []; /** @var array */ - private static $_arrParams = array(); + private static $_arrParams = []; /** @var array */ - private static $_arrConsole = array(); + private static $_arrConsole = []; /** @var array */ - private static $_arrWarnings = array(); + private static $_arrWarnings = []; /** @var array */ - private static $_arrErrors = array(); + private static $_arrErrors = []; /** @var array */ - private static $_arrQueries = array(); + private static $_arrQueries = []; /** @var array */ private static $_arrData; /** @var float */ @@ -169,7 +169,7 @@ public static function write($val = '', $key = '', $storeType = '') * @param array $traceData * @return string */ - public static function prepareBacktrace($traceData = array()) + public static function prepareBacktrace($traceData = []) { $stack = ''; $i = 0; @@ -203,7 +203,7 @@ public static function prepareBacktrace($traceData = array()) * @param bool $formatted * @return HTML */ - public static function backtrace($message = '', $traceData = array(), $formatted = true) + public static function backtrace($message = '', $traceData = [], $formatted = true) { if (APPHP_MODE == 'debug') { $stack = self::prepareBacktrace($traceData); @@ -553,7 +553,7 @@ function appExpandTabs(act, key){ $output .= '<strong>$_GET</strong>:'; $output .= '<pre style="white-space:pre-wrap;">'; - $arrGet = array(); + $arrGet = []; if (isset($_GET)) { foreach ($_GET as $key => $val) { $arrGet[$key] = is_array($val) ? $val : strip_tags($val); @@ -566,7 +566,7 @@ function appExpandTabs(act, key){ $output .= '<strong>$_POST</strong>:'; $output .= '<pre style="white-space:pre-wrap;">'; - $arrPost = array(); + $arrPost = []; if (isset($_POST)) { foreach ($_POST as $key => $val) { $arrPost[$key] = is_array($val) ? $val : strip_tags($val); @@ -579,7 +579,7 @@ function appExpandTabs(act, key){ $output .= '<strong>$_FILES</strong>:'; $output .= '<pre style="white-space:pre-wrap;">'; - $arrFiles = array(); + $arrFiles = []; if (isset($_FILES)) { foreach ($_FILES as $key => $val) { $arrFiles[$key] = is_array($val) ? $val : strip_tags($val); @@ -592,7 +592,7 @@ function appExpandTabs(act, key){ $output .= '<strong>$_COOKIE</strong>:'; $output .= '<pre style="white-space:pre-wrap;">'; - $arrCookie = array(); + $arrCookie = []; if (isset($_COOKIE)) { foreach ($_COOKIE as $key => $val) { $arrCookie[$key] = is_array($val) ? $val : strip_tags($val); @@ -605,7 +605,7 @@ function appExpandTabs(act, key){ $output .= '<strong>$_SESSION</strong>:'; $output .= '<pre style="white-space:pre-wrap;">'; - $arrSession = array(); + $arrSession = []; if (isset($_SESSION)) { foreach ($_SESSION as $key => $val) { $arrSession[$key] = is_array($val) ? $val : strip_tags($val); @@ -619,7 +619,7 @@ function appExpandTabs(act, key){ $output .= '<strong>CONSTANTS</strong>:'; $output .= '<pre style="white-space:pre-wrap;">'; $arrConstants = @get_defined_constants(true); - $arrUserConstants = isset($arrConstants['user']) ? print_r($arrConstants['user'], true) : array(); + $arrUserConstants = isset($arrConstants['user']) ? print_r($arrConstants['user'], true) : []; $output .= $htmlCompression ? nl2br($arrUserConstants) : $arrUserConstants; $output .= '</pre>'; $output .= '<br>'; diff --git a/framework/core/CModel.php b/framework/core/CModel.php index 1d7ab20..ad92405 100644 --- a/framework/core/CModel.php +++ b/framework/core/CModel.php @@ -34,7 +34,7 @@ abstract class CModel * Class constructor * @param array $params */ - public function __construct($params = array()) + public function __construct($params = []) { $this->_db = CDatabase::init($params); @@ -47,7 +47,7 @@ public function __construct($params = array()) * @param array $params * @return CModel|object */ - public static function init($params = array()) + public static function init($params = []) { if (self::$_instance == null) self::$_instance = new self($params); return self::$_instance; diff --git a/framework/core/CRouter.php b/framework/core/CRouter.php index e89eab4..4bb1d9b 100644 --- a/framework/core/CRouter.php +++ b/framework/core/CRouter.php @@ -69,7 +69,7 @@ class CRouter /** @var string */ private $_module; /** @var array */ - private static $_params = array(); + private static $_params = []; /** diff --git a/framework/core/CView.php b/framework/core/CView.php index fa7542a..5c6d73e 100644 --- a/framework/core/CView.php +++ b/framework/core/CView.php @@ -56,11 +56,11 @@ class CView /** @var string */ private $_breadcrumbsTitle; /** @var array */ - private $_vars = array(); + private $_vars = []; /** @var bool */ private $_isRendered = false; /** @var array */ - private $_isCompRendered = array(); + private $_isCompRendered = []; /** @var boolean to enable html output compression */ private $_htmlCompression = false; /** @var int */ @@ -444,7 +444,7 @@ public function renderContent($view, $return = false) * @throws Exception * @return void */ - public function renderView($params, $data = array(), $return = false) + public function renderView($params, $data = [], $return = false) { try { // Set default controller and action @@ -652,8 +652,16 @@ public function isDefaultPage() private function _renderHeaders() { header('X-Author: ApPHP'); - //header('X-Framework-Name: ApPHP'); - //header('X-Framework-Version: '.A::version()); - //CSecureHeaders::renderHeaders(); + + // Framework info headers + if (CConfig::get('httpHeaders.framework') === true) { + header('X-Framework-Name: ApPHP'); + header('X-Framework-Version: '.A::version()); + } + + // Secure headers + if (CConfig::get('httpHeaders.secure') === true) { + CSecureHeaders::renderHeaders(); + } } } \ No newline at end of file diff --git a/framework/helpers/CGeoLocation.php b/framework/helpers/CGeoLocation.php index 8d31637..6f5c2fe 100644 --- a/framework/helpers/CGeoLocation.php +++ b/framework/helpers/CGeoLocation.php @@ -38,7 +38,7 @@ public static function coordinatesByAddress($address = '', $region = '', $key = '®ion='.$region. (!empty($key) ? '&key='.$key : ''); - $json = A::app()->getRequest()->getUrlContent($url, 'get', array(), array(), 'curl'); + $json = A::app()->getRequest()->getUrlContent($url, 'get', [], [], 'curl'); $json = json_decode($json); if(!empty($json) && $json->{'results'} != false){ diff --git a/framework/helpers/widgets/CFormValidation.php b/framework/helpers/widgets/CFormValidation.php index 8c98ea4..3fccba7 100644 --- a/framework/helpers/widgets/CFormValidation.php +++ b/framework/helpers/widgets/CFormValidation.php @@ -21,7 +21,7 @@ class CFormValidation extends CWidgs /** @var string */ private static $_errorMessage = ''; - private static $_output = array('error'=>false, 'uploadedFiles'=>array()); + private static $_output = array('error'=>false, 'uploadedFiles'=>[]); /** * Performs form validation @@ -60,7 +60,7 @@ class CFormValidation extends CWidgs * * 3. <input type="file" name="listing_image[]" value="" /> * ... - * $fieldsImages = array(); + * $fieldsImages = []; * for($i = 1; $i <= 10; $i++){ * $fieldsImages['listing_image'][] = array('title'=>A::t('autoportal', 'Image').' #'.$i, 'validation'=>array('required'=>false, 'type'=>'image', 'targetPath'=>'assets/modules/gallery/images/items/', 'maxSize'=>'990k', 'fileName'=>'l'.$listingId.'_'.CHash::getRandomString(10), 'mimeType'=>'image/jpeg, image/jpg, image/png, image/gif')); * } @@ -98,11 +98,11 @@ class CFormValidation extends CWidgs * // your code here to handle a successful submission... * } */ - public static function init($params = array()) + public static function init($params = []) { parent::init($params); - $fields = self::params('fields', array()); + $fields = self::params('fields', []); $isMultiArray = (bool)self::params('multiArray', false); $ind = 0; @@ -135,7 +135,7 @@ private static function _handleField($field, $fieldInfo, $isMultiArray = false, { $cRequest = A::app()->getRequest(); - $fields = self::params('fields', array()); + $fields = self::params('fields', []); $msgSource = self::params('messagesSource', 'core'); $showAllErrors = self::params('showAllErrors', false); $requestMethod = strtolower(self::params('method', 'post')) == 'get' ? 'getQuery' : 'getPost'; @@ -144,8 +144,8 @@ private static function _handleField($field, $fieldInfo, $isMultiArray = false, $required = self::keyAt('validation.required', $fieldInfo, false); $type = self::keyAt('validation.type', $fieldInfo, 'any'); $viewType = self::keyAt('validation.viewType', $fieldInfo, ''); - $forbiddenChars = self::keyAt('validation.forbiddenChars', $fieldInfo, array()); - $allowedChars = self::keyAt('validation.allowedChars', $fieldInfo, array()); + $forbiddenChars = self::keyAt('validation.forbiddenChars', $fieldInfo, []); + $allowedChars = self::keyAt('validation.allowedChars', $fieldInfo, []); $minLength = self::keyAt('validation.minLength', $fieldInfo, ''); $maxLength = self::keyAt('validation.maxLength', $fieldInfo, ''); $minValue = self::keyAt('validation.minValue', $fieldInfo, ''); @@ -161,7 +161,7 @@ private static function _handleField($field, $fieldInfo, $isMultiArray = false, $targetPath = self::keyAt('validation.targetPath', $fieldInfo, ''); $fileMimeType = self::keyAt('validation.mimeType', $fieldInfo, ''); - $fileMimeTypes = (!empty($fileMimeType)) ? explode(',', str_replace(' ', '', $fileMimeType)) : array(); + $fileMimeTypes = (!empty($fileMimeType)) ? explode(',', str_replace(' ', '', $fileMimeType)) : []; $fileDefinedName = self::keyAt('validation.fileName', $fieldInfo, ''); $trim = (bool)self::keyAt('validation.trim', $fieldInfo, false); $format = self::keyAt('validation.format', $fieldInfo, ''); @@ -419,7 +419,7 @@ private static function _handleField($field, $fieldInfo, $isMultiArray = false, } break; case 'set': - $sourceArray = self::keyAt('validation.source', $fieldInfo, array()); + $sourceArray = self::keyAt('validation.source', $fieldInfo, []); if (is_array($fieldValue)) { foreach ($fieldValue as $key => $val) { $valid = CValidator::inArray($val, $sourceArray); diff --git a/framework/helpers/widgets/CGridView.php b/framework/helpers/widgets/CGridView.php index f172c3c..3262e57 100644 --- a/framework/helpers/widgets/CGridView.php +++ b/framework/helpers/widgets/CGridView.php @@ -92,23 +92,23 @@ class CGridView extends CWidgs * 'gridTable' => array('class'=>''), * ), * 'filters' => array( - * 'field_1' => ['title'=>'Field 1', 'type'=>'textbox', 'table'=>'', 'operator'=>'=', 'default'=>'', 'width'=>'', 'maxLength'=>'', 'htmlOptions'=>array()], - * 'field_2' => ['title'=>'Field 2', 'type'=>'textbox', 'table'=>'', 'operator'=>'=', 'default'=>'', 'width'=>'', 'maxLength'=>'', 'autocomplete'=>array('enable'=>true, 'ajaxHandler'=>'path/to/handler/file', 'minLength'=>3, 'returnId'=>true), 'htmlOptions'=>array()], + * 'field_1' => ['title'=>'Field 1', 'type'=>'textbox', 'table'=>'', 'operator'=>'=', 'default'=>'', 'width'=>'', 'maxLength'=>'', 'htmlOptions'=>[]], + * 'field_2' => ['title'=>'Field 2', 'type'=>'textbox', 'table'=>'', 'operator'=>'=', 'default'=>'', 'width'=>'', 'maxLength'=>'', 'autocomplete'=>array('enable'=>true, 'ajaxHandler'=>'path/to/handler/file', 'minLength'=>3, 'returnId'=>true), 'htmlOptions'=>[]], * 'field_3' => ['title'=>'Field 3', 'type'=>'enum', 'table'=>'', 'operator'=>'=', 'default'=>'', 'width'=>'', 'source'=>array('0'=>'No', '1'=>'Yes'), 'emptyOption'=>true, 'emptyValue'=>'', 'htmlOptions'=>array('class'=>'chosen-select-filter')], - * 'field_4' => ['title'=>'Field 5', 'type'=>'datetime', 'table'=>'', 'operator'=>'=', 'default'=>'', 'width'=>'80px', 'maxLength'=>'', 'format'=>'', 'htmlOptions'=>array(), 'viewType'=>'datetime|date|time'], + * 'field_4' => ['title'=>'Field 5', 'type'=>'datetime', 'table'=>'', 'operator'=>'=', 'default'=>'', 'width'=>'80px', 'maxLength'=>'', 'format'=>'', 'htmlOptions'=>[], 'viewType'=>'datetime|date|time'], * ), * 'fields' => array( * 'field_1' => array('title'=>'Field 1', 'type'=>'index', 'align'=>'', 'width'=>'', 'class'=>'left', 'headerTooltip'=>'', 'headerClass'=>'left', 'isSortable'=>false), * 'field_2' => array('title'=>'Field 2', 'type'=>'concat', 'align'=>'', 'width'=>'', 'class'=>'left', 'headerTooltip'=>'', 'headerClass'=>'left', 'isSortable'=>true, 'concatFields'=>array('first_name', 'last_name'), 'concatSeparator'=>', ',), * 'field_3' => array('title'=>'Field 3', 'type'=>'decimal', 'align'=>'', 'width'=>'', 'class'=>'right', 'headerTooltip'=>'', 'headerClass'=>'right', 'isSortable'=>true, 'format'=>'american|european', 'decimalPoints'=>''), - * 'field_4' => array('title'=>'Field 4', 'type'=>'datetime', 'align'=>'', 'width'=>'', 'class'=>'left', 'headerTooltip'=>'', 'headerClass'=>'left', 'isSortable'=>true, 'definedValues'=>array(), 'format'=>''), + * 'field_4' => array('title'=>'Field 4', 'type'=>'datetime', 'align'=>'', 'width'=>'', 'class'=>'left', 'headerTooltip'=>'', 'headerClass'=>'left', 'isSortable'=>true, 'definedValues'=>[], 'format'=>''), * 'field_5' => array('title'=>'Field 5', 'type'=>'enum', 'align'=>'', 'width'=>'', 'class'=>'center', 'headerTooltip'=>'', 'headerClass'=>'center', 'isSortable'=>true, 'source'=>array('0'=>'No', '1'=>'Yes')), * 'field_6' => array('title'=>'Field 6', 'type'=>'image', 'align'=>'', 'width'=>'', 'class'=>'center', 'headerTooltip'=>'', 'headerClass'=>'center', 'isSortable'=>false, 'imagePath'=>'images/flags/', 'defaultImage'=>'', 'imageWidth'=>'16px', 'imageHeight'=>'16px', 'alt'=>'', 'showImageInfo'=>true), - * 'field_7' => array('title'=>'Field 7', 'type'=>'label', 'align'=>'', 'width'=>'', 'class'=>'left', 'headerTooltip'=>'', 'headerClass'=>'left', 'isSortable'=>true, 'changeOrder'=>false, 'definedValues'=>array(), 'stripTags'=>false, 'case'=>'', 'maxLength'=>'', 'showTooltip'=>true, 'callback'=>array('function'=>$functionName, 'params'=>$functionParams), 'trigger'=>array('trigger_key'=>'', 'trigger_operation'=>'!=', 'trigger_value'=>'', 'success_value'=>'', 'wrong_value'=>'')), - * 'field_8' => array('title'=>'Field 8', 'type'=>'html', 'align'=>'', 'width'=>'', 'class'=>'left', 'headerTooltip'=>'', 'headerClass'=>'left', 'isSortable'=>true, 'definedValues'=>array(), 'stripTags'=>false, 'case'=>'', 'maxLength'=>'', 'showTooltip'=>true, 'callback'=>array('function'=>$functionName, 'params'=>$functionParams), 'trigger'=>array('trigger_key'=>'', 'trigger_operation'=>'!=', 'trigger_value'=>'', 'success_value'=>'', 'wrong_value'=>'')), - * 'field_9' => array('title'=>'Field 9', 'type'=>'link', 'align'=>'', 'width'=>'', 'class'=>'center', 'headerTooltip'=>'', 'headerClass'=>'center', 'isSortable'=>false, 'linkUrl'=>'path/to/param/{field_name}/page/{page}', 'linkText'=>'{field_name}|free text', 'definedValues'=>array(), 'htmlOptions'=>array()), - * 'field_10' => array('title'=>'Field 10', 'type'=>'evaluation', 'align'=>'', 'width'=>'', 'class'=>'center', 'headerTooltip'=>'', 'headerClass'=>'center', 'isSortable'=>false, 'minValue'=>1, 'maxValue'=>5, 'tooltip'=>A::t('app', 'Value'), 'counts'=>array('fieldName'=>'', 'title'=>A::t('app', 'Evaluations')), 'definedValues'=>array(), 'htmlOptions'=>array()), - * 'field_11' => array('title'=>'Field 11', 'type'=>'template', 'align'=>'', 'width'=>'', 'class'=>'left', 'headerTooltip'=>'', 'headerClass'=>'left', 'isSortable'=>false, 'sortBy'=>'', 'html'=>'{category_id}', 'fields'=>array('category_id'=>array('default'=>'', 'prefix'=>'', 'postfix'=>'', 'source'=>array()))), + * 'field_7' => array('title'=>'Field 7', 'type'=>'label', 'align'=>'', 'width'=>'', 'class'=>'left', 'headerTooltip'=>'', 'headerClass'=>'left', 'isSortable'=>true, 'changeOrder'=>false, 'definedValues'=>[], 'stripTags'=>false, 'case'=>'', 'maxLength'=>'', 'showTooltip'=>true, 'callback'=>array('function'=>$functionName, 'params'=>$functionParams), 'trigger'=>array('trigger_key'=>'', 'trigger_operation'=>'!=', 'trigger_value'=>'', 'success_value'=>'', 'wrong_value'=>'')), + * 'field_8' => array('title'=>'Field 8', 'type'=>'html', 'align'=>'', 'width'=>'', 'class'=>'left', 'headerTooltip'=>'', 'headerClass'=>'left', 'isSortable'=>true, 'definedValues'=>[], 'stripTags'=>false, 'case'=>'', 'maxLength'=>'', 'showTooltip'=>true, 'callback'=>array('function'=>$functionName, 'params'=>$functionParams), 'trigger'=>array('trigger_key'=>'', 'trigger_operation'=>'!=', 'trigger_value'=>'', 'success_value'=>'', 'wrong_value'=>'')), + * 'field_9' => array('title'=>'Field 9', 'type'=>'link', 'align'=>'', 'width'=>'', 'class'=>'center', 'headerTooltip'=>'', 'headerClass'=>'center', 'isSortable'=>false, 'linkUrl'=>'path/to/param/{field_name}/page/{page}', 'linkText'=>'{field_name}|free text', 'definedValues'=>[], 'htmlOptions'=>[]), + * 'field_10' => array('title'=>'Field 10', 'type'=>'evaluation', 'align'=>'', 'width'=>'', 'class'=>'center', 'headerTooltip'=>'', 'headerClass'=>'center', 'isSortable'=>false, 'minValue'=>1, 'maxValue'=>5, 'tooltip'=>A::t('app', 'Value'), 'counts'=>array('fieldName'=>'', 'title'=>A::t('app', 'Evaluations')), 'definedValues'=>[], 'htmlOptions'=>[]), + * 'field_11' => array('title'=>'Field 11', 'type'=>'template', 'align'=>'', 'width'=>'', 'class'=>'left', 'headerTooltip'=>'', 'headerClass'=>'left', 'isSortable'=>false, 'sortBy'=>'', 'html'=>'{category_id}', 'fields'=>array('category_id'=>array('default'=>'', 'prefix'=>'', 'postfix'=>'', 'source'=>[]))), * ), * 'actions' => array( * 'edit' => array('link'=>'locations/edit/id/{id}/page/{page}', 'imagePath'=>'templates/backend/images/edit.png', 'title'=>'Edit this record'), @@ -117,7 +117,7 @@ class CGridView extends CWidgs * 'return'=>true, * )); */ - public static function init($params = array()) + public static function init($params = []) { parent::init($params); @@ -133,15 +133,15 @@ public static function init($params = array()) $passParameters = (bool)self::params('passParameters', false); $customParameters = self::params('customParameters', false); $return = (bool)self::params('return', true); - $fields = self::params('fields', array()); - $filters = self::params('filters', array()); - $actions = self::params('actions', array()); + $fields = self::params('fields', []); + $filters = self::params('filters', []); + $actions = self::params('actions', []); $sortingEnabled = (bool)self::params('sorting', false); - $filterDiv = self::params('options.filterDiv', array()); - $filterForm = self::params('options.filterForm', array()); - $filterItemDiv = self::params('options.filterItemDiv', array()); + $filterDiv = self::params('options.filterDiv', []); + $filterForm = self::params('options.filterForm', []); + $filterItemDiv = self::params('options.filterItemDiv', []); $filterType = self::params('options.filterType', 'default'); - $gridWrapper = self::params('options.gridWrapper', array()); + $gridWrapper = self::params('options.gridWrapper', []); $gridTable = self::params('options.gridTable', array()); $linkType = (int)self::params('linkType', 0); /* Link type: 0 - standard, 1 - SEO */ $pagination = (bool)self::params('pagination.enable', ''); diff --git a/framework/helpers/widgets/CMessage.php b/framework/helpers/widgets/CMessage.php index 45d9245..f33947b 100644 --- a/framework/helpers/widgets/CMessage.php +++ b/framework/helpers/widgets/CMessage.php @@ -30,19 +30,19 @@ class CMessage extends CWidgs * @param array $params * * Usage: - * CWidget::create('CMessage', array( + * CWidget::create('CMessage', [ * 'info|success|error|warning|validation', * 'message', - * array( - * 'id'=>'', + * [ + * 'id'=>'', * 'button'=>true, * 'return'=>true - * ) - * )); + * ] + * ]); */ - public static function init($type = '', $text = '', $params = array()) - { - parent::init($params); + public static function init($type = '', $text = '', $params = []) + { + parent::init($params); // Change type to lowercase if (!CConfig::get('widgets.paramKeysSensitive')) { @@ -56,10 +56,10 @@ public static function init($type = '', $text = '', $params = array()) $output = ''; $tagName = 'div'; - $htmlOptions = array(); - $type = (in_array($type, array('info', 'success', 'error', 'warning', 'validation'))) ? $type : ''; - - if (!empty($text)) { + $htmlOptions = []; + $type = (in_array($type, ['info', 'success', 'error', 'warning', 'validation'])) ? $type : ''; + + if (!empty($text)) { $htmlOptions['class'] = 'alert alert-' . $type; if ($param_id) $htmlOptions['id'] = $param_id; $output .= CHtml::openTag($tagName, $htmlOptions); diff --git a/framework/vendors/tcpdf/tcpdf_parser.php b/framework/vendors/tcpdf/tcpdf_parser.php index 05a0588..249fe03 100644 --- a/framework/vendors/tcpdf/tcpdf_parser.php +++ b/framework/vendors/tcpdf/tcpdf_parser.php @@ -63,13 +63,13 @@ class TCPDF_PARSER { * XREF data. * @protected */ - protected $xref = array(); + protected $xref = []; /** * Array of PDF objects. * @protected */ - protected $objects = array(); + protected $objects = []; /** * Class object for decoding filters. @@ -99,7 +99,7 @@ class TCPDF_PARSER { * @public * @since 1.0.000 (2011-05-24) */ - public function __construct($data, $cfg=array()) { + public function __construct($data, $cfg=[]) { if (empty($data)) { $this->Error('Empty PDF data.'); } @@ -116,7 +116,7 @@ public function __construct($data, $cfg=array()) { // get xref and trailer data $this->xref = $this->getXrefData(); // parse all document objects - $this->objects = array(); + $this->objects = []; foreach ($this->xref['xref'] as $obj => $offset) { if (!isset($this->objects[$obj]) AND ($offset > 0)) { // decode objects with positive offset @@ -166,7 +166,7 @@ public function getParsedData() { * @protected * @since 1.0.000 (2011-05-24) */ - protected function getXrefData($offset=0, $xref=array()) { + protected function getXrefData($offset=0, $xref=[]) { if ($offset == 0) { // find last startxref if (preg_match_all('/[\r\n]startxref[\s]*[\r\n]+([0-9]+)[\s]*[\r\n]+%%EOF/i', $this->pdfdata, $matches, PREG_SET_ORDER, $offset) == 0) { @@ -208,7 +208,7 @@ protected function getXrefData($offset=0, $xref=array()) { * @protected * @since 1.0.000 (2011-06-20) */ - protected function decodeXref($startxref, $xref=array()) { + protected function decodeXref($startxref, $xref=[]) { $startxref += 4; // 4 is the length of the word 'xref' // skip initial white space chars: \x00 null (NUL), \x09 horizontal tab (HT), \x0A line feed (LF), \x0C form feed (FF), \x0D carriage return (CR), \x20 space (SP) $offset = $startxref + strspn($this->pdfdata, "\x00\x09\x0a\x0c\x0d\x20", $startxref); @@ -242,7 +242,7 @@ protected function decodeXref($startxref, $xref=array()) { $trailer_data = $matches[1][0]; if (!isset($xref['trailer']) OR empty($xref['trailer'])) { // get only the last updated version - $xref['trailer'] = array(); + $xref['trailer'] = []; // parse trailer_data if (preg_match('/Size[\s]+([0-9]+)/i', $trailer_data, $matches) > 0) { $xref['trailer']['size'] = intval($matches[1]); @@ -257,7 +257,7 @@ protected function decodeXref($startxref, $xref=array()) { $xref['trailer']['info'] = intval($matches[1]).'_'.intval($matches[2]); } if (preg_match('/ID[\s]*[\[][\s]*[<]([^>]*)[>][\s]*[<]([^>]*)[>]/i', $trailer_data, $matches) > 0) { - $xref['trailer']['id'] = array(); + $xref['trailer']['id'] = []; $xref['trailer']['id'][0] = $matches[1]; $xref['trailer']['id'][1] = $matches[2]; } @@ -280,25 +280,25 @@ protected function decodeXref($startxref, $xref=array()) { * @protected * @since 1.0.003 (2013-03-16) */ - protected function decodeXrefStream($startxref, $xref=array()) { + protected function decodeXrefStream($startxref, $xref=[]) { // try to read Cross-Reference Stream $xrefobj = $this->getRawObject($startxref); $xrefcrs = $this->getIndirectObject($xrefobj[1], $startxref, true); if (!isset($xref['trailer']) OR empty($xref['trailer'])) { // get only the last updated version - $xref['trailer'] = array(); + $xref['trailer'] = []; $filltrailer = true; } else { $filltrailer = false; } if (!isset($xref['xref'])) { - $xref['xref'] = array(); + $xref['xref'] = []; } $valid_crs = false; $columns = 0; $sarr = $xrefcrs[0][1]; if (!is_array($sarr)) { - $sarr = array(); + $sarr = []; } foreach ($sarr as $k => $v) { if (($v[0] == '/') AND ($v[1] == 'Type') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == '/') AND ($sarr[($k +1)][1] == 'XRef'))) { diff --git a/utils/generators/inc/functions.inc.php b/utils/generators/inc/functions.inc.php index 399ebbb..533ed19 100644 --- a/utils/generators/inc/functions.inc.php +++ b/utils/generators/inc/functions.inc.php @@ -1,6 +1,6 @@ <?php -function render_file($_params_ = array()){ +function render_file($_params_ = []){ $_file_ = dirname(__FILE__).'/../views/index.php'; extract($_params_); require($_file_); diff --git a/utils/generators/index.php b/utils/generators/index.php index daaa079..67c5a94 100644 --- a/utils/generators/index.php +++ b/utils/generators/index.php @@ -5,15 +5,15 @@ * This script will help you to generate codes for framework and existing applications */ -$arr_generation_types = array( - 'controller' => array('name'=>'Simple Controller', 'path'=>''), - 'model' => array('name'=>'Simple Model', 'path'=>''), - 'view' => array('name'=>'Simple View', 'path'=>''), - 'ar_controller' => array('name'=>'Active Records Controller', 'path'=>''), - 'ar_model' => array('name'=>'Active Records Model', 'path'=>''), - 'ar_view' => array('name'=>'Active Records View', 'path'=>''), +$arr_generation_types = [ + 'controller' => ['name' => 'Simple Controller', 'path' => ''], + 'model' => ['name' => 'Simple Model', 'path' => ''], + 'view' => ['name' => 'Simple View', 'path' => ''], + 'ar_controller' => ['name' => 'Active Records Controller', 'path' => ''], + 'ar_model' => ['name' => 'Active Records Model', 'path' => ''], + 'ar_view' => ['name' => 'Active Records View', 'path' => ''], //'module' => array('name'=>'Module', 'path'=>''), -); +]; $generation_type = isset($_GET['generation_type']) ? filter_var($_GET['generation_type'], FILTER_SANITIZE_STRING) : ''; $content = '<h2>Code Generator</h2>To start code generation select a Generation Type from the left dropdown box, then follow instructions.'; diff --git a/utils/requirements/inc/functions.inc.php b/utils/requirements/inc/functions.inc.php index d79f395..47e6126 100644 --- a/utils/requirements/inc/functions.inc.php +++ b/utils/requirements/inc/functions.inc.php @@ -7,7 +7,7 @@ function check_server_vars($realpath = '') { $vars = array('HTTP_HOST', 'SERVER_NAME', 'SERVER_PORT', 'SCRIPT_NAME', 'SCRIPT_FILENAME', 'PHP_SELF', 'HTTP_ACCEPT', 'HTTP_USER_AGENT'); - $missing = array(); + $missing = []; foreach($vars as $var){ if(!isset($_SERVER[$var])) $missing[] = $var; } @@ -105,7 +105,7 @@ function get_footer_info() * Render file * @return void */ -function render_file($_params_ = array()) +function render_file($_params_ = []) { $_file_ = dirname(__FILE__).'/../views/index.php'; extract($_params_); @@ -165,13 +165,13 @@ function get_php_info() { ob_start(); if(function_exists('phpinfo')) @phpinfo(-1); - $phpInfo = array('phpinfo' => array()); + $phpInfo = array('phpinfo' => []); if(preg_match_all('#(?:<h2>(?:<a name=".*?">)?(.*?)(?:</a>)?</h2>)|(?:<tr(?: class=".*?")?><t[hd](?: class=".*?")?>(.*?)\s*</t[hd]>(?:<t[hd](?: class=".*?")?>(.*?)\s*</t[hd]>(?:<t[hd](?: class=".*?")?>(.*?)\s*</t[hd]>)?)?</tr>)#s', ob_get_clean(), $matches, PREG_SET_ORDER)) foreach($matches as $match){ $arrayKeys = array_keys($phpInfo); $endArrayKeys = end($arrayKeys); if(strlen($match[1])){ - $phpInfo[$match[1]] = array(); + $phpInfo[$match[1]] = []; }elseif(isset($match[3])){ $phpInfo[$endArrayKeys][$match[2]] = isset($match[4]) ? array($match[3], $match[4]) : $match[3]; }else{ diff --git a/utils/requirements/index.php b/utils/requirements/index.php index 084ee4b..bcc4bd0 100644 --- a/utils/requirements/index.php +++ b/utils/requirements/index.php @@ -13,28 +13,33 @@ * list of requirements ([0]name, [1]required or not, [2]value, [3]result, [4]used by, [5]memo) */ $requirements = array( - array('Web Server', false, get_server_info(), true, 'ApPHP Framework', ''), - array('PHP version', true, phpversion(), version_compare(phpversion(), '5.4.0', '>='), 'ApPHP Framework', 'PHP 5.4.0 or higher is required.'), - array('PHP Short Open Tag', true, (($message = check_short_open_tag()) == 'on' ? 'enabled' : ''), $message, 'ApPHP Framework', 'PHP 5.4.0 or higher is required or PHP must be configured with the <b>--enable-short-tags</b> option.'), - array('PHP "mcrypt_" functions', false, (function_exists('mcrypt_decrypt') && function_exists('mcrypt_encrypt')) ? 'exists' : 'not found', (function_exists('mcrypt_decrypt') && function_exists('mcrypt_encrypt')), 'ApPHP Framework', 'PHP 4 >= 4.0.2, PHP 5'), - array('$_POST variable', true, (($message = check_post_vars()) === '' ? 'exists' : ''), ($message === ''), 'ApPHP Framework', $message), - array('$_SERVER variable', true, (($message = check_server_vars(realpath(__FILE__))) === '' ? 'exists' : ''), ($message === ''), 'ApPHP Framework', $message), - array('$_SESSION variable', true, (($message = check_session_vars()) === '') ? 'exists' : '', ($message === ''), 'ApPHP Framework', $message), - array('Apache module "mod_rewrite"', true, (($message = check_module_mod_rewrite()) == true ? 'enabled' : ''), $message, 'ApPHP Framework', 'Required for normal site work, SEO links.'), - array('PDO extension', true, (extension_loaded('pdo') ? 'installed' : ''), extension_loaded('pdo'), 'All DB-related classes', ''), - array('PDO MySQL extension', true, (extension_loaded('pdo_mysql') ? 'installed' : ''), extension_loaded('pdo_mysql'), 'All DB-related classes', 'Required if you are using MySQL database.'), - array('PDO SQLite extension', false, (extension_loaded('pdo_sqlite') ? 'installed' : ''), extension_loaded('pdo_sqlite'), 'All DB-related classes', 'Required if you are using SQLite database.'), + ['Web Server', false, get_server_info(), true, 'ApPHP Framework', ''], + ['PHP version', true, phpversion(), version_compare(phpversion(), '5.4.0', '>='), 'ApPHP Framework', 'PHP 5.4.0 or higher is required.'], + ['PHP Short Open Tag', true, (($message = check_short_open_tag()) == 'on' ? 'enabled' : ''), $message, 'ApPHP Framework', 'PHP 5.4.0 or higher is required or PHP must be configured with the <b>--enable-short-tags</b> option.'], + ['PHP "mcrypt_" functions', false, (function_exists('mcrypt_decrypt') && function_exists('mcrypt_encrypt')) ? 'exists' : 'not found', (function_exists('mcrypt_decrypt') && function_exists('mcrypt_encrypt')), 'ApPHP Framework', 'PHP 4 >= 4.0.2, PHP 5'], + ['$_POST variable', true, (($message = check_post_vars()) === '' ? 'exists' : ''), ($message === ''), 'ApPHP Framework', $message], + ['$_SERVER variable', true, (($message = check_server_vars(realpath(__FILE__))) === '' ? 'exists' : ''), ($message === ''), 'ApPHP Framework', $message], + ['$_SESSION variable', true, (($message = check_session_vars()) === '') ? 'exists' : '', ($message === ''), 'ApPHP Framework', $message], + ['Apache module "mod_rewrite"', true, (($message = check_module_mod_rewrite()) == true ? 'enabled' : ''), $message, 'ApPHP Framework', 'Required for normal site work, SEO links.'], + ['PDO extension', true, (extension_loaded('pdo') ? 'installed' : ''), extension_loaded('pdo'), 'All DB-related classes', ''], + ['PDO MySQL extension', true, (extension_loaded('pdo_mysql') ? 'installed' : ''), extension_loaded('pdo_mysql'), 'All DB-related classes', 'Required if you are using MySQL database.'], + ['PDO SQLite extension', false, (extension_loaded('pdo_sqlite') ? 'installed' : ''), extension_loaded('pdo_sqlite'), 'All DB-related classes', 'Required if you are using SQLite database.'], ); // 1 - passed, 0 - failed, -1 - passed with warnings -$result = 1; - -foreach($requirements as $i => $requirement){ - if($requirement[1] && !$requirement[2]) $result = 0; - elseif($result > 0 && !$requirement[1] && !$requirement[2]) $result = -1; - if($requirement[4] === '') $requirements[$i][4] = ' '; +$result = 1; + +foreach ($requirements as $i => $requirement) { + if ($requirement[1] && ! $requirement[2]) { + $result = 0; + } elseif ($result > 0 && ! $requirement[1] && ! $requirement[2]) { + $result = -1; + } + + if ($requirement[4] === '') { + $requirements[$i][4] = ' '; + } } -render_file(array('requirements'=>$requirements, 'result'=>$result, 'server_info'=>get_footer_info())); - +render_file(['requirements' => $requirements, 'result' => $result, 'server_info' => get_footer_info()]); diff --git a/utils/tests/inc/controller/data.php b/utils/tests/inc/controller/data.php index a33f3b9..b59d508 100644 --- a/utils/tests/inc/controller/data.php +++ b/utils/tests/inc/controller/data.php @@ -3,7 +3,7 @@ $dir = $arr_projects[$project]['path']; // Open a known directory, and proceed to read its contents -$prepare_data = array(); +$prepare_data = []; if(is_dir($dir)){ if($dh = opendir($dir)){ while(($file = readdir($dh)) !== false){ diff --git a/utils/tests/inc/filter/data.php b/utils/tests/inc/filter/data.php index 2063e92..872817f 100644 --- a/utils/tests/inc/filter/data.php +++ b/utils/tests/inc/filter/data.php @@ -2,30 +2,30 @@ /** * Format: type, value, result */ -$prepare_data = array( - 'sanitize' => array( - array('string', 'wrwer_wer', true), - array('string', 'asd$56fgh', true), - array('string', 'a_+sdTgg#$56fgh', true), - array('email', "^()!#$%&'*+-/=?^_`{|}~@.[]", false), - array('email', 'email.me@email.me', true), - array('email', 'email@e+-mail.me', true), - array('url', "http://www.domain.com/$-_!2=+-", true), - array('alpha', 'asd@#$23423234', false), - array('alpha', 'asdAss', true), - array('alpha', 'abc123', false), - array('alphanumeric', 'asdAss_+12345', false), - array('alphanumeric', 'asdAss12345', true), - array('number_int', '12345', true), - array('number_int', '0123', true), - array('number_int', '1_eRf45_)(*', true), - array('number_float', '123', true), - array('number_float', '+123', true), - array('number_float', '123.12', true), - array('number_float', '123,12', true), - array('number_float', '123.12a', true), - array('number_float', '123e+02', true), - array('number_float', '0.123e+02', true), - ), -); +$prepare_data = [ + 'sanitize' => [ + ['string', 'wrwer_wer', true], + ['string', 'asd$56fgh', true], + ['string', 'a_+sdTgg#$56fgh', true], + ['email', "^()!#$%&'*+-/=?^_`{|}~@.[]", false], + ['email', 'email.me@email.me', true], + ['email', 'email@e+-mail.me', true], + ['url', "http://www.domain.com/$-_!2=+-", true], + ['alpha', 'asd@#$23423234', false], + ['alpha', 'asdAss', true], + ['alpha', 'abc123', false], + ['alphanumeric', 'asdAss_+12345', false], + ['alphanumeric', 'asdAss12345', true], + ['number_int', '12345', true], + ['number_int', '0123', true], + ['number_int', '1_eRf45_)(*', true], + ['number_float', '123', true], + ['number_float', '+123', true], + ['number_float', '123.12', true], + ['number_float', '123,12', true], + ['number_float', '123.12a', true], + ['number_float', '123e+02', true], + ['number_float', '0.123e+02', true], + ], +]; \ No newline at end of file diff --git a/utils/tests/inc/functions.inc.php b/utils/tests/inc/functions.inc.php index 0e50421..c2de66c 100644 --- a/utils/tests/inc/functions.inc.php +++ b/utils/tests/inc/functions.inc.php @@ -8,7 +8,7 @@ function starts_with($str, $sub) { return strpos($str, $sub) === 0; } -function render_file($_params_ = array()){ +function render_file($_params_ = []){ $_file_ = dirname(__FILE__).'/../views/index.php'; extract($_params_); require($_file_); diff --git a/utils/tests/inc/validator/data.php b/utils/tests/inc/validator/data.php index c201552..6dff68d 100644 --- a/utils/tests/inc/validator/data.php +++ b/utils/tests/inc/validator/data.php @@ -3,43 +3,43 @@ /** * Format: 'value' => expected result true|false */ -$prepare_data = array( - 'isAlpha' => array( - 'abcdef' => true, - 'AbcdZxc' => true, - '123abc' => false, - 12345 => false, - "-*.,/" => false, - 'zxbcde-' => array('expected'=>true, 'allowed'=>'-'), - 'zxbcdef-' => array('expected'=>false, 'allowed'=>array('=','_')) - ), - 'isNumeric' => array( - '12345' => true, - '01234' => true, - '123abc' => false, - 12345 => true, - "-*.,/" => false, - +12 => true, - '+12' => false, - -1 => false, - '+1' => false, - 0 => true - ), - 'isEmail' => array( - 'me@example.com' => true, - 'me.email' => false, - 'email@email@.com' => false, - 'com.email@me' => false, - 'me.email@.com' => false, - 'me.email@example.com' => true, - 'me.email.me@email.info' => true, - 'me.e_mail99@email.info' => true, - 'me.e_*mail@email.info' => false - ), - 'validateRegex' => array( - 'abcDef' => array('expected'=>true, 'pattern'=>'^[a-zA-Z]+$'), - 'abcDef-' => array('expected'=>true, 'pattern'=>'^[a-zA-Z\-]+$'), - 'abcDef34-' => array('expected'=>true, 'pattern'=>'^[a-zA-Z0-9\-]+$'), - 'abcDef34_' => array('expected'=>false, 'pattern'=>'^[a-zA-Z\-]+$'), - ) -); \ No newline at end of file +$prepare_data = [ + 'isAlpha' => [ + 'abcdef' => true, + 'AbcdZxc' => true, + '123abc' => false, + 12345 => false, + "-*.,/" => false, + 'zxbcde-' => ['expected' => true, 'allowed' => '-'], + 'zxbcdef-' => ['expected' => false, 'allowed' => ['=', '_']] + ], + 'isNumeric' => [ + '12345' => true, + '01234' => true, + '123abc' => false, + 12345 => true, + "-*.,/" => false, + +12 => true, + '+12' => false, + -1 => false, + '+1' => false, + 0 => true + ], + 'isEmail' => [ + 'me@example.com' => true, + 'me.email' => false, + 'email@email@.com' => false, + 'com.email@me' => false, + 'me.email@.com' => false, + 'me.email@example.com' => true, + 'me.email.me@email.info' => true, + 'me.e_mail99@email.info' => true, + 'me.e_*mail@email.info' => false + ], + 'validateRegex' => [ + 'abcDef' => ['expected' => true, 'pattern' => '^[a-zA-Z]+$'], + 'abcDef-' => ['expected' => true, 'pattern' => '^[a-zA-Z\-]+$'], + 'abcDef34-' => ['expected' => true, 'pattern' => '^[a-zA-Z0-9\-]+$'], + 'abcDef34_' => ['expected' => false, 'pattern' => '^[a-zA-Z\-]+$'], + ] +]; \ No newline at end of file From 95984991d5ba5e813b9a4021ea22e94461a26003 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 29 Aug 2020 18:04:05 +0300 Subject: [PATCH 33/45] Added documentation for chunk method of AR --- docs/js/highlight/lang-php.js | 1 + docs/pages/models.html | 20 +++++++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/docs/js/highlight/lang-php.js b/docs/js/highlight/lang-php.js index 2e0d8fd..87bc696 100644 --- a/docs/js/highlight/lang-php.js +++ b/docs/js/highlight/lang-php.js @@ -291,6 +291,7 @@ "setGuarded", "CTime", "getMicrotime", + "chunk", ]; var BUILTINS = {}; diff --git a/docs/pages/models.html b/docs/pages/models.html index 35c97ca..a4d0df6 100644 --- a/docs/pages/models.html +++ b/docs/pages/models.html @@ -11,7 +11,7 @@ <h1>Development - Models</h1> <li><a href="#creating_record">Creating Record</a></li> <li><a href="#updating_record">Updating Record</a></li> <li><a href="#deleting_record">Deleting Record</a></li> - <li><a href="#reading_record">Reading Record</a></li> + <li><a href="#reading_records">Reading Records</a></li> <li><a href="#additional_methods">Additional Methods</a></li> </ul> </li> @@ -415,8 +415,8 @@ <h4>Deleting Record</h4> <br> -<a name="reading_record"></a> -<h4>Reading Record</h4> +<a name="reading_records"></a> +<h4>Reading Records</h4> To read data from a database table, we can use one of the find methods as follows. <pre name="dlhl" class="php"> @@ -433,6 +433,20 @@ <h4>Reading Record</h4> // Finds all rows satisfying the specified conditions with %LIKE% $news = News:model()->findAll(CConfig::get('db.prefix').$this->_tableTranslation.'.news_text LIKE :keywords', array(':keywords'=>'%'.$keywords.'%')); </pre> + +Reading records with chunks. The chunk method breaks the record set into small parts of a given size +<pre name="dlhl" class="php"> +$posts = []; +// 1st parameter - conditions +// 2nd parameter - condition parameters +// 3rd parameter - chunk size +// 4th parameter - callback function +Posts::model()->chunk($conditions, [], 10, function ($records) use(&$posts){ + foreach ($records as $key => $record) { + $posts[] = $record; + } +}); +</pre> <br> From 9ba47ff48157c6d97d914394c9d44dc3f53756c1 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Fri, 2 Oct 2020 14:34:53 +0300 Subject: [PATCH 34/45] Removed using of array of globals in nusoap --- framework/vendors/nusoap/nusoap.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/framework/vendors/nusoap/nusoap.php b/framework/vendors/nusoap/nusoap.php index d18f2cb..4e58b01 100644 --- a/framework/vendors/nusoap/nusoap.php +++ b/framework/vendors/nusoap/nusoap.php @@ -54,6 +54,7 @@ * -------- * 07/07/2020 - class declaration changed to PHP5-7 * 07/07/2020 - undefined var fix + * 02/10/2020 - removed using of globals array */ /* load classes @@ -76,7 +77,7 @@ // class variable emulation // cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html -$GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = 9; + /** * @@ -229,7 +230,7 @@ class nusoap_base { * @access public */ function __construct() { - $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel']; + $this->debugLevel = 9; } /** @@ -239,7 +240,7 @@ function __construct() { * @access public */ function getGlobalDebugLevel() { - return $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel']; + return $this->debugLevel; } /** @@ -249,7 +250,7 @@ function getGlobalDebugLevel() { * @access public */ function setGlobalDebugLevel($level) { - $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = $level; + $this->debugLevel = $level; } /** From 27a096c67b4bb247ea706cce9c09e268442016ca Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Fri, 2 Oct 2020 14:35:23 +0300 Subject: [PATCH 35/45] Removed closing PHP tag --- framework/vendors/dbug/dbug.php | 1 - 1 file changed, 1 deletion(-) diff --git a/framework/vendors/dbug/dbug.php b/framework/vendors/dbug/dbug.php index 4b5e287..e90e390 100644 --- a/framework/vendors/dbug/dbug.php +++ b/framework/vendors/dbug/dbug.php @@ -555,4 +555,3 @@ function dBug_toggleTable(source) { } } -?> \ No newline at end of file From 2403f400133b44fd56921d834352ccabc35f2e11 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 31 Oct 2020 21:59:01 +0200 Subject: [PATCH 36/45] Added cleaning empty fileds on form submission --- framework/helpers/CString.php | 16 +- framework/helpers/widgets/CGridView.php | 460 +++++++++++++----------- 2 files changed, 257 insertions(+), 219 deletions(-) diff --git a/framework/helpers/CString.php b/framework/helpers/CString.php index e31dca7..83ba6ec 100644 --- a/framework/helpers/CString.php +++ b/framework/helpers/CString.php @@ -19,7 +19,8 @@ * humanize * plural * isSerialized - * + * shortenUrl + * */ class CString @@ -237,4 +238,17 @@ public static function isSerialized($string) return false; } + + /** + * Returns shorten URL + * @param string $url + * @param int $len1 + * @param int $len2 + * @return string|string[]|null + */ + public static function shortenUrl($url = '', $len1 = 0, $len2 = 0) + { + return preg_replace("/(?<=.{{$len1}})(.+)(?=.{{$len2}})/", '...', $url); + } + } \ No newline at end of file diff --git a/framework/helpers/widgets/CGridView.php b/framework/helpers/widgets/CGridView.php index 3262e57..48fa009 100644 --- a/framework/helpers/widgets/CGridView.php +++ b/framework/helpers/widgets/CGridView.php @@ -8,79 +8,79 @@ * @copyright Copyright (c) 2012 - 2020 ApPHP Framework * @license http://www.apphpframework.com/license/ * - * PUBLIC (static): PROTECTED: PRIVATE (static): + * PUBLIC (static): PROTECTED: PRIVATE (static): * ---------- ---------- ---------- * init _additionalParams * _customParams * _getFieldParam * _getAllRecords * _countAllRecords - */ + */ class CGridView extends CWidgs { /** @const string */ - const NL = "\n"; - /** @var string */ - private static $_rowCount = 0; - /** @var string */ - private static $_pickerCount = 0; - /** @var string */ - private static $_autocompleteCount = 0; - - /** - * Draws grid view - * @param array $params - * - * Notes: - * *** FIELD ATTRIBUTES: - * - to disable any field, including filtering or button use: 'disabled'=>true - * - 'prependCode=>'', 'appendCode'=>'' - insert code before or after field (for all fields): - * - 'data'=>'' - attribute for type 'label', allows to show data from PHP variables - * - 'case'=>'normal' - attribute for type 'label', allows to convert value to 'upper', 'lower', 'camel' or 'humanize' cases - * - 'maxLength'=>'X' - attribute for type 'label', specifies to show maximum X characters of the string - * 'showTooltip'=>true - specifies whether to show tooltip on field if it's length was reduced - * - 'aggregate'=>['function'=>'sum|avg'] - allow to run aggregate function on specific column - * - 'sourceField'=>'' - used to show data from another field - * - 'callback'=>array('class'=>'className', 'function'=>'functionName', 'params'=>$functionParams) - * callback of closure function that is called when item created (available for labels only), $record - all current record - * PHP_VERSION >= 5.3.0 $functionName = function($record, $params){ return record['field_name']; } - * Ex.: function callbackFunction($record, $params){...} - passed a whole record - * - 'trigger'=>array('trigger_key'=>'field name', 'trigger_operation'=>'!=', 'trigger_value'=>'0', 'success_value'=>'0', 'wrong_value'=>'0'), - * trigger is used for changing field valut depending on simple condition - * Ex.: 'trigger'=>array('trigger_key'=>'is_active', 'trigger_operation'=>'==', 'trigger_value'=>'1', 'success_value'=>A::t('app', 'Active), 'wrong_value'=>''), - * - select classes: 'class'=>'chosen-select-filter' or 'class'=>'chosen-select' - * - Encryption for standard label or html fields: 'encryption'=>array('enabled'=>CConfig::get('text.encryption'), 'encryptAlgorithm'=>CConfig::get('text.encryptAlgorithm'), 'encryptKey'=>CConfig::get('text.encryptKey')) - * - * *** SORTING: - * - 'sortType'=>'string|numeric' - defines soritng type ('string' is default) - * - 'sortBy'=>'' - defines field to perform sorting by - * - 'changeOrder'=>true - allowd to change rows order from main view by clicking of arrows - * - * *** FILTERING: - * - to perform search by few fields define them comma separated: 'field1,field2' => array(...) - * - for filters attribute 'table' is empty by default. Remember: to add CConfig::get('db.prefix') in 'table'=>CConfig::get('db.prefix').'table' - * - 'compareType'=>'string|numeric|binary' - attribute for filtering fields - * - 'visible'=>true|false - attribute for visibility of filtering fileds - * - 'sourceFilter'=>'' - used to filter from another field - * - * *** MODEL: - * - 'relationType' (optional) - defines a type of relation for specific model, if not defined - used default relation type - * - 'getAllRecords' - specify custom methods for select of all records of model (optional). Ex.: 'getAllRecords'=>'findAll' - * - 'countAllRecords' - specify custom methods for select of all records of model (optional). Ex.: 'countAllRecords'=>'count' - * - * Usage: - * echo CWidget::create('CGridView', array( - * 'model' => 'ModelName', - * 'relationType' => '', - * 'actionPath' => 'controller/action', - * 'condition' => CConfig::get('db.prefix').'countries.id <= 30', - * 'groupBy' => '', - * 'limit' => '', - * 'defaultOrder' => array('field_1'=>'DESC', 'field_2'=>'ASC' [,...]), - * 'passParameters' => false, - * [DEPRECATED from v0.7.1] 'customParameters' => array('param_1'=>'integer', 'param_1'=>'string' [,...]), + const NL = "\n"; + /** @var string */ + private static $_rowCount = 0; + /** @var string */ + private static $_pickerCount = 0; + /** @var string */ + private static $_autocompleteCount = 0; + + /** + * Draws grid view + * @param array $params + * + * Notes: + * *** FIELD ATTRIBUTES: + * - to disable any field, including filtering or button use: 'disabled'=>true + * - 'prependCode=>'', 'appendCode'=>'' - insert code before or after field (for all fields): + * - 'data'=>'' - attribute for type 'label', allows to show data from PHP variables + * - 'case'=>'normal' - attribute for type 'label', allows to convert value to 'upper', 'lower', 'camel' or 'humanize' cases + * - 'maxLength'=>'X' - attribute for type 'label', specifies to show maximum X characters of the string + * 'showTooltip'=>true - specifies whether to show tooltip on field if it's length was reduced + * - 'aggregate'=>['function'=>'sum|avg'] - allow to run aggregate function on specific column + * - 'sourceField'=>'' - used to show data from another field + * - 'callback'=>array('class'=>'className', 'function'=>'functionName', 'params'=>$functionParams) + * callback of closure function that is called when item created (available for labels only), $record - all current record + * PHP_VERSION >= 5.3.0 $functionName = function($record, $params){ return record['field_name']; } + * Ex.: function callbackFunction($record, $params){...} - passed a whole record + * - 'trigger'=>array('trigger_key'=>'field name', 'trigger_operation'=>'!=', 'trigger_value'=>'0', 'success_value'=>'0', 'wrong_value'=>'0'), + * trigger is used for changing field valut depending on simple condition + * Ex.: 'trigger'=>array('trigger_key'=>'is_active', 'trigger_operation'=>'==', 'trigger_value'=>'1', 'success_value'=>A::t('app', 'Active), 'wrong_value'=>''), + * - select classes: 'class'=>'chosen-select-filter' or 'class'=>'chosen-select' + * - Encryption for standard label or html fields: 'encryption'=>array('enabled'=>CConfig::get('text.encryption'), 'encryptAlgorithm'=>CConfig::get('text.encryptAlgorithm'), 'encryptKey'=>CConfig::get('text.encryptKey')) + * + * *** SORTING: + * - 'sortType'=>'string|numeric' - defines soritng type ('string' is default) + * - 'sortBy'=>'' - defines field to perform sorting by + * - 'changeOrder'=>true - allowd to change rows order from main view by clicking of arrows + * + * *** FILTERING: + * - to perform search by few fields define them comma separated: 'field1,field2' => array(...) + * - for filters attribute 'table' is empty by default. Remember: to add CConfig::get('db.prefix') in 'table'=>CConfig::get('db.prefix').'table' + * - 'compareType'=>'string|numeric|binary' - attribute for filtering fields + * - 'visible'=>true|false - attribute for visibility of filtering fileds + * - 'sourceFilter'=>'' - used to filter from another field + * + * *** MODEL: + * - 'relationType' (optional) - defines a type of relation for specific model, if not defined - used default relation type + * - 'getAllRecords' - specify custom methods for select of all records of model (optional). Ex.: 'getAllRecords'=>'findAll' + * - 'countAllRecords' - specify custom methods for select of all records of model (optional). Ex.: 'countAllRecords'=>'count' + * + * Usage: + * echo CWidget::create('CGridView', array( + * 'model' => 'ModelName', + * 'relationType' => '', + * 'actionPath' => 'controller/action', + * 'condition' => CConfig::get('db.prefix').'countries.id <= 30', + * 'groupBy' => '', + * 'limit' => '', + * 'defaultOrder' => array('field_1'=>'DESC', 'field_2'=>'ASC' [,...]), + * 'passParameters' => false, + * [DEPRECATED from v0.7.1] 'customParameters' => array('param_1'=>'integer', 'param_1'=>'string' [,...]), * 'pagination' => array('enable'=>true, 'pageSize'=>20), * 'sorting' => true, * 'linkType' => 0, @@ -91,12 +91,12 @@ class CGridView extends CWidgs * 'gridWrapper' => array('tag'=>'div', 'class'=>''), * 'gridTable' => array('class'=>''), * ), - * 'filters' => array( - * 'field_1' => ['title'=>'Field 1', 'type'=>'textbox', 'table'=>'', 'operator'=>'=', 'default'=>'', 'width'=>'', 'maxLength'=>'', 'htmlOptions'=>[]], - * 'field_2' => ['title'=>'Field 2', 'type'=>'textbox', 'table'=>'', 'operator'=>'=', 'default'=>'', 'width'=>'', 'maxLength'=>'', 'autocomplete'=>array('enable'=>true, 'ajaxHandler'=>'path/to/handler/file', 'minLength'=>3, 'returnId'=>true), 'htmlOptions'=>[]], - * 'field_3' => ['title'=>'Field 3', 'type'=>'enum', 'table'=>'', 'operator'=>'=', 'default'=>'', 'width'=>'', 'source'=>array('0'=>'No', '1'=>'Yes'), 'emptyOption'=>true, 'emptyValue'=>'', 'htmlOptions'=>array('class'=>'chosen-select-filter')], - * 'field_4' => ['title'=>'Field 5', 'type'=>'datetime', 'table'=>'', 'operator'=>'=', 'default'=>'', 'width'=>'80px', 'maxLength'=>'', 'format'=>'', 'htmlOptions'=>[], 'viewType'=>'datetime|date|time'], - * ), + * 'filters' => array( + * 'field_1' => ['title'=>'Field 1', 'type'=>'textbox', 'table'=>'', 'operator'=>'=', 'default'=>'', 'width'=>'', 'maxLength'=>'', 'htmlOptions'=>[]], + * 'field_2' => ['title'=>'Field 2', 'type'=>'textbox', 'table'=>'', 'operator'=>'=', 'default'=>'', 'width'=>'', 'maxLength'=>'', 'autocomplete'=>array('enable'=>true, 'ajaxHandler'=>'path/to/handler/file', 'minLength'=>3, 'returnId'=>true), 'htmlOptions'=>[]], + * 'field_3' => ['title'=>'Field 3', 'type'=>'enum', 'table'=>'', 'operator'=>'=', 'default'=>'', 'width'=>'', 'source'=>array('0'=>'No', '1'=>'Yes'), 'emptyOption'=>true, 'emptyValue'=>'', 'htmlOptions'=>array('class'=>'chosen-select-filter')], + * 'field_4' => ['title'=>'Field 5', 'type'=>'datetime', 'table'=>'', 'operator'=>'=', 'default'=>'', 'width'=>'80px', 'maxLength'=>'', 'format'=>'', 'htmlOptions'=>[], 'viewType'=>'datetime|date|time'], + * ), * 'fields' => array( * 'field_1' => array('title'=>'Field 1', 'type'=>'index', 'align'=>'', 'width'=>'', 'class'=>'left', 'headerTooltip'=>'', 'headerClass'=>'left', 'isSortable'=>false), * 'field_2' => array('title'=>'Field 2', 'type'=>'concat', 'align'=>'', 'width'=>'', 'class'=>'left', 'headerTooltip'=>'', 'headerClass'=>'left', 'isSortable'=>true, 'concatFields'=>array('first_name', 'last_name'), 'concatSeparator'=>', ',), @@ -111,16 +111,16 @@ class CGridView extends CWidgs * 'field_11' => array('title'=>'Field 11', 'type'=>'template', 'align'=>'', 'width'=>'', 'class'=>'left', 'headerTooltip'=>'', 'headerClass'=>'left', 'isSortable'=>false, 'sortBy'=>'', 'html'=>'{category_id}', 'fields'=>array('category_id'=>array('default'=>'', 'prefix'=>'', 'postfix'=>'', 'source'=>[]))), * ), * 'actions' => array( - * 'edit' => array('link'=>'locations/edit/id/{id}/page/{page}', 'imagePath'=>'templates/backend/images/edit.png', 'title'=>'Edit this record'), - * 'delete' => array('link'=>'locations/delete/id/{id}/page/{page}', 'imagePath'=>'templates/backend/images/delete.png', 'title'=>'Delete this record', 'onDeleteAlert'=>true), - * ), + * 'edit' => array('link'=>'locations/edit/id/{id}/page/{page}', 'imagePath'=>'templates/backend/images/edit.png', 'title'=>'Edit this record'), + * 'delete' => array('link'=>'locations/delete/id/{id}/page/{page}', 'imagePath'=>'templates/backend/images/delete.png', 'title'=>'Delete this record', 'onDeleteAlert'=>true), + * ), * 'return'=>true, - * )); - */ + * )); + */ public static function init($params = []) { parent::init($params); - + $output = ''; $model = self::params('model', ''); $modelName = $model; @@ -148,16 +148,16 @@ public static function init($params = []) $pageSize = abs((int)self::params('pagination.pageSize', '10')); $activeActions = is_array($actions) ? count($actions) : 0; $onDeleteRecord = false; - + $baseUrl = A::app()->getRequest()->getBaseUrl(); $page = A::app()->getRequest()->getQuery('page', 'integer', 1); - + // Get pure model name $namespace = explode('\\', $model); if (count($namespace) > 1) { $modelName = $namespace[count($namespace) - 1]; } - + // Remove disabled actions if (is_array($actions)) { foreach ($actions as $key => $val) { @@ -170,7 +170,7 @@ public static function init($params = []) } $activeActions = count($actions); } - + // Prepare sorting variables // --------------------------------------- $sortBy = ''; @@ -181,7 +181,7 @@ public static function init($params = []) $sortBy = A::app()->getRequest()->getQuery('sort_by', 'dbfield', ''); $sortDir = (strtolower(A::app()->getRequest()->getQuery('sort_dir', 'alpha', '')) == 'desc') ? 'desc' : 'asc'; } - + if ($sortingEnabled && !empty($sortBy)) { $sortType = self::_getFieldParam($fields, $sortBy, 'sortType', array('string', 'numeric')); $orderClause = $sortBy . ($sortType == 'numeric' ? ' + 0 ' : '') . ' ' . $sortDir; @@ -191,7 +191,7 @@ public static function init($params = []) $orderClause .= (!empty($orderClause) ? ', ' : '') . $oField . ($sortType == 'numeric' ? ' + 0 ' : '') . ' ' . $oFieldType; } } - + // Prepare filter variables // --------------------------------------- $whereClause = (!empty($condition)) ? $condition : ''; @@ -202,7 +202,7 @@ public static function init($params = []) if ($filterMegaMenu) { $filterCount = 0; } - + // Remove disabled fields foreach ($filters as $key => $val) { if ((bool)self::keyAt('disabled', $val) === true) unset($filters[$key]); @@ -212,11 +212,11 @@ public static function init($params = []) } } } - + if ($filterMegaMenu) { $filterIterator = 0; $filterOddHalf = false; - + $filterHalf = ceil($filterCount / 4) * 2; // If the left half of the filter 3 element larger than the right half of the filter, move 1 element in the right half of filter if ($filterHalf * 2 - $filterCount == 3) { @@ -228,13 +228,32 @@ public static function init($params = []) $output .= CHtml::closeTag('a'); $output .= CHtml::openTag('div', array('class' => (!empty($filterDiv['class']) ? $filterDiv['class'] : 'filtering-wrapper'), 'style' => 'display:none;')) . self::NL; $output .= CHtml::openTag('div', array('class' => 'filtering-wrapper-inner')) . self::NL; - $output .= CHtml::openForm($actionPath, 'get', array('id' => 'frmFilter' . $modelName, 'class' => (!empty($filterForm['class']) ? $filterForm['class'] : null))) . self::NL; + $output .= CHtml::openForm($actionPath, 'get', array('id' => 'frmFilter' . $modelName, 'onSubmit'=>'return onSubmitForm()', 'class' => (!empty($filterForm['class']) ? $filterForm['class'] : null))) . self::NL; $output .= CHtml::openTag('div', array('class' => 'row')) . self::NL; } else { $output .= CHtml::openTag('div', array('class' => (!empty($filterDiv['class']) ? $filterDiv['class'] : 'filtering-wrapper'))) . self::NL; - $output .= CHtml::openForm($actionPath, 'get', array('id' => 'frmFilter' . $modelName)) . self::NL; + $output .= CHtml::openForm($actionPath, 'get', array('id' => 'frmFilter' . $modelName, 'onSubmit'=>'return onSubmitForm()')) . self::NL; } - + + // Register script for onSubmitForm + A::app()->getClientScript()->registerScript( + 'submit-filter', + 'function onSubmitForm(){ + let $form = $("#frmFilter'.$modelName.'"); + $form.find("input").each(function(index, obj){ + if($(obj).val() === "") $(obj).prop("disabled", true); + else $(obj).prop("readonly", true); + }); + $form.find("select").each(function(index, obj){ + if($(obj).val() === "") $(obj).prop("disabled", true); + else $(obj).addClass("readonly"); + }); + return true; + }', + 2 + ); + + // An array of iterations for the source filter $fArrSourceIter = array(); foreach ($filters as $fKey => $fValue) { @@ -251,7 +270,7 @@ public static function init($params = []) $htmlOptions = isset($fValue['htmlOptions']) ? $fValue['htmlOptions'] : array(); $fId = !empty($htmlOptions['id']) ? $htmlOptions['id'] : $fKey; $htmlOptions['id'] = $fId; - + // Check if we want to use another filter as a "source filter" $sourceFilter = self::keyAt('sourceFilter', $fValue, ''); if (!empty($sourceFilter)) { @@ -263,7 +282,7 @@ public static function init($params = []) $fName = $fKey; $fNameAbbr = $fKey; } - + if (A::app()->getRequest()->getQuery('but_filter')) { if ($fIsArray) { $fieldValue = ''; @@ -279,7 +298,7 @@ public static function init($params = []) } else { $fieldValue = $fieldDefaultValue; } - + if ($visible) { if ($filterMegaMenu) { $filterNewRow = $filterIterator > $filterHalf && $filterOddHalf @@ -291,19 +310,19 @@ public static function init($params = []) } elseif ($filterNewRow) { $output .= CHtml::openTag('div', array('class' => 'row')); } - + $output .= CHtml::openTag('div', array('class' => 'col-md-6')); } - + if (!empty($filterItemDiv)) { $output .= CHtml::openTag('div', array('class' => (!empty($filterItemDiv['class']) ? $filterItemDiv['class'] : ''))) . self::NL; } if ($filterMegaMenu && !empty($title)) { $output .= CHtml::tag('label', array(), $title); } - + $output .= !empty($title) ? $title . ': ' : ''; - + switch ($type) { case 'enum': $source = isset($fValue['source']) ? $fValue['source'] : array(); @@ -324,12 +343,12 @@ public static function init($params = []) } $output .= ' ' . self::NL; break; - + case 'datetime': case 'datetimepicker': $format = !empty($fValue['format']) ? $fValue['format'] : 'yy-mm-dd'; $viewType = !empty($fValue['viewType']) ? $fValue['viewType'] : 'date'; - + $htmlOptions['maxlength'] = $maxLength; $htmlOptions['style'] = $width; if ($filterMegaMenu && !empty($title)) { @@ -338,13 +357,13 @@ public static function init($params = []) $output .= CHtml::textField($fName, $fieldValue, $htmlOptions); A::app()->getClientScript()->registerCssFile('assets/vendors/jquery/jquery-ui.min.css'); A::app()->getClientScript()->registerCssFile('assets/vendors/datetimepicker/jquery-ui-timepicker-addon.css'); - + // It's better if it was alredy added in template file // A::app()->getClientScript()->registerScriptFile('assets/vendors/jquery/jquery-ui.min.js', 2); A::app()->getClientScript()->registerScriptFile('assets/vendors/datetimepicker/jquery-ui-timepicker-addon.js', 2); A::app()->getClientScript()->registerScriptFile('assets/vendors/datetimepicker/i18n/jquery-ui-timepicker-addon-i18n.min.js', 2); A::app()->getClientScript()->registerScriptFile('assets/vendors/datetimepicker/jquery-ui-slideraccess.js', 2); - + // UI: // dateFormat: dd/mm/yy | d M, y | mm/dd/yy | yy-mm-dd // Bootstrap: @@ -392,23 +411,23 @@ public static function init($params = []) ); } break; - + case 'textbox': default: $autocompleteEnabled = self::keyAt('enable', $autocomplete); $autocompleteAjaxHandler = self::keyAt('ajaxHandler', $autocomplete, ''); $autocompleteMinLength = self::keyAt('minLength', $autocomplete, 1); $autocompleteReturnId = self::keyAt('returnId', $autocomplete, true); - + if ($autocompleteEnabled) { $cRequest = A::app()->getRequest(); - + A::app()->getClientScript()->registerCssFile('assets/vendors/jquery/jquery-ui.min.css'); // Already included in backend default.php if (A::app()->view->getTemplate() != 'backend') { A::app()->getClientScript()->registerScriptFile('assets/vendors/jquery/jquery-ui.min.js', 2); } - + $fKeySearch = $autocompleteReturnId ? $fId . '_result' : $fId; A::app()->getClientScript()->registerScript( 'autocomplete_' . self::$_autocompleteCount++, @@ -455,7 +474,7 @@ public static function init($params = []) });', 4 ); - + if ($autocompleteReturnId) { // Draw hidden field for real field $output .= CHtml::hiddenField($fName, CHtml::encode($fieldValue), $htmlOptions) . self::NL; @@ -496,21 +515,21 @@ public static function init($params = []) $filterIterator++; } } - + if ($fieldValue !== '') { $filterUrl .= (!empty($filterUrl) ? '&' : '') . $fName . '=' . $fieldValue; - + // Check if there is an autocomplete key that must be added to filter string $autocompleteValue = A::app()->getRequest()->getQuery($fId . '_result'); if ($autocompleteValue != '') { $filterUrl .= (!empty($filterUrl) ? '&' : '') . $fId . '_result=' . $autocompleteValue; } - + $escapedFieldValue = strip_tags(CString::quote($fieldValue)); $quote = ($compareType == 'numeric' || $compareType == 'binary') ? '' : "'"; $binary = ($compareType == 'binary') ? 'BINARY ' : ''; $whereClauseMiddle = ''; - + $fKeyParts = explode(',', $fNameAbbr); $fKeyPartsCount = count($fKeyParts); foreach ($fKeyParts as $key => $val) { @@ -566,7 +585,7 @@ public static function init($params = []) } } } - + if ($filterMegaMenu) { $output .= CHtml::tag('div', array('class' => 'spacer-20'), ''); $output .= CHtml::openTag('div', array('class' => 'col-md-12')) . self::NL; @@ -584,7 +603,7 @@ public static function init($params = []) } $output .= CHtml::submitButton(A::t('core', 'Filter'), array('name' => 'but_filter')) . self::NL; } - + if ($filterMegaMenu) $output .= CHtml::closeTag('div') . self::NL; $output .= CHtml::closeTag('div') . self::NL; $output .= CHtml::closeForm() . self::NL; @@ -592,18 +611,18 @@ public static function init($params = []) $output .= CHtml::closeTag('div') . self::NL; $filterUrl = CHtml::encode($filterUrl); } - + // Prepare pagination variables // --------------------------------------- $totalRecords = $totalPageRecords = 0; $currentPage = ''; - $modelParams = ! empty($relationType) ? [$relationType] : []; - $objModel = call_user_func_array($model . '::model', $modelParams); + $modelParams = ! empty($relationType) ? [$relationType] : []; + $objModel = call_user_func_array($model . '::model', $modelParams); if (!$objModel) { - CDebug::addMessage('errors', 'missing-model', A::t('core', 'Unable to find class "{class}".', ['{class}' => $model]), 'session'); - return ''; + CDebug::addMessage('errors', 'missing-model', A::t('core', 'Unable to find class "{class}".', ['{class}' => $model]), 'session'); + return ''; } - + // Replacing rows // --------------------------------------- $act = A::app()->getRequest()->getQuery('act', 'alpha', ''); @@ -623,30 +642,30 @@ public static function init($params = []) $val2 = $record2->$replaceField; } if ($val1 != '' && $val2 != '') { - $objModel->updateByPk($id1, [$replaceField => $val2]); - $objModel->updateByPk($id2, [$replaceField => $val1]); - if (APPHP_MODE == 'demo') { + $objModel->updateByPk($id1, [$replaceField => $val2]); + $objModel->updateByPk($id2, [$replaceField => $val1]); + if (APPHP_MODE == 'demo') { A::app()->getSession()->setFlash('alert', A::t('core', 'This operation is blocked in Demo Mode!')); A::app()->getSession()->setFlash('alertType', 'warning'); } else { A::app()->getSession()->setFlash('alert', A::t('core', 'The changing order operation has been successfully completed!')); A::app()->getSession()->setFlash('alertType', 'success'); } - + // Add sorting and custom parameters to URL $searchActionPath = $actionPath; $separateSymbol = preg_match('/\?/', $searchActionPath) ? '&' : '?'; $searchActionPath .= self::_additionalParams($passParameters, $linkType, $separateSymbol); $separateSymbol = preg_match('/\?/', $searchActionPath) ? '&' : '?'; $searchActionPath .= self::_customParams($customParameters, $linkType, $separateSymbol); - + header('location: ' . $baseUrl . $searchActionPath); exit; } } } } - + if ($pagination) { $currentPage = A::app()->getRequest()->getQuery('page', 'integer', 1); $totalRecords = self::_countAllRecords($objModel, ['condition' => $whereClause, 'group' => $groupBy]); @@ -656,19 +675,19 @@ public static function init($params = []) } if (!$totalPageRecords || !$currentPage) { if (A::app()->getRequest()->getQuery('but_filter')) { - $output .= CWidget::create('CMessage', ['warning', A::t('core', 'No records found or incorrect parameters passed')]); - } else { - $output .= CWidget::create('CMessage', ['warning', A::t('core', 'No records found')]); - } - } + $output .= CWidget::create('CMessage', ['warning', A::t('core', 'No records found or incorrect parameters passed')]); + } else { + $output .= CWidget::create('CMessage', ['warning', A::t('core', 'No records found')]); + } + } } else { $records = self::_getAllRecords($objModel, ['condition' => $whereClause, 'order' => $orderClause, 'group' => $groupBy, 'limit' => $limit]); $totalPageRecords = is_array($records) ? count($records) : 0; if (!$totalPageRecords) { - $output .= CWidget::create('CMessage', ['warning', A::t('core', 'No records found')]); - } + $output .= CWidget::create('CMessage', ['warning', A::t('core', 'No records found')]); + } } - + // Draw table // --------------------------------------- if ($totalPageRecords > 0) { @@ -676,27 +695,27 @@ public static function init($params = []) foreach ($fields as $key => $val) { if ((bool)self::keyAt('disabled', $val) === true) unset($fields[$key]); } - + // ---------------------------------------------- // Draw TABLE wrapper // ---------------------------------------------- if (!empty($gridWrapper['tag'])) { - $output .= CHtml::openTag($gridWrapper['tag'], ['class' => (! empty($gridWrapper['class']) ? $gridWrapper['class'] : null)]).self::NL; - } + $output .= CHtml::openTag($gridWrapper['tag'], ['class' => (! empty($gridWrapper['class']) ? $gridWrapper['class'] : null)]).self::NL; + } // ---------------------------------------------- - // Draw <THEAD> rows + // Draw <THEAD> rows // ---------------------------------------------- - $output .= CHtml::openTag('table', ['class' => 'grid-view-table'.(! empty($gridTable['class']) ? ' '.$gridTable['class'] : '')]).self::NL; - $output .= CHtml::openTag('thead') . self::NL; - $output .= CHtml::openTag('tr', ['id' => 'tr'.$modelName.'_'.self::$_rowCount++]).self::NL; - foreach ($fields as $key => $val) { - + $output .= CHtml::openTag('table', ['class' => 'grid-view-table'.(! empty($gridTable['class']) ? ' '.$gridTable['class'] : '')]).self::NL; + $output .= CHtml::openTag('thead') . self::NL; + $output .= CHtml::openTag('tr', ['id' => 'tr'.$modelName.'_'.self::$_rowCount++]).self::NL; + foreach ($fields as $key => $val) { + // Check if we want to use another field as a "source field" $sourceField = self::keyAt('sourceField', $val, ''); if (!empty($sourceField)) { $key = $sourceField; } - + $type = self::keyAt('type', $val, ''); $title = self::keyAt('title', $val, ''); $headerClass = self::keyAt('headerClass', $val, ''); @@ -705,18 +724,18 @@ public static function init($params = []) $widthAttr = self::keyAt('width', $val); $alignAttr = self::keyAt('align', $val); $headerTooltip = self::keyAt('headerTooltip', $val); - + // Prepare style attributes $width = (!empty($widthAttr) && CValidator::isHtmlSize($widthAttr)) ? 'width:' . $widthAttr . ';' : ''; $align = (!empty($alignAttr) && CValidator::isAlignment($alignAttr)) ? 'text-align:' . $alignAttr . ';' : ''; $style = $width . $align; - + if ($sortingEnabled && $isSortable && ($type != 'template' || ($type == 'template' && !empty($sortField)))) { $sortByField = !empty($sortField) ? $sortField : $key; $colSortDir = (($sortBy != $sortByField) ? 'asc' : (($sortDir == 'asc') ? 'desc' : 'asc')); $sortImg = ($sortBy == $sortByField) ? ' ' . CHtml::tag('span', ['class' => 'sort-arrow'], (($colSortDir == 'asc') ? '▼' : '▲')) : ''; if ($sortBy == $sortByField) $sortUrl = 'sort_by=' . $sortByField . '&sort_dir=' . $sortDir; - + $separateSymbol = preg_match('/\?/', $actionPath) ? '&' : '?'; $linkUrl = $actionPath . $separateSymbol . 'sort_by=' . $sortByField . '&sort_dir=' . $colSortDir; $linkUrl .= !empty($currentPage) ? '&page=' . $currentPage : ''; @@ -725,38 +744,38 @@ public static function init($params = []) $title = CHtml::link($title . $sortImg, $linkUrl); } - $title .= ! empty($headerTooltip) ? ' '.CHtml::link('', false, ['class' => 'tooltip-icon', 'title' => $headerTooltip]) : ''; + $title .= ! empty($headerTooltip) ? ' '.CHtml::link('', false, ['class' => 'tooltip-icon', 'title' => $headerTooltip]) : ''; - $output .= CHtml::tag('th', ['class' => $headerClass, 'style' => $style], $title).self::NL; - } + $output .= CHtml::tag('th', ['class' => $headerClass, 'style' => $style], $title).self::NL; + } if ($activeActions > 0) { - $output .= CHtml::tag('th', ['class' => 'actions'], A::t('core', 'Actions')).self::NL; - } + $output .= CHtml::tag('th', ['class' => 'actions'], A::t('core', 'Actions')).self::NL; + } $output .= CHtml::closeTag('tr') . self::NL;; $output .= CHtml::closeTag('thead') . self::NL; - + // ---------------------------------------------- - // Draw <TBODY> rows + // Draw <TBODY> rows // ---------------------------------------------- - $aggregateRow = []; - $output .= CHtml::openTag('tbody') . self::NL; + $aggregateRow = []; + $output .= CHtml::openTag('tbody') . self::NL; for ($i = 0; $i < $totalPageRecords; $i++) { - $output .= CHtml::openTag('tr', ['id' => 'tr'.$modelName.'_'.self::$_rowCount++]).self::NL; - $id = (isset($records[$i]['id'])) ? $records[$i]['id'] : ''; + $output .= CHtml::openTag('tr', ['id' => 'tr'.$modelName.'_'.self::$_rowCount++]).self::NL; + $id = (isset($records[$i]['id'])) ? $records[$i]['id'] : ''; $prevId = (isset($records[$i - 1]['id'])) ? $records[$i - 1]['id'] : ''; $nextId = (isset($records[$i + 1]['id'])) ? $records[$i + 1]['id'] : ''; - + // ---------------------------------------------- // Display columns in each row // ---------------------------------------------- foreach ($fields as $key => $val) { - + // Check if we want to use another field as a "source field" $sourceField = self::keyAt('sourceField', $val, ''); if (!empty($sourceField)) { $key = $sourceField; } - + $align = self::keyAt('align', $val, ''); $style = (!empty($align) && CValidator::isAlignment($align)) ? 'text-align:' . $align . ';' : ''; $class = self::keyAt('class', $val, ''); @@ -764,15 +783,15 @@ public static function init($params = []) $title = self::keyAt('title', $val, ''); $format = self::keyAt('format', $val, ''); $definedValues = self::keyAt('definedValues', $val, ''); - $htmlOptions = (array)self::keyAt('htmlOptions', $val, []); - $prependCode = self::keyAt('prependCode', $val, ''); + $htmlOptions = (array)self::keyAt('htmlOptions', $val, []); + $prependCode = self::keyAt('prependCode', $val, ''); $appendCode = self::keyAt('appendCode', $val, ''); $fieldValue = (isset($records[$i][$key])) ? $records[$i][$key] : ''; /* $key */ $fieldValueOriginal = $fieldValue; $aggregateFunction = self::keyAt('aggregate.function', $val, ''); - $aggregateFunction = in_array(strtolower($aggregateFunction), ['sum', 'avg']) ? strtolower($aggregateFunction) : ''; - $changeOrder = (bool)self::keyAt('changeOrder', $val, false); - + $aggregateFunction = in_array(strtolower($aggregateFunction), ['sum', 'avg']) ? strtolower($aggregateFunction) : ''; + $changeOrder = (bool)self::keyAt('changeOrder', $val, false); + $fieldOutput = ''; switch ($type) { case 'concat': @@ -787,7 +806,7 @@ public static function init($params = []) } $fieldOutput .= $concatResult; break; - + case 'decimal': $decimalPoints = (int)self::keyAt('decimalPoints', $val, 0); if ($format === 'european') { @@ -799,7 +818,7 @@ public static function init($params = []) } $fieldOutput .= $fieldValue; break; - + case 'datetime': if (is_array($definedValues) && isset($definedValues[$fieldValue])) { $fieldValue = $definedValues[$fieldValue]; @@ -808,7 +827,7 @@ public static function init($params = []) } $fieldOutput .= $fieldValue; break; - + case 'enum': $source = self::keyAt('source', $val, ''); $outputValue = isset($source[$fieldValue]) ? $source[$fieldValue] : ''; @@ -818,11 +837,11 @@ public static function init($params = []) $fieldOutput .= $outputValue; } break; - + case 'index': $fieldOutput .= ($i + 1) . '.'; break; - + case 'image': $imagePath = self::keyAt('imagePath', $val, ''); $defaultImage = self::keyAt('defaultImage', $val, ''); @@ -830,7 +849,7 @@ public static function init($params = []) $imageWidth = self::keyAt('imageWidth', $val, ''); $imageHeight = self::keyAt('imageHeight', $val, ''); $showImageInfo = (bool)self::keyAt('showImageInfo', $val, true); - + $htmlOptions = array(); if (!empty($imageWidth) && CValidator::isHtmlSize($imageWidth)) $htmlOptions['width'] = $imageWidth; if (!empty($imageHeight) && CValidator::isHtmlSize($imageHeight)) $htmlOptions['height'] = $imageHeight; @@ -843,14 +862,14 @@ public static function init($params = []) //$htmlOptions['title'] .= ', '.$imageDimensions['width'].'x'.$imageDimensions['height']; //$htmlOptions['title'] .= ')'; } - + $fieldOutput .= CHtml::image($imagePath . $fieldValue, $alt, $htmlOptions) . self::NL; break; - + case 'link': $linkUrl = self::keyAt('linkUrl', $val, '#'); $linkText = self::keyAt('linkText', $val, ''); - + // Replace for linkURL if (preg_match_all('/{(.*?)}/i', $linkUrl, $matches)) { if (isset($matches[1]) && is_array($matches[1])) { @@ -865,7 +884,7 @@ public static function init($params = []) } } } - + // Replace for linkText $fieldValue = (isset($records[$i][$key])) ? $records[$i][$key] : ''; /* $key */ if (is_array($definedValues) && isset($definedValues[$fieldValue])) { @@ -880,32 +899,32 @@ public static function init($params = []) } } } - + $fieldOutput .= CHtml::link($linkText, $linkUrl, $htmlOptions); break; - + case 'evaluation': $minValue = self::keyAt('minValue', $val, 1); $maxValue = self::keyAt('maxValue', $val, 5); $size = max(0, (min($maxValue, $fieldValue))) * 16; $tooltip = self::keyAt('tooltip', $val, ''); $titleText = CHtml::encode($tooltip) . ': ' . $fieldValue; - + $countsField = self::keyAt('counts.fieldName', $val, ''); $countsTitle = self::keyAt('counts.title', $val, ''); if (!empty($countsField)) { $countsValue = !empty($countsField) && isset($records[$i][$countsField]) ? $records[$i][$countsField] : ''; $titleText .= ' / ' . $countsTitle . ': ' . $countsValue; } - + $fieldOutput .= CHtml::tag('label', array('class' => 'stars tooltip-link', 'title' => $titleText), '<label style="width:' . $size . 'px;"></label>'); break; - + case 'template': $htmlCode = self::keyAt('html', $val, ''); $templateFields = self::keyAt('fields', $val, array()); $templateSources = self::keyAt('sources', $val, array()); - + if (is_array($templateFields)) { foreach ($templateFields as $tfKey => $tfValue) { if (is_array($tfValue)) { @@ -913,7 +932,7 @@ public static function init($params = []) $prefix = isset($tfValue['prefix']) ? $tfValue['prefix'] : ''; $postfix = isset($tfValue['postfix']) ? $tfValue['postfix'] : ''; $source = isset($tfValue['source']) ? $tfValue['source'] : array(); - + $templateFieldValue = isset($records[$i][$tfKey]) ? $records[$i][$tfKey] : ''; // Check if there is an array with predefined values if (!empty($source) && is_array($source)) { @@ -921,7 +940,7 @@ public static function init($params = []) } if (empty($templateFieldValue)) $templateFieldValue = $default; if (!empty($templateFieldValue)) $templateFieldValue = $prefix . $templateFieldValue . $postfix; - + $htmlCode = str_ireplace('{' . $tfKey . '}', $templateFieldValue, $htmlCode); } else { $templateFieldValue = isset($records[$i][$tfValue]) ? $records[$i][$tfValue] : ''; @@ -933,10 +952,10 @@ public static function init($params = []) } } } - + $fieldOutput .= $htmlCode; break; - + case 'html': case 'label': default: @@ -950,7 +969,7 @@ public static function init($params = []) $fieldValue = CHash::decrypt($fieldValue, $encryptKey, $encryptAlgorithm); } } - + // Trigger $triggerKey = self::keyAt('trigger.trigger_key', $val); $triggerOperation = self::keyAt('trigger.trigger_operation', $val); @@ -981,7 +1000,7 @@ public static function init($params = []) } } } - + // Call of closure function on item creating event $callbackClass = self::keyAt('callback.class', $val); $callbackFunction = self::keyAt('callback.function', $val); @@ -1002,7 +1021,7 @@ public static function init($params = []) /// $fieldValue = call_user_func($callbackFunction, $records[$i], $callbackParams); } } - + $dataValue = self::keyAt('data', $val, ''); if (!empty($dataValue)) $fieldValue = $dataValue; if (is_array($definedValues) && isset($definedValues[$fieldValue])) { @@ -1024,7 +1043,7 @@ public static function init($params = []) } elseif ($case == 'humanize') { $fieldValue = CString::humanize($fieldValue); } - + $maxLength = (int)self::keyAt('maxLength', $val, ''); $showTooltip = (int)self::keyAt('showTooltip', $val, true); if (!empty($maxLength)) { @@ -1035,14 +1054,14 @@ public static function init($params = []) $fieldValue = $type == 'html' ? $fieldValue : CHtml::encode($fieldValue); } } - + $changeOrderLink = ''; if ($changeOrder) { $changeOrderUrl = $baseUrl . $actionPath; $changeOrderUrl .= !empty($sortUrl) ? '?' . $sortUrl : ''; $changeOrderUrl .= !empty($filterUrl) ? (empty($sortUrl) ? '?' : '&') . $filterUrl : ''; $changeOrderUrl .= (empty($sortUrl) && empty($filterUrl) ? '?' : '&'); - + if ($i > 0) { $changeOrderLink = ' <a style="text-decoration:none;" href="' . $changeOrderUrl . 'act=replace&replace_field=' . $key . '&replace_ids=' . $id . '-' . $prevId . (!empty($page) ? '&page=' . $page : '') . '" title="' . A::te('core', 'Move Up') . '" onclick="javascript:void()">▲</a>'; } @@ -1050,11 +1069,11 @@ public static function init($params = []) $changeOrderLink .= '<a style="text-decoration:none;" href="' . $changeOrderUrl . 'act=replace&replace_field=' . $key . '&replace_ids=' . $id . '-' . $nextId . (!empty($page) ? '&page=' . $page : '') . '" title="' . A::te('core', 'Move Down') . '" onclick="javascript:void()">▼</a>'; } } - + $fieldOutput .= $fieldValue . $changeOrderLink; break; } - + // Calculate aggregate data if (!empty($aggregateFunction)) { switch ($aggregateFunction) { @@ -1077,14 +1096,14 @@ public static function init($params = []) break; } } - + $output .= CHtml::openTag('td', array('class' => $class, 'style' => $style)); $output .= $prependCode; $output .= $fieldOutput; $output .= $appendCode; $output .= CHtml::closeTag('td') . self::NL; } - + if ($activeActions > 0) { $output .= CHtml::openTag('td', array('class' => 'actions')) . self::NL; foreach ($actions as $aKey => $aVal) { @@ -1106,9 +1125,9 @@ public static function init($params = []) $separateSymbol = preg_match('/\?/', $linkUrl) ? '&' : '?'; $linkUrl .= self::_customParams($customParameters, $linkType, $separateSymbol); } - + $linkLabel = (!empty($imagePath) ? '<img src="' . $imagePath . '" alt="' . $aKey . '" />' : $aKey); - + $output .= CHtml::link($linkLabel, $linkUrl, $htmlOptions) . self::NL; } $output .= CHtml::closeTag('td') . self::NL; @@ -1116,7 +1135,7 @@ public static function init($params = []) $output .= CHtml::closeTag('tr') . self::NL; } $output .= CHtml::closeTag('tbody') . self::NL; - + // ---------------------------------------------- // Draw <TFOOT> aggregate row // ---------------------------------------------- @@ -1128,17 +1147,17 @@ public static function init($params = []) $headerClass = self::keyAt('headerClass', $val, ''); $prependCode = self::keyAt('prependCode', $val, ''); $appendCode = self::keyAt('appendCode', $val, ''); - + $format = self::keyAt('format', $val, ''); $decimalPoints = (int)self::keyAt('decimalPoints', $val, 0); $widthAttr = self::keyAt('width', $val); $alignAttr = self::keyAt('align', $val); - + // Prepare style attributes $width = (!empty($widthAttr) && CValidator::isHtmlSize($widthAttr)) ? 'width:' . $widthAttr . ';' : ''; $align = (!empty($alignAttr) && CValidator::isAlignment($alignAttr)) ? 'text-align:' . $alignAttr . ';' : ''; $style = $width . $align; - + if (isset($aggregateRow[$key])) { $aggregateValue = $aggregateRow[$key]['result']; $aggregateValue = number_format((float)$aggregateValue, $decimalPoints); @@ -1149,7 +1168,7 @@ public static function init($params = []) } $title .= $aggregateRow[$key]['function'] . ': ' . $prependCode . $aggregateValue . $appendCode; } - + $output .= CHtml::tag('td', array('class' => $headerClass, 'style' => $style), $title) . self::NL; } if ($activeActions > 0) { @@ -1158,7 +1177,7 @@ public static function init($params = []) $output .= CHtml::closeTag('tr') . self::NL;; $output .= CHtml::closeTag('tfoot') . self::NL; } - + $output .= CHtml::closeTag('table') . self::NL; // ---------------------------------------------- // Draw TABLE wrapper @@ -1166,7 +1185,7 @@ public static function init($params = []) if (!empty($gridWrapper['tag'])) { $output .= CHtml::closeTag($gridWrapper['tag']) . self::NL; } - + // Register script if onDeleteAlert is true if ($onDeleteRecord) { A::app()->getClientScript()->registerScript( @@ -1175,7 +1194,12 @@ public static function init($params = []) 2 ); } - + + A::app()->getClientScript()->registerScript( + 'delete-record', + 'function onDeleteRecord(el){return confirm("ID: " + jQuery(el).data("id") + "\n' . A::te('core', 'Are you sure you want to delete this record?') . '");}', + 2 + ); // Draw pagination if ($pagination) { $paginationUrl = $actionPath; @@ -1191,11 +1215,11 @@ public static function init($params = []) )); } } - + if ($return) return $output; else echo $output; } - + /** * Prepare additional parameters that will be passed * @param bool $allow @@ -1206,12 +1230,12 @@ public static function init($params = []) private static function _additionalParams($allow = false, $linkType = 0, $separateSymbol = '&') { $output = ''; - + if ($allow) { $page = A::app()->getRequest()->getQuery('page', 'integer', 1); $sortBy = A::app()->getRequest()->getQuery('sort_by', 'string'); $sortDir = A::app()->getRequest()->getQuery('sort_dir', 'string'); - + if ($sortBy) { $output .= ($linkType == 1) ? '/sort_by/' . $sortBy : (!empty($output) ? '&' : $separateSymbol) . 'sort_by=' . $sortBy; } @@ -1222,10 +1246,10 @@ private static function _additionalParams($allow = false, $linkType = 0, $separa $output .= ($linkType == 1) ? '/page/' . $page : (!empty($output) ? '&' : $separateSymbol) . 'page=' . $page; } } - + return $output; } - + /** * Prepare custom parameters that will be passed * @param array $params @@ -1236,16 +1260,16 @@ private static function _additionalParams($allow = false, $linkType = 0, $separa private static function _customParams($params, $linkType = 0, $separateSymbol = '&') { $output = ''; - + if (is_array($params)) { foreach ($params as $key => $val) { $output .= ($linkType == 1) ? '/' . $key . '/' . $val : (!empty($output) ? '&' : $separateSymbol) . $key . '=' . $val; } } - + return $output; } - + /** * Returns field attribute * @param array $fields @@ -1257,7 +1281,7 @@ private static function _customParams($params, $linkType = 0, $separateSymbol = private static function _getFieldParam($fields = array(), $field = '', $attr = '', $allowedValues = array()) { $paramValue = ''; - + if (!empty($fields) && is_array($fields)) { if (!empty($allowedValues) && is_array($allowedValues)) { $paramValue = isset($fields[$field][$attr]) && in_array($fields[$field][$attr], $allowedValues) ? $fields[$field][$attr] : ''; @@ -1265,10 +1289,10 @@ private static function _getFieldParam($fields = array(), $field = '', $attr = ' $paramValue = isset($fields[$field][$attr]) ? $fields[$field][$attr] : ''; } } - + return $paramValue; } - + /** * Returns all records from defined SELECT query * @param object $objModel @@ -1280,7 +1304,7 @@ private static function _getAllRecords($objModel, $params = array()) $model = self::params('model', ''); $getAllRecords = self::params('getAllRecords', ''); $records = array(); - + if (!empty($getAllRecords)) { if (CClass::isMethodExists($objModel, $getAllRecords)) { $records = $objModel->$getAllRecords($params); @@ -1290,12 +1314,12 @@ private static function _getAllRecords($objModel, $params = array()) } else { $records = $objModel->findAll($params); } - + return $records; } - + /** - * Counts numbner of all records from defined SELECT query + * Counts number of all records from defined SELECT query * @param object $objModel * @param array $params * @return int @@ -1306,7 +1330,7 @@ private static function _countAllRecords($objModel, $params = array()) $getAllRecords = self::params('getAllRecords', ''); $countAllRecords = self::params('countAllRecords', ''); $totalRecords = 0; - + if (!empty($countAllRecords)) { if (CClass::isMethodExists($objModel, $countAllRecords)) { $totalRecords = $objModel->$countAllRecords($params); @@ -1318,7 +1342,7 @@ private static function _countAllRecords($objModel, $params = array()) } else { $totalRecords = $objModel->count($params); } - + return $totalRecords; } } From e3ebbaf518f3dd6a7607b3f56dc3082802579765 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 14 Nov 2020 13:17:56 +0200 Subject: [PATCH 37/45] Changes in syntaxt of array --- framework/console/CCacheClearCommand.php | 6 +-- framework/console/CMakeControllerCommand.php | 53 ++++++++++++++++++-- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/framework/console/CCacheClearCommand.php b/framework/console/CCacheClearCommand.php index 0deedcd..103c2df 100644 --- a/framework/console/CCacheClearCommand.php +++ b/framework/console/CCacheClearCommand.php @@ -42,7 +42,7 @@ public static function handle($param = '') if (CConfig::get('cache.db.path') == '') { $output .= CConsole::redbg("Config value 'cache.db.path' is not defined. Check your configuration file.") . PHP_EOL; }else{ - $result = CFile::emptyDirectory(CConfig::get('cache.db.path'), array('index.html')); + $result = CFile::emptyDirectory(CConfig::get('cache.db.path'), ['index.html']); $output .= 'DB cache ' . ($result ? 'successfully cleaned' : 'error'); } } @@ -50,7 +50,7 @@ public static function handle($param = '') if (CConfig::get('compression.css.path') == '') { $output .= CConsole::redbg("Config value 'compression.css.path' is not defined. Check your configuration file.") . PHP_EOL; }else{ - $result = CFile::emptyDirectory(CConfig::get('compression.css.path'), array('index.html')); + $result = CFile::emptyDirectory(CConfig::get('compression.css.path'), ['index.html']); $output .= 'CSS cache ' . ($result ? 'successfully cleaned' : 'error'); } } @@ -58,7 +58,7 @@ public static function handle($param = '') if (CConfig::get('compression.js.path') == '') { $output .= CConsole::redbg("Config value 'compression.js.path' is not defined. Check your configuration file.") . PHP_EOL; }else{ - $result = CFile::emptyDirectory(CConfig::get('compression.js.path'), array('index.html')); + $result = CFile::emptyDirectory(CConfig::get('compression.js.path'), ['index.html']); $output .= 'JS cache ' . ($result ? 'successfully cleaned' : 'error'); } } diff --git a/framework/console/CMakeControllerCommand.php b/framework/console/CMakeControllerCommand.php index a545765..dd1dbd3 100644 --- a/framework/console/CMakeControllerCommand.php +++ b/framework/console/CMakeControllerCommand.php @@ -29,21 +29,64 @@ public static function handle($param = '') $output = ''; if (empty($param)) { - $output .= CConsole::redbg("No model name is defined. Type make:controller -h or --help").PHP_EOL; + $output .= CConsole::redbg("No controller name is defined. Type make:controller -h or --help").PHP_EOL; } elseif ($param === '-h' || $param === '--help') { $output .= CConsole::yellow("Usage:") . PHP_EOL; - $output .= " make:controller [model]\t Create a new controller class". PHP_EOL; - $output .= " \t\t\t\t[model] - Generate a resource controller for the given model.". PHP_EOL; + $output .= " make:controller\t[controller]\tCreate a new controller class". PHP_EOL; + $output .= " \t\t\t[model] -ar\tGenerate a resource controller for the given model.". PHP_EOL; } elseif (CValidator::isVariable($param)) { // TODO: create controller + //die($param); + + $controllerFile = $param.'.php'; + $controllerClass = str_ireplace('Controller', '', $param).'Controller'; + $self = '$this'; + + $content = "<?php +/** + * {$controllerClass} controller + * + * PUBLIC: PRIVATE + * ----------- ------------------ + * __construct + * indexAction + * + */ + +class {$controllerClass} extends CController +{ + /** + * Class default constructor + */ + public function __construct() + { + parent::__construct(); + + // set backend mode + // Website::setBackend(); + // set backend mode + // Website::setFrontend(); + } + + /** + * Controller default action handler + */ + public function indexAction() + { + // {$self}->_view->render(\'{$param}/index\'); + } +} +"; + CFile::writeToFile($controllerFile, $content, 'w'); + $output .= CConsole::green("Controller $param has been successfully created.").PHP_EOL; } else { if (!CValidator::isVariable($param)){ - $output .= CConsole::redbg("The model name must be a valid controller name (alphanumeric, starts with letter and can contain an underscore)! Please re-enter.").PHP_EOL; + $output .= CConsole::redbg("The controller name must be a valid controller name (alphanumeric, starts with letter and can contain an underscore)! Please re-enter.").PHP_EOL; } else { - $output .= CConsole::redbg("No model name is defined or wrong parameters. Type make:controller -h or --help").PHP_EOL; + $output .= CConsole::redbg("No controller name is defined or wrong parameters. Type make:controller -h or --help").PHP_EOL; } } From af9c39c7671965780bcdbaf6f7946c929757247d Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 14 Nov 2020 13:18:34 +0200 Subject: [PATCH 38/45] Implemented make:controller [controller] console command --- .../protected/components/Bootstrap.php | 18 +- .../controllers/AccountController.php | 15 +- .../protected/controllers/LoginController.php | 23 +- .../setup/controllers/SetupController.php | 136 +++-- .../protected/views/index/index.php | 2 +- .../protected/views/login/index.php | 34 +- .../templates/default/default.php | 76 ++- .../login-system/templates/setup/default.php | 33 +- .../protected/modules/setup/config/main.php | 12 +- .../modules/setup/views/setup/database.php | 22 +- .../protected/components/Bootstrap.php | 34 +- framework/helpers/CArray.php | 42 +- framework/helpers/CHtml.php | 535 +++++++++--------- framework/helpers/COauth.php | 127 ++--- framework/helpers/CRss.php | 30 +- framework/helpers/CWidget.php | 16 +- 16 files changed, 606 insertions(+), 549 deletions(-) diff --git a/demos/login-system/protected/components/Bootstrap.php b/demos/login-system/protected/components/Bootstrap.php index 76fa107..51f8e6e 100644 --- a/demos/login-system/protected/components/Bootstrap.php +++ b/demos/login-system/protected/components/Bootstrap.php @@ -24,15 +24,15 @@ class Bootstrap extends CComponent */ function __construct() { - A::app()->attachEventHandler('_onBeginRequest', array($this, 'setTimeZone')); - A::app()->attachEventHandler('_onBeginRequest', array($this, 'setSslMode')); - A::app()->attachEventHandler('_onBeginRequest', array($this, 'setCron')); - - A::app()->attachEventHandler('_onEndRequest', array($this, 'setLastVisitedPage')); - } - - /** - * Returns the instance of object + A::app()->attachEventHandler('_onBeginRequest', [$this, 'setTimeZone']); + A::app()->attachEventHandler('_onBeginRequest', [$this, 'setSslMode']); + A::app()->attachEventHandler('_onBeginRequest', [$this, 'setCron']); + + A::app()->attachEventHandler('_onEndRequest', [$this, 'setLastVisitedPage']); + } + + /** + * Returns the instance of object * @return current class */ public static function init() diff --git a/demos/login-system/protected/controllers/AccountController.php b/demos/login-system/protected/controllers/AccountController.php index 9b1b241..903bebd 100644 --- a/demos/login-system/protected/controllers/AccountController.php +++ b/demos/login-system/protected/controllers/AccountController.php @@ -33,12 +33,11 @@ public function editAction() if ($cRequest->getPost('act') == 'send') { // Perform account edit form validation - $result = CWidget::create('CFormValidation', array( - 'fields' => array( - //'username'=>array('title'=>'Username' 'validation'=>array('required'=>true, 'type'=>'username', 'minLength'=>4)), - 'password' => array('title' => 'Password', 'validation' => array('required' => true, 'type' => 'password', 'minLength' => 4)), - ), - )); + $result = CWidget::create('CFormValidation', [ + 'fields' => [ + 'password' => ['title' => 'Password', 'validation' => ['required' => true, 'type' => 'password', 'minLength' => 4]], + ], + ]); if ($result['error']) { $msg = $result['errorMessage']; @@ -62,8 +61,8 @@ public function editAction() if (!empty($msg)) { $this->_view->username = $cRequest->getPost('username', 'string'); - $this->_view->actionMessage = CWidget::create('CMessage', array($msgType, $msg, array('button' => true))); - } else { + $this->_view->actionMessage = CWidget::create('CMessage', [$msgType, $msg, ['button' => true]]); + } else { $this->_view->username = $info['username']; } } else { diff --git a/demos/login-system/protected/controllers/LoginController.php b/demos/login-system/protected/controllers/LoginController.php index 2234043..3ddbe26 100644 --- a/demos/login-system/protected/controllers/LoginController.php +++ b/demos/login-system/protected/controllers/LoginController.php @@ -41,14 +41,17 @@ public function runAction() if ($cRequest->getPost('act') == 'send') { // perform login form validation - $result = CWidget::create('CFormValidation', array( - 'fields' => array( - 'username' => array('title' => 'Username', 'validation' => array('required' => true, 'type' => 'any')), - 'password' => array('title' => 'Password', 'validation' => array('required' => true, 'type' => 'any')), - ), - )); - - if ($result['error']) { + $result = CWidget::create( + 'CFormValidation', + [ + 'fields' => [ + 'username' => ['title' => 'Username', 'validation' => ['required' => true, 'type' => 'any']], + 'password' => ['title' => 'Password', 'validation' => ['required' => true, 'type' => 'any']], + ], + ] + ); + + if ($result['error']) { $msg = $result['errorMessage']; $msgType = 'validation'; $this->_view->errorField = $result['errorField']; @@ -66,8 +69,8 @@ public function runAction() if (!empty($msg)) { $this->_view->username = $cRequest->getPost('username', 'string'); $this->_view->password = $cRequest->getPost('password', 'string'); - $this->_view->actionMessage = CWidget::create('CMessage', array($msgType, $msg)); - } + $this->_view->actionMessage = CWidget::create('CMessage', [$msgType, $msg]); + } } $this->_view->render('login/index'); } diff --git a/demos/login-system/protected/modules/setup/controllers/SetupController.php b/demos/login-system/protected/modules/setup/controllers/SetupController.php index 51ef9e0..6c2864b 100644 --- a/demos/login-system/protected/modules/setup/controllers/SetupController.php +++ b/demos/login-system/protected/modules/setup/controllers/SetupController.php @@ -80,18 +80,28 @@ public function indexAction() $this->_view->actionMessage = ''; $msg = ''; - - $this->_view->formFields = array( - 'act' => array('type' => 'hidden', 'value' => 'send'), - 'language' => array('type' => 'dropdownlist', 'value' => $language, 'title' => A::t('setup', 'Language'), 'mandatoryStar' => false, 'data' => $this->_languages, 'htmlOptions' => [], 'validation' => array('required' => true, 'type' => 'set', 'source' => array_keys($this->_languages))), - ); - - if ($this->_cRequest->getPost('act') == 'send') { - $result = CWidget::create('CFormValidation', array( - 'fields' => $this->_view->formFields - )); - - if ($result['error']) { + + $this->_view->formFields = [ + 'act' => ['type' => 'hidden', 'value' => 'send'], + 'language' => ['type' => 'dropdownlist', + 'value' => $language, + 'title' => A::t('setup', 'Language'), + 'mandatoryStar' => false, + 'data' => $this->_languages, + 'htmlOptions' => [], + 'validation' => ['required' => true, 'type' => 'set', 'source' => array_keys($this->_languages)] + ], + ]; + + if ($this->_cRequest->getPost('act') == 'send') { + $result = CWidget::create( + 'CFormValidation', + [ + 'fields' => $this->_view->formFields + ] + ); + + if ($result['error']) { $msg = $result['errorMessage']; $this->_view->errorField = $result['errorField']; } else { @@ -100,26 +110,44 @@ public function indexAction() } if (!empty($msg)) { - $this->_view->actionMessage = CWidget::create('CMessage', array('validation', $msg)); - } + $this->_view->actionMessage = CWidget::create('CMessage', ['validation', $msg]); + } } $modeRewrite = $this->_checkModRewrite(); if (!$modeRewrite) { - $this->_view->actionMessage = CWidget::create('CMessage', array('warning', 'This program requires "<b>mod_rewrite</b>" module to use friendly URLs, but it is not enabled or its status unknown. You may proceed current installation on your own risk.')); - } - - $htaccessFile = !CFile::fileExists('.htaccess'); + $this->_view->actionMessage = CWidget::create( + 'CMessage', + [ + 'warning', + 'This program requires "<b>mod_rewrite</b>" module to use friendly URLs, but it is not enabled or its status unknown. You may proceed current installation on your own risk.' + ] + ); + } + + $htaccessFile = !CFile::fileExists('.htaccess'); if ($htaccessFile) { - $this->_view->actionMessage .= CWidget::create('CMessage', array('warning', 'This program requires "<b>.htaccess</b>" file with "<b>mod_rewrite</b>" rules in the root directory. You may proceed current installation on your own risk.')); - } - - $hostName = A::app()->getRequest()->getHostName(); + $this->_view->actionMessage .= CWidget::create( + 'CMessage', + [ + 'warning', + 'This program requires "<b>.htaccess</b>" file with "<b>mod_rewrite</b>" rules in the root directory. You may proceed current installation on your own risk.' + ] + ); + } + + $hostName = A::app()->getRequest()->getHostName(); if (CValidator::isIpAddress($hostName)) { - $this->_view->actionMessage .= CWidget::create('CMessage', array('warning', 'You\'re trying to install this script using IP address (without domain name), so you have to add some changes in your .htaccess file to provide a correct work of the "<b>mod_rewrite</b>". Find more information <a href="http://www.apphp.net/forum/viewtopic.php?f=80&t=6614" target="_blank" rel="noopener noreferrer">here</a>.')); - } - - $phpInfo = $this->_getPhpInfo(); + $this->_view->actionMessage .= CWidget::create( + 'CMessage', + [ + 'warning', + 'You\'re trying to install this script using IP address (without domain name), so you have to add some changes in your .htaccess file to provide a correct work of the "<b>mod_rewrite</b>". Find more information <a href="http://www.apphp.net/forum/viewtopic.php?f=80&t=6614" target="_blank" rel="noopener noreferrer">here</a>.' + ] + ); + } + + $phpInfo = $this->_getPhpInfo(); // Check pdoExtension $pdoExtension = $this->_checkPdoExtension($phpInfo); @@ -160,28 +188,28 @@ public function requirementsAction() $shortOpenTag = isset($phpInfo[$phpCoreIndex]['short_open_tag'][0]) ? strtolower($phpInfo[$phpCoreIndex]['short_open_tag'][0]) : false; if (version_compare(phpversion(), '5.4.0', '<')) { - $this->_view->notifyMessage = CWidget::create('CMessage', array('error', 'This program requires at least <b>PHP version 5.4.0</b> installed. You cannot proceed current installation.')); + $this->_view->notifyMessage = CWidget::create('CMessage', ['error', 'This program requires at least <b>PHP version 5.4.0</b> installed. You cannot proceed current installation.']); $this->_view->isCriticalError = true; } elseif (!is_writable(APPHP_PATH . '/protected/config/')) { - $this->_view->notifyMessage = CWidget::create('CMessage', array('error', 'The directory <b>' . APPHP_PATH . '/protected/config/</b> is not writable! <br>You must grant "write" permissions (access rights 0755 or 777, depending on your system settings) to this directory before you start current installation!')); + $this->_view->notifyMessage = CWidget::create('CMessage', ['error', 'The directory <b>' . APPHP_PATH . '/protected/config/</b> is not writable! <br>You must grant "write" permissions (access rights 0755 or 777, depending on your system settings) to this directory before you start current installation!']); $this->_view->isCriticalError = true; } elseif (!is_writable(APPHP_PATH . '/assets/modules/')) { - $this->_view->notifyMessage = CWidget::create('CMessage', array('error', 'The directory <b>' . APPHP_PATH . '/assets/modules/</b> is not writable! <br>You must grant "write" permissions (access rights 0755 or 777, depending on your system settings) to this directory before you start current installation!')); + $this->_view->notifyMessage = CWidget::create('CMessage', ['error', 'The directory <b>' . APPHP_PATH . '/assets/modules/</b> is not writable! <br>You must grant "write" permissions (access rights 0755 or 777, depending on your system settings) to this directory before you start current installation!']); $this->_view->isCriticalError = true; } elseif (!is_writable(APPHP_PATH . '/protected/messages/')) { - $this->_view->notifyMessage = CWidget::create('CMessage', array('error', 'The directory <b>' . APPHP_PATH . '/protected/messages/</b> is not writable! <br>You must grant "write" permissions (access rights 0755 or 777, depending on your system settings) to this directory before you start current installation!')); + $this->_view->notifyMessage = CWidget::create('CMessage', ['error', 'The directory <b>' . APPHP_PATH . '/protected/messages/</b> is not writable! <br>You must grant "write" permissions (access rights 0755 or 777, depending on your system settings) to this directory before you start current installation!']); $this->_view->isCriticalError = true; } elseif (!is_writable(APPHP_PATH . '/templates/backend/images/icons/')) { - $this->_view->notifyMessage = CWidget::create('CMessage', array('error', 'The directory <b>' . APPHP_PATH . '/templates/backend/images/icons/</b> is not writable! <br>You must grant "write" permissions (access rights 0755 or 777, depending on your system settings) to this directory before you start current installation!')); + $this->_view->notifyMessage = CWidget::create('CMessage', ['error', 'The directory <b>' . APPHP_PATH . '/templates/backend/images/icons/</b> is not writable! <br>You must grant "write" permissions (access rights 0755 or 777, depending on your system settings) to this directory before you start current installation!']); $this->_view->isCriticalError = true; } elseif (!$modeRewrite) { - $this->_view->notifyMessage = CWidget::create('CMessage', array('warning', 'This program requires "<b>mod_rewrite</b>" module to use friendly URLs, but it is not enabled or its status unknown. You may proceed current installation on your own risk.')); + $this->_view->notifyMessage = CWidget::create('CMessage', ['warning', 'This program requires "<b>mod_rewrite</b>" module to use friendly URLs, but it is not enabled or its status unknown. You may proceed current installation on your own risk.']); $this->_view->isCriticalError = false; } elseif ($this->_pdoExtensionRequired && !$pdoExtension) { - $this->_view->notifyMessage = CWidget::create('CMessage', array('error', 'This program requires "<b>PDO</b>" extension enabled. You cannot proceed current installation.')); + $this->_view->notifyMessage = CWidget::create('CMessage', ['error', 'This program requires "<b>PDO</b>" extension enabled. You cannot proceed current installation.']); $this->_view->isCriticalError = true; } elseif ($shortOpenTag != 'on' && version_compare(phpversion(), '5.4.0', '<')) { - $this->_view->notifyMessage = CWidget::create('CMessage', array('warning', 'This program requires "<b>Short Open Tag</b>" enabled. You cannot proceed current installation.')); + $this->_view->notifyMessage = CWidget::create('CMessage', ['warning', 'This program requires "<b>Short Open Tag</b>" enabled. You cannot proceed current installation.']); $this->_view->isCriticalError = true; } @@ -248,15 +276,15 @@ public function databaseAction() } $this->_view->actionMessage = ''; - $dbDrivers = array('mysql' => 'MySql'); - $dbConnectTypes = array('host' => A::t('setup', 'host'), 'socket' => A::t('setup', 'socket')); - $msg = ''; + $dbDrivers = ['mysql' => 'MySql']; + $dbConnectTypes = ['host' => A::t('setup', 'host'), 'socket' => A::t('setup', 'socket')]; + $msg = ''; $separatorGeneralFields = array( - 'separatorInfo' => array('legend' => 'General Settings'), - 'setupType' => array('type' => 'dropdownlist', 'value' => $this->_view->setupType, 'title' => A::t('setup', 'Setup Type'), 'mandatoryStar' => false, 'data' => array('install' => A::t('setup', 'New Installation'), 'update' => A::t('setup', 'Update')), 'htmlOptions' => [], 'validation' => array('required' => true, 'type' => 'text', 'source' => array('install'))), - 'dbDriver' => array('type' => 'dropdownlist', 'value' => $this->_view->dbDriver, 'title' => A::t('setup', 'Database Driver'), 'mandatoryStar' => true, 'data' => $dbDrivers, 'htmlOptions' => array('style' => 'width:85px'), 'validation' => array('required' => true, 'type' => 'text', 'source' => array_keys($dbDrivers))), - 'dbPrefix' => array('type' => 'textbox', 'value' => $this->_view->dbPrefix, 'title' => A::t('setup', 'Database (tables) Prefix'), 'mandatoryStar' => false, 'htmlOptions' => array('maxLength' => '10', 'autocomplete' => 'off'), 'validation' => array('required' => false, 'type' => 'variable')), + 'separatorInfo' => ['legend' => 'General Settings'], + 'setupType' => ['type' => 'dropdownlist', 'value' => $this->_view->setupType, 'title' => A::t('setup', 'Setup Type'), 'mandatoryStar' => false, 'data' => array('install' => A::t('setup', 'New Installation'), 'update' => A::t('setup', 'Update')), 'htmlOptions' => [], 'validation' => array('required' => true, 'type' => 'text', 'source' => array('install'))], + 'dbDriver' => ['type' => 'dropdownlist', 'value' => $this->_view->dbDriver, 'title' => A::t('setup', 'Database Driver'), 'mandatoryStar' => true, 'data' => $dbDrivers, 'htmlOptions' => array('style' => 'width:85px'), 'validation' => array('required' => true, 'type' => 'text', 'source' => array_keys($dbDrivers))], + 'dbPrefix' => ['type' => 'textbox', 'value' => $this->_view->dbPrefix, 'title' => A::t('setup', 'Database (tables) Prefix'), 'mandatoryStar' => false, 'htmlOptions' => array('maxLength' => '10', 'autocomplete' => 'off'), 'validation' => array('required' => false, 'type' => 'variable')], ); $separatorConenctionSettingsFields = array( 'separatorInfo' => array('legend' => 'Connection Settings'), @@ -300,8 +328,8 @@ public function databaseAction() )); if ($model->getError()) { - $this->_view->actionMessage = CWidget::create('CMessage', array('error', $model->getErrorMessage())); - } else { + $this->_view->actionMessage = CWidget::create('CMessage', ['error', $model->getErrorMessage()]); + } else { // Go to the next step $this->_cSession->set('setupType', $this->_view->setupType); $this->_cSession->set('dbDriver', $this->_view->dbDriver); @@ -320,8 +348,8 @@ public function databaseAction() } if (!empty($msg)) { - $this->_view->actionMessage = CWidget::create('CMessage', array('validation', $msg)); - } + $this->_view->actionMessage = CWidget::create('CMessage', ['validation', $msg]); + } } $this->_view->setMetaTags('title', A::t('setup', 'Database Settings | Setup Wizard')); @@ -351,13 +379,13 @@ public function administratorAction() $this->_view->username = $this->_cRequest->getPost('username'); $this->_view->password = $this->_cRequest->getPost('password'); - $result = CWidget::create('CFormValidation', array( - 'fields' => array( + $result = CWidget::create('CFormValidation', [ + 'fields' => [ 'email' => array('title' => A::t('setup', 'Email'), 'validation' => array('required' => false, 'type' => 'email')), 'username' => array('title' => A::t('setup', 'Username'), 'validation' => array('required' => true, 'type' => 'any', 'minLength' => 4, 'maxLength' => 32)), 'password' => array('title' => A::t('setup', 'Password'), 'validation' => array('required' => true, 'type' => 'any', 'minLength' => 4, 'maxLength' => 25)), - ), - )); + ], + ]); if ($result['error']) { $msg = $result['errorMessage']; @@ -373,8 +401,8 @@ public function administratorAction() } if (!empty($msg)) { - $this->_view->actionMessage = CWidget::create('CMessage', array('validation', $msg)); - } + $this->_view->actionMessage = CWidget::create('CMessage', ['validation', $msg]); + } } $this->_view->setMetaTags('title', A::t('setup', 'Administrator Account | Setup Wizard')); @@ -398,7 +426,7 @@ public function readyAction() $sqlDumpPath = APPHP_PATH . '/protected/data/schema' . ($this->_cSession->get('setupType') == 'update' ? '.update' : '') . '.' . strtolower($dbDriver) . '.sql'; $sqlDump = file($sqlDumpPath); if (empty($sqlDump)) { - $this->_view->actionMessage = CWidget::create('CMessage', array('error', 'Could not read file <b>' . $sqlDumpPath . '</b>! Please check if this file exists.')); + $this->_view->actionMessage = CWidget::create('CMessage', ['error', 'Could not read file <b>' . $sqlDumpPath . '</b>! Please check if this file exists.']); } else { $encryption = isset($this->_configMain['password']['encryption']) ? $this->_configMain['password']['encryption'] : false; $encryptAlgorithm = isset($this->_configMain['password']['encryptAlgorithm']) ? $this->_configMain['password']['encryptAlgorithm'] : ''; @@ -416,7 +444,7 @@ public function readyAction() $sqlDump = str_ireplace('<CURRENT_DATE>', date('Y-m-d', time() + (date('I', time()) ? 3600 : 0)), $sqlDump); $sqlDump = str_ireplace('<CURRENT_DATETIME>', date('Y-m-d H:i:s', time() + (date('I', time()) ? 3600 : 0)), $sqlDump); - $model = new Setup(array( + $model = new Setup([ 'dbDriver' => $dbDriver, 'dbConnectType' => $this->_cSession->get('dbConnectType'), 'dbSocket' => $this->_cSession->get('dbSocket'), @@ -425,7 +453,7 @@ public function readyAction() 'dbName' => $this->_cSession->get('dbName'), 'dbUser' => $this->_cSession->get('dbUser'), 'dbPassword' => $this->_cSession->get('dbPassword') - )); + ]); if ($model->getError()) { $this->_view->actionMessage = CWidget::create('CMessage', array('error', $model->getErrorMessage())); diff --git a/demos/login-system/protected/views/index/index.php b/demos/login-system/protected/views/index/index.php index 1975146..75b8984 100644 --- a/demos/login-system/protected/views/index/index.php +++ b/demos/login-system/protected/views/index/index.php @@ -9,6 +9,6 @@ </article> <?php if(!CAuth::isLoggedIn()){ - echo CWidget::create('CMessage', array('info', 'Click <a href="login/index"><b>here</b></a> to log into the system as administrator.')); + echo CWidget::create('CMessage', ['info', 'Click <a href="login/index"><b>here</b></a> to log into the system as administrator.']); } ?> diff --git a/demos/login-system/protected/views/login/index.php b/demos/login-system/protected/views/login/index.php index 235dfc9..8c09884 100644 --- a/demos/login-system/protected/views/login/index.php +++ b/demos/login-system/protected/views/login/index.php @@ -6,7 +6,7 @@ <?php if(APPHP_MODE == 'demo'){ - echo CWidget::create('CMessage', array('info', 'To access the demo account enter<br>Username: <b>admin</b><br>Password: <b>test</b>')); + echo CWidget::create('CMessage', ['info', 'To access the demo account enter<br>Username: <b>admin</b><br>Password: <b>test</b>']); } ?> @@ -17,25 +17,25 @@ <?php // draw login form - echo CWidget::create('CFormView', array( + echo CWidget::create('CFormView', [ 'action'=>'login/run', 'method'=>'post', - 'htmlOptions'=>array( - 'name'=>'frmLogin' - ), - 'fields'=>array( - 'act' =>array('type'=>'hidden', 'value'=>'send'), - 'username'=>array('type'=>'textbox', 'value'=>$username, 'title'=>'Username', 'mandatoryStar'=>false, 'htmlOptions'=>array('maxlength'=>'32', 'autocomplete'=>'off')), - 'password'=>array('type'=>'password', 'value'=>$password, 'title'=>'Password', 'mandatoryStar'=>false, 'htmlOptions'=>array('maxLength'=>'20')), - ), - 'buttons'=>array( - 'submit'=>array('type'=>'submit', 'value'=>'Login'), - ), - 'events'=>array( - 'focus'=>array('field'=>$errorField) - ), + 'htmlOptions' => [ + 'name' => 'frmLogin' + ], + 'fields'=>[ + 'act' =>['type'=>'hidden', 'value'=>'send'], + 'username'=>['type'=>'textbox', 'value'=>$username, 'title'=>'Username', 'mandatoryStar'=>false, 'htmlOptions'=>array('maxlength'=>'32', 'autocomplete'=>'off')], + 'password'=>['type'=>'password', 'value'=>$password, 'title'=>'Password', 'mandatoryStar'=>false, 'htmlOptions'=>array('maxLength'=>'20')], + ], + 'buttons' => [ + 'submit' => ['type' => 'submit', 'value' => 'Login'], + ], + 'events' => [ + 'focus' => ['field' => $errorField] + ], 'return'=>true, - )); + ]); ?> </fieldset> diff --git a/demos/login-system/templates/default/default.php b/demos/login-system/templates/default/default.php index 9eaaf56..162f092 100644 --- a/demos/login-system/templates/default/default.php +++ b/demos/login-system/templates/default/default.php @@ -19,41 +19,55 @@ <header> <nav> <?php - CWidget::create('CMenu', array( - 'items' => array( - array('label' => 'Home', 'url' => 'index/index'), - (CAuth::isLoggedIn() == true) ? array('label' => 'Dashboard', 'url' => 'page/dashboard') : '', - (CAuth::isLoggedIn() == true) ? array('label' => 'My Account', 'url' => 'account/edit') : '', - array('label' => 'Public Page #1', 'url' => 'page/public/id/1'), - array('label' => 'Public Page #2', 'url' => 'page/public/id/2'), - ), - 'type' => 'horizontal', - 'selected' => $this->_activeMenu, - 'return' => false, - )); - ?> - - <?php - CWidget::create('CMenu', array( - 'items' => array( - (CAuth::isLoggedIn() == true) ? array('label' => 'Logout', 'url' => 'login/logout') : array('label' => 'Login', 'url' => 'login/index'), - ), - 'type' => 'horizontal', - 'class' => 'user_menu', - 'selected' => $this->_activeMenu, - 'return' => false, - )); - ?> + CWidget::create( + 'CMenu', + [ + 'items' => [ + ['label' => 'Home', 'url' => 'index/index'], + (CAuth::isLoggedIn() == true) ? ['label' => 'Dashboard', 'url' => 'page/dashboard'] : '', + (CAuth::isLoggedIn() == true) ? ['label' => 'My Account', 'url' => 'account/edit'] : '', + ['label' => 'Public Page #1', 'url' => 'page/public/id/1'], + ['label' => 'Public Page #2', 'url' => 'page/public/id/2'], + ], + 'type' => 'horizontal', + 'selected' => $this->_activeMenu, + 'return' => false, + ] + ); + ?> + + <?php + CWidget::create( + 'CMenu', + [ + 'items' => [ + (CAuth::isLoggedIn() == true) + ? ['label' => 'Logout', 'url' => 'login/logout'] + : [ + 'label' => 'Login', + 'url' => 'login/index' + ], + ], + 'type' => 'horizontal', + 'class' => 'user_menu', + 'selected' => $this->_activeMenu, + 'return' => false, + ] + ); + ?> </nav> </header> <section> <?php - CWidget::create('CBreadCrumbs', array( - 'links' => $this->_breadCrumbs, - 'return' => false, - )); - ?> - <?= A::app()->view->getContent(); ?> + CWidget::create( + 'CBreadCrumbs', + [ + 'links' => $this->_breadCrumbs, + 'return' => false, + ] + ); + ?> + <?= A::app()->view->getContent(); ?> </section> <footer> <p class="copyright">Copyright © <?= @date('Y'); ?> Your Site</p> diff --git a/demos/login-system/templates/setup/default.php b/demos/login-system/templates/setup/default.php index 9a8091c..f729fe6 100644 --- a/demos/login-system/templates/setup/default.php +++ b/demos/login-system/templates/setup/default.php @@ -29,23 +29,26 @@ </div> <?php - CWidget::create('CMenu', array( - 'type' => 'vertical', - 'items' => array( - array('label' => '1. ' . A::t('setup', 'General'), 'url' => 'setup/index', 'readonly' => true), - array('label' => '2. ' . A::t('setup', 'Check Requirements'), 'url' => 'setup/requirements', 'readonly' => true), - array('label' => '3. ' . A::t('setup', 'Database Settings'), 'url' => 'setup/database', 'readonly' => true), - array('label' => '4. ' . A::t('setup', 'Administrator Account'), 'url' => 'setup/administrator', 'readonly' => true), - array('label' => '5. ' . A::t('setup', 'Ready to Install'), 'url' => 'setup/ready', 'readonly' => true), - array('label' => '6. ' . A::t('setup', 'Completed'), 'url' => 'setup/completed', 'readonly' => true), - ), - 'selected' => $this->_activeMenu, - 'return' => false, - )); - ?> + CWidget::create( + 'CMenu', + [ + 'type' => 'vertical', + 'items' => [ + ['label' => '1. '.A::t('setup', 'General'), 'url' => 'setup/index', 'readonly' => true], + ['label' => '2. '.A::t('setup', 'Check Requirements'), 'url' => 'setup/requirements', 'readonly' => true], + ['label' => '3. '.A::t('setup', 'Database Settings'), 'url' => 'setup/database', 'readonly' => true], + ['label' => '4. '.A::t('setup', 'Administrator Account'), 'url' => 'setup/administrator', 'readonly' => true], + ['label' => '5. '.A::t('setup', 'Ready to Install'), 'url' => 'setup/ready', 'readonly' => true], + ['label' => '6. '.A::t('setup', 'Completed'), 'url' => 'setup/completed', 'readonly' => true], + ], + 'selected' => $this->_activeMenu, + 'return' => false, + ] + ); + ?> </aside> <article> - <?= A::app()->view->getContent(); ?> + <?= A::app()->view->getContent(); ?> </article> </section> <footer> diff --git a/demos/simple-blog/protected/modules/setup/config/main.php b/demos/simple-blog/protected/modules/setup/config/main.php index 05d143e..de6d505 100644 --- a/demos/simple-blog/protected/modules/setup/config/main.php +++ b/demos/simple-blog/protected/modules/setup/config/main.php @@ -1,8 +1,8 @@ <?php -return array( - // Module classes - 'classes' => array( - 'Modules\Setup\Controllers\Setup', - ), -); +return [ + // Module classes + 'classes' => [ + 'Modules\Setup\Controllers\Setup', + ], +]; diff --git a/demos/simple-blog/protected/modules/setup/views/setup/database.php b/demos/simple-blog/protected/modules/setup/views/setup/database.php index 4a64d1a..a3c78cb 100644 --- a/demos/simple-blog/protected/modules/setup/views/setup/database.php +++ b/demos/simple-blog/protected/modules/setup/views/setup/database.php @@ -12,22 +12,22 @@ <br> <?php -echo CWidget::create('CFormView', array( +echo CWidget::create('CFormView', [ 'action' => 'setup/database', 'method' => 'post', - 'htmlOptions' => array( + 'htmlOptions' => [ 'name' => 'frmSetup', 'id' => 'frmSetup', - ), + ], 'fields' => $formFields, - 'buttons' => array( - 'back' => array('type' => 'button', 'value' => A::t('setup', 'Previous'), 'htmlOptions' => array('name' => '', 'onclick' => "$(location).attr('href','setup/requirements');")), - 'submit' => array('type' => 'submit', 'value' => A::t('setup', 'Next'), 'htmlOptions' => array('name' => '')), - ), - 'events' => array( - 'focus' => array('field' => $errorField), - ), + 'buttons' => [ + 'back' => ['type' => 'button', 'value' => A::t('setup', 'Previous'), 'htmlOptions' => ['name' => '', 'onclick' => "$(location).attr('href','setup/requirements');"]], + 'submit' => ['type' => 'submit', 'value' => A::t('setup', 'Next'), 'htmlOptions' => ['name' => '']], + ], + 'events' => [ + 'focus' => ['field' => $errorField], + ], 'return' => true, -)); +]); ?> <br> diff --git a/demos/simple-cms/protected/components/Bootstrap.php b/demos/simple-cms/protected/components/Bootstrap.php index 73e676e..7f0d780 100644 --- a/demos/simple-cms/protected/components/Bootstrap.php +++ b/demos/simple-cms/protected/components/Bootstrap.php @@ -34,8 +34,8 @@ function __construct() if (CAuth::isLoggedInAsAdmin() || stripos(A::app()->getRequest()->getRequestUri(), 'backend/login')) { // Allow viewing } else { - $siteInfo = SiteInfo::model()->find('language_code = :lang', array(':lang' => A::app()->getLanguage())); - A::app()->view->sitePhone = $siteInfo ? $siteInfo->site_phone : ''; + $siteInfo = SiteInfo::model()->find('language_code = :lang', [':lang' => A::app()->getLanguage()]); + A::app()->view->sitePhone = $siteInfo ? $siteInfo->site_phone : ''; A::app()->view->siteFax = $siteInfo ? $siteInfo->site_fax : ''; A::app()->view->siteEmail = $siteInfo ? $siteInfo->site_email : ''; A::app()->view->siteAddress = $siteInfo ? $siteInfo->site_address : ''; @@ -47,19 +47,19 @@ function __construct() exit; } } - - A::app()->attachEventHandler('_onBeginRequest', array($this, 'setTimeZone')); - //A::app()->attachEventHandler('_onBeginRequest', array($this, 'setWebsiteInfo')); - //A::app()->attachEventHandler('_onBeginRequest', array($this, 'setDefaultLanguage')); - //A::app()->attachEventHandler('_onBeginRequest', array($this, 'setDefaultCurrency')); - A::app()->attachEventHandler('_onBeginRequest', array($this, 'setSslMode')); - A::app()->attachEventHandler('_onBeginRequest', array($this, 'setCron')); - - A::app()->attachEventHandler('_onEndRequest', array($this, 'setLastVisitedPage')); - } - - /** - * Returns the instance of object + + A::app()->attachEventHandler('_onBeginRequest', [$this, 'setTimeZone']); + //A::app()->attachEventHandler('_onBeginRequest', array($this, 'setWebsiteInfo')); + //A::app()->attachEventHandler('_onBeginRequest', array($this, 'setDefaultLanguage')); + //A::app()->attachEventHandler('_onBeginRequest', array($this, 'setDefaultCurrency')); + A::app()->attachEventHandler('_onBeginRequest', [$this, 'setSslMode']); + A::app()->attachEventHandler('_onBeginRequest', [$this, 'setCron']); + + A::app()->attachEventHandler('_onEndRequest', [$this, 'setLastVisitedPage']); + } + + /** + * Returns the instance of object * @return current class */ public static function init() @@ -96,13 +96,13 @@ public function setDefaultLanguage($force = false) { // if(A::app()->getLanguage('', false) == '' || $force){ // if($defaultLang = Languages::model()->find('is_default = 1')){ -// $params = array( +// $params = [ // 'name' => $defaultLang->name, // 'name_native' => $defaultLang->name_native, // 'locale' => $defaultLang->lc_time_name, // 'direction' => $defaultLang->direction, // 'icon' => $defaultLang->icon, -// ); +// ]; // A::app()->setLanguage($defaultLang->code, $params); // } // } diff --git a/framework/helpers/CArray.php b/framework/helpers/CArray.php index 008f9cf..efeec9b 100644 --- a/framework/helpers/CArray.php +++ b/framework/helpers/CArray.php @@ -24,30 +24,30 @@ class CArray * Exchanges all keys with values from defined field in sub-arrays * * Usage: - * $array = array( - * [0] => array( + * $array = [ + * [0] => [ * 'field1' => value01 * 'field2' => value02 * 'field3' => value03 - * ), - * [1] => array( + * ], + * [1] => [ * 'field1' => value11 * 'field2' => value12 * 'field3' => value13 - * )); + * ]]; * * Result: - * $array = array( - * ['value01'] => array( + * $array = [ + * ['value01'] => [ * 'field1' => value01 * 'field2' => value02 * 'field3' => value03 - * ), - * ['value11'] => array( + * ], + * ['value11'] => [ * 'field1' => value11 * 'field2' => value12 * 'field3' => value13 - * )); + * ]]; * * flipByField($array, 'field3'); * @@ -79,17 +79,17 @@ public static function flipByField($array, $field = '', $group = false) * Returns array of unique values from specified filed in sub-array * * Usage: - * $array = array( - * [0] => array( + * $array = [ + * [0] => [ * 'field1' => ..v1 * 'field2' => ..v2 * 'field3' => ..v3 - * ), - * [1] => array( + * ], + * [1] => [ * 'field1' => ..v1 * 'field2' => ..v2 * 'field3' => ..v3 - * )); + * ]]; * * uniqueByField($array, 'field3'); * @@ -100,9 +100,9 @@ public static function flipByField($array, $field = '', $group = false) */ public static function uniqueByField($array, $field = '', $unique = false) { - $return = array(); - - if (is_array($array)) { + $return = []; + + if (is_array($array)) { foreach ($array as $k => $v) { if (isset($v[$field])) { $return[] = $v[$field]; @@ -126,9 +126,9 @@ public static function uniqueByField($array, $field = '', $unique = false) public static function changeKeysCase($array, $case = CASE_LOWER) { $function = ($case == CASE_UPPER) ? 'strtoupper' : 'strtolower'; - $newArray = array(); - - foreach ($array as $key => $value) { + $newArray = []; + + foreach ($array as $key => $value) { if (is_array($value)) { // $value is an array, handle keys too $newArray[$function($key)] = self::changeKeysCase($value, $case); diff --git a/framework/helpers/CHtml.php b/framework/helpers/CHtml.php index d7216ef..22c81d4 100644 --- a/framework/helpers/CHtml.php +++ b/framework/helpers/CHtml.php @@ -57,14 +57,14 @@ class CHtml { - + /** @const string */ const ID_PREFIX = 'ap'; /** @var string */ public static $afterRequiredLabel = ' <span class="required">*</span>'; /** @var string */ private static $_count = 0; - + /** * Generates an HTML tag * @param string $tag @@ -73,27 +73,27 @@ class CHtml * @param boolean $closeTag * @return string - HTML tag */ - public static function tag($tag, $htmlOptions = array(), $content = false, $closeTag = true) - { - $html = '<' . $tag . self::_renderAttributes($htmlOptions); + public static function tag($tag, $htmlOptions = [], $content = false, $closeTag = true) + { + $html = '<' . $tag . self::_renderAttributes($htmlOptions); if ($content === false) { return $closeTag ? $html . ' />' : $html . '>'; } else { return $closeTag ? $html . '>' . $content . '</' . $tag . '>' : $html . '>' . $content; } } - + /** * Generates an open HTML tag * @param string $tag * @param array $htmlOptions * @return string - HTML tag */ - public static function openTag($tag, $htmlOptions = array()) - { - return '<' . $tag . self::_renderAttributes($htmlOptions) . '>'; + public static function openTag($tag, $htmlOptions = []) + { + return '<' . $tag . self::_renderAttributes($htmlOptions) . '>'; } - + /** * Generates a close HTML tag * @param string $tag @@ -103,7 +103,7 @@ public static function closeTag($tag) { return '</' . $tag . '>'; } - + /** * Generates a hyperlink tag * @param string $text @@ -111,9 +111,9 @@ public static function closeTag($tag) * @param array $htmlOptions * @return string - HTML tag */ - public static function link($text, $url = '#', $htmlOptions = array()) - { - if ($url !== '') $htmlOptions['href'] = $url; + public static function link($text, $url = '#', $htmlOptions = []) + { + if ($url !== '') $htmlOptions['href'] = $url; if (isset($htmlOptions['escape']) && $htmlOptions['escape'] === true) { $text = self::escapeHexEntity($text); $htmlOptions['href'] = self::escapeHex($htmlOptions['href']); @@ -125,7 +125,7 @@ public static function link($text, $url = '#', $htmlOptions = array()) } return self::tag('a', $htmlOptions, $text); } - + /** * Generates a label tag * @param string $label @@ -133,16 +133,16 @@ public static function link($text, $url = '#', $htmlOptions = array()) * @param array $htmlOptions * @return string - HTML tag */ - public static function label($label, $for = false, $htmlOptions = array()) - { - if ($for === false) { + public static function label($label, $for = false, $htmlOptions = []) + { + if ($for === false) { if (isset($htmlOptions['for'])) unset($htmlOptions['for']); } else { $htmlOptions['for'] = $for; } return self::tag('label', $htmlOptions, $label); } - + /** * Encodes special characters into HTML entities * @param string $text @@ -158,7 +158,7 @@ public static function encode($text, $flag = ENT_QUOTES) return htmlspecialchars($text, $flag, A::app()->charset); } } - + /** * Decodes special HTML entities back to the corresponding characters * @param string $text @@ -169,7 +169,7 @@ public static function decode($text, $flag = ENT_QUOTES) { return htmlspecialchars_decode($text, $flag); } - + /** * Encloses the passed CSS content with a CSS tag * @param string $text @@ -183,7 +183,7 @@ public static function css($text, $media = '', $newLine = true) $newLine = (($newLine) ? "\n" : ''); return "<style type=\"text/css\"{$media}>" . $newLine . "/*<![CDATA[*/\n{$text}\n/*]]>*/" . $newLine . "</style>"; } - + /** * Links to required CSS file * @param string $url @@ -196,22 +196,22 @@ public static function cssFile($url, $media = '', $newLine = true) if ($media !== '') $media = ' media="' . $media . '"'; return '<link rel="stylesheet" type="text/css" href="' . self::encode($url) . '"' . $media . ' />' . (($newLine) ? "\n" : ''); } - + /** * Links to required CSS files - * @param array $urls Usage: array('url1', 'url2' => array('media'=>'print')) + * @param array $urls Usage: ['url1', 'url2' => ['media'=>'print']] * @param string $path * @param bool $newLine * @return string - HTML tag */ - public static function cssFiles($urls = array(), $path = '', $newLine = true) - { - $output = ''; - + public static function cssFiles($urls = [], $path = '', $newLine = true) + { + $output = ''; + if (!is_array($urls)) { return $output; } - + foreach ($urls as $key => $val) { if (empty($val)) continue; $path = !empty($path) ? trim($path, '/') . '/' : ''; @@ -219,10 +219,10 @@ public static function cssFiles($urls = array(), $path = '', $newLine = true) $media = (is_array($val) && !empty($val['media'])) ? ' media="' . $val['media'] . '"' : ''; $output .= '<link rel="stylesheet" type="text/css" href="' . $path . self::encode($href) . '"' . $media . ' />' . (($newLine) ? "\n" : ''); } - + return $output; } - + /** * Encloses the passed JavaScript within a Script tag * @param string $text @@ -232,7 +232,7 @@ public static function script($text) { return "<script type=\"text/javascript\">\n/*<![CDATA[*/\n{$text}\n/*]]>*/\n</script>"; } - + /** * Includes a JavaScript file * @param string $url @@ -241,9 +241,9 @@ public static function script($text) * @param array $htmlOptions * @return string - HTML tag */ - public static function scriptFile($url, $newLine = true, $preventDouble = false, $htmlOptions = array()) - { - $include = false; + public static function scriptFile($url, $newLine = true, $preventDouble = false, $htmlOptions = []) + { + $include = false; if ($preventDouble) { $hash_name = md5($url); if (!defined($hash_name)) { @@ -253,7 +253,7 @@ public static function scriptFile($url, $newLine = true, $preventDouble = false, } else { $include = true; } - + if ($include) { return '<script type="text/javascript" src="' . self::encode($url) . '"' . @@ -261,35 +261,35 @@ public static function scriptFile($url, $newLine = true, $preventDouble = false, '></script>' . (($newLine) ? "\n" : ''); } } - + /** * Links to required JavaScript files - * @param array $urls Usage: array('url1', 'url2' => array('integrity'=>'...', 'crossorigin'=>'...')) + * @param array $urls Usage: ['url1', 'url2' => array['integrity'=>'...', 'crossorigin'=>'...']] * @param string $path * @param bool $newLine * @return string - HTML tag */ - public static function scriptFiles($urls = array(), $path = '', $newLine = true) - { - $output = ''; - + public static function scriptFiles($urls = [], $path = '', $newLine = true) + { + $output = ''; + if (!is_array($urls)) { return $output; } - + foreach ($urls as $key => $val) { $path = !empty($path) ? trim($path, '/') . '/' : ''; $href = is_array($val) ? $key : $val; - $htmlOptions = is_array($val) ? $val : array(); - $output .= '<script type="text/javascript" src="' . + $htmlOptions = is_array($val) ? $val : []; + $output .= '<script type="text/javascript" src="' . $path . self::encode($href) . '"' . self::_renderAttributes($htmlOptions) . '></script>' . (($newLine) ? "\n" : ''); } - + return $output; } - + /** * Generates an open form tag * This is a shortcut to {@link openForm} @@ -298,11 +298,11 @@ public static function scriptFiles($urls = array(), $path = '', $newLine = true) * @param array $htmlOptions * @return string */ - public static function form($action = '', $method = 'post', $htmlOptions = array()) - { - return self::openForm($action, $method, $htmlOptions); + public static function form($action = '', $method = 'post', $htmlOptions = []) + { + return self::openForm($action, $method, $htmlOptions); } - + /** * Generates an opening form tag * Only the open tag is generated, a close tag should be placed manually at the end of the form @@ -312,31 +312,31 @@ public static function form($action = '', $method = 'post', $htmlOptions = array * @return string * @see endForm */ - public static function openForm($action = '', $method = 'post', $htmlOptions = array()) - { - $htmlOptions['action'] = $url = $action; + public static function openForm($action = '', $method = 'post', $htmlOptions = []) + { + $htmlOptions['action'] = $url = $action; $htmlOptions['method'] = $method; $form = self::tag('form', $htmlOptions, false, false); - $hiddens = array(); - if (!strcasecmp($method, 'get') && ($pos = strpos($url, '?')) !== false) { + $hiddens = []; + if (!strcasecmp($method, 'get') && ($pos = strpos($url, '?')) !== false) { foreach (explode('&', substr($url, $pos + 1)) as $pair) { if (($pos = strpos($pair, '=')) !== false) { - $hiddens[] = self::hiddenField(urldecode(substr($pair, 0, $pos)), urldecode(substr($pair, $pos + 1)), array('id' => false)); - } + $hiddens[] = self::hiddenField(urldecode(substr($pair, 0, $pos)), urldecode(substr($pair, $pos + 1)), ['id' => false]); + } } } - + $request = A::app()->getRequest(); if ($request->getCsrfValidation() && !strcasecmp($method, 'post')) { - $hiddens[] = self::hiddenField($request->getCsrfTokenKey(), $request->getCsrfTokenValue(), array('id' => false)); - } - if ($hiddens !== array()) { - $form .= "\n" . implode("\n", $hiddens) . "\n"; - } - - return $form; + $hiddens[] = self::hiddenField($request->getCsrfTokenKey(), $request->getCsrfTokenValue(), ['id' => false]); + } + if ($hiddens !== []) { + $form .= "\n".implode("\n", $hiddens)."\n"; + } + + return $form; } - + /** * Generates a closing form tag * @return string @@ -346,7 +346,7 @@ public static function closeForm() { return '</form>'; } - + /** * Generates a hidden input * @param string $name @@ -355,11 +355,11 @@ public static function closeForm() * @return string * @see inputField */ - public static function hiddenField($name, $value = '', $htmlOptions = array()) - { - return self::_inputField('hidden', $name, $value, $htmlOptions) . "\n"; + public static function hiddenField($name, $value = '', $htmlOptions = []) + { + return self::_inputField('hidden', $name, $value, $htmlOptions) . "\n"; } - + /** * Generates a textbox input * @param string $name @@ -368,11 +368,11 @@ public static function hiddenField($name, $value = '', $htmlOptions = array()) * @return string * @see inputField */ - public static function textField($name, $value = '', $htmlOptions = array()) - { - return self::_inputField('text', $name, $value, $htmlOptions); + public static function textField($name, $value = '', $htmlOptions = []) + { + return self::_inputField('text', $name, $value, $htmlOptions); } - + /** * Generates a password field * @param string $name @@ -381,11 +381,11 @@ public static function textField($name, $value = '', $htmlOptions = array()) * @return string * @see inputField */ - public static function passwordField($name, $value = '', $htmlOptions = array()) - { - return self::_inputField('password', $name, $value, $htmlOptions); + public static function passwordField($name, $value = '', $htmlOptions = []) + { + return self::_inputField('password', $name, $value, $htmlOptions); } - + /** * Generates a file field * @param string $name @@ -394,11 +394,11 @@ public static function passwordField($name, $value = '', $htmlOptions = array()) * @return string * @see inputField */ - public static function fileField($name, $value = '', $htmlOptions = array()) - { - return self::_inputField('file', $name, $value, $htmlOptions); + public static function fileField($name, $value = '', $htmlOptions = []) + { + return self::_inputField('file', $name, $value, $htmlOptions); } - + /** * Generates a color input * @param string $name @@ -407,11 +407,11 @@ public static function fileField($name, $value = '', $htmlOptions = array()) * @return string * @see inputField */ - public static function colorField($name, $value = '', $htmlOptions = array()) - { - return self::_inputField('color', $name, $value, $htmlOptions); + public static function colorField($name, $value = '', $htmlOptions = []) + { + return self::_inputField('color', $name, $value, $htmlOptions); } - + /** * Generates a email input * @param string $name @@ -420,11 +420,11 @@ public static function colorField($name, $value = '', $htmlOptions = array()) * @return string * @see inputField */ - public static function emailField($name, $value = '', $htmlOptions = array()) - { - return self::_inputField('email', $name, $value, $htmlOptions); + public static function emailField($name, $value = '', $htmlOptions = []) + { + return self::_inputField('email', $name, $value, $htmlOptions); } - + /** * Generates a search input * @param string $name @@ -433,11 +433,11 @@ public static function emailField($name, $value = '', $htmlOptions = array()) * @return string * @see inputField */ - public static function searchField($name, $value = '', $htmlOptions = array()) - { - return self::_inputField('search', $name, $value, $htmlOptions); + public static function searchField($name, $value = '', $htmlOptions = []) + { + return self::_inputField('search', $name, $value, $htmlOptions); } - + /** * Generates a valid HTML ID based on name * @param string $name @@ -445,10 +445,10 @@ public static function searchField($name, $value = '', $htmlOptions = array()) */ public static function getIdByName($name) { - return str_replace(array('#', '[]', '][', '[', ']'), array('-', '', '_', '_', ''), $name); - } - - /** + return str_replace(['#', '[]', '][', '[', ']'], ['-', '', '_', '_', ''], $name); + } + + /** * Generates an input HTML tag * This method generates an input HTML tag based on the given name of input tag and value * @param string $type @@ -466,7 +466,7 @@ protected static function _inputField($type, $name, $value, $htmlOptions) elseif ($htmlOptions['id'] === false) unset($htmlOptions['id']); return self::tag('input', $htmlOptions, false); } - + /** * Draws textarea * @param string $name @@ -474,14 +474,14 @@ protected static function _inputField($type, $name, $value, $htmlOptions) * @param array $htmlOptions * @return string */ - public static function textArea($name, $value = '', $htmlOptions = array()) - { - $htmlOptions['name'] = $name; + public static function textArea($name, $value = '', $htmlOptions = []) + { + $htmlOptions['name'] = $name; if (!isset($htmlOptions['id'])) $htmlOptions['id'] = self::getIdByName($name); elseif ($htmlOptions['id'] === false) unset($htmlOptions['id']); return self::tag('textarea', $htmlOptions, isset($htmlOptions['encode']) && !$htmlOptions['encode'] ? $value : self::encode($value)); } - + /** * Generates a check box * @param string $name @@ -489,40 +489,40 @@ public static function textArea($name, $value = '', $htmlOptions = array()) * @param array $htmlOptions * @see inputField */ - public static function checkBox($name, $checked = false, $htmlOptions = array()) - { - if ($checked) { + public static function checkBox($name, $checked = false, $htmlOptions = []) + { + if ($checked) { $htmlOptions['checked'] = 'checked'; } elseif (isset($htmlOptions['checked'])) { unset($htmlOptions['checked']); } - + $value = (isset($htmlOptions['value']) && $htmlOptions['value'] !== '') ? $htmlOptions['value'] : 1; /// TODO self::_clientChange('click', $htmlOptions); - + if (array_key_exists('uncheckValue', $htmlOptions)) { $uncheck = $htmlOptions['uncheckValue']; unset($htmlOptions['uncheckValue']); } else { $uncheck = null; } - + if ($uncheck !== null) { // Add a hidden field so that if the checkbox is not selected, it still submits a value if (isset($htmlOptions['id']) && $htmlOptions['id'] !== false) { - $uncheckOptions = array('id' => self::ID_PREFIX . $htmlOptions['id']); - } else { - $uncheckOptions = array('id' => false); - } + $uncheckOptions = ['id' => self::ID_PREFIX.$htmlOptions['id']]; + } else { + $uncheckOptions = ['id' => false]; + } $hidden = self::hiddenField($name, $uncheck, $uncheckOptions); } else { $hidden = ''; } - + // Add a hidden field so that if the checkbox is not selected, it still submits a value return $hidden . self::_inputField('checkbox', $name, $value, $htmlOptions); } - + /** * Generates a check box list * @param string $name @@ -531,42 +531,42 @@ public static function checkBox($name, $checked = false, $htmlOptions = array()) * @param array $htmlOptions * @see tag */ - public static function checkBoxList($name, $select, $data, $htmlOptions = array()) - { - $listWrapperTag = isset($htmlOptions['listWrapperTag']) ? $htmlOptions['listWrapperTag'] : 'span'; + public static function checkBoxList($name, $select, $data, $htmlOptions = []) + { + $listWrapperTag = isset($htmlOptions['listWrapperTag']) ? $htmlOptions['listWrapperTag'] : 'span'; $listWrapperClass = isset($htmlOptions['listWrapperClass']) ? $htmlOptions['listWrapperClass'] : ''; $template = isset($htmlOptions['template']) ? $htmlOptions['template'] : '{input} {label}'; $separator = isset($htmlOptions['separator']) ? $htmlOptions['separator'] : "<br/>\n"; $multiple = isset($htmlOptions['multiple']) ? (bool)$htmlOptions['multiple'] : true; - + unset($htmlOptions['template'], $htmlOptions['separator'], $htmlOptions['listWrapperTag'], $htmlOptions['listWrapperClass'], $htmlOptions['multiple']); - + if ($multiple && substr($name, -2) !== '[]') { $name .= '[]'; } - + // Get Check All option if (isset($htmlOptions['checkAll'])) { $checkAllLabel = $htmlOptions['checkAll']; $checkAllLast = isset($htmlOptions['checkAllLast']) && $htmlOptions['checkAllLast']; } unset($htmlOptions['checkAll'], $htmlOptions['checkAllLast']); - - $labelOptions = array(); - if (isset($htmlOptions['labelOptions'])) { + + $labelOptions = []; + if (isset($htmlOptions['labelOptions'])) { $labelOptions = $htmlOptions['labelOptions']; unset($htmlOptions['labelOptions']); } - - $items = array(); - $baseID = self::getIdByName($name); + + $items = []; + $baseID = self::getIdByName($name); $id = 0; $checkAll = true; - + foreach ($data as $value => $label) { $checked = !is_array($select) && !strcmp($value, $select) || is_array($select) && in_array($value, $select); $checkAll = $checkAll && $checked; @@ -574,46 +574,46 @@ public static function checkBoxList($name, $select, $data, $htmlOptions = array( $htmlOptions['id'] = $baseID . '_' . $id++; $option = self::checkBox($name, $checked, $htmlOptions); $label = self::label($label, $htmlOptions['id'], $labelOptions); - $items[] = strtr($template, array('{input}' => $option, '{label}' => $label)); - } - - if (isset($checkAllLabel)) { + $items[] = strtr($template, ['{input}' => $option, '{label}' => $label]); + } + + if (isset($checkAllLabel)) { $htmlOptions['value'] = 1; $htmlOptions['id'] = $id = $baseID . '_all'; $option = self::checkBox($id, $checkAll, $htmlOptions); $label = self::label($checkAllLabel, $id, $labelOptions); - $item = strtr($template, array('{input}' => $option, '{label}' => $label)); - if ($checkAllLast) { + $item = strtr($template, ['{input}' => $option, '{label}' => $label]); + if ($checkAllLast) { $items[] = $item; } else { array_unshift($items, $item); } - $name = strtr($name, array('[' => '\\[', ']' => '\\]')); - $js = '$(\'#' . $id . '\').click(function() {$("input[name=\'' . $name . '\']").prop(\'checked\', this.checked);});'; + $name = strtr($name, ['[' => '\\[', ']' => '\\]']); + $js = '$(\'#' . $id . '\').click(function() {$("input[name=\'' . $name . '\']").prop(\'checked\', this.checked);});'; $js .= '$("input[name=\'' . $name . '\']").click(function() {$(\'#' . $id . '\').prop(\'checked\', !$("input[name=\'' . $name . '\']:not(:checked)").length);});'; $js .= '$(\'#' . $id . '\').prop(\'checked\', !$("input[name=\'' . $name . '\']:not(:checked)").length);'; - + $clientScript = A::app()->getClientScript(); $clientScript->registerScript('Apphp.CHtml.#' . $id, $js); } - - return self::tag($listWrapperTag, array('id' => $baseID, 'class' => $listWrapperClass), implode($separator, $items)); - } - - /** + + return self::tag($listWrapperTag, ['id' => $baseID, 'class' => $listWrapperClass], implode($separator, $items)); + } + + /** * Generates a radio button * @param string $name * @param boolean $checked * @param array $htmlOptions * @see inputField */ - public static function radioButton($name, $checked = false, $htmlOptions = array()) - { - if ($checked) $htmlOptions['checked'] = 'checked'; + public static function radioButton($name, $checked = false, $htmlOptions = []) + { + if ($checked) $htmlOptions['checked'] = 'checked'; elseif (isset($htmlOptions['checked'])) unset($htmlOptions['checked']); - + $value = isset($htmlOptions['value']) ? $htmlOptions['value'] : 1; - + /// TODO self::_clientChange('click', $htmlOptions); if (array_key_exists('uncheckValue', $htmlOptions)) { $uncheck = $htmlOptions['uncheckValue']; @@ -621,21 +621,21 @@ public static function radioButton($name, $checked = false, $htmlOptions = array } else { $uncheck = null; } - + if ($uncheck !== null) { // Add a hidden field (if radio button is not selected, it still will submit a value) if (isset($htmlOptions['id']) && $htmlOptions['id'] !== false) { - $uncheckOptions = array('id' => self::ID_PREFIX . $htmlOptions['id']); - } else { - $uncheckOptions = array('id' => false); - } - $hidden = self::hiddenField($name, $uncheck, $uncheckOptions); + $uncheckOptions = ['id' => self::ID_PREFIX.$htmlOptions['id']]; + } else { + $uncheckOptions = ['id' => false]; + } + $hidden = self::hiddenField($name, $uncheck, $uncheckOptions); } else { $hidden = ''; } return $hidden . self::_inputField('radio', $name, $value, $htmlOptions); } - + /** * Generates radio buttons list * @param string $name @@ -644,18 +644,18 @@ public static function radioButton($name, $checked = false, $htmlOptions = array * @param array $htmlOptions * @see tag */ - public static function radioButtonList($name, $select, $data, $htmlOptions = array()) - { - $template = isset($htmlOptions['template']) ? $htmlOptions['template'] : '{input} {label}'; + public static function radioButtonList($name, $select, $data, $htmlOptions = []) + { + $template = isset($htmlOptions['template']) ? $htmlOptions['template'] : '{input} {label}'; $separator = isset($htmlOptions['separator']) ? $htmlOptions['separator'] : "\n"; unset($htmlOptions['template'], $htmlOptions['separator']); - $labelOptions = array(); - if (isset($htmlOptions['labelOptions'])) { + $labelOptions = []; + if (isset($htmlOptions['labelOptions'])) { $labelOptions = $htmlOptions['labelOptions']; unset($htmlOptions['labelOptions']); } - $items = array(); - $baseID = self::getIdByName($name); + $items = []; + $baseID = self::getIdByName($name); $id = 0; foreach ($data as $value => $label) { $checked = !strcmp($value, $select); @@ -663,12 +663,13 @@ public static function radioButtonList($name, $select, $data, $htmlOptions = arr $htmlOptions['id'] = $baseID . '_' . $id++; $option = self::radioButton($name, $checked, $htmlOptions); $label = self::label($label, $htmlOptions['id'], $labelOptions); - $items[] = strtr($template, array('{input}' => $option, '{label}' => $label)); - } - return self::tag('span', array('id' => $baseID), implode($separator, $items)); - } - - /** + $items[] = strtr($template, ['{input}' => $option, '{label}' => $label]); + } + + return self::tag('span', ['id' => $baseID], implode($separator, $items)); + } + + /** * Draws dropdown list * @param string $name * @param mixed $select @@ -677,18 +678,18 @@ public static function radioButtonList($name, $select, $data, $htmlOptions = arr * @param array $specialOptions * @return string */ - public static function dropDownList($name, $select = '', $data = array(), $htmlOptions = array(), $specialOptions = array()) - { - $multiple = isset($htmlOptions['multiple']) ? (bool)$htmlOptions['multiple'] : false; + public static function dropDownList($name, $select = '', $data = [], $htmlOptions = [], $specialOptions = []) + { + $multiple = isset($htmlOptions['multiple']) ? (bool)$htmlOptions['multiple'] : false; if ($multiple && substr($name, -2) !== '[]') { $name .= '[]'; } - + $htmlOptions['name'] = $name; if (!isset($htmlOptions['id'])) $htmlOptions['id'] = self::getIdByName($name); elseif ($htmlOptions['id'] === false) unset($htmlOptions['id']); self::_clientChange('change', $htmlOptions); - + $specialType = isset($specialOptions['type']) ? $specialOptions['type'] : ''; $specialStep = isset($specialOptions['step']) ? (int)$specialOptions['step'] : 1; if ($specialType == 'hours') { @@ -707,7 +708,7 @@ public static function dropDownList($name, $select = '', $data = array(), $htmlO $options = "\n" . self::listOptions($select, $data, $htmlOptions); return self::tag('select', $htmlOptions, $options); } - + /** * Draws dropdown list * @param string $name @@ -716,15 +717,15 @@ public static function dropDownList($name, $select = '', $data = array(), $htmlO * @param array $htmlOptions * @return string */ - public static function listBox($name, $select = '', $data = array(), $htmlOptions = array()) - { - if (!isset($htmlOptions['size'])) $htmlOptions['size'] = 4; + public static function listBox($name, $select = '', $data = [], $htmlOptions = []) + { + if (!isset($htmlOptions['size'])) $htmlOptions['size'] = 4; if (isset($htmlOptions['multiple'])) { if (substr($name, -2) !== '[]') $name .= '[]'; } return self::dropDownList($name, $select, $data, $htmlOptions); } - + /** * Generates the list of options * @param mixed $selection @@ -733,31 +734,33 @@ public static function listBox($name, $select = '', $data = array(), $htmlOption * @return string * * Usage: - * $array=>('0'=>'Option A', '1'=>'Option B', '2'=>'Option C'); - * $array=>('0'=>'Option A', '1'=>'Option B', '2'=>array('optionValue'=>'Option C', 'optionDisabled'=>true)); + * $array=>['0'=>'Option A', '1'=>'Option B', '2'=>'Option C']; + * $array=>['0'=>'Option A', '1'=>'Option B', '2'=>['optionValue'=>'Option C', 'optionDisabled'=>true]]; */ public static function listOptions($selection, $listData, &$htmlOptions) { $raw = isset($htmlOptions['encode']) && !$htmlOptions['encode']; $content = ''; if (isset($htmlOptions['prompt'])) { - $content .= '<option value="">' . strtr($htmlOptions['prompt'], array('<' => '<', '>' => '>')) . "</option>\n"; - unset($htmlOptions['prompt']); - } - if (isset($htmlOptions['empty'])) { - if (!is_array($htmlOptions['empty'])) $htmlOptions['empty'] = array('' => $htmlOptions['empty']); - foreach ($htmlOptions['empty'] as $value => $label) { - $content .= '<option value="' . self::encode($value) . '">' . strtr($label, array('<' => '<', '>' => '>')) . "</option>\n"; - } + $content .= '<option value="">'.strtr($htmlOptions['prompt'], ['<' => '<', '>' => '>'])."</option>\n"; + unset($htmlOptions['prompt']); + } + if (isset($htmlOptions['empty'])) { + if ( ! is_array($htmlOptions['empty'])) { + $htmlOptions['empty'] = ['' => $htmlOptions['empty']]; + } + foreach ($htmlOptions['empty'] as $value => $label) { + $content .= '<option value="'.self::encode($value).'">'.strtr($label, ['<' => '<', '>' => '>'])."</option>\n"; + } unset($htmlOptions['empty']); } if (isset($htmlOptions['options'])) { $options = $htmlOptions['options']; unset($htmlOptions['options']); } else { - $options = array(); - } - $key = isset($htmlOptions['key']) ? $htmlOptions['key'] : 'primaryKey'; + $options = []; + } + $key = isset($htmlOptions['key']) ? $htmlOptions['key'] : 'primaryKey'; if (is_array($selection)) { foreach ($selection as $i => $item) { if (is_object($item)) $selection[$i] = $item->$key; @@ -770,8 +773,8 @@ public static function listOptions($selection, $listData, &$htmlOptions) if (is_array($value)) { if (isset($value['optionValue'])) { // For single-level arrays where additional options available - $attributes = array('value' => (string)$key, 'encode' => !$raw); - if (!empty($value['optionDisabled'])) $attributes['disabled'] = true; + $attributes = ['value' => (string)$key, 'encode' => ! $raw]; + if (!empty($value['optionDisabled'])) $attributes['disabled'] = true; if (!is_array($selection) && !strcmp($key, $selection) || is_array($selection) && in_array($key, $selection)) { $attributes['selected'] = 'selected'; } @@ -780,14 +783,14 @@ public static function listOptions($selection, $listData, &$htmlOptions) } else { // For multi-level arrays $content .= '<optgroup label="' . ($raw ? $key : self::encode($key)) . "\">\n"; - $dummy = array('options' => $options); - if (isset($htmlOptions['encode'])) $dummy['encode'] = $htmlOptions['encode']; + $dummy = ['options' => $options]; + if (isset($htmlOptions['encode'])) $dummy['encode'] = $htmlOptions['encode']; $content .= self::listOptions($selection, $value, $dummy); $content .= '</optgroup>' . "\n"; } } else { - $attributes = array('value' => (string)$key, 'encode' => !$raw); - if (!is_array($selection) && !strcmp($key, $selection) || is_array($selection) && in_array($key, $selection)) { + $attributes = ['value' => (string)$key, 'encode' => ! $raw]; + if (!is_array($selection) && !strcmp($key, $selection) || is_array($selection) && in_array($key, $selection)) { $attributes['selected'] = 'selected'; } if (isset($options[$key])) $attributes = array_merge($attributes, $options[$key]); @@ -797,50 +800,50 @@ public static function listOptions($selection, $listData, &$htmlOptions) if (isset($htmlOptions['key'])) unset($htmlOptions['key']); return $content; } - + /** * Draws submit button * @param string $label * @param array $htmlOptions * @return string */ - public static function submitButton($label = 'submit', $htmlOptions = array()) - { - $htmlOptions['type'] = 'submit'; + public static function submitButton($label = 'submit', $htmlOptions = []) + { + $htmlOptions['type'] = 'submit'; return self::button($label, $htmlOptions); } - + /** * Generates reset button * @param string $label * @param array $htmlOptions * @return string */ - public static function resetButton($label = 'reset', $htmlOptions = array()) - { - $htmlOptions['type'] = 'reset'; + public static function resetButton($label = 'reset', $htmlOptions = []) + { + $htmlOptions['type'] = 'reset'; return self::button($label, $htmlOptions); } - + /** * Draws button * @param string $label * @param array $htmlOptions * @return string */ - public static function button($label = 'button', $htmlOptions = array()) - { - if (!isset($htmlOptions['name'])) { + public static function button($label = 'button', $htmlOptions = []) + { + if (!isset($htmlOptions['name'])) { if (!array_key_exists('name', $htmlOptions)) $htmlOptions['name'] = self::ID_PREFIX . self::$_count++; } - + if (!isset($htmlOptions['type'])) $htmlOptions['type'] = 'button'; $buttonTag = 'input'; if (isset($htmlOptions['buttonTag'])) { $buttonTag = $htmlOptions['buttonTag']; unset($htmlOptions['buttonTag']); } - + if ($buttonTag == 'button') { if (isset($htmlOptions['value'])) { $buttonValue = $htmlOptions['value']; @@ -855,7 +858,7 @@ public static function button($label = 'button', $htmlOptions = array()) return self::tag('input', $htmlOptions); } } - + /** * Generates an image tag * @param string $src @@ -863,33 +866,33 @@ public static function button($label = 'button', $htmlOptions = array()) * @param array $htmlOptions * @return string */ - public static function image($src, $alt = '', $htmlOptions = array()) - { - $htmlOptions['src'] = $src; + public static function image($src, $alt = '', $htmlOptions = []) + { + $htmlOptions['src'] = $src; $htmlOptions['alt'] = $alt; return self::tag('img', $htmlOptions); } - + /** * Generates an video tag * @param string $src * @param array $options - * Ex.: array('width'=>'560', 'height'=>'350', 'autoplay'=>true, 'allowfullscreen'=>true, 'controls'=>true) + * Ex.: ['width'=>'560', 'height'=>'350', 'autoplay'=>true, 'allowfullscreen'=>true, 'controls'=>true] * @return string */ - public static function video($src, $options = array()) - { - $videoHtml = ''; - + public static function video($src, $options = []) + { + $videoHtml = ''; + $srcParts = explode('/', $src); $videoId = array_pop($srcParts); - + $htmlOptions = array(); $width = !empty($options['width']) ? $options['width'] : '560'; $htmlOptions['width'] = $width; $height = !empty($options['height']) ? $options['height'] : '315'; $htmlOptions['height'] = $height; - + if (preg_match('/(youtube\.|youtu\.)/i', $src)) { $autoplayParam = !empty($options['autoplay']) ? '?autoplay=1' : ''; $htmlOptions['frameborder'] = '0'; @@ -911,34 +914,34 @@ public static function video($src, $options = array()) $videoHtml .= self::tag('source', array('src' => $src, 'type' => 'video/mp4')); $videoHtml .= self::closeTag('video'); } - + if (!empty($htmlOptions)) { $videoHtml = self::openTag('iframe', $htmlOptions, false, false) . self::closeTag('iframe'); } - + return $videoHtml; } - + /** * Generates an audio tag * @param string $src * @param array $options - * Ex.: array('autoplay'=>true, 'controls'=>true) + * Ex.: ['autoplay'=>true, 'controls'=>true] * @return string */ - public static function audio($src, $options = array()) - { - $htmlOptions = array(); - $htmlOptions['autoplay'] = !empty($options['autoplay']) ? ' autoplay' : null; - $htmlOptions['controls'] = !empty($options['controls']) ? ' controls' : null; - - $audioHtml = self::openTag('audio', $htmlOptions); - $audioHtml .= self::tag('source', array('src' => $src, 'type' => 'audio/mpeg')); - $audioHtml .= self::closeTag('audio'); - - return $audioHtml; + public static function audio($src, $options = []) + { + $htmlOptions = []; + $htmlOptions['autoplay'] = ! empty($options['autoplay']) ? ' autoplay' : null; + $htmlOptions['controls'] = ! empty($options['controls']) ? ' controls' : null; + + $audioHtml = self::openTag('audio', $htmlOptions); + $audioHtml .= self::tag('source', ['src' => $src, 'type' => 'audio/mpeg']); + $audioHtml .= self::closeTag('audio'); + + return $audioHtml; } - + /** * Returns a file size in bytes from the given string * @param mixed $fileSize @@ -957,7 +960,7 @@ public static function convertFileSize($fileSize) } return $return; } - + /** * Returns an image width or height in pixels from the given string * @param mixed $fileDimension @@ -972,7 +975,7 @@ public static function convertImageDimensions($fileDimension) } return $return; } - + /** * Renders escaped hex string * Ex. for link: '<a href="'.CHtml::escapeHex($string).'">...</a>' @@ -986,7 +989,7 @@ public static function escapeHex($string) } return $return; } - + /** * Renders escaped hex entity string * Ex. for text: '<a href="...">'.CHtml::escapeHexEntity($string).'</a>' @@ -1000,7 +1003,7 @@ public static function escapeHexEntity($string) } return $return; } - + /** * Generates JavaScript code with specified client changes * @param string $event @@ -1011,37 +1014,37 @@ protected static function _clientChange($event, &$htmlOptions) if (!isset($htmlOptions['submit'])) { return; } - + $clientScript = A::app()->getClientScript(); $request = A::app()->getRequest(); $handler = ''; - + if (isset($htmlOptions['id'])) { $id = $htmlOptions['id']; } else { $id = $htmlOptions['id'] = isset($htmlOptions['name']) ? $htmlOptions['name'] : self::ID_PREFIX . self::$_count++; } - + $csrf = isset($htmlOptions['csrf']) ? (bool)$htmlOptions['csrf'] : false; - - // Add csrf token key if needed + + // Add csrf token key if needed if ($request->getCsrfValidation() && $csrf) { $handler .= '$(this).closest("form").append(\'<input type="hidden" name="' . $request->getCsrfTokenKey() . '" value="' . $request->getCsrfTokenValue() . '">\');'; } - + if (!empty($htmlOptions['submit']) && !is_bool($htmlOptions['submit'])) { $handler .= $htmlOptions['submit']; } - + /// Check? document.forms["'.$formName.'"].submit();'; $handler .= '$(this).closest("form").submit();'; - + $clientScript->registerScript('Apphp.CHtml.#' . $id, "$('body').on('$event','#$id',function(){{$handler}});"); /// Check? $clientScript->registerScript('Apphp.CHtml.#'.$id, "$('#$id').on('$event', function(){{$handler}});"); - + unset($htmlOptions['submit']); } - + /** * Renders the HTML tag attributes * @param string $htmlOptions @@ -1049,7 +1052,7 @@ protected static function _clientChange($event, &$htmlOptions) private static function _renderAttributes($htmlOptions) { // Attributes that looks like attribute = "attribute" - static $specialAttributes = array( + static $specialAttributes = [ 'checked' => 1, 'declare' => 1, 'defer' => 1, @@ -1061,24 +1064,26 @@ private static function _renderAttributes($htmlOptions) 'readonly' => 1, 'selected' => 1, 'autofocus' => 1, - ); - - if ($htmlOptions === array()) return ''; - - $output = ''; + ]; + + if ($htmlOptions === []) { + return ''; + } + + $output = ''; $encode = false; - + if (isset($htmlOptions['encode'])) { $encode = (bool)$htmlOptions['encode']; unset($htmlOptions['encode']); } - + if (isset($htmlOptions['id']) && $htmlOptions['id'] === false) unset($htmlOptions['id']); if (isset($htmlOptions['href']) && $htmlOptions['href'] === false) unset($htmlOptions['href']); if (isset($htmlOptions['class']) && $htmlOptions['class'] == '') unset($htmlOptions['class']); if (isset($htmlOptions['style']) && $htmlOptions['style'] == '') unset($htmlOptions['style']); if (isset($htmlOptions['showAlways'])) unset($htmlOptions['showAlways']); - + if (is_array($htmlOptions)) { foreach ($htmlOptions as $name => $value) { if (isset($specialAttributes[$name])) { @@ -1088,8 +1093,8 @@ private static function _renderAttributes($htmlOptions) } } } - + return $output; } - + } diff --git a/framework/helpers/COauth.php b/framework/helpers/COauth.php index 636ee92..6f6fe66 100644 --- a/framework/helpers/COauth.php +++ b/framework/helpers/COauth.php @@ -26,71 +26,72 @@ class COauth { /* @var */ - private static $config = array( - 'path' => '/', - 'callback_url' => '', - 'security_salt' => '', - 'security_iteration' => 300, - 'security_timeout' => '2 minutes', - - 'callback_transport' => 'session', - 'debug' => false, - 'Strategy' => array( - 'Facebook' => array( - 'app_id' => '', - 'app_secret' => '', - 'scope' => 'public_profile,email', - 'fields' => 'id,name,first_name,last_name,gender,email', - ), - 'Google' => array( - 'client_id' => '', - 'client_secret' => '', - 'scope' => 'email', - ), - 'Twitter' => array( - 'key' => '', - 'secret' => '', - 'scope' => 'include_email', - ), - 'LinkedIn' => array( - 'api_key' => '', - 'secret_key' => '', - 'scope' => 'r_basicprofile r_emailaddress', - ), - ), - ); - - /** - * Sets a basic configuration + private static $config + = [ + 'path' => '/', + 'callback_url' => '', + 'security_salt' => '', + 'security_iteration' => 300, + 'security_timeout' => '2 minutes', + + 'callback_transport' => 'session', + 'debug' => false, + 'Strategy' => [ + 'Facebook' => [ + 'app_id' => '', + 'app_secret' => '', + 'scope' => 'public_profile,email', + 'fields' => 'id,name,first_name,last_name,gender,email', + ], + 'Google' => [ + 'client_id' => '', + 'client_secret' => '', + 'scope' => 'email', + ], + 'Twitter' => [ + 'key' => '', + 'secret' => '', + 'scope' => 'include_email', + ], + 'LinkedIn' => [ + 'api_key' => '', + 'secret_key' => '', + 'scope' => 'r_basicprofile r_emailaddress', + ], + ], + ]; + + /** + * Sets a basic configuration * More information - https://github.com/opauth/opauth/wiki/Opauth-configuration * @param array $params - * Usage: - * COauth::config(array( - * 'path' => '/customer/login/type/', // If url address: http://my_site/customer/login/type/facebook - * 'callback_url' => 'http://my_site/customer/success_return', - * 'security_salt' => '{random_string}', - * 'security_iteration' => '300', - * 'security_timeout' => '2 minutes', - * 'callback_transport' => 'session', // It can take the following parameters: 'session', 'post' or 'get'; - * 'debug' => false, - * 'Strategy' => array( - * 'Facebook' => array( - * 'app_id' => '{application_id}', - * 'app_secret' => '{application_secret}', - * 'score' => 'public_profile,email', // More - https://developers.facebook.com/docs/facebook-login/permissions - * 'fields' => 'id,name,first_name,last_name,gender,email' // More (look fields) - https://developers.facebook.com/docs/graph-api/reference/v2.6/user - * ), - * 'Google' => array( - * 'client_id' => '{application_id}', - * 'client_secret' => '{application_secret}', - * 'score' => 'email', // More - https://developers.google.com/+/web/api/rest/oauth#authorization-scopes - * ), - * 'Twitter' => array( - * 'key' => '{application_id}', - * 'secret' => '{application_secret}' - * ) - * ), - * )) + * Usage: + * COauth::config([ + * 'path' => '/customer/login/type/', // If url address: http://my_site/customer/login/type/facebook + * 'callback_url' => 'http://my_site/customer/success_return', + * 'security_salt' => '{random_string}', + * 'security_iteration' => '300', + * 'security_timeout' => '2 minutes', + * 'callback_transport' => 'session', // It can take the following parameters: 'session', 'post' or 'get'; + * 'debug' => false, + * 'Strategy' => [ + * 'Facebook' => [ + * 'app_id' => '{application_id}', + * 'app_secret' => '{application_secret}', + * 'score' => 'public_profile,email', // More - https://developers.facebook.com/docs/facebook-login/permissions + * 'fields' => 'id,name,first_name,last_name,gender,email' // More (look fields) - https://developers.facebook.com/docs/graph-api/reference/v2.6/user + * ], + * 'Google' => [ + * 'client_id' => '{application_id}', + * 'client_secret' => '{application_secret}', + * 'score' => 'email', // More - https://developers.google.com/+/web/api/rest/oauth#authorization-scopes + * ], + * 'Twitter' => [ + * 'key' => '{application_id}', + * 'secret' => '{application_secret}' + * ] + * ], + * ]) * * @return void */ diff --git a/framework/helpers/CRss.php b/framework/helpers/CRss.php index cfce726..a2a4291 100644 --- a/framework/helpers/CRss.php +++ b/framework/helpers/CRss.php @@ -42,7 +42,7 @@ * #$rss_text = htmlentities($post_text, ENT_COMPAT, 'UTF-8'); * self::SetItem(APPHP_BASE.'index.php?page=news&nid='.$allNews[0][$i]['id'], $allNews[0][$i]['header_text'], $rss_text, $allNews[0][$i]['date_created']); * } - * News::UpdateFields(array('rss_last_ids'=>$rss_ids)); + * News::UpdateFields(['rss_last_ids'=>$rss_ids]); * } * * self::SaveFeed(); @@ -63,12 +63,12 @@ class CRss private static $_channelSubject = ''; private static $_rssType = 'rss1'; - private static $_rssTypes = array('rss1', 'rss2', 'atom'); - - private static $_imageUrl = ''; + private static $_rssTypes = ['rss1', 'rss2', 'atom']; + + private static $_imageUrl = ''; - private static $_arrItems = array(); - private static $_countItems = 0; + private static $_arrItems = []; + private static $_countItems = 0; private static $_filePath = 'feeds/'; private static $_fileName = 'rss.xml'; @@ -87,9 +87,9 @@ public static function setType($type = '') * Sets Channel * @param array $params */ - public static function setChannel($params = array()) - { - // $creator, $subject + public static function setChannel($params = []) + { + // $creator, $subject self::$_channelUrl = isset($params['url']) ? $params['url'] : ''; self::$_channelTitle = isset($params['title']) ? $params['title'] : ''; self::$_channelDescription = isset($params['description']) ? $params['description'] : ''; @@ -266,10 +266,14 @@ public static function saveFeed() @fclose($handle); $result = ''; } else { - $result = A::t('core', 'Cannot open RSS file to add a new item! Please check your access rights to {file} or try again later.', array('{file}' => self::$_filePath . self::$_fileName)); - } - - return $result; + $result = A::t( + 'core', + 'Cannot open RSS file to add a new item! Please check your access rights to {file} or try again later.', + ['{file}' => self::$_filePath.self::$_fileName] + ); + } + + return $result; } /** diff --git a/framework/helpers/CWidget.php b/framework/helpers/CWidget.php index 85bd873..86cfc78 100644 --- a/framework/helpers/CWidget.php +++ b/framework/helpers/CWidget.php @@ -22,20 +22,20 @@ class CWidget * @param string $className * @param array $params */ - public static function create($className, $params = array()) - { - include_once('widgets/CWidgs.php'); + public static function create($className, $params = []) + { + include_once('widgets/CWidgs.php'); include_once('widgets/' . $className . '.php'); if (!CClass::isExists($className)) { - CDebug::addMessage('warnings', 'missing-helper', A::t('core', 'Cannot find widget class: {class}', array('{class}' => $className))); - } else { + CDebug::addMessage('warnings', 'missing-helper', A::t('core', 'Cannot find widget class: {class}', ['{class}' => $className])); + } else { // Init if (strtolower($className) == 'cmessage') { $type = isset($params[0]) ? $params[0] : ''; $text = isset($params[1]) ? $params[1] : ''; - $init_params = isset($params[2]) ? $params[2] : array(); - $result = $className::init($type, $text, $init_params); + $init_params = isset($params[2]) ? $params[2] : []; + $result = $className::init($type, $text, $init_params); } else { $result = $className::init($params); } @@ -43,7 +43,7 @@ public static function create($className, $params = array()) // if(strtolower($className) == 'cmessage'){ // $result = call_user_func_array($className.'::init', $params); // }else{ - // // Params is assosiative array + // // Params is associative array // $result = call_user_func($className.'::init', $params); // } return $result; From 0e9762a95823ecb0ed5f7e8ba47c970a5c658118 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 21 Nov 2020 23:58:32 +0200 Subject: [PATCH 39/45] Added parent::__construct(); to each component class --- framework/components/CClientScript.php | 1 + framework/components/CComponent.php | 1 + framework/components/CDbHttpSession.php | 2 ++ framework/components/CHttpCookie.php | 2 ++ framework/components/CHttpRequest.php | 2 ++ framework/components/CHttpSession.php | 2 ++ framework/components/CLocalTime.php | 1 + framework/components/CLogger.php | 2 ++ framework/components/CMessageSource.php | 2 ++ framework/components/CMobileDetect.php | 1 + framework/components/CShoppingCart.php | 2 ++ framework/components/CUri.php | 2 ++ 12 files changed, 20 insertions(+) diff --git a/framework/components/CClientScript.php b/framework/components/CClientScript.php index 7cc2d5c..b5b80cd 100644 --- a/framework/components/CClientScript.php +++ b/framework/components/CClientScript.php @@ -76,6 +76,7 @@ class CClientScript extends CComponent */ function __construct() { + parent::__construct(); } /** diff --git a/framework/components/CComponent.php b/framework/components/CComponent.php index b0174cd..b6eae80 100644 --- a/framework/components/CComponent.php +++ b/framework/components/CComponent.php @@ -60,6 +60,7 @@ public static function __callStatic($method, $args) * return parent::init(__CLASS__); * } * </pre> + * @return mixed */ private static function _parentInit($className = __CLASS__) { diff --git a/framework/components/CDbHttpSession.php b/framework/components/CDbHttpSession.php index 45fc208..24010cf 100644 --- a/framework/components/CDbHttpSession.php +++ b/framework/components/CDbHttpSession.php @@ -66,6 +66,8 @@ class CDbHttpSession extends CComponent */ function __construct() { + parent::__construct(); + $this->_db = CDatabase::init(); @session_set_save_handler( diff --git a/framework/components/CHttpCookie.php b/framework/components/CHttpCookie.php index 60eb8d7..8dd0744 100644 --- a/framework/components/CHttpCookie.php +++ b/framework/components/CHttpCookie.php @@ -43,6 +43,8 @@ class CHttpCookie extends CComponent */ function __construct() { + parent::__construct(); + if (CConfig::get('cookies.domain') != '') { $this->setDomain(CConfig::get('cookies.domain')); } diff --git a/framework/components/CHttpRequest.php b/framework/components/CHttpRequest.php index fa09c27..1cf1f8e 100644 --- a/framework/components/CHttpRequest.php +++ b/framework/components/CHttpRequest.php @@ -101,6 +101,8 @@ class CHttpRequest extends CComponent */ function __construct() { + parent::__construct(); + $this->_csrfValidation = (CConfig::get('validation.csrf.enable') === true) ? true : false; $this->_csrfExclude = CConfig::exists('validation.csrf.exclude') ? CConfig::get('validation.csrf.exclude') : []; diff --git a/framework/components/CHttpSession.php b/framework/components/CHttpSession.php index 5514c92..283e135 100644 --- a/framework/components/CHttpSession.php +++ b/framework/components/CHttpSession.php @@ -64,6 +64,8 @@ class CHttpSession extends CComponent */ function __construct() { + parent::__construct(); + if ($this->_cookieMode !== 'only') { $this->_setCookieMode($this->_cookieMode); } diff --git a/framework/components/CLocalTime.php b/framework/components/CLocalTime.php index 8bfd7fb..f29b1fe 100644 --- a/framework/components/CLocalTime.php +++ b/framework/components/CLocalTime.php @@ -28,6 +28,7 @@ class CLocalTime extends CComponent */ function __construct() { + parent::__construct(); } /** diff --git a/framework/components/CLogger.php b/framework/components/CLogger.php index 06e83ac..fe27a06 100644 --- a/framework/components/CLogger.php +++ b/framework/components/CLogger.php @@ -44,6 +44,8 @@ class CLogger extends CComponent */ function __construct() { + parent::__construct(); + $this->_enabled = CConfig::get('log.enable') !== '' ? CConfig::get('log.enable') : false; $this->_logPath = APPHP_PATH.DS.(CConfig::get('log.path') !== '' ? CConfig::get('log.path') : 'protected/tmp/logs/'); $this->_fileExtension = CConfig::exists('log.fileExtension') && CConfig::get('log.fileExtension') !== '' ? ltrim(CConfig::get('log.fileExtension'), '.') : 'php'; diff --git a/framework/components/CMessageSource.php b/framework/components/CMessageSource.php index 3edc50c..164930f 100644 --- a/framework/components/CMessageSource.php +++ b/framework/components/CMessageSource.php @@ -29,6 +29,8 @@ class CMessageSource extends CComponent */ function __construct() { + parent::__construct(); + $this->_basePath = dirname(__FILE__); } diff --git a/framework/components/CMobileDetect.php b/framework/components/CMobileDetect.php index 950c05d..1d2d7dd 100644 --- a/framework/components/CMobileDetect.php +++ b/framework/components/CMobileDetect.php @@ -32,6 +32,7 @@ class CMobileDetect extends CComponent */ function __construct() { + parent::__construct(); } /** diff --git a/framework/components/CShoppingCart.php b/framework/components/CShoppingCart.php index efd321e..e68d10a 100644 --- a/framework/components/CShoppingCart.php +++ b/framework/components/CShoppingCart.php @@ -67,6 +67,8 @@ class CShoppingCart extends CComponent */ function __construct() { + parent::__construct(); + // Grab the shopping cart array from the session and initialize it $this->_cartContent = A::app()->getSession()->get('shopping_cart_content', null); if ($this->_cartContent === null) { diff --git a/framework/components/CUri.php b/framework/components/CUri.php index 17adf02..a0e5aa0 100644 --- a/framework/components/CUri.php +++ b/framework/components/CUri.php @@ -46,6 +46,8 @@ class CUri extends CComponent */ function __construct() { + parent::__construct(); + $this->_uriString = $this->_detectUri(); $this->_explodeSegments(); } From 0da93cede7c7f2628b23fdd62d9400a83fab0d77 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 21 Nov 2020 23:58:58 +0200 Subject: [PATCH 40/45] Created CCollection class --- framework/collections/CCollection.php | 56 +++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 framework/collections/CCollection.php diff --git a/framework/collections/CCollection.php b/framework/collections/CCollection.php new file mode 100644 index 0000000..ddae1cb --- /dev/null +++ b/framework/collections/CCollection.php @@ -0,0 +1,56 @@ +<?php +/** + * CCollect provides a wrapper for working with arrays of data + * + * @project ApPHP Framework + * @author ApPHP <info@apphp.com> + * @link http://www.apphpframework.com/ + * @copyright Copyright (c) 2012 - 2020 ApPHP Framework + * @license http://www.apphpframework.com/license/ + * + * PUBLIC: PROTECTED: PRIVATE: + * ---------- ---------- ---------- + * __construct + * + * init (static) + * all + * + */ + +class CCollection extends CComponent +{ + + /** + * The items contained in the collection + * @var array + */ + protected $_items = []; + + /** + * Class default constructor + */ + function __construct() + { + + } + + /** + * Returns the instance of object + * @return current class + */ + public static function init() + { + return parent::init(__CLASS__); + } + + /** + * Get all of the items in the collection + * + * @return array + */ + public function all() + { + return $this->_items; + } + +} \ No newline at end of file From 9e696d7be695bcc286a852081807b5fd487f5f94 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sun, 22 Nov 2020 00:07:40 +0200 Subject: [PATCH 41/45] Changed array() with [] --- .../setup/controllers/SetupController.php | 55 +- .../protected/controllers/PostsController.php | 97 +-- .../protected/entities/PostEntity.php | 4 +- framework/helpers/CHash.php | 12 +- framework/helpers/CLocale.php | 729 +++++++++--------- framework/helpers/widgets/CFormView.php | 38 +- 6 files changed, 478 insertions(+), 457 deletions(-) diff --git a/demos/login-system/protected/modules/setup/controllers/SetupController.php b/demos/login-system/protected/modules/setup/controllers/SetupController.php index 6c2864b..36232da 100644 --- a/demos/login-system/protected/modules/setup/controllers/SetupController.php +++ b/demos/login-system/protected/modules/setup/controllers/SetupController.php @@ -49,9 +49,9 @@ public function __construct() $this->_cRequest = A::app()->getRequest(); $this->_pdoExtensionRequired = true; $this->_configMain = include(APPHP_PATH . '/protected/data/config.main.tpl'); - $this->_languages = array('en' => 'English', 'es' => utf8_encode('Español'), 'de' => utf8_encode('Deutsch')); - - $this->_view->errorField = ''; + $this->_languages = ['en' => 'English', 'es' => utf8_encode('Español'), 'de' => utf8_encode('Deutsch')]; + + $this->_view->errorField = ''; $this->_view->_programName = isset($this->_configMain['name']) ? $this->_configMain['name'] : ''; $this->_view->_programVersion = isset($this->_configMain['version']) ? $this->_configMain['version'] : ''; @@ -280,22 +280,22 @@ public function databaseAction() $dbConnectTypes = ['host' => A::t('setup', 'host'), 'socket' => A::t('setup', 'socket')]; $msg = ''; - $separatorGeneralFields = array( + $separatorGeneralFields = [ 'separatorInfo' => ['legend' => 'General Settings'], 'setupType' => ['type' => 'dropdownlist', 'value' => $this->_view->setupType, 'title' => A::t('setup', 'Setup Type'), 'mandatoryStar' => false, 'data' => array('install' => A::t('setup', 'New Installation'), 'update' => A::t('setup', 'Update')), 'htmlOptions' => [], 'validation' => array('required' => true, 'type' => 'text', 'source' => array('install'))], 'dbDriver' => ['type' => 'dropdownlist', 'value' => $this->_view->dbDriver, 'title' => A::t('setup', 'Database Driver'), 'mandatoryStar' => true, 'data' => $dbDrivers, 'htmlOptions' => array('style' => 'width:85px'), 'validation' => array('required' => true, 'type' => 'text', 'source' => array_keys($dbDrivers))], 'dbPrefix' => ['type' => 'textbox', 'value' => $this->_view->dbPrefix, 'title' => A::t('setup', 'Database (tables) Prefix'), 'mandatoryStar' => false, 'htmlOptions' => array('maxLength' => '10', 'autocomplete' => 'off'), 'validation' => array('required' => false, 'type' => 'variable')], - ); - $separatorConenctionSettingsFields = array( - 'separatorInfo' => array('legend' => 'Connection Settings'), - 'dbConnectType' => array('type' => 'dropdownlist', 'value' => $this->_view->dbConnectType, 'title' => A::t('setup', 'Connection Type'), 'mandatoryStar' => true, 'data' => $dbConnectTypes, 'htmlOptions' => array('style' => 'width:85px'), 'validation' => array('required' => true, 'type' => 'text', 'source' => array_keys($dbConnectTypes))), - 'dbSocket' => array('type' => 'textbox', 'value' => $this->_view->dbSocket, 'title' => A::t('setup', 'Database Socket'), 'mandatoryStar' => true, 'htmlOptions' => array('maxLength' => '60', 'autocomplete' => 'off', 'placeholder' => '/tmp/mysql.sock'), 'validation' => array('required' => ($this->_view->dbConnectType == 'socket' ? true : false), 'type' => 'text'), 'disabled' => ($this->_view->dbConnectType == 'socket' ? false : true)), - 'dbHost' => array('type' => 'textbox', 'value' => $this->_view->dbHost, 'title' => A::t('setup', 'Database Host'), 'mandatoryStar' => true, 'htmlOptions' => array('maxLength' => '60', 'autocomplete' => 'off', 'placeholder' => 'e.g. localhost'), 'validation' => array('required' => ($this->_view->dbConnectType == 'host' ? true : false), 'type' => 'text'), 'disabled' => ($this->_view->dbConnectType == 'host' ? false : true)), - 'dbPort' => array('type' => 'textbox', 'value' => $this->_view->dbPort, 'title' => A::t('setup', 'Database Port'), 'mandatoryStar' => false, 'htmlOptions' => array('maxLength' => '10', 'autocomplete' => 'off', 'placeholder' => 'e.g. 3306', 'style' => 'width:80px'), 'validation' => array('required' => false, 'type' => 'integer'), 'disabled' => ($this->_view->dbConnectType == 'host' ? false : true)), - 'dbName' => array('type' => 'textbox', 'value' => $this->_view->dbName, 'title' => A::t('setup', 'Database Name'), 'mandatoryStar' => true, 'htmlOptions' => array('maxLength' => '30', 'autocomplete' => 'off'), 'validation' => array('required' => true, 'type' => 'text')), - 'dbUser' => array('type' => 'textbox', 'value' => $this->_view->dbUser, 'title' => A::t('setup', 'Database User'), 'mandatoryStar' => true, 'htmlOptions' => array('maxLength' => '30', 'autocomplete' => 'off'), 'validation' => array('required' => true, 'type' => 'text')), - 'dbPassword' => array('type' => 'password', 'value' => $this->_view->dbPassword, 'title' => A::t('setup', 'Database Password'), 'mandatoryStar' => false, 'htmlOptions' => array('maxLength' => '20', 'autocomplete' => 'off', 'id' => 'db_password'), 'validation' => array('required' => false, 'type' => 'text'), 'appendCode' => '<div for="db_password" class="toggle_password" data-field="db_password"></div>'), - ); + ]; + $separatorConenctionSettingsFields = [ + 'separatorInfo' => ['legend' => 'Connection Settings'], + 'dbConnectType' => ['type' => 'dropdownlist', 'value' => $this->_view->dbConnectType, 'title' => A::t('setup', 'Connection Type'), 'mandatoryStar' => true, 'data' => $dbConnectTypes, 'htmlOptions' => array('style' => 'width:85px'), 'validation' => ['required' => true, 'type' => 'text', 'source' => array_keys($dbConnectTypes)]], + 'dbSocket' => ['type' => 'textbox', 'value' => $this->_view->dbSocket, 'title' => A::t('setup', 'Database Socket'), 'mandatoryStar' => true, 'htmlOptions' => array('maxLength' => '60', 'autocomplete' => 'off', 'placeholder' => '/tmp/mysql.sock'), 'validation' => array('required' => ($this->_view->dbConnectType == 'socket' ? true : false), 'type' => 'text'), 'disabled' => ($this->_view->dbConnectType == 'socket' ? false : true)], + 'dbHost' => ['type' => 'textbox', 'value' => $this->_view->dbHost, 'title' => A::t('setup', 'Database Host'), 'mandatoryStar' => true, 'htmlOptions' => array('maxLength' => '60', 'autocomplete' => 'off', 'placeholder' => 'e.g. localhost'), 'validation' => array('required' => ($this->_view->dbConnectType == 'host' ? true : false), 'type' => 'text'), 'disabled' => ($this->_view->dbConnectType == 'host' ? false : true)], + 'dbPort' => ['type' => 'textbox', 'value' => $this->_view->dbPort, 'title' => A::t('setup', 'Database Port'), 'mandatoryStar' => false, 'htmlOptions' => array('maxLength' => '10', 'autocomplete' => 'off', 'placeholder' => 'e.g. 3306', 'style' => 'width:80px'), 'validation' => array('required' => false, 'type' => 'integer'), 'disabled' => ($this->_view->dbConnectType == 'host' ? false : true)], + 'dbName' => ['type' => 'textbox', 'value' => $this->_view->dbName, 'title' => A::t('setup', 'Database Name'), 'mandatoryStar' => true, 'htmlOptions' => array('maxLength' => '30', 'autocomplete' => 'off'), 'validation' => array('required' => true, 'type' => 'text')], + 'dbUser' => ['type' => 'textbox', 'value' => $this->_view->dbUser, 'title' => A::t('setup', 'Database User'), 'mandatoryStar' => true, 'htmlOptions' => array('maxLength' => '30', 'autocomplete' => 'off'), 'validation' => array('required' => true, 'type' => 'text')], + 'dbPassword' => ['type' => 'password', 'value' => $this->_view->dbPassword, 'title' => A::t('setup', 'Database Password'), 'mandatoryStar' => false, 'htmlOptions' => array('maxLength' => '20', 'autocomplete' => 'off', 'id' => 'db_password'), 'validation' => array('required' => false, 'type' => 'text'), 'appendCode' => '<div for="db_password" class="toggle_password" data-field="db_password"></div>'], + ]; $validationFields = array_merge($separatorGeneralFields, $separatorConenctionSettingsFields); $this->_view->formFields = array( 'act' => array('type' => 'hidden', 'value' => 'send'), @@ -307,16 +307,13 @@ public function databaseAction() if ($this->_cSession->get('step') < 2) { $this->redirect('setup/index'); } elseif ($this->_cRequest->getPost('act') == 'send') { - - $result = CWidget::create('CFormValidation', array( - 'fields' => $validationFields - )); - - if ($result['error']) { + $result = CWidget::create('CFormValidation', ['fields' => $validationFields]); + + if ($result['error']) { $msg = $result['errorMessage']; $this->_view->errorField = $result['errorField']; } else { - $model = new Setup(array( + $model = new Setup([ 'dbDriver' => $this->_view->dbDriver, 'dbConnectType' => $this->_view->dbConnectType, 'dbSocket' => $this->_view->dbSocket, @@ -325,7 +322,7 @@ public function databaseAction() 'dbName' => $this->_view->dbName, 'dbUser' => $this->_view->dbUser, 'dbPassword' => $this->_view->dbPassword - )); + ]); if ($model->getError()) { $this->_view->actionMessage = CWidget::create('CMessage', ['error', $model->getErrorMessage()]); @@ -381,9 +378,9 @@ public function administratorAction() $result = CWidget::create('CFormValidation', [ 'fields' => [ - 'email' => array('title' => A::t('setup', 'Email'), 'validation' => array('required' => false, 'type' => 'email')), - 'username' => array('title' => A::t('setup', 'Username'), 'validation' => array('required' => true, 'type' => 'any', 'minLength' => 4, 'maxLength' => 32)), - 'password' => array('title' => A::t('setup', 'Password'), 'validation' => array('required' => true, 'type' => 'any', 'minLength' => 4, 'maxLength' => 25)), + 'email' => ['title' => A::t('setup', 'Email'), 'validation' => ['required' => false, 'type' => 'email']], + 'username' => ['title' => A::t('setup', 'Username'), 'validation' => ['required' => true, 'type' => 'any', 'minLength' => 4, 'maxLength' => 32]], + 'password' => ['title' => A::t('setup', 'Password'), 'validation' => ['required' => true, 'type' => 'any', 'minLength' => 4, 'maxLength' => 25]], ], ]); @@ -456,8 +453,8 @@ public function readyAction() ]); if ($model->getError()) { - $this->_view->actionMessage = CWidget::create('CMessage', array('error', $model->getErrorMessage())); - } else { + $this->_view->actionMessage = CWidget::create('CMessage', ['error', $model->getErrorMessage()]); + } else { if ($model->install($sqlDump)) { $modulesError = false; $modulesWarning = false; @@ -481,7 +478,7 @@ public function readyAction() $model->doBeginTransaction(); if (!$model->install($sqlDump, false)) { $modulesError = true; - $this->_view->actionMessage = CWidget::create('CMessage', array('error', $model->getErrorMessage())); + $this->_view->actionMessage = CWidget::create('CMessage', ['error', $model->getErrorMessage()]); } else { // Copy module files foreach ($xml->files->children() as $folder) { diff --git a/demos/simple-blog/protected/controllers/PostsController.php b/demos/simple-blog/protected/controllers/PostsController.php index 34299ba..d1fd143 100644 --- a/demos/simple-blog/protected/controllers/PostsController.php +++ b/demos/simple-blog/protected/controllers/PostsController.php @@ -64,22 +64,24 @@ public function viewAction($postId = null) $msg = 'Wrong parameter passed! Please try again later.'; $msgType = 'error'; } else { - $result = $postsModel->findAll(array( - 'limit' => (($this->_view->currentPage - 1) * $this->_view->pageSize) . ', ' . $this->_view->pageSize, - 'order' => 'post_datetime DESC', - )); - } + $result = $postsModel->findAll( + [ + 'limit' => (($this->_view->currentPage - 1) * $this->_view->pageSize).', '.$this->_view->pageSize, + 'order' => 'post_datetime DESC', + ] + ); + } } else { $viewOnePost = true; - $result = $postsModel->find(CConfig::get('db.prefix') . 'posts.id = :id', array(':id' => $postId)); - } - $this->_view->viewOnePost = $viewOnePost; + $result = $postsModel->find(CConfig::get('db.prefix').'posts.id = :id', [':id' => $postId]); + } + $this->_view->viewOnePost = $viewOnePost; if (!$result) { $msg = (!empty($msg)) ? $msg : 'There are still no posts.'; $msgType = (!empty($msgType)) ? $msgType : 'info'; - $this->_view->mainText = CWidget::create('CMessage', array($msgType, $msg, array('button' => false))); - } else { + $this->_view->mainText = CWidget::create('CMessage', [$msgType, $msg, ['button' => false]]); + } else { $this->_view->mainText = ''; if ($viewOnePost) { // meta tags specific for the post @@ -123,28 +125,35 @@ public function indexAction($msg = '') $msg_text = 'Wrong parameter passed! Check post ID.'; $msgType = 'error'; } - if (!empty($msg_text)) $this->_view->actionMessage = CWidget::create('CMessage', array($msgType, $msg_text, array('button' => true))); - } - - // prepare pagination vars + if ( ! empty($msg_text)) { + $this->_view->actionMessage = CWidget::create('CMessage', [$msgType, $msg_text, ['button' => true]]); + } + } + + // prepare pagination vars $this->_view->targetPage = 'posts/index'; $this->_view->currentPage = A::app()->getRequest()->getQuery('page', 'integer', 1); $this->_view->pageSize = 15; $this->_view->totalRecords = Posts::model()->count(); if (!$this->_view->currentPage) { - $this->_view->actionMessage = CWidget::create('CMessage', array('error', 'Wrong parameter passed! Please try again later.', array('button' => true))); - } else { - $conditions = array( - 'limit' => (($this->_view->currentPage - 1) * $this->_view->pageSize) . ', ' . $this->_view->pageSize, - 'order' => 'post_datetime DESC', + $this->_view->actionMessage = CWidget::create( + 'CMessage', + ['error', 'Wrong parameter passed! Please try again later.', ['button' => true]] ); + } else { + $conditions = [ + 'limit' => (($this->_view->currentPage - 1) * $this->_view->pageSize).', '.$this->_view->pageSize, + 'order' => 'post_datetime DESC', + ]; if (!true) { - $this->_view->posts = Posts::model()->findAll(array( - 'limit' => (($this->_view->currentPage - 1) * $this->_view->pageSize) . ', ' . $this->_view->pageSize, - 'order' => 'post_datetime DESC', - )); + $this->_view->posts = Posts::model()->findAll( + [ + 'limit' => (($this->_view->currentPage - 1) * $this->_view->pageSize).', '.$this->_view->pageSize, + 'order' => 'post_datetime DESC', + ] + ); }else{ $posts = null; Posts::model()->chunk($conditions, [], 10, function ($records) use(&$posts){ @@ -216,11 +225,11 @@ public function insertAction() // Perform post add form validation $result = CWidget::create('CFormValidation', array( 'fields' => array( - 'header' => array('title' => 'Header', 'validation' => array('required' => true, 'type' => 'any', 'maxLength' => 100)), - 'postText' => array('title' => 'Post Text', 'validation' => array('required' => true, 'type' => 'any', 'maxLength' => 4000)), - 'metaTagTitle' => array('title' => CHtml::encode('Tag <TITLE>'), 'validation' => array('required' => false, 'type' => 'any', 'maxLength' => 250)), - 'metaTagKeywords' => array('title' => CHtml::encode('Meta tag <KEYWORDS>'), 'validation' => array('required' => false, 'type' => 'any', 'maxLength' => 250)), - 'metaTagDescription' => array('title' => CHtml::encode('Meta tag <DESCRIPTION>'), 'validation' => array('required' => false, 'type' => 'any', 'maxLength' => 250)), + 'header' => ['title' => 'Header', 'validation' => ['required' => true, 'type' => 'any', 'maxLength' => 100]], + 'postText' => ['title' => 'Post Text', 'validation' => ['required' => true, 'type' => 'any', 'maxLength' => 4000]], + 'metaTagTitle' => ['title' => CHtml::encode('Tag <TITLE>'), 'validation' => ['required' => false, 'type' => 'any', 'maxLength' => 250]], + 'metaTagKeywords' => ['title' => CHtml::encode('Meta tag <KEYWORDS>'), 'validation' => ['required' => false, 'type' => 'any', 'maxLength' => 250]], + 'metaTagDescription' => ['title' => CHtml::encode('Meta tag <DESCRIPTION>'), 'validation' => ['required' => false, 'type' => 'any', 'maxLength' => 250]], ), )); @@ -271,8 +280,8 @@ public function insertAction() } } if (!empty($msg)) { - $this->_view->actionMessage = CWidget::create('CMessage', array($msgType, $msg, array('button' => true))); - $this->_view->render('posts/add'); + $this->_view->actionMessage = CWidget::create('CMessage', [$msgType, $msg, ['button' => true]]); + $this->_view->render('posts/add'); } } else { $this->redirect('posts/add'); @@ -333,11 +342,11 @@ public function updateAction() // perform post edit form validation $result = CWidget::create('CFormValidation', array( 'fields' => array( - 'header' => array('title' => 'Header', 'validation' => array('required' => true, 'type' => 'any', 'maxLength' => 100)), - 'postText' => array('title' => 'Post Text', 'validation' => array('required' => true, 'type' => 'any', 'maxLength' => 4000)), - 'metaTagTitle' => array('title' => CHtml::encode('Tag <TITLE>'), 'validation' => array('required' => false, 'type' => 'any', 'maxLength' => 250)), - 'metaTagKeywords' => array('title' => CHtml::encode('Meta tag <KEYWORDS>'), 'validation' => array('required' => false, 'type' => 'any', 'maxLength' => 250)), - 'metaTagDescription' => array('title' => CHtml::encode('Meta tag <DESCRIPTION>'), 'validation' => array('required' => false, 'type' => 'any', 'maxLength' => 250)), + 'header' => ['title' => 'Header', 'validation' => ['required' => true, 'type' => 'any', 'maxLength' => 100]], + 'postText' => ['title' => 'Post Text', 'validation' => ['required' => true, 'type' => 'any', 'maxLength' => 4000]], + 'metaTagTitle' => ['title' => CHtml::encode('Tag <TITLE>'), 'validation' => ['required' => false, 'type' => 'any', 'maxLength' => 250]], + 'metaTagKeywords' => ['title' => CHtml::encode('Meta tag <KEYWORDS>'), 'validation' => ['required' => false, 'type' => 'any', 'maxLength' => 250]], + 'metaTagDescription' => ['title' => CHtml::encode('Meta tag <DESCRIPTION>'), 'validation' => ['required' => false, 'type' => 'any', 'maxLength' => 250]], ), )); @@ -363,8 +372,8 @@ public function updateAction() $post->metatag_title = $this->_view->metaTagTitle; $post->metatag_keywords = $this->_view->metaTagKeywords; $post->metatag_description = $this->_view->metaTagDescription; - $post->setGuarded(array('author_id', 'post_datetime')); - $saveResult = $posts->save($post); + $post->setGuarded(['author_id', 'post_datetime']); + $saveResult = $posts->save($post); } else { // Use model $posts = Posts::model()->findByPk($this->_view->postId); @@ -389,9 +398,9 @@ public function updateAction() } } if (!empty($msg)) { - $this->_view->actionMessage = CWidget::create('CMessage', array($msgType, $msg, array('button' => true))); - } - $this->_view->render('posts/edit'); + $this->_view->actionMessage = CWidget::create('CMessage', [$msgType, $msg, ['button' => true]]); + } + $this->_view->render('posts/edit'); } else { $this->redirect('posts/index'); } @@ -420,10 +429,10 @@ public function deleteAction($postId) $msgType = 'error'; } if (!empty($msg)) { - $this->_view->actionMessage = CWidget::create('CMessage', array($msgType, $msg, array('button' => true))); - } - - $this->redirect('posts/index/msg/deleted'); + $this->_view->actionMessage = CWidget::create('CMessage', [$msgType, $msg, ['button' => true]]); + } + + $this->redirect('posts/index/msg/deleted'); } } diff --git a/demos/simple-blog/protected/entities/PostEntity.php b/demos/simple-blog/protected/entities/PostEntity.php index 03cab5a..8c37373 100644 --- a/demos/simple-blog/protected/entities/PostEntity.php +++ b/demos/simple-blog/protected/entities/PostEntity.php @@ -17,9 +17,9 @@ class PostEntity extends CRecordEntity /** @var */ protected $_fillable = []; /** @var */ - protected $_guarded = array('post_datetime'); + protected $_guarded = ['post_datetime']; - /** + /** * Class constructor * @param int $pkVal */ diff --git a/framework/helpers/CHash.php b/framework/helpers/CHash.php index 8aa78ab..f565eb1 100644 --- a/framework/helpers/CHash.php +++ b/framework/helpers/CHash.php @@ -109,9 +109,9 @@ public static function getRandomToken($length = 32) * case: 'upper', 'lower' (default) * @return string */ - public static function getRandomString($length = 10, $params = array()) - { - $type = isset($params['type']) ? $params['type'] : ''; + public static function getRandomString($length = 10, $params = []) + { + $type = isset($params['type']) ? $params['type'] : ''; $case = isset($params['case']) ? $params['case'] : ''; if ($type == 'numeric') { @@ -234,9 +234,9 @@ private static function _padKey($key) if (strlen($key) > 32) return false; // Set sizes - $sizes = array(16, 24, 32); - - // Loop through sizes and pad key + $sizes = [16, 24, 32]; + + // Loop through sizes and pad key foreach ($sizes as $s) { if ($s > strlen($key)) { $key = str_pad($key, $s, "\0"); diff --git a/framework/helpers/CLocale.php b/framework/helpers/CLocale.php index 19eb169..faf9a58 100644 --- a/framework/helpers/CLocale.php +++ b/framework/helpers/CLocale.php @@ -20,361 +20,376 @@ class CLocale { - - protected static $_arrDateFormats = array( - 'Y-m-d' => array('preview' => '[ Y-m-d ]', 'converted_format' => '%Y-%m-%d'), - 'm-d-Y' => array('preview' => '[ m-d-Y ]', 'converted_format' => '%m-%d-%Y'), - 'd-m-Y' => array('preview' => '[ d-m-Y ]', 'converted_format' => '%d-%m-%Y'), - - 'Y M d' => array('preview' => '[ Y M d ]', 'converted_format' => '%Y %M %d'), - 'M d Y' => array('preview' => '[ M d Y ]', 'converted_format' => '%M %d %Y'), - 'd M Y' => array('preview' => '[ d M Y ]', 'converted_format' => '%d %M %Y'), - 'M d, Y' => array('preview' => '[ M d, Y ]', 'converted_format' => '%M %d, %Y'), - 'd M, Y' => array('preview' => '[ d M, Y ]', 'converted_format' => '%d %M, %Y'), - - 'Y M j' => array('preview' => '[ Y M j ]', 'converted_format' => '%Y %M %j'), - 'M j, Y' => array('preview' => '[ M j, Y ]', 'converted_format' => '%M %j, %Y'), - 'j M, Y' => array('preview' => '[ j M, Y ]', 'converted_format' => '%j %M, %Y'), - - 'Y F d' => array('preview' => '[ Y F d ]', 'converted_format' => '%Y %F %d'), - 'F d Y' => array('preview' => '[ F d Y ]', 'converted_format' => '%F %d %Y'), - 'd F Y' => array('preview' => '[ d F Y ]', 'converted_format' => '%d %F %Y'), - - 'Y F j' => array('preview' => '[ Y F j ]', 'converted_format' => '%Y %F %j'), - 'F j, Y' => array('preview' => '[ F j, Y ]', 'converted_format' => '%F %j, %Y'), - 'j F, Y' => array('preview' => '[ j F, Y ]', 'converted_format' => '%j %F, %Y'), - ); - - protected static $_arrTimeFormats = array( - 'H:i:s' => array('preview' => '[ H:i:s ]', 'converted_format' => '%H:%i:%s'), - 'h:i:s' => array('preview' => '[ h:i:s ]', 'converted_format' => '%h:%i:%s'), - 'g:i:s' => array('preview' => '[ g:i:s ]', 'converted_format' => '%g:%i:%s'), - - 'h:i a' => array('preview' => '[ h:i a ]', 'converted_format' => '%h:%i %a'), - 'h:i A' => array('preview' => '[ h:i A ]', 'converted_format' => '%h:%i %A'), - 'g:i a' => array('preview' => '[ g:i a ]', 'converted_format' => '%g:%i %a'), - 'g:i A' => array('preview' => '[ g:i A ]', 'converted_format' => '%g:%i %A'), - ); - - protected static $_arrShortTimeFormats = array( - 'H:i' => array('preview' => '[ H:i ]', 'converted_format' => '%H:%i'), - 'h:i' => array('preview' => '[ h:i ]', 'converted_format' => '%h:%i'), - 'g:i' => array('preview' => '[ g:i ]', 'converted_format' => '%g:%i'), - ); - - protected static $_arrDateTimeFormats = array( - 'Y-m-d H:i:s' => array('preview' => '[ Y-m-d H:i:s ] ', 'converted_format' => '%Y-%m-%d %H:%i:%s'), - 'm-d-Y H:i:s' => array('preview' => '[ m-d-Y H:i:s ] ', 'converted_format' => '%m-%d-%Y %H:%i:%s'), - 'd-m-Y H:i:s' => array('preview' => '[ d-m-Y H:i:s ] ', 'converted_format' => '%d-%m-%Y %H:%i:%s'), - 'm-d-Y h:i:s' => array('preview' => '[ m-d-Y H:i:s ] ', 'converted_format' => '%m-%d-%Y %h:%i:%s'), - 'd-m-Y h:i:s' => array('preview' => '[ d-m-Y H:i:s ] ', 'converted_format' => '%d-%m-%Y %h:%i:%s'), - 'm-d-Y g:ia' => array('preview' => '[ m-d-Y g:ia ] ', 'converted_format' => '%m-%d-%Y %g:%i%a'), - 'd-m-Y g:ia' => array('preview' => '[ d-m-Y g:ia ] ', 'converted_format' => '%d-%m-%Y %g:%i%a'), - 'M d, Y g:ia' => array('preview' => '[ M d, Y g:ia ] ', 'converted_format' => '%M %d, %Y %g:%i%a'), - 'd M, Y g:ia' => array('preview' => '[ d M, Y g:ia ] ', 'converted_format' => '%d %M, %Y %g:%i%a'), - 'F j Y, g:ia' => array('preview' => '[ F j Y, g:ia ] ', 'converted_format' => '%F %j %Y, %g:%i%a'), - 'j F Y, g:ia' => array('preview' => '[ j F Y, g:ia ] ', 'converted_format' => '%j %F %Y, %g:%i%a'), - 'D, F j Y g:ia' => array('preview' => '[ D, F j Y g:ia ] ', 'converted_format' => '%D, %F %j %Y %g:%i%a'), - 'D, M d Y g:ia' => array('preview' => '[ D, M d Y g:ia ] ', 'converted_format' => '%D, %M %d %Y %g:%i%a'), - ); - - /** - * Transforms the given date into localazed date - * @param string $format - * @param string $date - * @param bool $unixFormat - * @return string - */ - public static function date($format = '', $date = '', $unixFormat = false) - { - $dateFormat = null; - $search = array(); - $replace = array(); - $result = ''; - $amPm = ''; - - if ($unixFormat) { - $date = !empty($date) ? date('Y-m-d H:i:s', $date) : date('Y-m-d H:i:s'); - } else { - $date = !empty($date) ? $date : date('Y-m-d H:i:s'); - } - - if (isset(self::$_arrDateTimeFormats[$format])) { - $dateFormat = self::$_arrDateTimeFormats[$format]; - $parts = explode(' ', $date); - - $dateParts = isset($parts[0]) ? explode('-', $parts[0]) : array(); - $year = isset($dateParts[0]) ? $dateParts[0] : ''; - $month = isset($dateParts[1]) ? $dateParts[1] : ''; - $day = isset($dateParts[2]) ? $dateParts[2] : ''; - $weekDay = date('w', strtotime($date)) + 1; - - $timeParts = isset($parts[1]) ? explode(':', $parts[1]) : array(); - $hour = isset($timeParts[0]) ? $timeParts[0] : ''; - $hour24 = $hour; - $hour12 = ($hour >= 13 ? $hour - 12 : $hour); - $minute = isset($timeParts[1]) ? $timeParts[1] : ''; - $second = isset($timeParts[2]) ? $timeParts[2] : ''; - - $amPm = ($hour24 < 12) ? A::t('i18n', 'amName') : A::t('i18n', 'pmName'); - - $convertedFormat = isset($dateFormat['converted_format']) ? $dateFormat['converted_format'] : ''; - } elseif (isset(self::$_arrDateFormats[$format])) { - $dateFormat = self::$_arrDateFormats[$format]; - - $parts = explode(' ', $date); - $dateParts = isset($parts[0]) ? explode('-', $parts[0]) : array(); - - $year = isset($dateParts[0]) ? $dateParts[0] : ''; - $month = isset($dateParts[1]) ? $dateParts[1] : ''; - $day = isset($dateParts[2]) ? $dateParts[2] : ''; - $dayParts = explode(' ', $day); - $day = isset($day[0]) ? $dayParts[0] : ''; - - $convertedFormat = isset($dateFormat['converted_format']) ? $dateFormat['converted_format'] : ''; - } elseif (isset(self::$_arrTimeFormats[$format])) { - $dateFormat = self::$_arrTimeFormats[$format]; - - if (strlen($date) > 8) { - $parts = explode(' ', $date); - $timeParts = isset($parts[1]) ? explode(':', $parts[1]) : array(); - } else { - $timeParts = explode(':', $date); - } - - $hour = isset($timeParts[0]) ? $timeParts[0] : ''; - $hour24 = $hour; - $hour12 = ($hour >= 13 ? $hour - 12 : $hour); - $minute = isset($timeParts[1]) ? $timeParts[1] : ''; - $second = isset($timeParts[2]) ? $timeParts[2] : ''; - - $amPm = ($hour24 < 12) ? A::t('i18n', 'amName') : A::t('i18n', 'pmName'); - - $convertedFormat = isset($dateFormat['converted_format']) ? $dateFormat['converted_format'] : ''; - } elseif (isset(self::$_arrShortTimeFormats[$format])) { - $dateFormat = self::$_arrShortTimeFormats[$format]; - - if (strlen($date) > 5) { - $parts = explode(' ', $date); - $timeParts = isset($parts[1]) ? explode(':', $parts[1]) : array(); - } else { - $timeParts = explode(':', $date); - } - - $hour = isset($timeParts[0]) ? $timeParts[0] : ''; - $hour24 = $hour; - $hour12 = ($hour >= 13 ? $hour - 12 : $hour); - $minute = isset($timeParts[1]) ? $timeParts[1] : ''; - - $convertedFormat = isset($dateFormat['converted_format']) ? $dateFormat['converted_format'] : ''; - } else { - $result = date($format, strtotime($date)); - } - - if ($dateFormat) { - - switch ($format) { - - /* - |--------------------------------------------------- - | Date Formats - |--------------------------------------------------- - */ - case 'Y-m-d': /* 2015-01-31 */ - case 'm-d-Y': /* 01-31-2015 */ - case 'd-m-Y': /* 31-01-2015 */ - - $search = array('%Y', '%m', '%d'); - $replace = array($year, $month, $day); - break; - - case 'Y M d': /* 2015 Oct 01 */ - case 'M d Y': /* Oct 01 2015 */ - case 'd M Y': /* 01 Oct 2015 */ - case 'M d, Y': /* Oct 01, 2015 */ - case 'd M, Y': /* 01 Oct, 2015 */ - - $search = array('%Y', '%M', '%d'); - $replace = array($year, A::t('i18n', 'monthNames.abbreviated.' . (int)$month), $day); - break; - - case 'Y M j': /* 2015 Oct 1 */ - case 'M j, Y': /* Oct 1, 2015 */ - case 'j M, Y': /* 1 Oct, 2015 */ - - $search = array('%Y', '%M', '%j'); - $replace = array($year, A::t('i18n', 'monthNames.abbreviated.' . (int)$month), (int)$day); - break; - - case 'Y F d': /* 2015 October 01 */ - case 'F d Y': /* October 01 2015 */ - case 'd F Y': /* 01 October 2015 */ - - $search = array('%Y', '%F', '%d'); - $replace = array($year, A::t('i18n', 'monthNames.wide.' . (int)$month), $day); - break; - - case 'Y F j': /* 2015 October 1 */ - case 'F j, Y': /* October 1, 2015 */ - case 'j F, Y': /* 1 October, 2015 */ - - $search = array('%Y', '%F', '%j'); - $replace = array($year, A::t('i18n', 'monthNames.wide.' . (int)$month), (int)$day); - break; - - /* - |--------------------------------------------------- - | Time Formats - |--------------------------------------------------- - */ - case 'H:i:s': /* 13:53:20 */ - case 'h:i:s': /* 01:53:20 */ - case 'g:i:s': /* 1:53:20 */ - - $search = array('%H', '%h', '%g', '%i', '%s'); - $replace = array($hour24, $hour12, (int)$hour12, $minute, $second); - break; - - case 'h:i a': /* 01:47 pm */ - case 'g:i a': /* 1:47 pm */ - - $search = array('%h', '%g', '%i', '%a'); - $replace = array($hour12, (int)$hour12, $minute, strtolower($amPm)); - break; - - case 'h:i A': /* 01:47 PM */ - case 'g:i A': /* 1:47 PM */ - - $search = array('%h', '%g', '%i', '%A'); - $replace = array($hour12, (int)$hour12, $minute, strtoupper($amPm)); - break; - - case 'H:i': /* 13:47 */ - case 'h:i': /* 01:47 */ - case 'g:i': /* 1:47 */ - - $search = array('%H', '%h', '%g', '%i'); - $replace = array($hour24, $hour12, (int)$hour12, $minute); - break; - - /* - |--------------------------------------------------- - | DateTime Formats - |--------------------------------------------------- - */ - case 'Y-m-d H:i:s': /* 2015-01-31 13:02:59 */ - case 'm-d-Y H:i:s': /* 01-31-2015 13:02:59 */ - case 'd-m-Y H:i:s': /* 31-01-2015 13:02:59 */ - case 'm-d-Y h:i:s': /* 01-31-2015 01:02:59 */ - case 'd-m-Y h:i:s': /* 31-01-2015 01:02:59 */ - - $search = array('%Y', '%m', '%d', '%H', '%h', '%g', '%i', '%s'); - $replace = array($year, $month, $day, $hour24, $hour12, (int)$hour12, $minute, $second); - break; - - case 'm-d-Y g:ia': /* 2015-01-31 1:02pm */ - case 'd-m-Y g:ia': /* 31-01-2015 1:02pm */ - - $search = array('%Y', '%m', '%d', '%g', '%i', '%a'); - $replace = array($year, $month, $day, (int)$hour12, $minute, strtolower($amPm)); - break; - - case 'M d, Y g:ia': /* Oct 09, 2015 1:02pm */ - case 'd M, Y g:ia': /* 09 Oct, 2015 1:02pm */ - - $monthAbbrev = A::t('i18n', 'monthNames.abbreviated.' . (int)$month); - $search = array('%Y', '%M', '%d', '%g', '%i', '%a'); - $replace = array($year, $monthAbbrev, $day, (int)$hour12, $minute, strtolower($amPm)); - break; - - case 'F j Y, g:ia': /* October 1 2015, 1:02pm */ - case 'j F Y, g:ia': /* 1 October 2015, 1:02pm */ - - $monthWide = A::t('i18n', 'monthNames.wide.' . (int)$month); - $search = array('%Y', '%F', '%j', '%g', '%i', '%a'); - $replace = array($year, $monthWide, (int)$day, (int)$hour12, $minute, strtolower($amPm)); - break; - - case 'D, F j Y g:ia': /* Mon, October 1 2015 1:02pm */ - case 'D, M d Y g:ia': /* Mon, Oct 1 2015 1:02pm */ - - $monthWide = A::t('i18n', 'monthNames.wide.' . (int)$month); - $monthAbbrev = A::t('i18n', 'monthNames.abbreviated.' . (int)$month); - $weekDayAbbrev = A::t('i18n', 'weekDayNames.abbreviated.' . (int)$weekDay); - $search = array('%Y', '%F', '%M', '%j', '%d', '%D', '%g', '%i', '%a'); - $replace = array($year, $monthWide, $monthAbbrev, (int)$day, $day, $weekDayAbbrev, (int)$hour12, $minute, strtolower($amPm)); - break; - - default: - $result = $date; - break; - } - - if (!empty($search) && !empty($replace)) { - $result = str_replace($search, $replace, $convertedFormat); - } - } - - return $result; - } - - /** - * Returns array of datetime formats supported by system - * @return array - */ - public static function getDateTimeFormats() - { - $result = array(); - - foreach (self::$_arrDateTimeFormats as $key => $dateTimeFormat) { - $result[$key] = $dateTimeFormat['preview']; - } - - return $result; - } - - /** - * Returns array of date formats supported by system - * @return array - */ - public static function getDateFormats() - { - $result = array(); - - foreach (self::$_arrDateFormats as $key => $dateFormat) { - $result[$key] = $dateFormat['preview']; - } - - return $result; - } - - /** - * Returns array of time formats supported by system - * @return array - */ - public static function getTimeFormats() - { - $result = array(); - - foreach (self::$_arrTimeFormats as $key => $timeFormat) { - $result[$key] = $timeFormat['preview']; - } - - return $result; - } - - /** - * Returns array of short time formats supported by system - * @return array - */ - public static function getShortTimeFormats() - { - $result = array(); - - foreach (self::$_arrShortTimeFormats as $key => $timeFormat) { - $result[$key] = $timeFormat['preview']; - } - - return $result; - } + + protected static $_arrDateFormats = [ + 'Y-m-d' => ['preview' => '[ Y-m-d ]', 'converted_format' => '%Y-%m-%d'], + 'm-d-Y' => ['preview' => '[ m-d-Y ]', 'converted_format' => '%m-%d-%Y'], + 'd-m-Y' => ['preview' => '[ d-m-Y ]', 'converted_format' => '%d-%m-%Y'], + + 'Y M d' => ['preview' => '[ Y M d ]', 'converted_format' => '%Y %M %d'], + 'M d Y' => ['preview' => '[ M d Y ]', 'converted_format' => '%M %d %Y'], + 'd M Y' => ['preview' => '[ d M Y ]', 'converted_format' => '%d %M %Y'], + 'M d, Y' => ['preview' => '[ M d, Y ]', 'converted_format' => '%M %d, %Y'], + 'd M, Y' => ['preview' => '[ d M, Y ]', 'converted_format' => '%d %M, %Y'], + + 'Y M j' => ['preview' => '[ Y M j ]', 'converted_format' => '%Y %M %j'], + 'M j, Y' => ['preview' => '[ M j, Y ]', 'converted_format' => '%M %j, %Y'], + 'j M, Y' => ['preview' => '[ j M, Y ]', 'converted_format' => '%j %M, %Y'], + + 'Y F d' => ['preview' => '[ Y F d ]', 'converted_format' => '%Y %F %d'], + 'F d Y' => ['preview' => '[ F d Y ]', 'converted_format' => '%F %d %Y'], + 'd F Y' => ['preview' => '[ d F Y ]', 'converted_format' => '%d %F %Y'], + + 'Y F j' => ['preview' => '[ Y F j ]', 'converted_format' => '%Y %F %j'], + 'F j, Y' => ['preview' => '[ F j, Y ]', 'converted_format' => '%F %j, %Y'], + 'j F, Y' => ['preview' => '[ j F, Y ]', 'converted_format' => '%j %F, %Y'], + ]; + + protected static $_arrTimeFormats = [ + 'H:i:s' => ['preview' => '[ H:i:s ]', 'converted_format' => '%H:%i:%s'], + 'h:i:s' => ['preview' => '[ h:i:s ]', 'converted_format' => '%h:%i:%s'], + 'g:i:s' => ['preview' => '[ g:i:s ]', 'converted_format' => '%g:%i:%s'], + + 'h:i a' => ['preview' => '[ h:i a ]', 'converted_format' => '%h:%i %a'], + 'h:i A' => ['preview' => '[ h:i A ]', 'converted_format' => '%h:%i %A'], + 'g:i a' => ['preview' => '[ g:i a ]', 'converted_format' => '%g:%i %a'], + 'g:i A' => ['preview' => '[ g:i A ]', 'converted_format' => '%g:%i %A'], + ]; + + protected static $_arrShortTimeFormats + = [ + 'H:i' => ['preview' => '[ H:i ]', 'converted_format' => '%H:%i'], + 'h:i' => ['preview' => '[ h:i ]', 'converted_format' => '%h:%i'], + 'g:i' => ['preview' => '[ g:i ]', 'converted_format' => '%g:%i'], + ]; + + protected static $_arrDateTimeFormats + = [ + 'Y-m-d H:i:s' => ['preview' => '[ Y-m-d H:i:s ] ', 'converted_format' => '%Y-%m-%d %H:%i:%s'], + 'm-d-Y H:i:s' => ['preview' => '[ m-d-Y H:i:s ] ', 'converted_format' => '%m-%d-%Y %H:%i:%s'], + 'd-m-Y H:i:s' => ['preview' => '[ d-m-Y H:i:s ] ', 'converted_format' => '%d-%m-%Y %H:%i:%s'], + 'm-d-Y h:i:s' => ['preview' => '[ m-d-Y H:i:s ] ', 'converted_format' => '%m-%d-%Y %h:%i:%s'], + 'd-m-Y h:i:s' => ['preview' => '[ d-m-Y H:i:s ] ', 'converted_format' => '%d-%m-%Y %h:%i:%s'], + 'm-d-Y g:ia' => ['preview' => '[ m-d-Y g:ia ] ', 'converted_format' => '%m-%d-%Y %g:%i%a'], + 'd-m-Y g:ia' => ['preview' => '[ d-m-Y g:ia ] ', 'converted_format' => '%d-%m-%Y %g:%i%a'], + 'M d, Y g:ia' => ['preview' => '[ M d, Y g:ia ] ', 'converted_format' => '%M %d, %Y %g:%i%a'], + 'd M, Y g:ia' => ['preview' => '[ d M, Y g:ia ] ', 'converted_format' => '%d %M, %Y %g:%i%a'], + 'F j Y, g:ia' => ['preview' => '[ F j Y, g:ia ] ', 'converted_format' => '%F %j %Y, %g:%i%a'], + 'j F Y, g:ia' => ['preview' => '[ j F Y, g:ia ] ', 'converted_format' => '%j %F %Y, %g:%i%a'], + 'D, F j Y g:ia' => ['preview' => '[ D, F j Y g:ia ] ', 'converted_format' => '%D, %F %j %Y %g:%i%a'], + 'D, M d Y g:ia' => ['preview' => '[ D, M d Y g:ia ] ', 'converted_format' => '%D, %M %d %Y %g:%i%a'], + ]; + + /** + * Transforms the given date into localazed date + * + * @param string $format + * @param string $date + * @param bool $unixFormat + * @return string + */ + public static function date($format = '', $date = '', $unixFormat = false) + { + $dateFormat = null; + $search = []; + $replace = []; + $result = ''; + $amPm = ''; + + if ($unixFormat) { + $date = ! empty($date) ? date('Y-m-d H:i:s', $date) : date('Y-m-d H:i:s'); + } else { + $date = ! empty($date) ? $date : date('Y-m-d H:i:s'); + } + + if (isset(self::$_arrDateTimeFormats[$format])) { + $dateFormat = self::$_arrDateTimeFormats[$format]; + $parts = explode(' ', $date); + + $dateParts = isset($parts[0]) ? explode('-', $parts[0]) : []; + $year = isset($dateParts[0]) ? $dateParts[0] : ''; + $month = isset($dateParts[1]) ? $dateParts[1] : ''; + $day = isset($dateParts[2]) ? $dateParts[2] : ''; + $weekDay = date('w', strtotime($date)) + 1; + + $timeParts = isset($parts[1]) ? explode(':', $parts[1]) : []; + $hour = isset($timeParts[0]) ? $timeParts[0] : ''; + $hour24 = $hour; + $hour12 = ($hour >= 13 ? $hour - 12 : $hour); + $minute = isset($timeParts[1]) ? $timeParts[1] : ''; + $second = isset($timeParts[2]) ? $timeParts[2] : ''; + + $amPm = ($hour24 < 12) ? A::t('i18n', 'amName') : A::t('i18n', 'pmName'); + + $convertedFormat = isset($dateFormat['converted_format']) ? $dateFormat['converted_format'] : ''; + } elseif (isset(self::$_arrDateFormats[$format])) { + $dateFormat = self::$_arrDateFormats[$format]; + + $parts = explode(' ', $date); + $dateParts = isset($parts[0]) ? explode('-', $parts[0]) : []; + + $year = isset($dateParts[0]) ? $dateParts[0] : ''; + $month = isset($dateParts[1]) ? $dateParts[1] : ''; + $day = isset($dateParts[2]) ? $dateParts[2] : ''; + $dayParts = explode(' ', $day); + $day = isset($day[0]) ? $dayParts[0] : ''; + + $convertedFormat = isset($dateFormat['converted_format']) ? $dateFormat['converted_format'] : ''; + } elseif (isset(self::$_arrTimeFormats[$format])) { + $dateFormat = self::$_arrTimeFormats[$format]; + + if (strlen($date) > 8) { + $parts = explode(' ', $date); + $timeParts = isset($parts[1]) ? explode(':', $parts[1]) : []; + } else { + $timeParts = explode(':', $date); + } + + $hour = isset($timeParts[0]) ? $timeParts[0] : ''; + $hour24 = $hour; + $hour12 = ($hour >= 13 ? $hour - 12 : $hour); + $minute = isset($timeParts[1]) ? $timeParts[1] : ''; + $second = isset($timeParts[2]) ? $timeParts[2] : ''; + + $amPm = ($hour24 < 12) ? A::t('i18n', 'amName') : A::t('i18n', 'pmName'); + + $convertedFormat = isset($dateFormat['converted_format']) ? $dateFormat['converted_format'] : ''; + } elseif (isset(self::$_arrShortTimeFormats[$format])) { + $dateFormat = self::$_arrShortTimeFormats[$format]; + + if (strlen($date) > 5) { + $parts = explode(' ', $date); + $timeParts = isset($parts[1]) ? explode(':', $parts[1]) : []; + } else { + $timeParts = explode(':', $date); + } + + $hour = isset($timeParts[0]) ? $timeParts[0] : ''; + $hour24 = $hour; + $hour12 = ($hour >= 13 ? $hour - 12 : $hour); + $minute = isset($timeParts[1]) ? $timeParts[1] : ''; + + $convertedFormat = isset($dateFormat['converted_format']) ? $dateFormat['converted_format'] : ''; + } else { + $result = date($format, strtotime($date)); + } + + if ($dateFormat) { + switch ($format) { + /* + |--------------------------------------------------- + | Date Formats + |--------------------------------------------------- + */ + case 'Y-m-d': /* 2015-01-31 */ + case 'm-d-Y': /* 01-31-2015 */ + case 'd-m-Y': /* 31-01-2015 */ + + $search = ['%Y', '%m', '%d']; + $replace = [$year, $month, $day]; + break; + + case 'Y M d': /* 2015 Oct 01 */ + case 'M d Y': /* Oct 01 2015 */ + case 'd M Y': /* 01 Oct 2015 */ + case 'M d, Y': /* Oct 01, 2015 */ + case 'd M, Y': /* 01 Oct, 2015 */ + + $search = ['%Y', '%M', '%d']; + $replace = [$year, A::t('i18n', 'monthNames.abbreviated.'.(int)$month), $day]; + break; + + case 'Y M j': /* 2015 Oct 1 */ + case 'M j, Y': /* Oct 1, 2015 */ + case 'j M, Y': /* 1 Oct, 2015 */ + + $search = ['%Y', '%M', '%j']; + $replace = [$year, A::t('i18n', 'monthNames.abbreviated.'.(int)$month), (int)$day]; + break; + + case 'Y F d': /* 2015 October 01 */ + case 'F d Y': /* October 01 2015 */ + case 'd F Y': /* 01 October 2015 */ + + $search = ['%Y', '%F', '%d']; + $replace = [$year, A::t('i18n', 'monthNames.wide.'.(int)$month), $day]; + break; + + case 'Y F j': /* 2015 October 1 */ + case 'F j, Y': /* October 1, 2015 */ + case 'j F, Y': /* 1 October, 2015 */ + + $search = ['%Y', '%F', '%j']; + $replace = [$year, A::t('i18n', 'monthNames.wide.'.(int)$month), (int)$day]; + break; + + /* + |--------------------------------------------------- + | Time Formats + |--------------------------------------------------- + */ + case 'H:i:s': /* 13:53:20 */ + case 'h:i:s': /* 01:53:20 */ + case 'g:i:s': /* 1:53:20 */ + + $search = ['%H', '%h', '%g', '%i', '%s']; + $replace = [$hour24, $hour12, (int)$hour12, $minute, $second]; + break; + + case 'h:i a': /* 01:47 pm */ + case 'g:i a': /* 1:47 pm */ + + $search = ['%h', '%g', '%i', '%a']; + $replace = [$hour12, (int)$hour12, $minute, strtolower($amPm)]; + break; + + case 'h:i A': /* 01:47 PM */ + case 'g:i A': /* 1:47 PM */ + + $search = ['%h', '%g', '%i', '%A']; + $replace = [$hour12, (int)$hour12, $minute, strtoupper($amPm)]; + break; + + case 'H:i': /* 13:47 */ + case 'h:i': /* 01:47 */ + case 'g:i': /* 1:47 */ + + $search = ['%H', '%h', '%g', '%i']; + $replace = [$hour24, $hour12, (int)$hour12, $minute]; + break; + + /* + |--------------------------------------------------- + | DateTime Formats + |--------------------------------------------------- + */ + case 'Y-m-d H:i:s': /* 2015-01-31 13:02:59 */ + case 'm-d-Y H:i:s': /* 01-31-2015 13:02:59 */ + case 'd-m-Y H:i:s': /* 31-01-2015 13:02:59 */ + case 'm-d-Y h:i:s': /* 01-31-2015 01:02:59 */ + case 'd-m-Y h:i:s': /* 31-01-2015 01:02:59 */ + + $search = ['%Y', '%m', '%d', '%H', '%h', '%g', '%i', '%s']; + $replace = [$year, $month, $day, $hour24, $hour12, (int)$hour12, $minute, $second]; + break; + + case 'm-d-Y g:ia': /* 2015-01-31 1:02pm */ + case 'd-m-Y g:ia': /* 31-01-2015 1:02pm */ + + $search = ['%Y', '%m', '%d', '%g', '%i', '%a']; + $replace = [$year, $month, $day, (int)$hour12, $minute, strtolower($amPm)]; + break; + + case 'M d, Y g:ia': /* Oct 09, 2015 1:02pm */ + case 'd M, Y g:ia': /* 09 Oct, 2015 1:02pm */ + + $monthAbbrev = A::t('i18n', 'monthNames.abbreviated.'.(int)$month); + $search = ['%Y', '%M', '%d', '%g', '%i', '%a']; + $replace = [$year, $monthAbbrev, $day, (int)$hour12, $minute, strtolower($amPm)]; + break; + + case 'F j Y, g:ia': /* October 1 2015, 1:02pm */ + case 'j F Y, g:ia': /* 1 October 2015, 1:02pm */ + + $monthWide = A::t('i18n', 'monthNames.wide.'.(int)$month); + $search = ['%Y', '%F', '%j', '%g', '%i', '%a']; + $replace = [$year, $monthWide, (int)$day, (int)$hour12, $minute, strtolower($amPm)]; + break; + + case 'D, F j Y g:ia': /* Mon, October 1 2015 1:02pm */ + case 'D, M d Y g:ia': /* Mon, Oct 1 2015 1:02pm */ + + $monthWide = A::t('i18n', 'monthNames.wide.'.(int)$month); + $monthAbbrev = A::t('i18n', 'monthNames.abbreviated.'.(int)$month); + $weekDayAbbrev = A::t('i18n', 'weekDayNames.abbreviated.'.(int)$weekDay); + $search = ['%Y', '%F', '%M', '%j', '%d', '%D', '%g', '%i', '%a']; + $replace = [ + $year, + $monthWide, + $monthAbbrev, + (int)$day, + $day, + $weekDayAbbrev, + (int)$hour12, + $minute, + strtolower($amPm) + ]; + break; + + default: + $result = $date; + break; + } + + if ( ! empty($search) && ! empty($replace)) { + $result = str_replace($search, $replace, $convertedFormat); + } + } + + return $result; + } + + /** + * Returns array of datetime formats supported by system + * + * @return array + */ + public static function getDateTimeFormats() + { + $result = []; + + foreach (self::$_arrDateTimeFormats as $key => $dateTimeFormat) { + $result[$key] = $dateTimeFormat['preview']; + } + + return $result; + } + + /** + * Returns array of date formats supported by system + * + * @return array + */ + public static function getDateFormats() + { + $result = []; + + foreach (self::$_arrDateFormats as $key => $dateFormat) { + $result[$key] = $dateFormat['preview']; + } + + return $result; + } + + /** + * Returns array of time formats supported by system + * + * @return array + */ + public static function getTimeFormats() + { + $result = []; + + foreach (self::$_arrTimeFormats as $key => $timeFormat) { + $result[$key] = $timeFormat['preview']; + } + + return $result; + } + + /** + * Returns array of short time formats supported by system + * + * @return array + */ + public static function getShortTimeFormats() + { + $result = []; + + foreach (self::$_arrShortTimeFormats as $key => $timeFormat) { + $result[$key] = $timeFormat['preview']; + } + + return $result; + } } diff --git a/framework/helpers/widgets/CFormView.php b/framework/helpers/widgets/CFormView.php index c9aac59..2c4e313 100644 --- a/framework/helpers/widgets/CFormView.php +++ b/framework/helpers/widgets/CFormView.php @@ -118,15 +118,15 @@ class CFormView extends CWidgs * 'return'=>true, * )); */ - public static function init($params = array()) - { - parent::init($params); + public static function init($params = []) + { + parent::init($params); $output = ''; $action = self::params('action', ''); $method = self::params('method', 'post'); - $htmlOptions = self::params('htmlOptions', array(), 'is_array'); - $autoGenerateId = self::params('htmlOptions.autoGenerateId', false); + $htmlOptions = self::params('htmlOptions', [], 'is_array'); + $autoGenerateId = self::params('htmlOptions.autoGenerateId', false); $formName = self::params('htmlOptions.name', ''); $requiredFieldsAlert = self::params('requiredFieldsAlert', false); $fields = self::params('fields', array()); @@ -216,8 +216,8 @@ public static function init($params = array()) $content .= self::_formField($iField, $iFieldInfo, $events, $formName, $autoGenerateId, array('fieldWrapperTag' => $fieldWrapperTag, 'fieldWrapperClass' => $fieldWrapperClass)); } $tabsCount++; - $tabs[$legend] = array('href' => '#tab' . $field . $tabsCount, 'id' => 'tab' . $field . $tabsCount, 'content' => $content); - } else { + $tabs[$legend] = ['href' => '#tab'.$field.$tabsCount, 'id' => 'tab'.$field.$tabsCount, 'content' => $content]; + } else { $output .= CHtml::openTag('fieldset') . self::NL; $output .= CHtml::tag('legend', array(), $legend, true) . self::NL; foreach ($fieldInfo as $iField => $iFieldInfo) { @@ -312,9 +312,9 @@ public static function init($params = array()) * @param array $params * @see init() */ - private static function _formField($field, $fieldInfo, $events, $formName = '', $autoGenerateId = false, $params = array()) - { - $output = ''; + private static function _formField($field, $fieldInfo, $events, $formName = '', $autoGenerateId = false, $params = []) + { + $output = ''; $type = strtolower(self::keyAt('type', $fieldInfo, 'textbox')); $value = self::keyAt('value', $fieldInfo, ''); @@ -374,8 +374,8 @@ private static function _formField($field, $fieldInfo, $events, $formName = '', if ($preview == true && !empty($value)) { $fieldHtml = CHtml::openTag('div', array('style' => 'display:inline-block;')); - $matches = array(); - if (preg_match('/vimeo\./', $value)) { + $matches = []; + if (preg_match('/vimeo\./', $value)) { preg_match('/^(?:http(?:s)?:\/\/)?(?:www\.)?vimeo.com\/([0-9]+)/i', $value, $matches); $id = $matches[1]; $fieldHtml .= '<iframe width="240" height="140" src="https://player.vimeo.com/video/' . $id . '" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe><br>'; @@ -554,8 +554,8 @@ private static function _formField($field, $fieldInfo, $events, $formName = '', $fieldHtml = CHtml::checkBoxList($field, $selectedValues, $data, $htmlOptions); } else { if ($emptyOption) { - $data = array('' => $emptyValue) + $data; - } + $data = ['' => $emptyValue] + $data; + } $htmlOptions['multiple'] = $multiple; $fieldHtml = CHtml::dropDownList($field, $selectedValues, $data, $htmlOptions); } @@ -589,8 +589,8 @@ private static function _formField($field, $fieldInfo, $events, $formName = '', $showImageSize = (bool)self::keyAt('imageOptions.showImageSize', $fieldInfo, false); $showImageDimensions = (bool)self::keyAt('imageOptions.showImageDimensions', $fieldInfo, false); $imageClass = self::keyAt('imageOptions.imageClass', $fieldInfo, ''); - $imageHtmlOptions = array(); - if (!empty($imageClass)) $imageHtmlOptions['class'] = $imageClass; + $imageHtmlOptions = []; + if (!empty($imageClass)) $imageHtmlOptions['class'] = $imageClass; // Delete link options $showDeleteLink = (bool)self::keyAt('deleteOptions.showLink', $fieldInfo, false); $deleteLinkPath = self::keyAt('deleteOptions.linkUrl', $fieldInfo, ''); @@ -671,9 +671,9 @@ private static function _formField($field, $fieldInfo, $events, $formName = '', $showFileSize = (bool)self::keyAt('iconOptions.showFileSize', $fieldInfo, false); $filePath = self::keyAt('fileOptions.filePath', $fieldInfo, ''); $fileDownload = self::keyAt('download', $fieldInfo, false); - - $imageHtmlOptions = array(); - if (!empty($imageClass)) $imageHtmlOptions['class'] = $imageClass; + + $imageHtmlOptions = []; + if (!empty($imageClass)) $imageHtmlOptions['class'] = $imageClass; // Delete link options $showDeleteLink = (bool)self::keyAt('deleteOptions.showLink', $fieldInfo, false); $deleteLinkPath = self::keyAt('deleteOptions.linkUrl', $fieldInfo, ''); From feafa2b2ffa01c72606948a10d0a76e4f3185db7 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Fri, 11 Dec 2020 12:39:18 +0200 Subject: [PATCH 42/45] Removed magic_quotes functionality from all code --- .../vendors/phpmailer/class.phpmailer.php | 39 ++++++++++--------- .../vendors/tcpdf/include/tcpdf_static.php | 20 +++++++--- 2 files changed, 35 insertions(+), 24 deletions(-) diff --git a/framework/vendors/phpmailer/class.phpmailer.php b/framework/vendors/phpmailer/class.phpmailer.php index dc2f2ef..4de4683 100644 --- a/framework/vendors/phpmailer/class.phpmailer.php +++ b/framework/vendors/phpmailer/class.phpmailer.php @@ -23,6 +23,7 @@ * #002 - 26.06.2012 : commented echo invalid_address (doesn't present in current version) * #003 - 13.03.2015 : added auto include of class.smtp.php * #004 - 14.12.2016 : default CharSet changed from 'iso-8859-1' to 'utf-8' + * #005 - 11.12.2020 : commented magic_quotes functionality */ /** @@ -2711,26 +2712,28 @@ protected function encodeFile($path, $encoding = 'base64') if (!is_readable($path)) { throw new phpmailerException($this->lang('file_open') . $path, self::STOP_CONTINUE); } - $magic_quotes = get_magic_quotes_runtime(); - if ($magic_quotes) { - if (version_compare(phpversion(), '5.3.0', '<')) { - set_magic_quotes_runtime(false); - } else { - //Doesn't exist in PHP 5.4, but we don't need to check because - //get_magic_quotes_runtime always returns false in 5.4+ - //so it will never get here - ini_set('magic_quotes_runtime', false); - } - } + //#005 + //$magic_quotes = get_magic_quotes_runtime(); + //if ($magic_quotes) { + // if (version_compare(phpversion(), '5.3.0', '<')) { + // set_magic_quotes_runtime(false); + // } else { + // //Doesn't exist in PHP 5.4, but we don't need to check because + // //get_magic_quotes_runtime always returns false in 5.4+ + // //so it will never get here + // ini_set('magic_quotes_runtime', false); + // } + //} $file_buffer = file_get_contents($path); $file_buffer = $this->encodeString($file_buffer, $encoding); - if ($magic_quotes) { - if (version_compare(phpversion(), '5.3.0', '<')) { - set_magic_quotes_runtime($magic_quotes); - } else { - ini_set('magic_quotes_runtime', $magic_quotes); - } - } + //#005 + //if ($magic_quotes) { + // if (version_compare(phpversion(), '5.3.0', '<')) { + // set_magic_quotes_runtime($magic_quotes); + // } else { + // ini_set('magic_quotes_runtime', $magic_quotes); + // } + //} return $file_buffer; } catch (Exception $exc) { $this->setError($exc->getMessage()); diff --git a/framework/vendors/tcpdf/include/tcpdf_static.php b/framework/vendors/tcpdf/include/tcpdf_static.php index 16353e0..1681001 100644 --- a/framework/vendors/tcpdf/include/tcpdf_static.php +++ b/framework/vendors/tcpdf/include/tcpdf_static.php @@ -41,6 +41,12 @@ * @version 1.1.2 */ +/** + * ApPHP Changes to compatible this class with ApPHP Framework: + * #001 - 11.12.2020 : commented magic_quotes functionality + */ + + /** * @class TCPDF_STATIC * Static methods used by the TCPDF class. @@ -139,9 +145,10 @@ public static function set_mqr($mqr) { $version = PHP_VERSION; define('PHP_VERSION_ID', (($version[0] * 10000) + ($version[2] * 100) + $version[4])); } - if (PHP_VERSION_ID < 50300) { - @set_magic_quotes_runtime($mqr); - } + //#001 + //if (PHP_VERSION_ID < 50300) { + // @set_magic_quotes_runtime($mqr); + //} } /** @@ -155,9 +162,10 @@ public static function get_mqr() { $version = PHP_VERSION; define('PHP_VERSION_ID', (($version[0] * 10000) + ($version[2] * 100) + $version[4])); } - if (PHP_VERSION_ID < 50300) { - return @get_magic_quotes_runtime(); - } + //#001 + //if (PHP_VERSION_ID < 50300) { + // return @get_magic_quotes_runtime(); + //} return 0; } From 6405d573f3af30b676f82f8fbaa7086732855e34 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <> Date: Sat, 12 Dec 2020 17:18:59 +0200 Subject: [PATCH 43/45] Changes in AR methods definitions --- framework/db/CActiveRecord.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/framework/db/CActiveRecord.php b/framework/db/CActiveRecord.php index 797c3d1..d6d72ba 100644 --- a/framework/db/CActiveRecord.php +++ b/framework/db/CActiveRecord.php @@ -714,7 +714,7 @@ public function chunk(array $conditions = [], array $params = [], int $size = 0, /** * This method queries your database to find first related object * Ex.: find('postID = :postID AND isActive = :isActive', [':postID'=>10, ':isActive'=>1]); - * Ex.: find(['condition'=>'postID = :postID AND isActive = :isActive', 'order|orderBy'=>'id DESC'], 'params'=>[':postID'=>10, ':isActive'=>1]); + * Ex.: find(['condition'=>'postID = :postID AND isActive = :isActive', 'order|orderBy'=>'id DESC'], [':postID'=>10, ':isActive'=>1]); * * @param mixed $conditions * @param array $params @@ -773,7 +773,7 @@ public function find($conditions = '', $params = [], $cacheId = false) /** * This method queries your database to find related objects by PK * Ex.: findByPk($pk, 'postID = :postID AND isActive = :isActive', array(':postID'=>10, ':isActive'=>1)); - * Ex.: findByPk($pk, array('condition'=>'postID = :postID AND isActive = :isActive', 'order|orderBy'=>'id DESC'), 'params'=>array(':postID'=>10, ':isActive'=>1)); + * Ex.: findByPk($pk, array('condition'=>'postID = :postID AND isActive = :isActive', 'order|orderBy'=>'id DESC'), array(':postID'=>10, ':isActive'=>1)); * * @param string $pk * @param mixed $conditions @@ -832,7 +832,7 @@ public function findByPk($pk, $conditions = '', $params = [], $cacheId = false) /** * This method queries your database to find related objects by attributes * Ex.: findByAttributes($attributes, 'postID = :postID AND isActive = :isActive', array(':postID'=>10, ':isActive'=>1)); - * Ex.: findByAttributes($attributes, array('condition'=>'postID = :postID AND isActive = :isActive', 'order|orderBy'=>'id DESC', 'limit'=>'0, 10'), 'params'=>array(':postID'=>10, ':isActive'=>1)); + * Ex.: findByAttributes($attributes, array('condition'=>'postID = :postID AND isActive = :isActive', 'order|orderBy'=>'id DESC', 'limit'=>'0, 10'), array(':postID'=>10, ':isActive'=>1)); * Ex.: $attributes = array('first_name'=>$firstName, 'last_name'=>$lastName); * * @param array $attributes From fb0aec90219af39620ecf441fadda78ed95ae858 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <leumas.a@gmail.com> Date: Wed, 13 Jan 2021 12:11:31 +0200 Subject: [PATCH 44/45] Fix: CSS error in debug panel --- framework/core/CDebug.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/core/CDebug.php b/framework/core/CDebug.php index c892f73..7f7cfd2 100644 --- a/framework/core/CDebug.php +++ b/framework/core/CDebug.php @@ -401,7 +401,7 @@ public static function displayInfo() #debug-panel fieldset legend ul li.title > .item-debug {display:none;} #debug-panel fieldset legend ul li.item a {display:block;visibility:hidden;} #debug-panel fieldset legend ul li.item a:first-letter {visibility:visible !important;} - #debug-panel fieldset legend ul li.item {width:30px; height:15px; margin-bottom:3px;) + #debug-panel fieldset legend ul li.item {width:30px; height:15px; margin-bottom:3px;} } </style>'; From 6781d6a5bf41afe332115fbeac75259211bbf952 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan <leumas.a@gmail.com> Date: Fri, 22 Jan 2021 10:29:04 +0200 Subject: [PATCH 45/45] PHP7 fix in nusoap --- framework/vendors/nusoap/nusoap.php | 61 +++++++++++++++-------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/framework/vendors/nusoap/nusoap.php b/framework/vendors/nusoap/nusoap.php index 4e58b01..8f8f2e0 100644 --- a/framework/vendors/nusoap/nusoap.php +++ b/framework/vendors/nusoap/nusoap.php @@ -55,6 +55,7 @@ * 07/07/2020 - class declaration changed to PHP5-7 * 07/07/2020 - undefined var fix * 02/10/2020 - removed using of globals array + * 22/01/2021 - $HTTP_SERVER_VARS replaced with $_SERVER */ /* load classes @@ -3625,14 +3626,14 @@ function __construct($wsdl=false){ parent::nusoap_base(); // turn on debugging? global $debug; - global $HTTP_SERVER_VARS; + global $_SERVER; if (isset($_SERVER)) { $this->debug("_SERVER is defined:"); $this->appendDebug($this->varDump($_SERVER)); - } elseif (isset($HTTP_SERVER_VARS)) { + } elseif (isset($_SERVER)) { $this->debug("HTTP_SERVER_VARS is defined:"); - $this->appendDebug($this->varDump($HTTP_SERVER_VARS)); + $this->appendDebug($this->varDump($_SERVER)); } else { $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined."); } @@ -3648,8 +3649,8 @@ function __construct($wsdl=false){ $this->debug_flag = substr($v, 6); } } - } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { - $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']); + } elseif (isset($_SERVER['QUERY_STRING'])) { + $qs = explode('&', $_SERVER['QUERY_STRING']); foreach ($qs as $v) { if (substr($v, 0, 6) == 'debug=') { $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2"); @@ -3681,24 +3682,24 @@ function __construct($wsdl=false){ /** * processes request and returns response * - * @param string $data usually is the value of $HTTP_RAW_POST_DATA + * @param string $data usually is the value of POST data * @access public */ function service($data){ - global $HTTP_SERVER_VARS; + global $_SERVER; if (isset($_SERVER['REQUEST_METHOD'])) { $rm = $_SERVER['REQUEST_METHOD']; - } elseif (isset($HTTP_SERVER_VARS['REQUEST_METHOD'])) { - $rm = $HTTP_SERVER_VARS['REQUEST_METHOD']; + } elseif (isset($_SERVER['REQUEST_METHOD'])) { + $rm = $_SERVER['REQUEST_METHOD']; } else { $rm = ''; } if (isset($_SERVER['QUERY_STRING'])) { $qs = $_SERVER['QUERY_STRING']; - } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { - $qs = $HTTP_SERVER_VARS['QUERY_STRING']; + } elseif (isset($_SERVER['QUERY_STRING'])) { + $qs = $_SERVER['QUERY_STRING']; } else { $qs = ''; } @@ -3769,7 +3770,7 @@ function service($data){ * @access private */ function parse_http_headers() { - global $HTTP_SERVER_VARS; + global $_SERVER; $this->request = ''; $this->SOAPAction = ''; @@ -3832,9 +3833,9 @@ function parse_http_headers() { $this->request .= "$k: $v\r\n"; $this->debug("$k: $v"); } - } elseif (is_array($HTTP_SERVER_VARS)) { + } elseif (is_array($_SERVER)) { $this->debug("In parse_http_headers, use HTTP_SERVER_VARS"); - foreach ($HTTP_SERVER_VARS as $k => $v) { + foreach ($_SERVER as $k => $v) { if (substr($k, 0, 5) == 'HTTP_') { $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); $k = strtolower(substr($k, 5)); } else { @@ -4409,7 +4410,7 @@ function add_to_map($methodname,$in,$out){ * @access public */ function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=false,$style=false,$use=false,$documentation='',$encodingStyle=''){ - global $HTTP_SERVER_VARS; + global $_SERVER; if($this->externalWSDLURL){ die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.'); @@ -4429,11 +4430,11 @@ function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=fa if (isset($_SERVER)) { $SERVER_NAME = $_SERVER['SERVER_NAME']; $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; - $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'); - } elseif (isset($HTTP_SERVER_VARS)) { - $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; - $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; - $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'; + $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : 'off'); + } elseif (isset($_SERVER)) { + $SERVER_NAME = $_SERVER['SERVER_NAME']; + $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; + $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : 'off'; } else { $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); } @@ -4498,18 +4499,18 @@ function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){ */ function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false) { - global $HTTP_SERVER_VARS; + global $_SERVER; if (isset($_SERVER)) { $SERVER_NAME = $_SERVER['SERVER_NAME']; $SERVER_PORT = $_SERVER['SERVER_PORT']; $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; - $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'); - } elseif (isset($HTTP_SERVER_VARS)) { - $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; - $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT']; - $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; - $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'; + $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : 'off'); + } elseif (isset($_SERVER)) { + $SERVER_NAME = $_SERVER['SERVER_NAME']; + $SERVER_PORT = $_SERVER['SERVER_PORT']; + $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; + $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : 'off'; } else { $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); } @@ -5326,12 +5327,12 @@ function getTypeDef($type, $ns) { * @access private */ function webDescription(){ - global $HTTP_SERVER_VARS; + global $_SERVER; if (isset($_SERVER)) { $PHP_SELF = $_SERVER['PHP_SELF']; - } elseif (isset($HTTP_SERVER_VARS)) { - $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF']; + } elseif (isset($_SERVER)) { + $PHP_SELF = $_SERVER['PHP_SELF']; } else { $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); }