From 6f526597536ac4d7e0ef763be929115cf8170564 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Tue, 22 Oct 2013 13:25:26 +0200 Subject: [PATCH 01/40] no need to check for trait_exists in autoloader anymore --- framework/yii/BaseYii.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/framework/yii/BaseYii.php b/framework/yii/BaseYii.php index 49499fb..ad93d42 100644 --- a/framework/yii/BaseYii.php +++ b/framework/yii/BaseYii.php @@ -335,8 +335,7 @@ class BaseYii include($classFile); - if (YII_DEBUG && !class_exists($className, false) && !interface_exists($className, false) && - (!function_exists('trait_exists') || !trait_exists($className, false))) { + if (YII_DEBUG && !class_exists($className, false) && !interface_exists($className, false) && !trait_exists($className, false)) { throw new UnknownClassException("Unable to find '$className' in file: $classFile"); } } From a6b7d75b71eeed5ea11ea23871511d309bf02019 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 23 Oct 2013 01:43:47 +0200 Subject: [PATCH 02/40] added replacement class for intl MessageFormatter --- framework/yii/i18n/BaseMessageFormatter.php | 168 ++++++++++++++++++++++++++++ framework/yii/i18n/MessageFormatter.php | 4 + 2 files changed, 172 insertions(+) create mode 100644 framework/yii/i18n/BaseMessageFormatter.php diff --git a/framework/yii/i18n/BaseMessageFormatter.php b/framework/yii/i18n/BaseMessageFormatter.php new file mode 100644 index 0000000..73968c0 --- /dev/null +++ b/framework/yii/i18n/BaseMessageFormatter.php @@ -0,0 +1,168 @@ + + * @since 2.0 + */ +class BaseMessageFormatter +{ + private $_locale; + private $_pattern; + + /** + * Constructs a new Message Formatter + * @link http://php.net/manual/en/messageformatter.create.php + * @param string $locale The locale to use when formatting arguments + * @param string $pattern The pattern string to stick arguments into. + * The pattern uses an 'apostrophe-friendly' syntax; it is run through + * umsg_autoQuoteApostrophe before being interpreted. + */ + public function __construct($locale, $pattern) + { + $this->_locale = $locale; + $this->_pattern = $pattern; + } + + /** + * Constructs a new Message Formatter + * @link http://php.net/manual/en/messageformatter.create.php + * @param string $locale The locale to use when formatting arguments + * @param string $pattern The pattern string to stick arguments into. + * The pattern uses an 'apostrophe-friendly' syntax; it is run through + * umsg_autoQuoteApostrophe before being interpreted. + * @return MessageFormatter The formatter object + */ + public static function create($locale, $pattern) + { + return new static($locale, $pattern); + } + + /** + * Format the message + * @link http://php.net/manual/en/messageformatter.format.php + * @param array $args Arguments to insert into the format string + * @return string The formatted string, or FALSE if an error occurred + */ + public function format(array $args) + { + return static::formatMessage($this->_locale, $this->_pattern, $args); + } + + /** + * Quick format message + * @link http://php.net/manual/en/messageformatter.formatmessage.php + * @param string $locale The locale to use for formatting locale-dependent parts + * @param string $pattern The pattern string to insert things into. + * The pattern uses an 'apostrophe-friendly' syntax; it is run through + * umsg_autoQuoteApostrophe before being interpreted. + * @param array $args The array of values to insert into the format string + * @return string The formatted pattern string or FALSE if an error occurred + */ + public static function formatMessage($locale, $pattern, array $args) + { + // TODO implement plural format + + $a = []; + foreach($args as $name => $value) { + $a['{' . $name . '}'] = $value; + } + return strtr($pattern, $a); + } + + /** + * Parse input string according to pattern + * @link http://php.net/manual/en/messageformatter.parse.php + * @param string $value The string to parse + * @return array An array containing the items extracted, or FALSE on error + */ + public function parse ($value) + { + throw new NotSupportedException('You have to install PHP intl extension to use this feature.'); + } + + /** + * Quick parse input string + * @link http://php.net/manual/en/messageformatter.parsemessage.php + * @param string $locale The locale to use for parsing locale-dependent parts + * @param string $pattern The pattern with which to parse the value. + * @param string $source The string to parse, conforming to the pattern. + * @return array An array containing items extracted, or FALSE on error + */ + public static function parseMessage ($locale, $pattern, $source) + { + throw new NotSupportedException('You have to install PHP intl extension to use this feature.'); + } + + /** + * Set the pattern used by the formatter + * @link http://php.net/manual/en/messageformatter.setpattern.php + * @param string $pattern The pattern string to use in this message formatter. + * The pattern uses an 'apostrophe-friendly' syntax; it is run through + * umsg_autoQuoteApostrophe before being interpreted. + * @return bool TRUE on success or FALSE on failure. + */ + public function setPattern ($pattern) + { + $this->_pattern = $pattern; + return true; + } + + /** + * Get the pattern used by the formatter + * @link http://php.net/manual/en/messageformatter.getpattern.php + * @return string The pattern string for this message formatter + */ + public function getPattern() + { + return $this->_pattern; + } + + /** + * Get the locale for which the formatter was created. + * @link http://php.net/manual/en/messageformatter.getlocale.php + * @return string The locale name + */ + public function getLocale() + { + return $this->_locale; + } + + /** + * Get the error code from last operation + * @link http://php.net/manual/en/messageformatter.geterrorcode.php + * @return int The error code, one of UErrorCode values. Initial value is U_ZERO_ERROR. + */ + public function getErrorCode() + { + return 0; + } + + /** + * Get the error text from the last operation + * @link http://php.net/manual/en/messageformatter.geterrormessage.php + * @return string Description of the last error. + */ + public function getErrorMessage() + { + return ''; + } +} + +if (!class_exists('MessageFormatter', false)) { + class_alias('yii\\i18n\\BaseMessageFormatter', 'MessageFormatter'); +} + diff --git a/framework/yii/i18n/MessageFormatter.php b/framework/yii/i18n/MessageFormatter.php index 93c4563..6521d65 100644 --- a/framework/yii/i18n/MessageFormatter.php +++ b/framework/yii/i18n/MessageFormatter.php @@ -7,6 +7,10 @@ namespace yii\i18n; +if (!class_exists('MessageFormatter', false)) { + require_once(__DIR__ . '/BaseMessageFormatter.php'); +} + /** * MessageFormatter is an enhanced version of PHP intl class that no matter which PHP and ICU versions are used: * From 553ac1f157004f70c9ea8e23fffcb3b47e40a9a9 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 23 Oct 2013 01:45:12 +0200 Subject: [PATCH 03/40] as we have a replacement, do not check for intl MessageFormatter --- framework/yii/i18n/I18N.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/yii/i18n/I18N.php b/framework/yii/i18n/I18N.php index 779d89f..57978a0 100644 --- a/framework/yii/i18n/I18N.php +++ b/framework/yii/i18n/I18N.php @@ -78,7 +78,7 @@ class I18N extends Component return $message; } - if (class_exists('MessageFormatter', false) && preg_match('~{\s*[\d\w]+\s*,~u', $message)) { + if (preg_match('~{\s*[\d\w]+\s*,~u', $message)) { $formatter = new MessageFormatter($language, $message); if ($formatter === null) { Yii::warning("$language message from category $category is invalid. Message is: $message."); From 0c517ce969829d3f5beafb0fb3230a7a30185667 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 22 Oct 2013 21:06:17 -0400 Subject: [PATCH 04/40] Renamed InstallerPlugin to Plugin --- extensions/composer/composer.json | 2 +- .../composer/yii/composer/InstallerPlugin.php | 34 ---------------------- extensions/composer/yii/composer/Plugin.php | 34 ++++++++++++++++++++++ 3 files changed, 35 insertions(+), 35 deletions(-) delete mode 100644 extensions/composer/yii/composer/InstallerPlugin.php create mode 100644 extensions/composer/yii/composer/Plugin.php diff --git a/extensions/composer/composer.json b/extensions/composer/composer.json index 1b2d720..74295a0 100644 --- a/extensions/composer/composer.json +++ b/extensions/composer/composer.json @@ -22,7 +22,7 @@ "psr-0": { "yii\\composer\\": "" } }, "extra": { - "class": "yii\\composer\\InstallerPlugin" + "class": "yii\\composer\\Plugin" }, "require": { "composer-plugin-api": "1.0.0" diff --git a/extensions/composer/yii/composer/InstallerPlugin.php b/extensions/composer/yii/composer/InstallerPlugin.php deleted file mode 100644 index 0b8ce5f..0000000 --- a/extensions/composer/yii/composer/InstallerPlugin.php +++ /dev/null @@ -1,34 +0,0 @@ - - * @since 2.0 - */ -class InstallerPlugin implements PluginInterface -{ - /** - * @inheritdoc - */ - public function activate(Composer $composer, IOInterface $io) - { - $installer = new Installer($io, $composer); - $composer->getInstallationManager()->addInstaller($installer); - $file = rtrim($composer->getConfig()->get('vendor-dir'), '/') . '/yii-extensions.php'; - if (!is_file($file)) { - file_put_contents($file, " + * @since 2.0 + */ +class Plugin implements PluginInterface +{ + /** + * @inheritdoc + */ + public function activate(Composer $composer, IOInterface $io) + { + $installer = new Installer($io, $composer); + $composer->getInstallationManager()->addInstaller($installer); + $file = rtrim($composer->getConfig()->get('vendor-dir'), '/') . '/yii-extensions.php'; + if (!is_file($file)) { + file_put_contents($file, " Date: Tue, 22 Oct 2013 21:06:46 -0400 Subject: [PATCH 05/40] cleaned up Installer. --- extensions/composer/yii/composer/Installer.php | 41 ++------------------------ 1 file changed, 3 insertions(+), 38 deletions(-) diff --git a/extensions/composer/yii/composer/Installer.php b/extensions/composer/yii/composer/Installer.php index 8b7363c..0dda073 100644 --- a/extensions/composer/yii/composer/Installer.php +++ b/extensions/composer/yii/composer/Installer.php @@ -11,8 +11,6 @@ use Composer\Package\PackageInterface; use Composer\Installer\LibraryInstaller; use Composer\Repository\InstalledRepositoryInterface; use Composer\Script\CommandEvent; -use yii\console\Application; -use yii\console\Exception; /** * @author Qiang Xue @@ -20,11 +18,9 @@ use yii\console\Exception; */ class Installer extends LibraryInstaller { + const EXTRA_BOOTSTRAP = 'bootstrap'; const EXTRA_WRITABLE = 'writable'; const EXTRA_EXECUTABLE = 'executable'; - const EXTRA_CONFIG = 'yii-config'; - const EXTRA_COMMANDS = 'yii-commands'; - const EXTRA_BOOTSTRAP = 'bootstrap'; /** * @inheritdoc @@ -101,10 +97,10 @@ class Installer extends LibraryInstaller /** - * Sets the correct permissions of files and directories. + * Sets the correct permission for the files and directories listed in the extra section. * @param CommandEvent $event */ - public static function setPermissions($event) + public static function setPermission($event) { $options = array_merge([ self::EXTRA_WRITABLE => [], @@ -133,35 +129,4 @@ class Installer extends LibraryInstaller } } } - - /** - * Executes a yii command. - * @param CommandEvent $event - */ - public static function run($event) - { - $options = array_merge([ - self::EXTRA_COMMANDS => [], - ], $event->getComposer()->getPackage()->getExtra()); - - if (!isset($options[self::EXTRA_CONFIG])) { - throw new Exception('Please specify the "' . self::EXTRA_CONFIG . '" parameter in composer.json.'); - } - $configFile = getcwd() . '/' . $options[self::EXTRA_CONFIG]; - if (!is_file($configFile)) { - throw new Exception("Config file does not exist: $configFile"); - } - - require_once(__DIR__ . '/../../../yii2/yii/Yii.php'); - $application = new Application(require($configFile)); - $request = $application->getRequest(); - - foreach ((array)$options[self::EXTRA_COMMANDS] as $command) { - $params = str_getcsv($command, ' '); // see http://stackoverflow.com/a/6609509/291573 - $request->setParams($params); - list($route, $params) = $request->resolve(); - echo "Running command: yii {$command}\n"; - $application->runAction($route, $params); - } - } } From 8fc489091b8fb7ac98a50d27b060376f862b1f01 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 22 Oct 2013 21:13:57 -0400 Subject: [PATCH 06/40] removed InstallHandler. --- apps/advanced/composer.json | 4 +- apps/basic/composer.json | 6 +- docs/guide/apps-advanced.md | 4 +- docs/guide/apps-basic.md | 6 +- .../composer/yii/composer/InstallHandler.php | 97 ---------------------- extensions/jui/yii/jui/AccordionAsset.php | 1 + extensions/jui/yii/jui/Extension.php | 27 ++++++ 7 files changed, 38 insertions(+), 107 deletions(-) delete mode 100644 extensions/composer/yii/composer/InstallHandler.php create mode 100644 extensions/jui/yii/jui/Extension.php diff --git a/apps/advanced/composer.json b/apps/advanced/composer.json index 88522f2..46ef86a 100644 --- a/apps/advanced/composer.json +++ b/apps/advanced/composer.json @@ -20,12 +20,12 @@ }, "scripts": { "post-create-project-cmd": [ - "yii\\composer\\InstallHandler::setPermissions", + "yii\\composer\\Installer::setPermission", "./init" ] }, "extra": { - "yii-install-writable": [ + "writable": [ "backend/runtime", "backend/web/assets", diff --git a/apps/basic/composer.json b/apps/basic/composer.json index e9af8b7..93e8253 100644 --- a/apps/basic/composer.json +++ b/apps/basic/composer.json @@ -20,15 +20,15 @@ }, "scripts": { "post-create-project-cmd": [ - "yii\\composer\\InstallHandler::setPermissions" + "yii\\composer\\Installer::setPermission" ] }, "extra": { - "yii-install-writable": [ + "writable": [ "runtime", "web/assets" ], - "yii-install-executable": [ + "executable": [ "yii" ] } diff --git a/docs/guide/apps-advanced.md b/docs/guide/apps-advanced.md index 9c6532a..9669217 100644 --- a/docs/guide/apps-advanced.md +++ b/docs/guide/apps-advanced.md @@ -144,11 +144,11 @@ directory: }, "scripts": { "post-create-project-cmd": [ - "yii\\composer\\InstallHandler::setPermissions" + "yii\\composer\\Installer::setPermission" ] }, "extra": { - "yii-install-writable": [ + "writable": [ "backend/runtime", "backend/web/assets", diff --git a/docs/guide/apps-basic.md b/docs/guide/apps-basic.md index 0f366af..386c202 100644 --- a/docs/guide/apps-basic.md +++ b/docs/guide/apps-basic.md @@ -134,15 +134,15 @@ directory: }, "scripts": { "post-create-project-cmd": [ - "yii\\composer\\InstallHandler::setPermissions" + "yii\\composer\\Installer::setPermission" ] }, "extra": { - "yii-install-writable": [ + "writable": [ "runtime", "web/assets" ], - "yii-install-executable": [ + "executable": [ "yii" ] } diff --git a/extensions/composer/yii/composer/InstallHandler.php b/extensions/composer/yii/composer/InstallHandler.php deleted file mode 100644 index 289262f..0000000 --- a/extensions/composer/yii/composer/InstallHandler.php +++ /dev/null @@ -1,97 +0,0 @@ - - * @author Tobias Munk - * @since 2.0 - */ -class InstallHandler -{ - const PARAM_WRITABLE = 'yii-install-writable'; - const PARAM_EXECUTABLE = 'yii-install-executable'; - const PARAM_CONFIG = 'yii-install-config'; - const PARAM_COMMANDS = 'yii-install-commands'; - - /** - * Sets the correct permissions of files and directories. - * @param CommandEvent $event - */ - public static function setPermissions($event) - { - $options = array_merge([ - self::PARAM_WRITABLE => [], - self::PARAM_EXECUTABLE => [], - ], $event->getComposer()->getPackage()->getExtra()); - - foreach ((array)$options[self::PARAM_WRITABLE] as $path) { - echo "Setting writable: $path ..."; - if (is_dir($path)) { - chmod($path, 0777); - echo "done\n"; - } else { - echo "The directory was not found: " . getcwd() . DIRECTORY_SEPARATOR . $path; - return; - } - } - - foreach ((array)$options[self::PARAM_EXECUTABLE] as $path) { - echo "Setting executable: $path ..."; - if (is_file($path)) { - chmod($path, 0755); - echo "done\n"; - } else { - echo "\n\tThe file was not found: " . getcwd() . DIRECTORY_SEPARATOR . $path . "\n"; - return; - } - } - } - - /** - * Executes a yii command. - * @param CommandEvent $event - */ - public static function run($event) - { - $options = array_merge([ - self::PARAM_COMMANDS => [], - ], $event->getComposer()->getPackage()->getExtra()); - - if (!isset($options[self::PARAM_CONFIG])) { - throw new Exception('Please specify the "' . self::PARAM_CONFIG . '" parameter in composer.json.'); - } - $configFile = getcwd() . '/' . $options[self::PARAM_CONFIG]; - if (!is_file($configFile)) { - throw new Exception("Config file does not exist: $configFile"); - } - - require_once(__DIR__ . '/../../../yii2/yii/Yii.php'); - $application = new Application(require($configFile)); - $request = $application->getRequest(); - - foreach ((array)$options[self::PARAM_COMMANDS] as $command) { - $params = str_getcsv($command, ' '); // see http://stackoverflow.com/a/6609509/291573 - $request->setParams($params); - list($route, $params) = $request->resolve(); - echo "Running command: yii {$command}\n"; - $application->runAction($route, $params); - } - } -} diff --git a/extensions/jui/yii/jui/AccordionAsset.php b/extensions/jui/yii/jui/AccordionAsset.php index a032429..05c1e20 100644 --- a/extensions/jui/yii/jui/AccordionAsset.php +++ b/extensions/jui/yii/jui/AccordionAsset.php @@ -6,6 +6,7 @@ */ namespace yii\jui; + use yii\web\AssetBundle; /** diff --git a/extensions/jui/yii/jui/Extension.php b/extensions/jui/yii/jui/Extension.php new file mode 100644 index 0000000..4b680ce --- /dev/null +++ b/extensions/jui/yii/jui/Extension.php @@ -0,0 +1,27 @@ + + * @since 2.0 + */ +class Extension extends \yii\base\Extension +{ + /** + * @inheritdoc + */ + public static function init() + { + Yii::setAlias('@yii/jui', __DIR__); + } +} From de59556d2d6c56cbb08c3589ca66a35b9f1ce4bb Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 22 Oct 2013 21:18:41 -0400 Subject: [PATCH 07/40] adjusted basic app to use the new yii extension installer. --- apps/basic/config/console.php | 3 +-- apps/basic/config/web.php | 1 + apps/basic/web/index-test.php | 1 - apps/basic/web/index.php | 1 - apps/basic/yii | 1 - 5 files changed, 2 insertions(+), 5 deletions(-) diff --git a/apps/basic/config/console.php b/apps/basic/config/console.php index cc1cdb8..598316f 100644 --- a/apps/basic/config/console.php +++ b/apps/basic/config/console.php @@ -6,8 +6,7 @@ return [ 'preload' => ['log'], 'controllerPath' => dirname(__DIR__) . '/commands', 'controllerNamespace' => 'app\commands', - 'modules' => [ - ], + 'extensions' => require(__DIR__ . '/../vendor/yii-extensions.php'), 'components' => [ 'cache' => [ 'class' => 'yii\caching\FileCache', diff --git a/apps/basic/config/web.php b/apps/basic/config/web.php index 6e4d2a1..e27754f 100644 --- a/apps/basic/config/web.php +++ b/apps/basic/config/web.php @@ -3,6 +3,7 @@ $params = require(__DIR__ . '/params.php'); $config = [ 'id' => 'bootstrap', 'basePath' => dirname(__DIR__), + 'extensions' => require(__DIR__ . '/../vendor/yii-extensions.php'), 'components' => [ 'request' => [ 'enableCsrfValidation' => true, diff --git a/apps/basic/web/index-test.php b/apps/basic/web/index-test.php index c9bd338..1593164 100644 --- a/apps/basic/web/index-test.php +++ b/apps/basic/web/index-test.php @@ -10,7 +10,6 @@ defined('YII_ENV') or define('YII_ENV', 'test'); require_once(__DIR__ . '/../vendor/autoload.php'); require_once(__DIR__ . '/../vendor/yiisoft/yii2/yii/Yii.php'); -Yii::importNamespaces(require(__DIR__ . '/../vendor/composer/autoload_namespaces.php')); $config = require(__DIR__ . '/../config/web-test.php'); diff --git a/apps/basic/web/index.php b/apps/basic/web/index.php index 51673d3..e9eeb33 100644 --- a/apps/basic/web/index.php +++ b/apps/basic/web/index.php @@ -6,7 +6,6 @@ defined('YII_ENV') or define('YII_ENV', 'dev'); require(__DIR__ . '/../vendor/autoload.php'); require(__DIR__ . '/../vendor/yiisoft/yii2/yii/Yii.php'); -Yii::importNamespaces(require(__DIR__ . '/../vendor/composer/autoload_namespaces.php')); $config = require(__DIR__ . '/../config/web.php'); diff --git a/apps/basic/yii b/apps/basic/yii index cd979ca..9188f85 100755 --- a/apps/basic/yii +++ b/apps/basic/yii @@ -15,7 +15,6 @@ defined('STDIN') or define('STDIN', fopen('php://stdin', 'r')); require(__DIR__ . '/vendor/autoload.php'); require(__DIR__ . '/vendor/yiisoft/yii2/yii/Yii.php'); -Yii::importNamespaces(require(__DIR__ . '/vendor/composer/autoload_namespaces.php')); $config = require(__DIR__ . '/config/console.php'); From 9636b0fcb732030fc83304dbba03278b78134357 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 22 Oct 2013 21:19:37 -0400 Subject: [PATCH 08/40] removed Yii::importNamespaces() in favor of the new yii extension installer. --- framework/yii/BaseYii.php | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/framework/yii/BaseYii.php b/framework/yii/BaseYii.php index ad93d42..cf9a96f 100644 --- a/framework/yii/BaseYii.php +++ b/framework/yii/BaseYii.php @@ -110,33 +110,6 @@ class BaseYii } /** - * Imports a set of namespaces. - * - * By importing a namespace, the method will create an alias for the directory corresponding - * to the namespace. For example, if "foo\bar" is a namespace associated with the directory - * "path/to/foo/bar", then an alias "@foo/bar" will be created for this directory. - * - * This method is typically invoked in the bootstrap file to import the namespaces of - * the installed extensions. By default, Composer, when installing new extensions, will - * generate such a mapping file which can be loaded and passed to this method. - * - * @param array $namespaces the namespaces to be imported. The keys are the namespaces, - * and the values are the corresponding directories. - */ - public static function importNamespaces($namespaces) - { - foreach ($namespaces as $name => $path) { - if ($name !== '') { - $name = trim(strtr($name, ['\\' => '/', '_' => '/']), '/'); - if (is_array($path)) { - $path = reset($path); - } - static::setAlias('@' . $name, rtrim($path, '/\\') . '/' . $name); - } - } - } - - /** * Translates a path alias into an actual path. * * The translation is done according to the following procedure: From 10553b6afc56484b676bba4d3e2bed73d48a6778 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Tue, 22 Oct 2013 21:29:42 -0400 Subject: [PATCH 09/40] adjusted the advanced app to use the new yii composer extension installer. --- apps/advanced/backend/config/main.php | 1 + apps/advanced/console/config/main.php | 1 + apps/advanced/environments/dev/frontend/web/index.php | 1 - apps/advanced/environments/dev/yii | 1 - apps/advanced/environments/prod/frontend/web/index.php | 1 - apps/advanced/environments/prod/yii | 1 - apps/advanced/frontend/config/main.php | 1 + 7 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/advanced/backend/config/main.php b/apps/advanced/backend/config/main.php index f820f4e..9c33d1f 100644 --- a/apps/advanced/backend/config/main.php +++ b/apps/advanced/backend/config/main.php @@ -15,6 +15,7 @@ return [ 'preload' => ['log'], 'controllerNamespace' => 'backend\controllers', 'modules' => [], + 'extensions' => require(__DIR__ . '/../../vendor/yii-extensions.php'), 'components' => [ 'request' => [ 'enableCsrfValidation' => true, diff --git a/apps/advanced/console/config/main.php b/apps/advanced/console/config/main.php index fbf452a..17e79c7 100644 --- a/apps/advanced/console/config/main.php +++ b/apps/advanced/console/config/main.php @@ -15,6 +15,7 @@ return [ 'controllerNamespace' => 'console\controllers', 'modules' => [ ], + 'extensions' => require(__DIR__ . '/../../vendor/yii-extensions.php'), 'components' => [ 'db' => $params['components.db'], 'cache' => $params['components.cache'], diff --git a/apps/advanced/environments/dev/frontend/web/index.php b/apps/advanced/environments/dev/frontend/web/index.php index 9a7cbae..2113419 100644 --- a/apps/advanced/environments/dev/frontend/web/index.php +++ b/apps/advanced/environments/dev/frontend/web/index.php @@ -4,7 +4,6 @@ defined('YII_ENV') or define('YII_ENV', 'dev'); require(__DIR__ . '/../../vendor/autoload.php'); require(__DIR__ . '/../../vendor/yiisoft/yii2/yii/Yii.php'); -Yii::importNamespaces(require(__DIR__ . '/../../vendor/composer/autoload_namespaces.php')); $config = yii\helpers\ArrayHelper::merge( require(__DIR__ . '/../config/main.php'), diff --git a/apps/advanced/environments/dev/yii b/apps/advanced/environments/dev/yii index e7d5f6c..5d1cd90 100644 --- a/apps/advanced/environments/dev/yii +++ b/apps/advanced/environments/dev/yii @@ -16,7 +16,6 @@ defined('STDIN') or define('STDIN', fopen('php://stdin', 'r')); require(__DIR__ . '/vendor/autoload.php'); require(__DIR__ . '/vendor/yiisoft/yii2/yii/Yii.php'); -Yii::importNamespaces(require(__DIR__ . '/vendor/composer/autoload_namespaces.php')); $config = yii\helpers\ArrayHelper::merge( require(__DIR__ . '/console/config/main.php'), diff --git a/apps/advanced/environments/prod/frontend/web/index.php b/apps/advanced/environments/prod/frontend/web/index.php index cbd096b..fc62a78 100644 --- a/apps/advanced/environments/prod/frontend/web/index.php +++ b/apps/advanced/environments/prod/frontend/web/index.php @@ -4,7 +4,6 @@ defined('YII_ENV') or define('YII_ENV', 'prod'); require(__DIR__ . '/../../vendor/autoload.php'); require(__DIR__ . '/../../vendor/yiisoft/yii2/yii/Yii.php'); -Yii::importNamespaces(require(__DIR__ . '/../../vendor/composer/autoload_namespaces.php')); $config = yii\helpers\ArrayHelper::merge( require(__DIR__ . '/../config/main.php'), diff --git a/apps/advanced/environments/prod/yii b/apps/advanced/environments/prod/yii index 9e13eb2..b17d9a7 100644 --- a/apps/advanced/environments/prod/yii +++ b/apps/advanced/environments/prod/yii @@ -16,7 +16,6 @@ defined('STDIN') or define('STDIN', fopen('php://stdin', 'r')); require(__DIR__ . '/vendor/autoload.php'); require(__DIR__ . '/vendor/yiisoft/yii2/yii/Yii.php'); -Yii::importNamespaces(require(__DIR__ . '/vendor/composer/autoload_namespaces.php')); $config = yii\helpers\ArrayHelper::merge( require(__DIR__ . '/console/config/main.php'), diff --git a/apps/advanced/frontend/config/main.php b/apps/advanced/frontend/config/main.php index fca46d9..a6a3861 100644 --- a/apps/advanced/frontend/config/main.php +++ b/apps/advanced/frontend/config/main.php @@ -16,6 +16,7 @@ return [ 'modules' => [ 'gii' => 'yii\gii\Module' ], + 'extensions' => require(__DIR__ . '/../../vendor/yii-extensions.php'), 'components' => [ 'request' => [ 'enableCsrfValidation' => true, From d5fd2bfe981cbfe184eaf690e719b1a82395525c Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Wed, 23 Oct 2013 20:11:04 +0400 Subject: [PATCH 10/40] Removed re-declaration of $preload from Application --- framework/yii/base/Application.php | 4 ---- framework/yii/base/Module.php | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/framework/yii/base/Application.php b/framework/yii/base/Application.php index 27dc37d..49b52d9 100644 --- a/framework/yii/base/Application.php +++ b/framework/yii/base/Application.php @@ -85,10 +85,6 @@ abstract class Application extends Module */ public $sourceLanguage = 'en_US'; /** - * @var array IDs of the components that need to be loaded when the application starts. - */ - public $preload = []; - /** * @var Controller the currently active controller instance */ public $controller; diff --git a/framework/yii/base/Module.php b/framework/yii/base/Module.php index fefdf1d..4bc5351 100644 --- a/framework/yii/base/Module.php +++ b/framework/yii/base/Module.php @@ -41,7 +41,7 @@ abstract class Module extends Component */ public $params = []; /** - * @var array the IDs of the components or modules that should be preloaded when this module is created. + * @var array the IDs of the components or modules that should be preloaded right after initialization. */ public $preload = []; /** From 5b9b97276e7e8a5c59aeb63e4e6314e78e86cd8e Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 23 Oct 2013 19:13:04 +0200 Subject: [PATCH 11/40] implemented plural and select for fallback intl message formatter --- framework/yii/i18n/BaseMessageFormatter.php | 168 ----------- framework/yii/i18n/FallbackMessageFormatter.php | 306 +++++++++++++++++++++ framework/yii/i18n/MessageFormatter.php | 10 +- .../i18n/FallbackMessageFormatterTest.php | 155 +++++++++++ 4 files changed, 468 insertions(+), 171 deletions(-) delete mode 100644 framework/yii/i18n/BaseMessageFormatter.php create mode 100644 framework/yii/i18n/FallbackMessageFormatter.php create mode 100644 tests/unit/framework/i18n/FallbackMessageFormatterTest.php diff --git a/framework/yii/i18n/BaseMessageFormatter.php b/framework/yii/i18n/BaseMessageFormatter.php deleted file mode 100644 index 73968c0..0000000 --- a/framework/yii/i18n/BaseMessageFormatter.php +++ /dev/null @@ -1,168 +0,0 @@ - - * @since 2.0 - */ -class BaseMessageFormatter -{ - private $_locale; - private $_pattern; - - /** - * Constructs a new Message Formatter - * @link http://php.net/manual/en/messageformatter.create.php - * @param string $locale The locale to use when formatting arguments - * @param string $pattern The pattern string to stick arguments into. - * The pattern uses an 'apostrophe-friendly' syntax; it is run through - * umsg_autoQuoteApostrophe before being interpreted. - */ - public function __construct($locale, $pattern) - { - $this->_locale = $locale; - $this->_pattern = $pattern; - } - - /** - * Constructs a new Message Formatter - * @link http://php.net/manual/en/messageformatter.create.php - * @param string $locale The locale to use when formatting arguments - * @param string $pattern The pattern string to stick arguments into. - * The pattern uses an 'apostrophe-friendly' syntax; it is run through - * umsg_autoQuoteApostrophe before being interpreted. - * @return MessageFormatter The formatter object - */ - public static function create($locale, $pattern) - { - return new static($locale, $pattern); - } - - /** - * Format the message - * @link http://php.net/manual/en/messageformatter.format.php - * @param array $args Arguments to insert into the format string - * @return string The formatted string, or FALSE if an error occurred - */ - public function format(array $args) - { - return static::formatMessage($this->_locale, $this->_pattern, $args); - } - - /** - * Quick format message - * @link http://php.net/manual/en/messageformatter.formatmessage.php - * @param string $locale The locale to use for formatting locale-dependent parts - * @param string $pattern The pattern string to insert things into. - * The pattern uses an 'apostrophe-friendly' syntax; it is run through - * umsg_autoQuoteApostrophe before being interpreted. - * @param array $args The array of values to insert into the format string - * @return string The formatted pattern string or FALSE if an error occurred - */ - public static function formatMessage($locale, $pattern, array $args) - { - // TODO implement plural format - - $a = []; - foreach($args as $name => $value) { - $a['{' . $name . '}'] = $value; - } - return strtr($pattern, $a); - } - - /** - * Parse input string according to pattern - * @link http://php.net/manual/en/messageformatter.parse.php - * @param string $value The string to parse - * @return array An array containing the items extracted, or FALSE on error - */ - public function parse ($value) - { - throw new NotSupportedException('You have to install PHP intl extension to use this feature.'); - } - - /** - * Quick parse input string - * @link http://php.net/manual/en/messageformatter.parsemessage.php - * @param string $locale The locale to use for parsing locale-dependent parts - * @param string $pattern The pattern with which to parse the value. - * @param string $source The string to parse, conforming to the pattern. - * @return array An array containing items extracted, or FALSE on error - */ - public static function parseMessage ($locale, $pattern, $source) - { - throw new NotSupportedException('You have to install PHP intl extension to use this feature.'); - } - - /** - * Set the pattern used by the formatter - * @link http://php.net/manual/en/messageformatter.setpattern.php - * @param string $pattern The pattern string to use in this message formatter. - * The pattern uses an 'apostrophe-friendly' syntax; it is run through - * umsg_autoQuoteApostrophe before being interpreted. - * @return bool TRUE on success or FALSE on failure. - */ - public function setPattern ($pattern) - { - $this->_pattern = $pattern; - return true; - } - - /** - * Get the pattern used by the formatter - * @link http://php.net/manual/en/messageformatter.getpattern.php - * @return string The pattern string for this message formatter - */ - public function getPattern() - { - return $this->_pattern; - } - - /** - * Get the locale for which the formatter was created. - * @link http://php.net/manual/en/messageformatter.getlocale.php - * @return string The locale name - */ - public function getLocale() - { - return $this->_locale; - } - - /** - * Get the error code from last operation - * @link http://php.net/manual/en/messageformatter.geterrorcode.php - * @return int The error code, one of UErrorCode values. Initial value is U_ZERO_ERROR. - */ - public function getErrorCode() - { - return 0; - } - - /** - * Get the error text from the last operation - * @link http://php.net/manual/en/messageformatter.geterrormessage.php - * @return string Description of the last error. - */ - public function getErrorMessage() - { - return ''; - } -} - -if (!class_exists('MessageFormatter', false)) { - class_alias('yii\\i18n\\BaseMessageFormatter', 'MessageFormatter'); -} - diff --git a/framework/yii/i18n/FallbackMessageFormatter.php b/framework/yii/i18n/FallbackMessageFormatter.php new file mode 100644 index 0000000..16d38f5 --- /dev/null +++ b/framework/yii/i18n/FallbackMessageFormatter.php @@ -0,0 +1,306 @@ + + * @since 2.0 + */ +class FallbackMessageFormatter +{ + private $_locale; + private $_pattern; + private $_errorMessage = ''; + private $_errorCode = 0; + + /** + * Constructs a new Message Formatter + * @link http://php.net/manual/en/messageformatter.create.php + * @param string $locale The locale to use when formatting arguments + * @param string $pattern The pattern string to stick arguments into. + */ + public function __construct($locale, $pattern) + { + $this->_locale = $locale; + $this->_pattern = $pattern; + } + + /** + * Constructs a new Message Formatter + * @link http://php.net/manual/en/messageformatter.create.php + * @param string $locale The locale to use when formatting arguments + * @param string $pattern The pattern string to stick arguments into. + * @return MessageFormatter The formatter object + */ + public static function create($locale, $pattern) + { + return new static($locale, $pattern); + } + + /** + * Format the message + * @link http://php.net/manual/en/messageformatter.format.php + * @param array $args Arguments to insert into the format string + * @return string The formatted string, or `FALSE` if an error occurred + */ + public function format(array $args) + { + return static::formatMessage($this->_locale, $this->_pattern, $args); + } + + /** + * Quick format message + * @link http://php.net/manual/en/messageformatter.formatmessage.php + * @param string $locale The locale to use for formatting locale-dependent parts + * @param string $pattern The pattern string to insert things into. + * @param array $args The array of values to insert into the format string + * @return string The formatted pattern string or `FALSE` if an error occurred + */ + public static function formatMessage($locale, $pattern, array $args) + { + if (($tokens = static::tokenizePattern($pattern)) === false) { + return false; + } + foreach($tokens as $i => $token) { + if (is_array($token)) { + if (($tokens[$i] = static::parseToken($token, $args, $locale)) === false) { + return false; + } + } + } + return implode('', $tokens); + } + + /** + * Tokenizes a pattern by separating normal text from replaceable patterns + * @param string $pattern patter to tokenize + * @return array|bool array of tokens or false on failure + */ + private static function tokenizePattern($pattern) + { + $depth = 1; + if (($start = $pos = mb_strpos($pattern, '{')) === false) { + return [$pattern]; + } + $tokens = [mb_substr($pattern, 0, $pos)]; + while(true) { + $open = mb_strpos($pattern, '{', $pos + 1); + $close = mb_strpos($pattern, '}', $pos + 1); + if ($open === false && $close === false) { + break; + } + if ($open === false) { + $open = mb_strlen($pattern); + } + if ($close > $open) { + $depth++; + $pos = $open; + } else { + $depth--; + $pos = $close; + } + if ($depth == 0) { + $tokens[] = explode(',', mb_substr($pattern, $start + 1, $pos - $start - 1), 3); + $start = $pos + 1; + $tokens[] = mb_substr($pattern, $start, $open - $start); + $start = $open; + } + } + if ($depth != 0) { + return false; + } + return $tokens; + } + + /** + * Parses a token + * @param array $token the token to parse + * @param array $args arguments to replace + * @param string $locale the locale + * @return bool|string parsed token or false on failure + * @throws \yii\base\NotSupportedException when unsupported formatting is used. + */ + private static function parseToken($token, $args, $locale) + { + $param = trim($token[0]); + if (isset($args[$param])) { + $arg = $args[$param]; + } else { + return '{' . implode(',', $token) . '}'; + } + $type = isset($token[1]) ? trim($token[1]) : 'none'; + switch($type) + { + case 'number': + case 'date': + case 'time': + case 'spellout': + case 'ordinal': + case 'duration': + case 'choice': + case 'selectordinal': + throw new NotSupportedException("Message format '$type' is not supported. You have to install PHP intl extension to use this feature."); + case 'none': return $arg; + case 'select': + /* http://icu-project.org/apiref/icu4c/classicu_1_1SelectFormat.html + selectStyle = (selector '{' message '}')+ + */ + $select = static::tokenizePattern($token[2]); + $c = count($select); + $message = false; + for($i = 0; $i + 1 < $c; $i++) { + if (is_array($select[$i]) || !is_array($select[$i + 1])) { + return false; + } + $selector = trim($select[$i++]); + if ($message === false && $selector == 'other' || $selector == $arg) { + $message = implode(',', $select[$i]); + } + } + if ($message !== false) { + return static::formatMessage($locale, $message, $args); + } + break; + case 'plural': + /* http://icu-project.org/apiref/icu4c/classicu_1_1PluralFormat.html + pluralStyle = [offsetValue] (selector '{' message '}')+ + offsetValue = "offset:" number + selector = explicitValue | keyword + explicitValue = '=' number // adjacent, no white space in between + keyword = [^[[:Pattern_Syntax:][:Pattern_White_Space:]]]+ + message: see MessageFormat + */ + $plural = static::tokenizePattern($token[2]); + $c = count($plural); + $message = false; + $offset = 0; + for($i = 0; $i + 1 < $c; $i++) { + if (is_array($plural[$i]) || !is_array($plural[$i + 1])) { + return false; + } + $selector = trim($plural[$i++]); + if ($i == 1 && substr($selector, 0, 7) == 'offset:') { + $offset = (int) trim(mb_substr($selector, 7, ($pos = mb_strpos(str_replace(["\n", "\r", "\t"], ' ', $selector), ' ', 7)) - 7)); + $selector = trim(mb_substr($selector, $pos + 1)); + } + if ($message === false && $selector == 'other' || + $selector[0] == '=' && (int) mb_substr($selector, 1) == $arg || + $selector == 'zero' && $arg - $offset == 0 || + $selector == 'one' && $arg - $offset == 1 || + $selector == 'two' && $arg - $offset == 2 + ) { + $message = implode(',', str_replace('#', $arg - $offset, $plural[$i])); + } + } + if ($message !== false) { + return static::formatMessage($locale, $message, $args); + } + break; + } + return false; + } + + /** + * Parse input string according to pattern + * @link http://php.net/manual/en/messageformatter.parse.php + * @param string $value The string to parse + * @return array An array containing the items extracted, or `FALSE` on error + */ + public function parse($value) + { + throw new NotSupportedException('You have to install PHP intl extension to use this feature.'); + } + + /** + * Quick parse input string + * @link http://php.net/manual/en/messageformatter.parsemessage.php + * @param string $locale The locale to use for parsing locale-dependent parts + * @param string $pattern The pattern with which to parse the `value`. + * @param string $source The string to parse, conforming to the `pattern`. + * @return array An array containing items extracted, or `FALSE` on error + */ + public static function parseMessage($locale, $pattern, $source) + { + throw new NotSupportedException('You have to install PHP intl extension to use this feature.'); + } + + /** + * Set the pattern used by the formatter + * @link http://php.net/manual/en/messageformatter.setpattern.php + * @param string $pattern The pattern string to use in this message formatter. + * @return bool `TRUE` on success or `FALSE` on failure. + */ + public function setPattern($pattern) + { + $this->_pattern = $pattern; + return true; + } + + /** + * Get the pattern used by the formatter + * @link http://php.net/manual/en/messageformatter.getpattern.php + * @return string The pattern string for this message formatter + */ + public function getPattern() + { + return $this->_pattern; + } + + /** + * Get the locale for which the formatter was created. + * @link http://php.net/manual/en/messageformatter.getlocale.php + * @return string The locale name + */ + public function getLocale() + { + return $this->_locale; + } + + /** + * Get the error code from last operation + * @link http://php.net/manual/en/messageformatter.geterrorcode.php + * @return int The error code, one of UErrorCode values. Initial value is U_ZERO_ERROR. + */ + public function getErrorCode() + { + return $this->_errorCode; + } + + /** + * Get the error text from the last operation + * @link http://php.net/manual/en/messageformatter.geterrormessage.php + * @return string Description of the last error. + */ + public function getErrorMessage() + { + return $this->_errorMessage; + } +} + +if (!class_exists('MessageFormatter', false)) { + class_alias('yii\\i18n\\FallbackMessageFormatter', 'MessageFormatter'); + define('YII_INTL_MESSAGE_FALLBACK', true); +} diff --git a/framework/yii/i18n/MessageFormatter.php b/framework/yii/i18n/MessageFormatter.php index 6521d65..106bf18 100644 --- a/framework/yii/i18n/MessageFormatter.php +++ b/framework/yii/i18n/MessageFormatter.php @@ -8,8 +8,9 @@ namespace yii\i18n; if (!class_exists('MessageFormatter', false)) { - require_once(__DIR__ . '/BaseMessageFormatter.php'); + require_once(__DIR__ . '/FallbackMessageFormatter.php'); } +defined('YII_INTL_MESSAGE_FALLBACK') || define('YII_INTL_MESSAGE_FALLBACK', false); /** * MessageFormatter is an enhanced version of PHP intl class that no matter which PHP and ICU versions are used: @@ -18,6 +19,9 @@ if (!class_exists('MessageFormatter', false)) { * - Issues no error when an insufficient number of arguments have been provided. Instead, the placeholders will not be * substituted. * - Fixes PHP 5.5 weird placeholder replacement in case no arguments are provided at all (https://bugs.php.net/bug.php?id=65920). + * - Offers limited support for message formatting in case PHP intl extension is not installed. + * However it is highly recommended that you install [PHP intl extension](http://php.net/manual/en/book.intl.php) if you want + * to use MessageFormatter features. * * @author Alexander Makarov * @author Carsten Brandt @@ -38,7 +42,7 @@ class MessageFormatter extends \MessageFormatter return $this->getPattern(); } - if (version_compare(PHP_VERSION, '5.5.0', '<')) { + if (version_compare(PHP_VERSION, '5.5.0', '<') && !YII_INTL_MESSAGE_FALLBACK) { $pattern = self::replaceNamedArguments($this->getPattern(), $args); $this->setPattern($pattern); $args = array_values($args); @@ -61,7 +65,7 @@ class MessageFormatter extends \MessageFormatter return $pattern; } - if (version_compare(PHP_VERSION, '5.5.0', '<')) { + if (version_compare(PHP_VERSION, '5.5.0', '<') && !YII_INTL_MESSAGE_FALLBACK) { $pattern = self::replaceNamedArguments($pattern, $args); $args = array_values($args); } diff --git a/tests/unit/framework/i18n/FallbackMessageFormatterTest.php b/tests/unit/framework/i18n/FallbackMessageFormatterTest.php new file mode 100644 index 0000000..407ec7f --- /dev/null +++ b/tests/unit/framework/i18n/FallbackMessageFormatterTest.php @@ -0,0 +1,155 @@ + + * @since 2.0 + * @group i18n + */ +class FallbackMessageFormatterTest extends TestCase +{ + const N = 'n'; + const N_VALUE = 42; + const SUBJECT = 'сабж'; + const SUBJECT_VALUE = 'Answer to the Ultimate Question of Life, the Universe, and Everything'; + + public function patterns() + { + return [ + [ + '{'.self::SUBJECT.'} is {'.self::N.'}', // pattern + self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected + [ // params + self::N => self::N_VALUE, + self::SUBJECT => self::SUBJECT_VALUE, + ] + ], + + // This one was provided by Aura.Intl. Thanks! + [<<<_MSG_ +{gender_of_host, select, + female {{num_guests, plural, offset:1 + =0 {{host} does not give a party.} + =1 {{host} invites {guest} to her party.} + =2 {{host} invites {guest} and one other person to her party.} + other {{host} invites {guest} and # other people to her party.}}} + male {{num_guests, plural, offset:1 + =0 {{host} does not give a party.} + =1 {{host} invites {guest} to his party.} + =2 {{host} invites {guest} and one other person to his party.} + other {{host} invites {guest} and # other people to his party.}}} + other {{num_guests, plural, offset:1 + =0 {{host} does not give a party.} + =1 {{host} invites {guest} to their party.} + =2 {{host} invites {guest} and one other person to their party.} + other {{host} invites {guest} and # other people to their party.}}}} +_MSG_ + , + 'ralph invites beep and 3 other people to his party.', + [ + 'gender_of_host' => 'male', + 'num_guests' => 4, + 'host' => 'ralph', + 'guest' => 'beep' + ] + ], + + [ + '{name} is {gender} and {gender, select, female{she} male{he} other{it}} loves Yii!', + 'Alexander is male and he loves Yii!', + [ + 'name' => 'Alexander', + 'gender' => 'male', + ], + ], + + // verify pattern in select does not get replaced + [ + '{name} is {gender} and {gender, select, female{she} male{he} other{it}} loves Yii!', + 'Alexander is male and he loves Yii!', + [ + 'name' => 'Alexander', + 'gender' => 'male', + // following should not be replaced + 'he' => 'wtf', + 'she' => 'wtf', + 'it' => 'wtf', + ] + ], + + // verify pattern in select message gets replaced + [ + '{name} is {gender} and {gender, select, female{she} male{{he}} other{it}} loves Yii!', + 'Alexander is male and wtf loves Yii!', + [ + 'name' => 'Alexander', + 'gender' => 'male', + 'he' => 'wtf', + 'she' => 'wtf', + ], + ], + + // some parser specific verifications + [ + '{gender} and {gender, select, female{she} male{{he}} other{it}} loves {nr} is {gender}!', + 'male and wtf loves 42 is male!', + [ + 'nr' => 42, + 'gender' => 'male', + 'he' => 'wtf', + 'she' => 'wtf', + ], + ], + ]; + } + + /** + * @dataProvider patterns + */ + public function testNamedArgumentsStatic($pattern, $expected, $args) + { + $result = FallbackMessageFormatter::formatMessage('en_US', $pattern, $args); + $this->assertEquals($expected, $result); + } + + /** + * @dataProvider patterns + */ + public function testNamedArgumentsObject($pattern, $expected, $args) + { + $formatter = new FallbackMessageFormatter('en_US', $pattern); + $result = $formatter->format($args); + $this->assertEquals($expected, $result, $formatter->getErrorMessage()); + } + + public function testInsufficientArguments() + { + $expected = '{'.self::SUBJECT.'} is '.self::N_VALUE; + + $result = FallbackMessageFormatter::formatMessage('en_US', '{'.self::SUBJECT.'} is {'.self::N.'}', [ + self::N => self::N_VALUE, + ]); + + $this->assertEquals($expected, $result); + } + + public function testNoParams() + { + $pattern = '{'.self::SUBJECT.'} is '.self::N; + $result = FallbackMessageFormatter::formatMessage('en_US', $pattern, []); + $this->assertEquals($pattern, $result); + + $formatter = new FallbackMessageFormatter('en_US', $pattern); + $result = $formatter->format([]); + $this->assertEquals($pattern, $result, $formatter->getErrorMessage()); + } +} \ No newline at end of file From 750267a82104ccfe4f096b8482372d3e1789f519 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 23 Oct 2013 19:32:43 +0200 Subject: [PATCH 12/40] fix tests when intl is not installed --- tests/unit/framework/i18n/I18NTest.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/unit/framework/i18n/I18NTest.php b/tests/unit/framework/i18n/I18NTest.php index a6d8d9f..924176f 100644 --- a/tests/unit/framework/i18n/I18NTest.php +++ b/tests/unit/framework/i18n/I18NTest.php @@ -51,7 +51,13 @@ class I18NTest extends TestCase $params = ['n' => 42]; $this->assertEquals('His speed is about 42 km/h.', $this->i18n->translate('test', $msg, $params, 'en_US')); $this->assertEquals('Seine Geschwindigkeit beträgt 42 km/h.', $this->i18n->translate('test', $msg, $params, 'de_DE')); + } + public function testTranslateParams2() + { + if (!extension_loaded("intl")) { + $this->markTestSkipped("intl not installed. Skipping."); + } $msg = 'His name is {name} and his speed is about {n, number} km/h.'; $params = [ 'n' => 42, From 33f6e8146328ce8f151fdb0ad4cee1f21bd97534 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 23 Oct 2013 19:49:29 +0200 Subject: [PATCH 13/40] make Yii::t fallback behavior consistent with I18N::translate --- framework/yii/BaseYii.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/framework/yii/BaseYii.php b/framework/yii/BaseYii.php index cf9a96f..21dc81c 100644 --- a/framework/yii/BaseYii.php +++ b/framework/yii/BaseYii.php @@ -515,7 +515,11 @@ class BaseYii if (self::$app !== null) { return self::$app->getI18n()->translate($category, $message, $params, $language ?: self::$app->language); } else { - return is_array($params) ? strtr($message, $params) : $message; + $p = []; + foreach((array) $params as $name => $value) { + $p['{' . $name . '}'] = $value; + } + return ($p === []) ? $message : strtr($message, $p); } } From 752037d95b20580b233d37fbf9e630caffb9a6ac Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 23 Oct 2013 20:22:43 +0200 Subject: [PATCH 14/40] removed value from client validation message this is not what is actually beeing validated --- framework/yii/captcha/CaptchaValidator.php | 1 - 1 file changed, 1 deletion(-) diff --git a/framework/yii/captcha/CaptchaValidator.php b/framework/yii/captcha/CaptchaValidator.php index c613979..e871669 100644 --- a/framework/yii/captcha/CaptchaValidator.php +++ b/framework/yii/captcha/CaptchaValidator.php @@ -113,7 +113,6 @@ class CaptchaValidator extends Validator 'caseSensitive' => $this->caseSensitive, 'message' => Html::encode(strtr($this->message, [ '{attribute}' => $object->getAttributeLabel($attribute), - '{value}' => $object->$attribute, ])), ]; if ($this->skipOnEmpty) { From cfc57c20f06a207a74b1effd9e46d6f31b5300aa Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 23 Oct 2013 20:25:38 +0200 Subject: [PATCH 15/40] Allow ITU message format in validator messages fixes #991 --- framework/yii/i18n/I18N.php | 41 +++++++++++++++++++++++ framework/yii/validators/BooleanValidator.php | 4 +-- framework/yii/validators/CompareValidator.php | 4 +-- framework/yii/validators/FileValidator.php | 10 +++--- framework/yii/validators/NumberValidator.php | 4 +-- framework/yii/validators/RequiredValidator.php | 2 +- framework/yii/validators/StringValidator.php | 6 ++-- framework/yii/validators/Validator.php | 6 ++-- tests/unit/framework/validators/ValidatorTest.php | 2 +- 9 files changed, 60 insertions(+), 19 deletions(-) diff --git a/framework/yii/i18n/I18N.php b/framework/yii/i18n/I18N.php index 57978a0..bd9409c 100644 --- a/framework/yii/i18n/I18N.php +++ b/framework/yii/i18n/I18N.php @@ -63,6 +63,9 @@ class I18N extends Component /** * Translates a message to the specified language. * + * After translation the message will be parsed using [[MessageFormatter]] if it contains + * ITU message format and `$params` are not empty. + * * @param string $category the message category. * @param string $message the message to be translated. * @param array $params the parameters that will be used to replace the corresponding placeholders in the message. @@ -102,6 +105,44 @@ class I18N extends Component } /** + * Formats a message using using [[MessageFormatter]]. + * + * @param string $message the message to be formatted. + * @param array $params the parameters that will be used to replace the corresponding placeholders in the message. + * @param string $language the language code (e.g. `en_US`, `en`). + * @return string the formatted message. + */ + public function format($message, $params, $language) + { + $params = (array)$params; + if ($params === []) { + return $message; + } + + if (preg_match('~{\s*[\d\w]+\s*,~u', $message)) { + $formatter = new MessageFormatter($language, $message); + if ($formatter === null) { + Yii::warning("Message for $language is invalid: $message."); + return $message; + } + $result = $formatter->format($params); + if ($result === false) { + $errorMessage = $formatter->getErrorMessage(); + Yii::warning("Formatting message for $language failed with error: $errorMessage. Message is: $message."); + return $message; + } else { + return $result; + } + } + + $p = []; + foreach($params as $name => $value) { + $p['{' . $name . '}'] = $value; + } + return strtr($message, $p); + } + + /** * Returns the message source for the given category. * @param string $category the category name. * @return MessageSource the message source for the given category. diff --git a/framework/yii/validators/BooleanValidator.php b/framework/yii/validators/BooleanValidator.php index 2504b8a..02b11d7 100644 --- a/framework/yii/validators/BooleanValidator.php +++ b/framework/yii/validators/BooleanValidator.php @@ -58,8 +58,8 @@ class BooleanValidator extends Validator $value = $object->$attribute; if (!$this->validateValue($value)) { $this->addError($object, $attribute, $this->message, [ - '{true}' => $this->trueValue, - '{false}' => $this->falseValue, + 'true' => $this->trueValue, + 'false' => $this->falseValue, ]); } } diff --git a/framework/yii/validators/CompareValidator.php b/framework/yii/validators/CompareValidator.php index 3ff459b..8a694ad 100644 --- a/framework/yii/validators/CompareValidator.php +++ b/framework/yii/validators/CompareValidator.php @@ -143,8 +143,8 @@ class CompareValidator extends Validator } if (!$valid) { $this->addError($object, $attribute, $this->message, [ - '{compareAttribute}' => $compareLabel, - '{compareValue}' => $compareValue, + 'compareAttribute' => $compareLabel, + 'compareValue' => $compareValue, ]); } } diff --git a/framework/yii/validators/FileValidator.php b/framework/yii/validators/FileValidator.php index 8024d10..f27c010 100644 --- a/framework/yii/validators/FileValidator.php +++ b/framework/yii/validators/FileValidator.php @@ -144,7 +144,7 @@ class FileValidator extends Validator $this->addError($object, $attribute, $this->uploadRequired); } if (count($files) > $this->maxFiles) { - $this->addError($object, $attribute, $this->tooMany, ['{attribute}' => $attribute, '{limit}' => $this->maxFiles]); + $this->addError($object, $attribute, $this->tooMany, ['limit' => $this->maxFiles]); } else { foreach ($files as $file) { $this->validateFile($object, $attribute, $file); @@ -171,18 +171,18 @@ class FileValidator extends Validator switch ($file->error) { case UPLOAD_ERR_OK: if ($this->maxSize !== null && $file->size > $this->maxSize) { - $this->addError($object, $attribute, $this->tooBig, ['{file}' => $file->name, '{limit}' => $this->getSizeLimit()]); + $this->addError($object, $attribute, $this->tooBig, ['file' => $file->name, 'limit' => $this->getSizeLimit()]); } if ($this->minSize !== null && $file->size < $this->minSize) { - $this->addError($object, $attribute, $this->tooSmall, ['{file}' => $file->name, '{limit}' => $this->minSize]); + $this->addError($object, $attribute, $this->tooSmall, ['file' => $file->name, 'limit' => $this->minSize]); } if (!empty($this->types) && !in_array(strtolower(pathinfo($file->name, PATHINFO_EXTENSION)), $this->types, true)) { - $this->addError($object, $attribute, $this->wrongType, ['{file}' => $file->name, '{extensions}' => implode(', ', $this->types)]); + $this->addError($object, $attribute, $this->wrongType, ['file' => $file->name, 'extensions' => implode(', ', $this->types)]); } break; case UPLOAD_ERR_INI_SIZE: case UPLOAD_ERR_FORM_SIZE: - $this->addError($object, $attribute, $this->tooBig, ['{file}' => $file->name, '{limit}' => $this->getSizeLimit()]); + $this->addError($object, $attribute, $this->tooBig, ['file' => $file->name, 'limit' => $this->getSizeLimit()]); break; case UPLOAD_ERR_PARTIAL: $this->addError($object, $attribute, $this->message); diff --git a/framework/yii/validators/NumberValidator.php b/framework/yii/validators/NumberValidator.php index ec72dcf..0df73e6 100644 --- a/framework/yii/validators/NumberValidator.php +++ b/framework/yii/validators/NumberValidator.php @@ -91,10 +91,10 @@ class NumberValidator extends Validator $this->addError($object, $attribute, $this->message); } if ($this->min !== null && $value < $this->min) { - $this->addError($object, $attribute, $this->tooSmall, ['{min}' => $this->min]); + $this->addError($object, $attribute, $this->tooSmall, ['min' => $this->min]); } if ($this->max !== null && $value > $this->max) { - $this->addError($object, $attribute, $this->tooBig, ['{max}' => $this->max]); + $this->addError($object, $attribute, $this->tooBig, ['max' => $this->max]); } } diff --git a/framework/yii/validators/RequiredValidator.php b/framework/yii/validators/RequiredValidator.php index 88bd03d..eb4a394 100644 --- a/framework/yii/validators/RequiredValidator.php +++ b/framework/yii/validators/RequiredValidator.php @@ -75,7 +75,7 @@ class RequiredValidator extends Validator $this->addError($object, $attribute, $this->message); } else { $this->addError($object, $attribute, $this->message, [ - '{requiredValue}' => $this->requiredValue, + 'requiredValue' => $this->requiredValue, ]); } } diff --git a/framework/yii/validators/StringValidator.php b/framework/yii/validators/StringValidator.php index a6383b9..329cab0 100644 --- a/framework/yii/validators/StringValidator.php +++ b/framework/yii/validators/StringValidator.php @@ -112,13 +112,13 @@ class StringValidator extends Validator $length = mb_strlen($value, $this->encoding); if ($this->min !== null && $length < $this->min) { - $this->addError($object, $attribute, $this->tooShort, ['{min}' => $this->min]); + $this->addError($object, $attribute, $this->tooShort, ['min' => $this->min]); } if ($this->max !== null && $length > $this->max) { - $this->addError($object, $attribute, $this->tooLong, ['{max}' => $this->max]); + $this->addError($object, $attribute, $this->tooLong, ['max' => $this->max]); } if ($this->length !== null && $length !== $this->length) { - $this->addError($object, $attribute, $this->notEqual, ['{length}' => $this->length]); + $this->addError($object, $attribute, $this->notEqual, ['length' => $this->length]); } } diff --git a/framework/yii/validators/Validator.php b/framework/yii/validators/Validator.php index 46ab673..dc0e935 100644 --- a/framework/yii/validators/Validator.php +++ b/framework/yii/validators/Validator.php @@ -251,9 +251,9 @@ abstract class Validator extends Component public function addError($object, $attribute, $message, $params = []) { $value = $object->$attribute; - $params['{attribute}'] = $object->getAttributeLabel($attribute); - $params['{value}'] = is_array($value) ? 'array()' : $value; - $object->addError($attribute, strtr($message, $params)); + $params['attribute'] = $object->getAttributeLabel($attribute); + $params['value'] = is_array($value) ? 'array()' : $value; + $object->addError($attribute, Yii::$app->getI18n()->format($message, $params, Yii::$app->language)); } /** diff --git a/tests/unit/framework/validators/ValidatorTest.php b/tests/unit/framework/validators/ValidatorTest.php index 351dba8..0cd56d9 100644 --- a/tests/unit/framework/validators/ValidatorTest.php +++ b/tests/unit/framework/validators/ValidatorTest.php @@ -220,7 +220,7 @@ class ValidatorTest extends TestCase $errors = $m->getErrors('attr_msg_val'); $this->assertEquals('attr_msg_val::array()', $errors[0]); $m = $this->getTestModel(['attr_msg_val' => 'abc']); - $val->addError($m, 'attr_msg_val', '{attribute}::{value}::{param}', ['{param}' => 'param_value']); + $val->addError($m, 'attr_msg_val', '{attribute}::{value}::{param}', ['param' => 'param_value']); $errors = $m->getErrors('attr_msg_val'); $this->assertEquals('attr_msg_val::abc::param_value', $errors[0]); } From 58e6a72987336e50e43ce5b2f8627ff01915e781 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 23 Oct 2013 20:35:28 +0200 Subject: [PATCH 16/40] fixes #991 for gridview summary, use ITU message format --- framework/yii/widgets/BaseListView.php | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/framework/yii/widgets/BaseListView.php b/framework/yii/widgets/BaseListView.php index bfa984f..27b2eaf 100644 --- a/framework/yii/widgets/BaseListView.php +++ b/framework/yii/widgets/BaseListView.php @@ -131,30 +131,32 @@ abstract class BaseListView extends Widget public function renderSummary() { $count = $this->dataProvider->getCount(); - if (($pagination = $this->dataProvider->getPagination()) !== false && $count > 0) { + if (($pagination = $this->dataProvider->getPagination()) !== false) { $totalCount = $this->dataProvider->getTotalCount(); $begin = $pagination->getPage() * $pagination->pageSize + 1; $end = $begin + $count - 1; $page = $pagination->getPage() + 1; $pageCount = $pagination->pageCount; if (($summaryContent = $this->summary) === null) { - $summaryContent = '
' . Yii::t('yii', 'Showing {begin}-{end} of {totalCount} {0, plural, =1{item} other{items}}.', $totalCount) . '
'; + $summaryContent = '
' + . Yii::t('yii', 'Showing {totalCount, plural, =0{0} other{{begin}-{end}}} of {totalCount} {totalCount, plural, one{item} other{items}}.') + . '
'; } } else { $begin = $page = $pageCount = 1; $end = $totalCount = $count; if (($summaryContent = $this->summary) === null) { - $summaryContent = '
' . Yii::t('yii', 'Total {count} {0, plural, =1{item} other{items}}.', $count) . '
'; + $summaryContent = '
' . Yii::t('yii', 'Total {count} {count, plural, one{item} other{items}}.') . '
'; } } - return strtr($summaryContent, [ - '{begin}' => $begin, - '{end}' => $end, - '{count}' => $count, - '{totalCount}' => $totalCount, - '{page}' => $page, - '{pageCount}' => $pageCount, - ]); + return Yii::$app->getI18n()->format($summaryContent, [ + 'begin' => $begin, + 'end' => $end, + 'count' => $count, + 'totalCount' => $totalCount, + 'page' => $page, + 'pageCount' => $pageCount, + ], Yii::$app->language); } /** From 47dfa69616f095989294e21005f16925e9a3eeca Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 23 Oct 2013 20:40:59 +0200 Subject: [PATCH 17/40] doc wording [ci skip] --- framework/yii/i18n/I18N.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/yii/i18n/I18N.php b/framework/yii/i18n/I18N.php index bd9409c..82ba86e 100644 --- a/framework/yii/i18n/I18N.php +++ b/framework/yii/i18n/I18N.php @@ -63,7 +63,7 @@ class I18N extends Component /** * Translates a message to the specified language. * - * After translation the message will be parsed using [[MessageFormatter]] if it contains + * After translation the message will be formatted using [[MessageFormatter]] if it contains * ITU message format and `$params` are not empty. * * @param string $category the message category. From 7e1dd6729358f5debf36ad8633011e648d14108e Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Wed, 23 Oct 2013 20:48:04 +0200 Subject: [PATCH 18/40] typo ITU -> ICU they are not responsible for i18n ;) --- framework/yii/i18n/I18N.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/yii/i18n/I18N.php b/framework/yii/i18n/I18N.php index 82ba86e..ef775a4 100644 --- a/framework/yii/i18n/I18N.php +++ b/framework/yii/i18n/I18N.php @@ -64,7 +64,7 @@ class I18N extends Component * Translates a message to the specified language. * * After translation the message will be formatted using [[MessageFormatter]] if it contains - * ITU message format and `$params` are not empty. + * ICU message format and `$params` are not empty. * * @param string $category the message category. * @param string $message the message to be translated. From 3631890cba7e4700499d440fe840e9f0ccdc4e28 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Thu, 24 Oct 2013 00:00:32 +0200 Subject: [PATCH 19/40] fixed failing validator tests --- tests/unit/framework/validators/BooleanValidatorTest.php | 6 ++++++ tests/unit/framework/validators/CompareValidatorTest.php | 5 +++++ tests/unit/framework/validators/DateValidatorTest.php | 6 ++++++ tests/unit/framework/validators/DefaultValueValidatorTest.php | 6 ++++++ tests/unit/framework/validators/EmailValidatorTest.php | 6 ++++++ tests/unit/framework/validators/ExistValidatorTest.php | 1 + tests/unit/framework/validators/FilterValidatorTest.php | 6 ++++++ tests/unit/framework/validators/NumberValidatorTest.php | 6 ++++++ tests/unit/framework/validators/RangeValidatorTest.php | 6 ++++++ tests/unit/framework/validators/RegularExpressionValidatorTest.php | 6 ++++++ tests/unit/framework/validators/RequiredValidatorTest.php | 6 ++++++ tests/unit/framework/validators/UniqueValidatorTest.php | 1 + tests/unit/framework/validators/UrlValidatorTest.php | 6 ++++++ tests/unit/framework/validators/ValidatorTest.php | 5 +++++ 14 files changed, 72 insertions(+) diff --git a/tests/unit/framework/validators/BooleanValidatorTest.php b/tests/unit/framework/validators/BooleanValidatorTest.php index f30aa3d..0f09daf 100644 --- a/tests/unit/framework/validators/BooleanValidatorTest.php +++ b/tests/unit/framework/validators/BooleanValidatorTest.php @@ -10,6 +10,12 @@ use yiiunit\TestCase; */ class BooleanValidatorTest extends TestCase { + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + public function testValidateValue() { $val = new BooleanValidator; diff --git a/tests/unit/framework/validators/CompareValidatorTest.php b/tests/unit/framework/validators/CompareValidatorTest.php index b3fd6b4..d1bdf34 100644 --- a/tests/unit/framework/validators/CompareValidatorTest.php +++ b/tests/unit/framework/validators/CompareValidatorTest.php @@ -10,6 +10,11 @@ use yiiunit\TestCase; class CompareValidatorTest extends TestCase { + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } public function testValidateValueException() { diff --git a/tests/unit/framework/validators/DateValidatorTest.php b/tests/unit/framework/validators/DateValidatorTest.php index 28a6a4a..6ae3521 100644 --- a/tests/unit/framework/validators/DateValidatorTest.php +++ b/tests/unit/framework/validators/DateValidatorTest.php @@ -10,6 +10,12 @@ use yiiunit\TestCase; class DateValidatorTest extends TestCase { + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + public function testEnsureMessageIsSet() { $val = new DateValidator; diff --git a/tests/unit/framework/validators/DefaultValueValidatorTest.php b/tests/unit/framework/validators/DefaultValueValidatorTest.php index 05a71b5..48537d8 100644 --- a/tests/unit/framework/validators/DefaultValueValidatorTest.php +++ b/tests/unit/framework/validators/DefaultValueValidatorTest.php @@ -8,6 +8,12 @@ use yiiunit\TestCase; */ class DefaultValueValidatorTest extends TestCase { + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + public function testValidateAttribute() { $val = new DefaultValueValidator; diff --git a/tests/unit/framework/validators/EmailValidatorTest.php b/tests/unit/framework/validators/EmailValidatorTest.php index 950ac97..eee708d 100644 --- a/tests/unit/framework/validators/EmailValidatorTest.php +++ b/tests/unit/framework/validators/EmailValidatorTest.php @@ -11,6 +11,12 @@ use yiiunit\TestCase; */ class EmailValidatorTest extends TestCase { + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + public function testValidateValue() { $validator = new EmailValidator(); diff --git a/tests/unit/framework/validators/ExistValidatorTest.php b/tests/unit/framework/validators/ExistValidatorTest.php index 5a3a175..a0f0328 100644 --- a/tests/unit/framework/validators/ExistValidatorTest.php +++ b/tests/unit/framework/validators/ExistValidatorTest.php @@ -18,6 +18,7 @@ class ExistValidatorTest extends DatabaseTestCase public function setUp() { parent::setUp(); + $this->mockApplication(); ActiveRecord::$db = $this->getConnection(); } diff --git a/tests/unit/framework/validators/FilterValidatorTest.php b/tests/unit/framework/validators/FilterValidatorTest.php index 139d51d..ec96f21 100644 --- a/tests/unit/framework/validators/FilterValidatorTest.php +++ b/tests/unit/framework/validators/FilterValidatorTest.php @@ -9,6 +9,12 @@ use yiiunit\TestCase; class FilterValidatorTest extends TestCase { + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + public function testAssureExceptionOnInit() { $this->setExpectedException('yii\base\InvalidConfigException'); diff --git a/tests/unit/framework/validators/NumberValidatorTest.php b/tests/unit/framework/validators/NumberValidatorTest.php index c2352ec..4e9897e 100644 --- a/tests/unit/framework/validators/NumberValidatorTest.php +++ b/tests/unit/framework/validators/NumberValidatorTest.php @@ -9,6 +9,12 @@ use yiiunit\TestCase; class NumberValidatorTest extends TestCase { + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + public function testEnsureMessageOnInit() { $val = new NumberValidator; diff --git a/tests/unit/framework/validators/RangeValidatorTest.php b/tests/unit/framework/validators/RangeValidatorTest.php index bfa7cae..345951c 100644 --- a/tests/unit/framework/validators/RangeValidatorTest.php +++ b/tests/unit/framework/validators/RangeValidatorTest.php @@ -9,6 +9,12 @@ use yiiunit\TestCase; class RangeValidatorTest extends TestCase { + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + public function testInitException() { $this->setExpectedException('yii\base\InvalidConfigException', 'The "range" property must be set.'); diff --git a/tests/unit/framework/validators/RegularExpressionValidatorTest.php b/tests/unit/framework/validators/RegularExpressionValidatorTest.php index 3262025..e5b33b2 100644 --- a/tests/unit/framework/validators/RegularExpressionValidatorTest.php +++ b/tests/unit/framework/validators/RegularExpressionValidatorTest.php @@ -9,6 +9,12 @@ use yiiunit\TestCase; class RegularExpressionValidatorTest extends TestCase { + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + public function testValidateValue() { $val = new RegularExpressionValidator(['pattern' => '/^[a-zA-Z0-9](\.)?([^\/]*)$/m']); diff --git a/tests/unit/framework/validators/RequiredValidatorTest.php b/tests/unit/framework/validators/RequiredValidatorTest.php index f60e69e..0708cc9 100644 --- a/tests/unit/framework/validators/RequiredValidatorTest.php +++ b/tests/unit/framework/validators/RequiredValidatorTest.php @@ -8,6 +8,12 @@ use yiiunit\TestCase; class RequiredValidatorTest extends TestCase { + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + public function testValidateValueWithDefaults() { $val = new RequiredValidator(); diff --git a/tests/unit/framework/validators/UniqueValidatorTest.php b/tests/unit/framework/validators/UniqueValidatorTest.php index 37d666f..d3d0882 100644 --- a/tests/unit/framework/validators/UniqueValidatorTest.php +++ b/tests/unit/framework/validators/UniqueValidatorTest.php @@ -19,6 +19,7 @@ class UniqueValidatorTest extends DatabaseTestCase public function setUp() { parent::setUp(); + $this->mockApplication(); ActiveRecord::$db = $this->getConnection(); } diff --git a/tests/unit/framework/validators/UrlValidatorTest.php b/tests/unit/framework/validators/UrlValidatorTest.php index 4d5fae2..1323434 100644 --- a/tests/unit/framework/validators/UrlValidatorTest.php +++ b/tests/unit/framework/validators/UrlValidatorTest.php @@ -9,6 +9,12 @@ use yiiunit\TestCase; */ class UrlValidatorTest extends TestCase { + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + public function testValidateValue() { $val = new UrlValidator; diff --git a/tests/unit/framework/validators/ValidatorTest.php b/tests/unit/framework/validators/ValidatorTest.php index 0cd56d9..fc69c2f 100644 --- a/tests/unit/framework/validators/ValidatorTest.php +++ b/tests/unit/framework/validators/ValidatorTest.php @@ -12,6 +12,11 @@ use yiiunit\TestCase; class ValidatorTest extends TestCase { + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } protected function getTestModel($additionalAttributes = []) { From ffb37f8eaba3625fb567579bf85b76d039861937 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Thu, 24 Oct 2013 02:00:43 +0400 Subject: [PATCH 20/40] fixes #1001 --- framework/yii/grid/DataColumn.php | 8 ++++---- framework/yii/validators/UniqueValidator.php | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/framework/yii/grid/DataColumn.php b/framework/yii/grid/DataColumn.php index 9459aae..e8a25a7 100644 --- a/framework/yii/grid/DataColumn.php +++ b/framework/yii/grid/DataColumn.php @@ -41,10 +41,10 @@ class DataColumn extends Column */ public $value; /** - * @var string in which format should the value of each data model be displayed as (e.g. "text", "html"). - * Supported formats are determined by the [[GridView::formatter|formatter]] used by the [[GridView]]. - * Default format is "text" which will format the value as an HTML-encoded plain text when - * [[\yii\base\Formatter]] or [[\yii\i18n\Formatter]] is used. + * @var string|array in which format should the value of each data model be displayed as (e.g. "text", "html", + * ['date', 'Y-m-d']). Supported formats are determined by the [[GridView::formatter|formatter]] used by + * the [[GridView]]. Default format is "text" which will format the value as an HTML-encoded plain text when + * [[\yii\base\Formatter::format()]] or [[\yii\i18n\Formatter::format()]] is used. */ public $format = 'text'; /** diff --git a/framework/yii/validators/UniqueValidator.php b/framework/yii/validators/UniqueValidator.php index a698d96..334d057 100644 --- a/framework/yii/validators/UniqueValidator.php +++ b/framework/yii/validators/UniqueValidator.php @@ -12,7 +12,7 @@ use yii\base\InvalidConfigException; use yii\db\ActiveRecord; /** - * CUniqueValidator validates that the attribute value is unique in the corresponding database table. + * UniqueValidator validates that the attribute value is unique in the corresponding database table. * * @author Qiang Xue * @since 2.0 From 616b406a0c8677065a64b9b7ab5318f053baa8ed Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Thu, 24 Oct 2013 02:06:35 +0400 Subject: [PATCH 21/40] fixes #979 --- framework/yii/web/AssetBundle.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/framework/yii/web/AssetBundle.php b/framework/yii/web/AssetBundle.php index 15ba3f6..5ea6f67 100644 --- a/framework/yii/web/AssetBundle.php +++ b/framework/yii/web/AssetBundle.php @@ -68,7 +68,16 @@ class AssetBundle extends Object */ public $baseUrl; /** - * @var array list of the bundle names that this bundle depends on + * @var array list of bundle class names that this bundle depends on. + * + * For example: + * + * ```php + * public $depends = [ + * 'yii\web\YiiAsset', + * 'yii\bootstrap\BootstrapAsset', + * ]; + * ``` */ public $depends = []; /** From 7ce6325de1e52df7bdedc55c795fd815b72911e0 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Thu, 24 Oct 2013 02:11:58 +0400 Subject: [PATCH 22/40] fixes #849 --- framework/yii/bootstrap/Dropdown.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/framework/yii/bootstrap/Dropdown.php b/framework/yii/bootstrap/Dropdown.php index e9ef0ef..fecfb0b 100644 --- a/framework/yii/bootstrap/Dropdown.php +++ b/framework/yii/bootstrap/Dropdown.php @@ -29,6 +29,8 @@ class Dropdown extends Widget * - visible: boolean, optional, whether this menu item is visible. Defaults to true. * - linkOptions: array, optional, the HTML attributes of the item link. * - options: array, optional, the HTML attributes of the item. + * + * To insert divider use ``. */ public $items = []; /** From c127171efbc0e2ebea5a963d89d9a1d9c5ef51a8 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Thu, 24 Oct 2013 02:31:05 +0400 Subject: [PATCH 23/40] Fixes #1003: DateValidator returned true for invalid dates --- framework/yii/validators/DateValidator.php | 4 +++- tests/unit/framework/validators/DateValidatorTest.php | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/framework/yii/validators/DateValidator.php b/framework/yii/validators/DateValidator.php index 2f9e18b..5354b71 100644 --- a/framework/yii/validators/DateValidator.php +++ b/framework/yii/validators/DateValidator.php @@ -70,6 +70,8 @@ class DateValidator extends Validator */ public function validateValue($value) { - return DateTime::createFromFormat($this->format, $value) !== false; + DateTime::createFromFormat($this->format, $value); + $errors = DateTime::getLastErrors(); + return $errors['error_count'] === 0 && $errors['warning_count'] === 0; } } diff --git a/tests/unit/framework/validators/DateValidatorTest.php b/tests/unit/framework/validators/DateValidatorTest.php index 28a6a4a..26c2b46 100644 --- a/tests/unit/framework/validators/DateValidatorTest.php +++ b/tests/unit/framework/validators/DateValidatorTest.php @@ -19,6 +19,7 @@ class DateValidatorTest extends TestCase public function testValidateValue() { $val = new DateValidator; + $this->assertFalse($val->validateValue('3232-32-32')); $this->assertTrue($val->validateValue('2013-09-13')); $this->assertFalse($val->validateValue('31.7.2013')); $this->assertFalse($val->validateValue('31-7-2013')); From ee2af2661cfcf15846b3bc75a7bcb40257866376 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Thu, 24 Oct 2013 03:12:25 +0400 Subject: [PATCH 24/40] Removed unneeded use statements --- framework/yii/BaseYii.php | 1 - framework/yii/base/Theme.php | 1 - framework/yii/bootstrap/Widget.php | 1 - framework/yii/gii/generators/crud/Generator.php | 1 - framework/yii/gii/views/default/view.php | 1 - framework/yii/gii/views/default/view/files.php | 1 - framework/yii/gii/views/default/view/results.php | 4 ---- framework/yii/grid/ActionColumn.php | 2 -- framework/yii/grid/GridView.php | 2 -- framework/yii/i18n/I18N.php | 1 - framework/yii/web/YiiAsset.php | 3 --- framework/yii/widgets/ActiveField.php | 1 - tests/unit/data/ar/ActiveRecord.php | 2 -- tests/unit/framework/caching/CacheTestCase.php | 1 - tests/unit/framework/caching/RedisCacheTest.php | 1 - tests/unit/framework/caching/ZendDataCacheTest.php | 1 - tests/unit/framework/db/ActiveRecordTest.php | 1 - tests/unit/framework/db/CommandTest.php | 3 --- tests/unit/framework/db/QueryTest.php | 3 --- tests/unit/framework/db/cubrid/CubridQueryBuilderTest.php | 1 - tests/unit/framework/i18n/GettextMessageSourceTest.php | 1 - tests/unit/framework/i18n/I18NTest.php | 1 - tests/unit/framework/validators/UniqueValidatorTest.php | 1 - 23 files changed, 35 deletions(-) diff --git a/framework/yii/BaseYii.php b/framework/yii/BaseYii.php index 21dc81c..5d546bd 100644 --- a/framework/yii/BaseYii.php +++ b/framework/yii/BaseYii.php @@ -6,7 +6,6 @@ */ namespace yii; -use yii\base\Exception; use yii\base\InvalidConfigException; use yii\base\InvalidParamException; use yii\base\UnknownClassException; diff --git a/framework/yii/base/Theme.php b/framework/yii/base/Theme.php index d21d4bf..ff6780c 100644 --- a/framework/yii/base/Theme.php +++ b/framework/yii/base/Theme.php @@ -8,7 +8,6 @@ namespace yii\base; use Yii; -use yii\base\InvalidConfigException; use yii\helpers\FileHelper; /** diff --git a/framework/yii/bootstrap/Widget.php b/framework/yii/bootstrap/Widget.php index db7f415..ff4084d 100644 --- a/framework/yii/bootstrap/Widget.php +++ b/framework/yii/bootstrap/Widget.php @@ -8,7 +8,6 @@ namespace yii\bootstrap; use Yii; -use yii\base\View; use yii\helpers\Json; /** diff --git a/framework/yii/gii/generators/crud/Generator.php b/framework/yii/gii/generators/crud/Generator.php index 671dfbd..cb4bce6 100644 --- a/framework/yii/gii/generators/crud/Generator.php +++ b/framework/yii/gii/generators/crud/Generator.php @@ -8,7 +8,6 @@ namespace yii\gii\generators\crud; use Yii; -use yii\base\Model; use yii\db\ActiveRecord; use yii\db\Schema; use yii\gii\CodeFile; diff --git a/framework/yii/gii/views/default/view.php b/framework/yii/gii/views/default/view.php index 1ef5c77..3123b57 100644 --- a/framework/yii/gii/views/default/view.php +++ b/framework/yii/gii/views/default/view.php @@ -1,6 +1,5 @@ diff --git a/framework/yii/grid/GridView.php b/framework/yii/grid/GridView.php index 4895781..8a3196b 100644 --- a/framework/yii/grid/GridView.php +++ b/framework/yii/grid/GridView.php @@ -11,8 +11,6 @@ use Yii; use Closure; use yii\base\Formatter; use yii\base\InvalidConfigException; -use yii\base\Widget; -use yii\db\ActiveRecord; use yii\helpers\Html; use yii\helpers\Json; use yii\widgets\BaseListView; diff --git a/framework/yii/i18n/I18N.php b/framework/yii/i18n/I18N.php index 57978a0..bf749a2 100644 --- a/framework/yii/i18n/I18N.php +++ b/framework/yii/i18n/I18N.php @@ -10,7 +10,6 @@ namespace yii\i18n; use Yii; use yii\base\Component; use yii\base\InvalidConfigException; -use yii\log\Logger; /** * I18N provides features related with internationalization (I18N) and localization (L10N). diff --git a/framework/yii/web/YiiAsset.php b/framework/yii/web/YiiAsset.php index 29796e7..e49082d 100644 --- a/framework/yii/web/YiiAsset.php +++ b/framework/yii/web/YiiAsset.php @@ -7,9 +7,6 @@ namespace yii\web; -use Yii; -use yii\base\View; - /** * @author Qiang Xue * @since 2.0 diff --git a/framework/yii/widgets/ActiveField.php b/framework/yii/widgets/ActiveField.php index b8924bd..fc30af5 100644 --- a/framework/yii/widgets/ActiveField.php +++ b/framework/yii/widgets/ActiveField.php @@ -8,7 +8,6 @@ namespace yii\widgets; use Yii; use yii\base\Component; -use yii\db\ActiveRecord; use yii\helpers\ArrayHelper; use yii\helpers\Html; use yii\base\Model; diff --git a/tests/unit/data/ar/ActiveRecord.php b/tests/unit/data/ar/ActiveRecord.php index f1194ea..bcb5b48 100644 --- a/tests/unit/data/ar/ActiveRecord.php +++ b/tests/unit/data/ar/ActiveRecord.php @@ -7,8 +7,6 @@ namespace yiiunit\data\ar; -use yii\db\Connection; - /** * ActiveRecord is ... * diff --git a/tests/unit/framework/caching/CacheTestCase.php b/tests/unit/framework/caching/CacheTestCase.php index 9ff6409..2952e87 100644 --- a/tests/unit/framework/caching/CacheTestCase.php +++ b/tests/unit/framework/caching/CacheTestCase.php @@ -13,7 +13,6 @@ function time() namespace yiiunit\framework\caching; -use yii\helpers\StringHelper; use yiiunit\TestCase; use yii\caching\Cache; diff --git a/tests/unit/framework/caching/RedisCacheTest.php b/tests/unit/framework/caching/RedisCacheTest.php index d4e414e..b9df7a9 100644 --- a/tests/unit/framework/caching/RedisCacheTest.php +++ b/tests/unit/framework/caching/RedisCacheTest.php @@ -2,7 +2,6 @@ namespace yiiunit\framework\caching; use yii\caching\MemCache; use yii\caching\RedisCache; -use yiiunit\TestCase; /** * Class for testing redis cache backend diff --git a/tests/unit/framework/caching/ZendDataCacheTest.php b/tests/unit/framework/caching/ZendDataCacheTest.php index 96354cd..2a0af9f 100644 --- a/tests/unit/framework/caching/ZendDataCacheTest.php +++ b/tests/unit/framework/caching/ZendDataCacheTest.php @@ -1,7 +1,6 @@ Date: Wed, 23 Oct 2013 21:20:31 -0400 Subject: [PATCH 25/40] refactoring I18N. --- framework/yii/i18n/I18N.php | 36 +++++---------------------------- framework/yii/i18n/MessageFormatter.php | 4 +++- 2 files changed, 8 insertions(+), 32 deletions(-) diff --git a/framework/yii/i18n/I18N.php b/framework/yii/i18n/I18N.php index 3ddffdd..cf8243e 100644 --- a/framework/yii/i18n/I18N.php +++ b/framework/yii/i18n/I18N.php @@ -45,14 +45,14 @@ class I18N extends Component parent::init(); if (!isset($this->translations['yii'])) { $this->translations['yii'] = [ - 'class' => 'yii\i18n\PhpMessageSource', + 'class' => PhpMessageSource::className(), 'sourceLanguage' => 'en_US', 'basePath' => '@yii/messages', ]; } if (!isset($this->translations['app'])) { $this->translations['app'] = [ - 'class' => 'yii\i18n\PhpMessageSource', + 'class' => PhpMessageSource::className(), 'sourceLanguage' => 'en_US', 'basePath' => '@app/messages', ]; @@ -74,33 +74,7 @@ class I18N extends Component public function translate($category, $message, $params, $language) { $message = $this->getMessageSource($category)->translate($category, $message, $language); - - $params = (array)$params; - if ($params === []) { - return $message; - } - - if (preg_match('~{\s*[\d\w]+\s*,~u', $message)) { - $formatter = new MessageFormatter($language, $message); - if ($formatter === null) { - Yii::warning("$language message from category $category is invalid. Message is: $message."); - return $message; - } - $result = $formatter->format($params); - if ($result === false) { - $errorMessage = $formatter->getErrorMessage(); - Yii::warning("$language message from category $category failed with error: $errorMessage. Message is: $message."); - return $message; - } else { - return $result; - } - } - - $p = []; - foreach($params as $name => $value) { - $p['{' . $name . '}'] = $value; - } - return strtr($message, $p); + return $this->format($message, $params, $language); } /** @@ -121,13 +95,13 @@ class I18N extends Component if (preg_match('~{\s*[\d\w]+\s*,~u', $message)) { $formatter = new MessageFormatter($language, $message); if ($formatter === null) { - Yii::warning("Message for $language is invalid: $message."); + Yii::warning("Unable to format message in language '$language': $message."); return $message; } $result = $formatter->format($params); if ($result === false) { $errorMessage = $formatter->getErrorMessage(); - Yii::warning("Formatting message for $language failed with error: $errorMessage. Message is: $message."); + Yii::warning("Formatting message for language '$language' failed with error: $errorMessage. The message being formatted was: $message."); return $message; } else { return $result; diff --git a/framework/yii/i18n/MessageFormatter.php b/framework/yii/i18n/MessageFormatter.php index 106bf18..9f198c9 100644 --- a/framework/yii/i18n/MessageFormatter.php +++ b/framework/yii/i18n/MessageFormatter.php @@ -13,7 +13,9 @@ if (!class_exists('MessageFormatter', false)) { defined('YII_INTL_MESSAGE_FALLBACK') || define('YII_INTL_MESSAGE_FALLBACK', false); /** - * MessageFormatter is an enhanced version of PHP intl class that no matter which PHP and ICU versions are used: + * MessageFormatter enhances the message formatter class provided by PHP intl extension. + * + * The following enhancements are provided: * * - Accepts named arguments and mixed numeric and named arguments. * - Issues no error when an insufficient number of arguments have been provided. Instead, the placeholders will not be From 6c6dd011228426be87dfc023e0a0b3d4aa59d2f9 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Wed, 23 Oct 2013 21:39:36 -0400 Subject: [PATCH 26/40] Fixes #1052: unset related data when ActiveRecord::refresh() is called. --- framework/yii/db/ActiveRecord.php | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/framework/yii/db/ActiveRecord.php b/framework/yii/db/ActiveRecord.php index 806a6c1..79d5146 100644 --- a/framework/yii/db/ActiveRecord.php +++ b/framework/yii/db/ActiveRecord.php @@ -1125,26 +1125,20 @@ class ActiveRecord extends Model /** * Repopulates this active record with the latest data. - * @param array $attributes * @return boolean whether the row still exists in the database. If true, the latest data - * will be populated to this active record. + * will be populated to this active record. Otherwise, this record will remain unchanged. */ - public function refresh($attributes = null) + public function refresh() { $record = $this->find($this->getPrimaryKey(true)); if ($record === null) { return false; } - if ($attributes === null) { - foreach ($this->attributes() as $name) { - $this->_attributes[$name] = $record->_attributes[$name]; - } - $this->_oldAttributes = $this->_attributes; - } else { - foreach ($attributes as $name) { - $this->_oldAttributes[$name] = $this->_attributes[$name] = $record->_attributes[$name]; - } + foreach ($this->attributes() as $name) { + $this->_attributes[$name] = $record->_attributes[$name]; } + $this->_oldAttributes = $this->_attributes; + $this->_related = null; return true; } From 0c1477c6021fa94a971186465cab614eb303783f Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Wed, 23 Oct 2013 21:52:22 -0400 Subject: [PATCH 27/40] Fixes #1050: renamed CaptchaValidator::getCaptchaAction() to createCaptchaAction(). --- framework/yii/captcha/CaptchaValidator.php | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/framework/yii/captcha/CaptchaValidator.php b/framework/yii/captcha/CaptchaValidator.php index e871669..9d9d0fd 100644 --- a/framework/yii/captcha/CaptchaValidator.php +++ b/framework/yii/captcha/CaptchaValidator.php @@ -18,8 +18,6 @@ use yii\validators\Validator; * * CaptchaValidator should be used together with [[CaptchaAction]]. * - * @property \yii\captcha\CaptchaAction $captchaAction The action object. This property is read-only. - * * @author Qiang Xue * @since 2.0 */ @@ -71,16 +69,16 @@ class CaptchaValidator extends Validator */ public function validateValue($value) { - $captcha = $this->getCaptchaAction(); + $captcha = $this->createCaptchaAction(); return !is_array($value) && $captcha->validate($value, $this->caseSensitive); } /** - * Returns the CAPTCHA action object. - * @throws InvalidConfigException + * Creates the CAPTCHA action object from the route specified by [[captchaAction]]. * @return \yii\captcha\CaptchaAction the action object + * @throws InvalidConfigException */ - public function getCaptchaAction() + public function createCaptchaAction() { $ca = Yii::$app->createController($this->captchaAction); if ($ca !== false) { @@ -104,7 +102,7 @@ class CaptchaValidator extends Validator */ public function clientValidateAttribute($object, $attribute, $view) { - $captcha = $this->getCaptchaAction(); + $captcha = $this->createCaptchaAction(); $code = $captcha->getVerifyCode(false); $hash = $captcha->generateValidationHash($this->caseSensitive ? $code : strtolower($code)); $options = [ From 8141fc19fb145165a35ebd5d4ebaa0a013997e9c Mon Sep 17 00:00:00 2001 From: Luciano Baraglia Date: Thu, 24 Oct 2013 02:33:02 -0300 Subject: [PATCH 28/40] More on short echo tags [skip ci] --- framework/yii/gii/generators/form/templates/action.php | 2 +- framework/yii/gii/generators/form/templates/form.php | 8 ++++---- framework/yii/gii/generators/module/templates/view.php | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/framework/yii/gii/generators/form/templates/action.php b/framework/yii/gii/generators/form/templates/action.php index 6b084f4..7e2f876 100644 --- a/framework/yii/gii/generators/form/templates/action.php +++ b/framework/yii/gii/generators/form/templates/action.php @@ -14,7 +14,7 @@ echo "viewName), '_')) ?>() { - $model = new modelClass ?>scenarioName) ? '' : "(['scenario' => '{$generator->scenarioName}'])" ?>; + $model = new modelClass ?>scenarioName) ? "" : "(['scenario' => '{$generator->scenarioName}'])" ?>; if ($model->load($_POST)) { if($model->validate()) { diff --git a/framework/yii/gii/generators/form/templates/form.php b/framework/yii/gii/generators/form/templates/form.php index a448687..12c2ac4 100644 --- a/framework/yii/gii/generators/form/templates/form.php +++ b/framework/yii/gii/generators/form/templates/form.php @@ -21,15 +21,15 @@ use yii\widgets\ActiveForm;
- $form = ActiveForm::begin(); ?> + $form = ActiveForm::begin(); ?> getModelAttributes() as $attribute): ?> - echo $form->field($model, ''); ?> + $form->field($model, '') ?>
- echo Html::submitButton('Submit', ['class' => 'btn btn-primary']); ?> + Html::submitButton('Submit', ['class' => 'btn btn-primary']) ?>
- ActiveForm::end(); ?> + ActiveForm::end(); ?>
diff --git a/framework/yii/gii/generators/module/templates/view.php b/framework/yii/gii/generators/module/templates/view.php index 311134d..80dd6b5 100644 --- a/framework/yii/gii/generators/module/templates/view.php +++ b/framework/yii/gii/generators/module/templates/view.php @@ -5,14 +5,14 @@ */ ?>
-

echo $this->context->action->uniqueId; ?>

+

$this->context->action->uniqueId ?>

- This is the view content for action " echo $this->context->action->id; ?>". - The action belongs to the controller " echo get_class($this->context); ?>" - in the " echo $this->context->module->id; ?>" module. + This is the view content for action "$this->context->action->id ?>". + The action belongs to the controller "get_class($this->context) ?>" + in the "$this->context->module->id ?>" module.

You may customize this page by editing the following file:
- echo __FILE__; ?> + __FILE__ ?>

From 757603220ac6501e9c4ffd2479e97f17297913a5 Mon Sep 17 00:00:00 2001 From: Luciano Baraglia Date: Thu, 24 Oct 2013 02:38:45 -0300 Subject: [PATCH 29/40] More on short echo tags [skip ci] --- framework/yii/gii/generators/module/templates/view.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/yii/gii/generators/module/templates/view.php b/framework/yii/gii/generators/module/templates/view.php index 80dd6b5..41e8bbc 100644 --- a/framework/yii/gii/generators/module/templates/view.php +++ b/framework/yii/gii/generators/module/templates/view.php @@ -5,7 +5,7 @@ */ ?>
-

$this->context->action->uniqueId ?>

+

$this->context->action->uniqueId ?>

This is the view content for action "$this->context->action->id ?>". The action belongs to the controller "get_class($this->context) ?>" From 2ce09559a207d6064d6b882f20faa62779ebc9ea Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Thu, 24 Oct 2013 14:50:39 +0400 Subject: [PATCH 30/40] fixes #1055 --- framework/yii/bootstrap/Carousel.php | 4 ++-- framework/yii/bootstrap/Nav.php | 2 +- framework/yii/data/ArrayDataProvider.php | 2 +- framework/yii/log/Logger.php | 2 +- framework/yii/web/AccessControl.php | 6 +++--- framework/yii/widgets/Menu.php | 6 +++--- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/framework/yii/bootstrap/Carousel.php b/framework/yii/bootstrap/Carousel.php index b7e378a..8344929 100644 --- a/framework/yii/bootstrap/Carousel.php +++ b/framework/yii/bootstrap/Carousel.php @@ -29,8 +29,8 @@ use yii\helpers\Html; * 'caption' => '

This is title

This is the caption text

', * 'options' => [...], * ], - * ) - * )); + * ] + * ]); * ``` * * @see http://twitter.github.io/bootstrap/javascript.html#carousel diff --git a/framework/yii/bootstrap/Nav.php b/framework/yii/bootstrap/Nav.php index 7d07a86..298f9b8 100644 --- a/framework/yii/bootstrap/Nav.php +++ b/framework/yii/bootstrap/Nav.php @@ -24,7 +24,7 @@ use yii\helpers\Html; * 'label' => 'Home', * 'url' => ['site/index'], * 'linkOptions' => [...], - * ), + * ], * [ * 'label' => 'Dropdown', * 'items' => [ diff --git a/framework/yii/data/ArrayDataProvider.php b/framework/yii/data/ArrayDataProvider.php index e3f1b34..2b694c7 100644 --- a/framework/yii/data/ArrayDataProvider.php +++ b/framework/yii/data/ArrayDataProvider.php @@ -33,7 +33,7 @@ use yii\helpers\ArrayHelper; * 'allModels' => $query->from('tbl_post')->all(), * 'sort' => [ * 'attributes' => ['id', 'username', 'email'], - * ), + * ], * 'pagination' => [ * 'pageSize' => 10, * ], diff --git a/framework/yii/log/Logger.php b/framework/yii/log/Logger.php index ad0ab8d..4e0e547 100644 --- a/framework/yii/log/Logger.php +++ b/framework/yii/log/Logger.php @@ -39,7 +39,7 @@ use yii\base\InvalidConfigException; * 'class' => 'yii\log\FileTarget', * 'levels' => ['trace', 'info'], * 'categories' => ['yii\*'], - * ), + * ], * 'email' => [ * 'class' => 'yii\log\EmailTarget', * 'levels' => ['error', 'warning'], diff --git a/framework/yii/web/AccessControl.php b/framework/yii/web/AccessControl.php index f9b82df..d11f59c 100644 --- a/framework/yii/web/AccessControl.php +++ b/framework/yii/web/AccessControl.php @@ -42,9 +42,9 @@ use yii\base\ActionFilter; * 'roles' => ['@'], * ], * // everything else is denied - * ), - * ), - * ); + * ], + * ], + * ]; * } * ~~~ * diff --git a/framework/yii/widgets/Menu.php b/framework/yii/widgets/Menu.php index db4a5d4..7ea7717 100644 --- a/framework/yii/widgets/Menu.php +++ b/framework/yii/widgets/Menu.php @@ -33,13 +33,13 @@ use yii\helpers\Html; * // not just as 'controller' even if default action is used. * ['label' => 'Home', 'url' => ['site/index']], * // 'Products' menu item will be selected as long as the route is 'product/index' - * ['label' => 'Products', 'url' => ['product/index'), 'items' => [ + * ['label' => 'Products', 'url' => ['product/index'], 'items' => [ * ['label' => 'New Arrivals', 'url' => ['product/index', 'tag' => 'new']], * ['label' => 'Most Popular', 'url' => ['product/index', 'tag' => 'popular']], * ]], * ['label' => 'Login', 'url' => ['site/login'], 'visible' => Yii::$app->user->isGuest], - * ), - * )); + * ], + * ]); * ~~~ * * @author Qiang Xue From 9963d47f1682fa38fd79979e2a575ee7e0652bd3 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Thu, 24 Oct 2013 07:20:10 -0400 Subject: [PATCH 31/40] revert back the change about message class so that the class can be lazily loaded. --- framework/yii/i18n/I18N.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/yii/i18n/I18N.php b/framework/yii/i18n/I18N.php index cf8243e..b2b99b5 100644 --- a/framework/yii/i18n/I18N.php +++ b/framework/yii/i18n/I18N.php @@ -45,14 +45,14 @@ class I18N extends Component parent::init(); if (!isset($this->translations['yii'])) { $this->translations['yii'] = [ - 'class' => PhpMessageSource::className(), + 'class' => 'yii\i18n\PhpMessageSource', 'sourceLanguage' => 'en_US', 'basePath' => '@yii/messages', ]; } if (!isset($this->translations['app'])) { $this->translations['app'] = [ - 'class' => PhpMessageSource::className(), + 'class' => 'yii\i18n\PhpMessageSource', 'sourceLanguage' => 'en_US', 'basePath' => '@app/messages', ]; From 1af4ffd21a816316cc5d10ee0e0eba40e0290930 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Thu, 24 Oct 2013 16:55:45 +0400 Subject: [PATCH 32/40] Fixes #1056: removed 5.3 compatibiltiy code from ArrayHelper::multisort, fixed phpdoc --- framework/yii/helpers/BaseArrayHelper.php | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/framework/yii/helpers/BaseArrayHelper.php b/framework/yii/helpers/BaseArrayHelper.php index b7d0a2f..a5382e7 100644 --- a/framework/yii/helpers/BaseArrayHelper.php +++ b/framework/yii/helpers/BaseArrayHelper.php @@ -336,7 +336,7 @@ class BaseArrayHelper * @param boolean|array $descending whether to sort in descending or ascending order. When * sorting by multiple keys with different descending orders, use an array of descending flags. * @param integer|array $sortFlag the PHP sort flag. Valid values include - * `SORT_REGULAR`, `SORT_NUMERIC`, `SORT_STRING` and `SORT_LOCALE_STRING`. + * `SORT_REGULAR`, `SORT_NUMERIC`, `SORT_STRING`, `SORT_LOCALE_STRING`, `SORT_NATURAL` and `SORT_FLAG_CASE`. * Please refer to [PHP manual](http://php.net/manual/en/function.sort.php) * for more details. When sorting by multiple keys with different sort flags, use an array of sort flags. * @param boolean|array $caseSensitive whether to sort string in case-sensitive manner. This parameter @@ -372,16 +372,8 @@ class BaseArrayHelper $flag = $sortFlag[$i]; $cs = $caseSensitive[$i]; if (!$cs && ($flag === SORT_STRING)) { - if (defined('SORT_FLAG_CASE')) { - $flag = $flag | SORT_FLAG_CASE; - $args[] = static::getColumn($array, $key); - } else { - $column = []; - foreach (static::getColumn($array, $key) as $k => $value) { - $column[$k] = mb_strtolower($value); - } - $args[] = $column; - } + $flag = $flag | SORT_FLAG_CASE; + $args[] = static::getColumn($array, $key); } else { $args[] = static::getColumn($array, $key); } From e67b9a8482fa3f0269cd76df4cce4a265c5b9955 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Thu, 24 Oct 2013 17:05:08 +0400 Subject: [PATCH 33/40] Removed check for PHP 5.4 from Session::open() --- framework/yii/web/Session.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/framework/yii/web/Session.php b/framework/yii/web/Session.php index d081cc9..b03c74b 100644 --- a/framework/yii/web/Session.php +++ b/framework/yii/web/Session.php @@ -118,12 +118,9 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co */ public function open() { - // this is available in PHP 5.4.0+ - if (function_exists('session_status')) { - if (session_status() == PHP_SESSION_ACTIVE) { - $this->_opened = true; - return; - } + if (session_status() == PHP_SESSION_ACTIVE) { + $this->_opened = true; + return; } if (!$this->_opened) { From 8c98d99596fdc77da72cf48741048d3fae0d0c58 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Thu, 24 Oct 2013 17:06:40 +0400 Subject: [PATCH 34/40] Removed fallback from mb_parse_str to parse_str from Request::getRestParams since mb_ availability is Yii2 requirement --- framework/yii/web/Request.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/framework/yii/web/Request.php b/framework/yii/web/Request.php index f326f6e..610e907 100644 --- a/framework/yii/web/Request.php +++ b/framework/yii/web/Request.php @@ -246,11 +246,7 @@ class Request extends \yii\base\Request $this->_restParams = $_POST; } else { $this->_restParams = []; - if (function_exists('mb_parse_str')) { - mb_parse_str($this->getRawBody(), $this->_restParams); - } else { - parse_str($this->getRawBody(), $this->_restParams); - } + mb_parse_str($this->getRawBody(), $this->_restParams); } } return $this->_restParams; From 28aa451557a0e3e80501f2a00c6f2871ca6fbb26 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Thu, 24 Oct 2013 17:40:42 +0400 Subject: [PATCH 35/40] Reverted 5.4 enhancements on requirements checked to be able to run it on lower PHP versions --- .../yii/requirements/YiiRequirementChecker.php | 42 +++++++++++----------- framework/yii/requirements/requirements.php | 30 ++++++++-------- framework/yii/requirements/views/web/index.php | 12 +++---- 3 files changed, 42 insertions(+), 42 deletions(-) diff --git a/framework/yii/requirements/YiiRequirementChecker.php b/framework/yii/requirements/YiiRequirementChecker.php index 77e98d7..c8ad45d 100644 --- a/framework/yii/requirements/YiiRequirementChecker.php +++ b/framework/yii/requirements/YiiRequirementChecker.php @@ -19,15 +19,15 @@ if (version_compare(PHP_VERSION, '4.3', '<')) { * ~~~php * require_once('path/to/YiiRequirementChecker.php'); * $requirementsChecker = new YiiRequirementChecker(); - * $requirements = [ - * [ + * $requirements = array( + * array( * 'name' => 'PHP Some Extension', * 'mandatory' => true, * 'condition' => extension_loaded('some_extension'), * 'by' => 'Some application feature', * 'memo' => 'PHP extension "some_extension" required', - * ], - * ]; + * ), + * ); * $requirementsChecker->checkYii()->check($requirements)->render(); * ~~~ * @@ -38,12 +38,12 @@ if (version_compare(PHP_VERSION, '4.3', '<')) { * For example: * * ~~~ - * $requirements = [ - * [ + * $requirements = array( + * array( * 'name' => 'Upload max file size', * 'condition' => 'eval:$this->checkUploadMaxFileSize("5M")', - * ], - * ]; + * ), + * ); * ~~~ * * Note: this class definition does not match ordinary Yii style, because it should match PHP 4.3 @@ -74,14 +74,14 @@ class YiiRequirementChecker $this->usageError('Requirements must be an array, "' . gettype($requirements) . '" has been given!'); } if (!isset($this->result) || !is_array($this->result)) { - $this->result = [ - 'summary' => [ + $this->result = array( + 'summary' => array( 'total' => 0, 'errors' => 0, 'warnings' => 0, - ], - 'requirements' => [], - ]; + ), + 'requirements' => array(), + ); } foreach ($requirements as $key => $rawRequirement) { $requirement = $this->normalizeRequirement($rawRequirement, $key); @@ -118,21 +118,21 @@ class YiiRequirementChecker * Return the check results. * @return array|null check results in format: * - * [ - * 'summary' => [ + * array( + * 'summary' => array( * 'total' => total number of checks, * 'errors' => number of errors, * 'warnings' => number of warnings, - * ], - * 'requirements' => [ - * [ + * ), + * 'requirements' => array( + * array( * ... * 'error' => is there an error, * 'warning' => is there a warning, - * ], + * ), * ... - * ], - * ] + * ), + * ) * */ function getResult() diff --git a/framework/yii/requirements/requirements.php b/framework/yii/requirements/requirements.php index 9f9f582..c722aa9 100644 --- a/framework/yii/requirements/requirements.php +++ b/framework/yii/requirements/requirements.php @@ -1,44 +1,44 @@ 'PHP version', 'mandatory' => true, 'condition' => version_compare(PHP_VERSION, '5.4.0', '>='), 'by' => 'Yii Framework', 'memo' => 'PHP 5.4.0 or higher is required.', - ], - [ + ), + array( 'name' => 'Reflection extension', 'mandatory' => true, 'condition' => class_exists('Reflection', false), 'by' => 'Yii Framework', - ], - [ + ), + array( 'name' => 'PCRE extension', 'mandatory' => true, 'condition' => extension_loaded('pcre'), 'by' => 'Yii Framework', - ], - [ + ), + array( 'name' => 'SPL extension', 'mandatory' => true, 'condition' => extension_loaded('SPL'), 'by' => 'Yii Framework', - ], - [ + ), + array( 'name' => 'MBString extension', 'mandatory' => true, 'condition' => extension_loaded('mbstring'), 'by' => 'Multibyte string processing', 'memo' => 'Required for multibyte encoding string processing.' - ], - [ + ), + array( 'name' => 'Intl extension', 'mandatory' => false, 'condition' => $this->checkPhpExtensionVersion('intl', '1.0.2', '>='), @@ -46,5 +46,5 @@ return [ 'memo' => 'PHP Intl extension 1.0.2 or higher is required when you want to use advanced parameters formatting in \Yii::t(), IDN-feature of EmailValidator or UrlValidator or the yii\i18n\Formatter class.' - ], -]; + ), +); diff --git a/framework/yii/requirements/views/web/index.php b/framework/yii/requirements/views/web/index.php index 82e3fdb..c45ce11 100644 --- a/framework/yii/requirements/views/web/index.php +++ b/framework/yii/requirements/views/web/index.php @@ -52,18 +52,18 @@ - + @@ -74,7 +74,7 @@
From 86c3fff07aa8642dfb36215ab7b3ccab5c5c75b2 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Thu, 24 Oct 2013 20:51:22 +0400 Subject: [PATCH 36/40] Fixes autoreplacement --- framework/yii/requirements/requirements.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/yii/requirements/requirements.php b/framework/yii/requirements/requirements.php index c722aa9..f70f414 100644 --- a/framework/yii/requirements/requirements.php +++ b/framework/yii/requirements/requirements.php @@ -1,6 +1,6 @@ Date: Thu, 24 Oct 2013 20:56:52 +0400 Subject: [PATCH 37/40] Fixes issue #858: Tabs::widget type problem --- framework/yii/bootstrap/Tabs.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/framework/yii/bootstrap/Tabs.php b/framework/yii/bootstrap/Tabs.php index 653ed68..2e76398 100644 --- a/framework/yii/bootstrap/Tabs.php +++ b/framework/yii/bootstrap/Tabs.php @@ -85,6 +85,10 @@ class Tabs extends Widget * @var boolean whether the labels for header items should be HTML-encoded. */ public $encodeLabels = true; + /** + * @var string, specifies the Bootstrap tab styling. + */ + public $navType = 'nav-tabs'; /** @@ -93,7 +97,7 @@ class Tabs extends Widget public function init() { parent::init(); - Html::addCssClass($this->options, 'nav nav-tabs'); + Html::addCssClass($this->options, 'nav ' . $this->navType); } /** From 9c5ba231a19e48e395a75b50076408acfb8e7699 Mon Sep 17 00:00:00 2001 From: Gudz Taras Date: Fri, 25 Oct 2013 01:48:32 +0400 Subject: [PATCH 38/40] Fixes issue #1063: Fatal Error while getting value from ActiveRelation generated by Gii --- framework/yii/gii/generators/model/Generator.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/framework/yii/gii/generators/model/Generator.php b/framework/yii/gii/generators/model/Generator.php index de9cc2f..9e8ac7d 100644 --- a/framework/yii/gii/generators/model/Generator.php +++ b/framework/yii/gii/generators/model/Generator.php @@ -265,8 +265,8 @@ class Generator extends \yii\gii\Generator $link = $this->generateRelationLink(array_flip($refs)); $relationName = $this->generateRelationName($relations, $className, $table, $fks[0], false); $relations[$className][$relationName] = [ - "return \$this->hasOne('$refClassName', $link);", - $refClassName, + "return \$this->hasOne('$this->ns\\$refClassName', $link);", + $this->ns . '\\' . $refClassName, false, ]; @@ -281,8 +281,8 @@ class Generator extends \yii\gii\Generator $link = $this->generateRelationLink($refs); $relationName = $this->generateRelationName($relations, $refClassName, $refTable, $className, $hasMany); $relations[$refClassName][$relationName] = [ - "return \$this->" . ($hasMany ? 'hasMany' : 'hasOne') . "('$className', $link);", - $className, + "return \$this->" . ($hasMany ? 'hasMany' : 'hasOne') . "('$this->ns\\$className', $link);", + $this->ns . '\\' . $className, $hasMany, ]; } @@ -299,8 +299,8 @@ class Generator extends \yii\gii\Generator $viaLink = $this->generateRelationLink([$table->primaryKey[0] => $fks[$table->primaryKey[0]][1]]); $relationName = $this->generateRelationName($relations, $className0, $db->getTableSchema($table0), $table->primaryKey[1], true); $relations[$className0][$relationName] = [ - "return \$this->hasMany('$className1', $link)->viaTable('{$table->name}', $viaLink);", - $className0, + "return \$this->hasMany('$this->ns\\$className1', $link)->viaTable('{$table->name}', $viaLink);", + $this->ns . '\\' . $className0, true, ]; @@ -308,8 +308,8 @@ class Generator extends \yii\gii\Generator $viaLink = $this->generateRelationLink([$table->primaryKey[1] => $fks[$table->primaryKey[1]][1]]); $relationName = $this->generateRelationName($relations, $className1, $db->getTableSchema($table1), $table->primaryKey[0], true); $relations[$className1][$relationName] = [ - "return \$this->hasMany('$className0', $link)->viaTable('{$table->name}', $viaLink);", - $className1, + "return \$this->hasMany('$this->ns\\$className0', $link)->viaTable('{$table->name}', $viaLink);", + $this->ns . '\\' . $className1, true, ]; } From 5b1ba04a9d9a8c1b4ff8f0d8e837f3ceb986048a Mon Sep 17 00:00:00 2001 From: Gudz Taras Date: Fri, 25 Oct 2013 04:10:26 +0400 Subject: [PATCH 39/40] Fixes #1063 --- framework/yii/gii/generators/model/Generator.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/framework/yii/gii/generators/model/Generator.php b/framework/yii/gii/generators/model/Generator.php index 9e8ac7d..bd42fab 100644 --- a/framework/yii/gii/generators/model/Generator.php +++ b/framework/yii/gii/generators/model/Generator.php @@ -265,8 +265,8 @@ class Generator extends \yii\gii\Generator $link = $this->generateRelationLink(array_flip($refs)); $relationName = $this->generateRelationName($relations, $className, $table, $fks[0], false); $relations[$className][$relationName] = [ - "return \$this->hasOne('$this->ns\\$refClassName', $link);", - $this->ns . '\\' . $refClassName, + "return \$this->hasOne($refClassName::className(), $link);", + $refClassName, false, ]; @@ -281,8 +281,8 @@ class Generator extends \yii\gii\Generator $link = $this->generateRelationLink($refs); $relationName = $this->generateRelationName($relations, $refClassName, $refTable, $className, $hasMany); $relations[$refClassName][$relationName] = [ - "return \$this->" . ($hasMany ? 'hasMany' : 'hasOne') . "('$this->ns\\$className', $link);", - $this->ns . '\\' . $className, + "return \$this->" . ($hasMany ? 'hasMany' : 'hasOne') . "($refClassName::className(), $link);", + $className, $hasMany, ]; } @@ -299,8 +299,8 @@ class Generator extends \yii\gii\Generator $viaLink = $this->generateRelationLink([$table->primaryKey[0] => $fks[$table->primaryKey[0]][1]]); $relationName = $this->generateRelationName($relations, $className0, $db->getTableSchema($table0), $table->primaryKey[1], true); $relations[$className0][$relationName] = [ - "return \$this->hasMany('$this->ns\\$className1', $link)->viaTable('{$table->name}', $viaLink);", - $this->ns . '\\' . $className0, + "return \$this->hasMany($className1::className(), $link)->viaTable('{$table->name}', $viaLink);", + $className0, true, ]; @@ -308,8 +308,8 @@ class Generator extends \yii\gii\Generator $viaLink = $this->generateRelationLink([$table->primaryKey[1] => $fks[$table->primaryKey[1]][1]]); $relationName = $this->generateRelationName($relations, $className1, $db->getTableSchema($table1), $table->primaryKey[0], true); $relations[$className1][$relationName] = [ - "return \$this->hasMany('$this->ns\\$className0', $link)->viaTable('{$table->name}', $viaLink);", - $this->ns . '\\' . $className1, + "return \$this->hasMany($className0::className(), $link)->viaTable('{$table->name}', $viaLink);", + $className1, true, ]; } From 2a71c72d7c8e3e2f66ef93c52952a6a3ad6da2c9 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Thu, 24 Oct 2013 21:24:30 -0400 Subject: [PATCH 40/40] fixes #1066: Added ActiveForm::validate() and validateMultiple() --- framework/yii/base/Model.php | 9 +++- framework/yii/widgets/ActiveForm.php | 89 ++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 2 deletions(-) diff --git a/framework/yii/base/Model.php b/framework/yii/base/Model.php index e469f66..99c1df9 100644 --- a/framework/yii/base/Model.php +++ b/framework/yii/base/Model.php @@ -748,16 +748,21 @@ class Model extends Component implements IteratorAggregate, ArrayAccess /** * Validates multiple models. + * This method will validate every model. The models being validated may + * be of the same or different types. * @param array $models the models to be validated + * @param array $attributes list of attributes that should be validated. + * If this parameter is empty, it means any attribute listed in the applicable + * validation rules should be validated. * @return boolean whether all models are valid. False will be returned if one * or multiple models have validation error. */ - public static function validateMultiple($models) + public static function validateMultiple($models, $attributes = null) { $valid = true; /** @var Model $model */ foreach ($models as $model) { - $valid = $model->validate() && $valid; + $valid = $model->validate($attributes) && $valid; } return $valid; } diff --git a/framework/yii/widgets/ActiveForm.php b/framework/yii/widgets/ActiveForm.php index 13135cf..c018011 100644 --- a/framework/yii/widgets/ActiveForm.php +++ b/framework/yii/widgets/ActiveForm.php @@ -265,4 +265,93 @@ class ActiveForm extends Widget 'form' => $this, ])); } + + /** + * Validates one or several models and returns an error message array indexed by the attribute IDs. + * This is a helper method that simplifies the way of writing AJAX validation code. + * + * For example, you may use the following code in a controller action to respond + * to an AJAX validation request: + * + * ~~~ + * $model = new Post; + * $model->load($_POST); + * if (Yii::$app->request->isAjax) { + * Yii::$app->response->format = Response::FORMAT_JSON; + * return ActiveForm::validate($model); + * } + * // ... respond to non-AJAX request ... + * ~~~ + * + * To validate multiple models, simply pass each model as a parameter to this method, like + * the following: + * + * ~~~ + * ActiveForm::validate($model1, $model2, ...); + * ~~~ + * + * @param Model $model the model to be validated + * @param mixed $attributes list of attributes that should be validated. + * If this parameter is empty, it means any attribute listed in the applicable + * validation rules should be validated. + * + * When this method is used to validate multiple models, this parameter will be interpreted + * as a model. + * + * @return array the error message array indexed by the attribute IDs. + */ + public static function validate($model, $attributes = null) + { + $result = []; + if ($attributes instanceof Model) { + // validating multiple models + $models = func_get_args(); + $attributes = null; + } else { + $models = [$model]; + } + /** @var Model $model */ + foreach ($models as $model) { + $model->validate($attributes); + foreach ($model->getErrors() as $attribute => $errors) { + $result[Html::getInputId($model, $attribute)] = $errors; + } + } + return $result; + } + + /** + * Validates an array of model instances and returns an error message array indexed by the attribute IDs. + * This is a helper method that simplifies the way of writing AJAX validation code for tabular input. + * + * For example, you may use the following code in a controller action to respond + * to an AJAX validation request: + * + * ~~~ + * // ... load $models ... + * if (Yii::$app->request->isAjax) { + * Yii::$app->response->format = Response::FORMAT_JSON; + * return ActiveForm::validateMultiple($models); + * } + * // ... respond to non-AJAX request ... + * ~~~ + * + * @param array $models an array of models to be validated. + * @param mixed $attributes list of attributes that should be validated. + * If this parameter is empty, it means any attribute listed in the applicable + * validation rules should be validated. + * @return array the error message array indexed by the attribute IDs. + */ + public static function validateMultiple($models, $attributes = null) + { + $result = []; + /** @var Model $model */ + foreach ($models as $i => $model) { + $model->validate($attributes); + foreach ($model->getErrors() as $attribute => $errors) { + $result[Html::getInputId($model, "[$i]" . $attribute)] = $errors; + } + } + return $result; + } }
NameResultRequired ByMemo
- + - + - + - +