init
This commit is contained in:
3
vendor/yiisoft/yii2/.gitignore
vendored
Normal file
3
vendor/yiisoft/yii2/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
phpunit.xml
|
||||
composer.lock
|
||||
|
||||
1
vendor/yiisoft/yii2/.htaccess
vendored
Normal file
1
vendor/yiisoft/yii2/.htaccess
vendored
Normal file
@@ -0,0 +1 @@
|
||||
deny from all
|
||||
564
vendor/yiisoft/yii2/BaseYii.php
vendored
Normal file
564
vendor/yiisoft/yii2/BaseYii.php
vendored
Normal file
@@ -0,0 +1,564 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii;
|
||||
|
||||
use yii\base\InvalidArgumentException;
|
||||
use yii\base\InvalidConfigException;
|
||||
use yii\base\UnknownClassException;
|
||||
use yii\di\Container;
|
||||
use yii\log\Logger;
|
||||
|
||||
/**
|
||||
* Gets the application start timestamp.
|
||||
*/
|
||||
defined('YII_BEGIN_TIME') or define('YII_BEGIN_TIME', microtime(true));
|
||||
/**
|
||||
* This constant defines the framework installation directory.
|
||||
*/
|
||||
defined('YII2_PATH') or define('YII2_PATH', __DIR__);
|
||||
/**
|
||||
* This constant defines whether the application should be in debug mode or not. Defaults to false.
|
||||
*/
|
||||
defined('YII_DEBUG') or define('YII_DEBUG', false);
|
||||
/**
|
||||
* This constant defines in which environment the application is running. Defaults to 'prod', meaning production environment.
|
||||
* You may define this constant in the bootstrap script. The value could be 'prod' (production), 'dev' (development), 'test', 'staging', etc.
|
||||
*/
|
||||
defined('YII_ENV') or define('YII_ENV', 'prod');
|
||||
/**
|
||||
* Whether the the application is running in production environment.
|
||||
*/
|
||||
defined('YII_ENV_PROD') or define('YII_ENV_PROD', YII_ENV === 'prod');
|
||||
/**
|
||||
* Whether the the application is running in development environment.
|
||||
*/
|
||||
defined('YII_ENV_DEV') or define('YII_ENV_DEV', YII_ENV === 'dev');
|
||||
/**
|
||||
* Whether the the application is running in testing environment.
|
||||
*/
|
||||
defined('YII_ENV_TEST') or define('YII_ENV_TEST', YII_ENV === 'test');
|
||||
|
||||
/**
|
||||
* This constant defines whether error handling should be enabled. Defaults to true.
|
||||
*/
|
||||
defined('YII_ENABLE_ERROR_HANDLER') or define('YII_ENABLE_ERROR_HANDLER', true);
|
||||
|
||||
/**
|
||||
* BaseYii is the core helper class for the Yii framework.
|
||||
*
|
||||
* Do not use BaseYii directly. Instead, use its child class [[\Yii]] which you can replace to
|
||||
* customize methods of BaseYii.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class BaseYii
|
||||
{
|
||||
/**
|
||||
* @var array class map used by the Yii autoloading mechanism.
|
||||
* The array keys are the class names (without leading backslashes), and the array values
|
||||
* are the corresponding class file paths (or [path aliases](guide:concept-aliases)). This property mainly affects
|
||||
* how [[autoload()]] works.
|
||||
* @see autoload()
|
||||
*/
|
||||
public static $classMap = [];
|
||||
/**
|
||||
* @var \yii\console\Application|\yii\web\Application the application instance
|
||||
*/
|
||||
public static $app;
|
||||
/**
|
||||
* @var array registered path aliases
|
||||
* @see getAlias()
|
||||
* @see setAlias()
|
||||
*/
|
||||
public static $aliases = ['@yii' => __DIR__];
|
||||
/**
|
||||
* @var Container the dependency injection (DI) container used by [[createObject()]].
|
||||
* You may use [[Container::set()]] to set up the needed dependencies of classes and
|
||||
* their initial property values.
|
||||
* @see createObject()
|
||||
* @see Container
|
||||
*/
|
||||
public static $container;
|
||||
|
||||
|
||||
/**
|
||||
* Returns a string representing the current version of the Yii framework.
|
||||
* @return string the version of Yii framework
|
||||
*/
|
||||
public static function getVersion()
|
||||
{
|
||||
return '2.0.15.1';
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates a path alias into an actual path.
|
||||
*
|
||||
* The translation is done according to the following procedure:
|
||||
*
|
||||
* 1. If the given alias does not start with '@', it is returned back without change;
|
||||
* 2. Otherwise, look for the longest registered alias that matches the beginning part
|
||||
* of the given alias. If it exists, replace the matching part of the given alias with
|
||||
* the corresponding registered path.
|
||||
* 3. Throw an exception or return false, depending on the `$throwException` parameter.
|
||||
*
|
||||
* For example, by default '@yii' is registered as the alias to the Yii framework directory,
|
||||
* say '/path/to/yii'. The alias '@yii/web' would then be translated into '/path/to/yii/web'.
|
||||
*
|
||||
* If you have registered two aliases '@foo' and '@foo/bar'. Then translating '@foo/bar/config'
|
||||
* would replace the part '@foo/bar' (instead of '@foo') with the corresponding registered path.
|
||||
* This is because the longest alias takes precedence.
|
||||
*
|
||||
* However, if the alias to be translated is '@foo/barbar/config', then '@foo' will be replaced
|
||||
* instead of '@foo/bar', because '/' serves as the boundary character.
|
||||
*
|
||||
* Note, this method does not check if the returned path exists or not.
|
||||
*
|
||||
* See the [guide article on aliases](guide:concept-aliases) for more information.
|
||||
*
|
||||
* @param string $alias the alias to be translated.
|
||||
* @param bool $throwException whether to throw an exception if the given alias is invalid.
|
||||
* If this is false and an invalid alias is given, false will be returned by this method.
|
||||
* @return string|bool the path corresponding to the alias, false if the root alias is not previously registered.
|
||||
* @throws InvalidArgumentException if the alias is invalid while $throwException is true.
|
||||
* @see setAlias()
|
||||
*/
|
||||
public static function getAlias($alias, $throwException = true)
|
||||
{
|
||||
if (strncmp($alias, '@', 1)) {
|
||||
// not an alias
|
||||
return $alias;
|
||||
}
|
||||
|
||||
$pos = strpos($alias, '/');
|
||||
$root = $pos === false ? $alias : substr($alias, 0, $pos);
|
||||
|
||||
if (isset(static::$aliases[$root])) {
|
||||
if (is_string(static::$aliases[$root])) {
|
||||
return $pos === false ? static::$aliases[$root] : static::$aliases[$root] . substr($alias, $pos);
|
||||
}
|
||||
|
||||
foreach (static::$aliases[$root] as $name => $path) {
|
||||
if (strpos($alias . '/', $name . '/') === 0) {
|
||||
return $path . substr($alias, strlen($name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($throwException) {
|
||||
throw new InvalidArgumentException("Invalid path alias: $alias");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the root alias part of a given alias.
|
||||
* A root alias is an alias that has been registered via [[setAlias()]] previously.
|
||||
* If a given alias matches multiple root aliases, the longest one will be returned.
|
||||
* @param string $alias the alias
|
||||
* @return string|bool the root alias, or false if no root alias is found
|
||||
*/
|
||||
public static function getRootAlias($alias)
|
||||
{
|
||||
$pos = strpos($alias, '/');
|
||||
$root = $pos === false ? $alias : substr($alias, 0, $pos);
|
||||
|
||||
if (isset(static::$aliases[$root])) {
|
||||
if (is_string(static::$aliases[$root])) {
|
||||
return $root;
|
||||
}
|
||||
|
||||
foreach (static::$aliases[$root] as $name => $path) {
|
||||
if (strpos($alias . '/', $name . '/') === 0) {
|
||||
return $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a path alias.
|
||||
*
|
||||
* A path alias is a short name representing a long path (a file path, a URL, etc.)
|
||||
* For example, we use '@yii' as the alias of the path to the Yii framework directory.
|
||||
*
|
||||
* A path alias must start with the character '@' so that it can be easily differentiated
|
||||
* from non-alias paths.
|
||||
*
|
||||
* Note that this method does not check if the given path exists or not. All it does is
|
||||
* to associate the alias with the path.
|
||||
*
|
||||
* Any trailing '/' and '\' characters in the given path will be trimmed.
|
||||
*
|
||||
* See the [guide article on aliases](guide:concept-aliases) for more information.
|
||||
*
|
||||
* @param string $alias the alias name (e.g. "@yii"). It must start with a '@' character.
|
||||
* It may contain the forward slash '/' which serves as boundary character when performing
|
||||
* alias translation by [[getAlias()]].
|
||||
* @param string $path the path corresponding to the alias. If this is null, the alias will
|
||||
* be removed. Trailing '/' and '\' characters will be trimmed. This can be
|
||||
*
|
||||
* - a directory or a file path (e.g. `/tmp`, `/tmp/main.txt`)
|
||||
* - a URL (e.g. `http://www.yiiframework.com`)
|
||||
* - a path alias (e.g. `@yii/base`). In this case, the path alias will be converted into the
|
||||
* actual path first by calling [[getAlias()]].
|
||||
*
|
||||
* @throws InvalidArgumentException if $path is an invalid alias.
|
||||
* @see getAlias()
|
||||
*/
|
||||
public static function setAlias($alias, $path)
|
||||
{
|
||||
if (strncmp($alias, '@', 1)) {
|
||||
$alias = '@' . $alias;
|
||||
}
|
||||
$pos = strpos($alias, '/');
|
||||
$root = $pos === false ? $alias : substr($alias, 0, $pos);
|
||||
if ($path !== null) {
|
||||
$path = strncmp($path, '@', 1) ? rtrim($path, '\\/') : static::getAlias($path);
|
||||
if (!isset(static::$aliases[$root])) {
|
||||
if ($pos === false) {
|
||||
static::$aliases[$root] = $path;
|
||||
} else {
|
||||
static::$aliases[$root] = [$alias => $path];
|
||||
}
|
||||
} elseif (is_string(static::$aliases[$root])) {
|
||||
if ($pos === false) {
|
||||
static::$aliases[$root] = $path;
|
||||
} else {
|
||||
static::$aliases[$root] = [
|
||||
$alias => $path,
|
||||
$root => static::$aliases[$root],
|
||||
];
|
||||
}
|
||||
} else {
|
||||
static::$aliases[$root][$alias] = $path;
|
||||
krsort(static::$aliases[$root]);
|
||||
}
|
||||
} elseif (isset(static::$aliases[$root])) {
|
||||
if (is_array(static::$aliases[$root])) {
|
||||
unset(static::$aliases[$root][$alias]);
|
||||
} elseif ($pos === false) {
|
||||
unset(static::$aliases[$root]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class autoload loader.
|
||||
*
|
||||
* This method is invoked automatically when PHP sees an unknown class.
|
||||
* The method will attempt to include the class file according to the following procedure:
|
||||
*
|
||||
* 1. Search in [[classMap]];
|
||||
* 2. If the class is namespaced (e.g. `yii\base\Component`), it will attempt
|
||||
* to include the file associated with the corresponding path alias
|
||||
* (e.g. `@yii/base/Component.php`);
|
||||
*
|
||||
* This autoloader allows loading classes that follow the [PSR-4 standard](http://www.php-fig.org/psr/psr-4/)
|
||||
* and have its top-level namespace or sub-namespaces defined as path aliases.
|
||||
*
|
||||
* Example: When aliases `@yii` and `@yii/bootstrap` are defined, classes in the `yii\bootstrap` namespace
|
||||
* will be loaded using the `@yii/bootstrap` alias which points to the directory where bootstrap extension
|
||||
* files are installed and all classes from other `yii` namespaces will be loaded from the yii framework directory.
|
||||
*
|
||||
* Also the [guide section on autoloading](guide:concept-autoloading).
|
||||
*
|
||||
* @param string $className the fully qualified class name without a leading backslash "\"
|
||||
* @throws UnknownClassException if the class does not exist in the class file
|
||||
*/
|
||||
public static function autoload($className)
|
||||
{
|
||||
if (isset(static::$classMap[$className])) {
|
||||
$classFile = static::$classMap[$className];
|
||||
if ($classFile[0] === '@') {
|
||||
$classFile = static::getAlias($classFile);
|
||||
}
|
||||
} elseif (strpos($className, '\\') !== false) {
|
||||
$classFile = static::getAlias('@' . str_replace('\\', '/', $className) . '.php', false);
|
||||
if ($classFile === false || !is_file($classFile)) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
include $classFile;
|
||||
|
||||
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. Namespace missing?");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new object using the given configuration.
|
||||
*
|
||||
* You may view this method as an enhanced version of the `new` operator.
|
||||
* The method supports creating an object based on a class name, a configuration array or
|
||||
* an anonymous function.
|
||||
*
|
||||
* Below are some usage examples:
|
||||
*
|
||||
* ```php
|
||||
* // create an object using a class name
|
||||
* $object = Yii::createObject('yii\db\Connection');
|
||||
*
|
||||
* // create an object using a configuration array
|
||||
* $object = Yii::createObject([
|
||||
* 'class' => 'yii\db\Connection',
|
||||
* 'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
|
||||
* 'username' => 'root',
|
||||
* 'password' => '',
|
||||
* 'charset' => 'utf8',
|
||||
* ]);
|
||||
*
|
||||
* // create an object with two constructor parameters
|
||||
* $object = \Yii::createObject('MyClass', [$param1, $param2]);
|
||||
* ```
|
||||
*
|
||||
* Using [[\yii\di\Container|dependency injection container]], this method can also identify
|
||||
* dependent objects, instantiate them and inject them into the newly created object.
|
||||
*
|
||||
* @param string|array|callable $type the object type. This can be specified in one of the following forms:
|
||||
*
|
||||
* - a string: representing the class name of the object to be created
|
||||
* - a configuration array: the array must contain a `class` element which is treated as the object class,
|
||||
* and the rest of the name-value pairs will be used to initialize the corresponding object properties
|
||||
* - a PHP callable: either an anonymous function or an array representing a class method (`[$class or $object, $method]`).
|
||||
* The callable should return a new instance of the object being created.
|
||||
*
|
||||
* @param array $params the constructor parameters
|
||||
* @return object the created object
|
||||
* @throws InvalidConfigException if the configuration is invalid.
|
||||
* @see \yii\di\Container
|
||||
*/
|
||||
public static function createObject($type, array $params = [])
|
||||
{
|
||||
if (is_string($type)) {
|
||||
return static::$container->get($type, $params);
|
||||
} elseif (is_array($type) && isset($type['class'])) {
|
||||
$class = $type['class'];
|
||||
unset($type['class']);
|
||||
return static::$container->get($class, $params, $type);
|
||||
} elseif (is_callable($type, true)) {
|
||||
return static::$container->invoke($type, $params);
|
||||
} elseif (is_array($type)) {
|
||||
throw new InvalidConfigException('Object configuration must be an array containing a "class" element.');
|
||||
}
|
||||
|
||||
throw new InvalidConfigException('Unsupported configuration type: ' . gettype($type));
|
||||
}
|
||||
|
||||
private static $_logger;
|
||||
|
||||
/**
|
||||
* @return Logger message logger
|
||||
*/
|
||||
public static function getLogger()
|
||||
{
|
||||
if (self::$_logger !== null) {
|
||||
return self::$_logger;
|
||||
}
|
||||
|
||||
return self::$_logger = static::createObject('yii\log\Logger');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the logger object.
|
||||
* @param Logger $logger the logger object.
|
||||
*/
|
||||
public static function setLogger($logger)
|
||||
{
|
||||
self::$_logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a debug message.
|
||||
* Trace messages are logged mainly for development purpose to see
|
||||
* the execution work flow of some code. This method will only log
|
||||
* a message when the application is in debug mode.
|
||||
* @param string|array $message the message to be logged. This can be a simple string or a more
|
||||
* complex data structure, such as array.
|
||||
* @param string $category the category of the message.
|
||||
* @since 2.0.14
|
||||
*/
|
||||
public static function debug($message, $category = 'application')
|
||||
{
|
||||
if (YII_DEBUG) {
|
||||
static::getLogger()->log($message, Logger::LEVEL_TRACE, $category);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias of [[debug()]].
|
||||
* @param string|array $message the message to be logged. This can be a simple string or a more
|
||||
* complex data structure, such as array.
|
||||
* @param string $category the category of the message.
|
||||
* @deprecated since 2.0.14. Use [[debug()]] instead.
|
||||
*/
|
||||
public static function trace($message, $category = 'application')
|
||||
{
|
||||
static::debug($message, $category);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs an error message.
|
||||
* An error message is typically logged when an unrecoverable error occurs
|
||||
* during the execution of an application.
|
||||
* @param string|array $message the message to be logged. This can be a simple string or a more
|
||||
* complex data structure, such as array.
|
||||
* @param string $category the category of the message.
|
||||
*/
|
||||
public static function error($message, $category = 'application')
|
||||
{
|
||||
static::getLogger()->log($message, Logger::LEVEL_ERROR, $category);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a warning message.
|
||||
* A warning message is typically logged when an error occurs while the execution
|
||||
* can still continue.
|
||||
* @param string|array $message the message to be logged. This can be a simple string or a more
|
||||
* complex data structure, such as array.
|
||||
* @param string $category the category of the message.
|
||||
*/
|
||||
public static function warning($message, $category = 'application')
|
||||
{
|
||||
static::getLogger()->log($message, Logger::LEVEL_WARNING, $category);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs an informative message.
|
||||
* An informative message is typically logged by an application to keep record of
|
||||
* something important (e.g. an administrator logs in).
|
||||
* @param string|array $message the message to be logged. This can be a simple string or a more
|
||||
* complex data structure, such as array.
|
||||
* @param string $category the category of the message.
|
||||
*/
|
||||
public static function info($message, $category = 'application')
|
||||
{
|
||||
static::getLogger()->log($message, Logger::LEVEL_INFO, $category);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the beginning of a code block for profiling.
|
||||
*
|
||||
* This has to be matched with a call to [[endProfile]] with the same category name.
|
||||
* The begin- and end- calls must also be properly nested. For example,
|
||||
*
|
||||
* ```php
|
||||
* \Yii::beginProfile('block1');
|
||||
* // some code to be profiled
|
||||
* \Yii::beginProfile('block2');
|
||||
* // some other code to be profiled
|
||||
* \Yii::endProfile('block2');
|
||||
* \Yii::endProfile('block1');
|
||||
* ```
|
||||
* @param string $token token for the code block
|
||||
* @param string $category the category of this log message
|
||||
* @see endProfile()
|
||||
*/
|
||||
public static function beginProfile($token, $category = 'application')
|
||||
{
|
||||
static::getLogger()->log($token, Logger::LEVEL_PROFILE_BEGIN, $category);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the end of a code block for profiling.
|
||||
* This has to be matched with a previous call to [[beginProfile]] with the same category name.
|
||||
* @param string $token token for the code block
|
||||
* @param string $category the category of this log message
|
||||
* @see beginProfile()
|
||||
*/
|
||||
public static function endProfile($token, $category = 'application')
|
||||
{
|
||||
static::getLogger()->log($token, Logger::LEVEL_PROFILE_END, $category);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an HTML hyperlink that can be displayed on your Web page showing "Powered by Yii Framework" information.
|
||||
* @return string an HTML hyperlink that can be displayed on your Web page showing "Powered by Yii Framework" information
|
||||
* @deprecated since 2.0.14, this method will be removed in 2.1.0.
|
||||
*/
|
||||
public static function powered()
|
||||
{
|
||||
return \Yii::t('yii', 'Powered by {yii}', [
|
||||
'yii' => '<a href="http://www.yiiframework.com/" rel="external">' . \Yii::t('yii',
|
||||
'Yii Framework') . '</a>',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates a message to the specified language.
|
||||
*
|
||||
* This is a shortcut method of [[\yii\i18n\I18N::translate()]].
|
||||
*
|
||||
* The translation will be conducted according to the message category and the target language will be used.
|
||||
*
|
||||
* You can add parameters to a translation message that will be substituted with the corresponding value after
|
||||
* translation. The format for this is to use curly brackets around the parameter name as you can see in the following example:
|
||||
*
|
||||
* ```php
|
||||
* $username = 'Alexander';
|
||||
* echo \Yii::t('app', 'Hello, {username}!', ['username' => $username]);
|
||||
* ```
|
||||
*
|
||||
* Further formatting of message parameters is supported using the [PHP intl extensions](http://www.php.net/manual/en/intro.intl.php)
|
||||
* message formatter. See [[\yii\i18n\I18N::translate()]] for more details.
|
||||
*
|
||||
* @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.
|
||||
* @param string $language the language code (e.g. `en-US`, `en`). If this is null, the current
|
||||
* [[\yii\base\Application::language|application language]] will be used.
|
||||
* @return string the translated message.
|
||||
*/
|
||||
public static function t($category, $message, $params = [], $language = null)
|
||||
{
|
||||
if (static::$app !== null) {
|
||||
return static::$app->getI18n()->translate($category, $message, $params, $language ?: static::$app->language);
|
||||
}
|
||||
|
||||
$placeholders = [];
|
||||
foreach ((array) $params as $name => $value) {
|
||||
$placeholders['{' . $name . '}'] = $value;
|
||||
}
|
||||
|
||||
return ($placeholders === []) ? $message : strtr($message, $placeholders);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures an object with the initial property values.
|
||||
* @param object $object the object to be configured
|
||||
* @param array $properties the property initial values given in terms of name-value pairs.
|
||||
* @return object the object itself
|
||||
*/
|
||||
public static function configure($object, $properties)
|
||||
{
|
||||
foreach ($properties as $name => $value) {
|
||||
$object->$name = $value;
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the public member variables of an object.
|
||||
* This method is provided such that we can get the public member variables of an object.
|
||||
* It is different from "get_object_vars()" because the latter will return private
|
||||
* and protected variables if it is called within the object itself.
|
||||
* @param object $object the object to be handled
|
||||
* @return array the public member variables of the object
|
||||
*/
|
||||
public static function getObjectVars($object)
|
||||
{
|
||||
return get_object_vars($object);
|
||||
}
|
||||
}
|
||||
2160
vendor/yiisoft/yii2/CHANGELOG.md
vendored
Normal file
2160
vendor/yiisoft/yii2/CHANGELOG.md
vendored
Normal file
File diff suppressed because it is too large
Load Diff
32
vendor/yiisoft/yii2/LICENSE.md
vendored
Normal file
32
vendor/yiisoft/yii2/LICENSE.md
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
The Yii framework is free software. It is released under the terms of
|
||||
the following BSD License.
|
||||
|
||||
Copyright © 2008 by Yii Software LLC (http://www.yiisoft.com)
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Yii Software LLC nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
28
vendor/yiisoft/yii2/README.md
vendored
Normal file
28
vendor/yiisoft/yii2/README.md
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
Yii PHP Framework Version 2
|
||||
===========================
|
||||
|
||||
This is the core framework code of [Yii 2](https://github.com/yiisoft/yii2#readme).
|
||||
|
||||
This repository is a read-only git subsplit of <https://github.com/yiisoft/yii2>.
|
||||
Please submit issue reports and pull requests to the main repository.
|
||||
For license information check the [LICENSE](LICENSE.md)-file.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
The preferred way to install the Yii framework is through [composer](http://getcomposer.org/download/).
|
||||
|
||||
Either run
|
||||
|
||||
```
|
||||
composer global require "fxp/composer-asset-plugin:^1.4.1"
|
||||
composer require yiisoft/yii2
|
||||
```
|
||||
|
||||
or add
|
||||
|
||||
```json
|
||||
"yiisoft/yii2": "~2.0.0",
|
||||
```
|
||||
|
||||
to the require section of your composer.json.
|
||||
745
vendor/yiisoft/yii2/UPGRADE.md
vendored
Normal file
745
vendor/yiisoft/yii2/UPGRADE.md
vendored
Normal file
@@ -0,0 +1,745 @@
|
||||
Upgrading Instructions for Yii Framework 2.0
|
||||
============================================
|
||||
|
||||
This file contains the upgrade notes for Yii 2.0. These notes highlight changes that
|
||||
could break your application when you upgrade Yii from one version to another.
|
||||
Even though we try to ensure backwards compabitilty (BC) as much as possible, sometimes
|
||||
it is not possible or very complicated to avoid it and still create a good solution to
|
||||
a problem. You may also want to check out the [versioning policy](https://github.com/yiisoft/yii2/blob/master/docs/internals/versions.md)
|
||||
for further details.
|
||||
|
||||
Upgrading in general is as simple as updating your dependency in your composer.json and
|
||||
running `composer update`. In a big application however there may be more things to consider,
|
||||
which are explained in the following.
|
||||
|
||||
> Note: This document assumes you have composer [installed globally](http://www.yiiframework.com/doc-2.0/guide-start-installation.html#installing-composer)
|
||||
so that you can run the `composer` command. If you have a `composer.phar` file inside of your project you need to
|
||||
replace `composer` with `php composer.phar` in the following.
|
||||
|
||||
> Tip: Upgrading dependencies of a complex software project always comes at the risk of breaking something, so make sure
|
||||
you have a backup (you should be doing this anyway ;) ).
|
||||
|
||||
In case you use [composer asset plugin](https://github.com/fxpio/composer-asset-plugin) instead of the currently recommended
|
||||
[asset-packagist.org](https://asset-packagist.org) to install Bower and NPM assets, make sure it is upgraded to the latest version as well. To ensure best stability you should also upgrade composer in this step:
|
||||
|
||||
composer self-update
|
||||
composer global require "fxp/composer-asset-plugin:^1.4.1" --no-plugins
|
||||
|
||||
The simple way to upgrade Yii, for example to version 2.0.10 (replace this with the version you want) will be running `composer require`:
|
||||
|
||||
composer require "yiisoft/yii2:~2.0.10" --update-with-dependencies
|
||||
|
||||
This command will only upgrade Yii and its direct dependencies, if necessary. Without `--update-with-dependencies` the
|
||||
upgrade might fail when the Yii version you chose has slightly different dependencies than the version you had before.
|
||||
`composer require` will by default not update any other packages as a safety feature.
|
||||
|
||||
Another way to upgrade is to change the `composer.json` file to require the new Yii version and then
|
||||
run `composer update` by specifying all packages that are allowed to be updated.
|
||||
|
||||
composer update yiisoft/yii2 yiisoft/yii2-composer bower-asset/inputmask
|
||||
|
||||
The above command will only update the specified packages and leave the versions of all other dependencies intact.
|
||||
This helps to update packages step by step without causing a lot of package version changes that might break in some way.
|
||||
If you feel lucky you can of course update everything to the latest version by running `composer update` without
|
||||
any restrictions.
|
||||
|
||||
After upgrading you should check whether your application still works as expected and no tests are broken.
|
||||
See the following notes on which changes to consider when upgrading from one version to another.
|
||||
|
||||
> Note: The following upgrading instructions are cumulative. That is,
|
||||
if you want to upgrade from version A to version C and there is
|
||||
version B between A and C, you need to follow the instructions
|
||||
for both A and B.
|
||||
|
||||
|
||||
Upgrade from Yii 2.0.14
|
||||
-----------------------
|
||||
|
||||
* When hash format condition (array) is used in `yii\db\ActiveRecord::findOne()` and `findAll()`, the array keys (column names)
|
||||
are now limited to the table column names. This is to prevent SQL injection if input was not filtered properly.
|
||||
You should check all usages of `findOne()` and `findAll()` to ensure that input is filtered correctly.
|
||||
If you need to find models using different keys than the table columns, use `find()->where(...)` instead.
|
||||
|
||||
It's not an issue in the default generated code though as ID is filtered by
|
||||
controller code:
|
||||
|
||||
The following code examples are **not** affected by this issue (examples shown for `findOne()` are valid also for `findAll()`):
|
||||
|
||||
```php
|
||||
// yii\web\Controller ensures that $id is scalar
|
||||
public function actionView($id)
|
||||
{
|
||||
$model = Post::findOne($id);
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
```php
|
||||
// casting to (int) or (string) ensures no array can be injected (an exception will be thrown so this is not a good practise)
|
||||
$model = Post::findOne((int) Yii::$app->request->get('id'));
|
||||
```
|
||||
|
||||
```php
|
||||
// explicitly specifying the colum to search, passing a scalar or array here will always result in finding a single record
|
||||
$model = Post::findOne(['id' => Yii::$app->request->get('id')]);
|
||||
```
|
||||
|
||||
The following code however **is vulnerable**, an attacker could inject an array with an arbitrary condition and even exploit SQL injection:
|
||||
|
||||
```php
|
||||
$model = Post::findOne(Yii::$app->request->get('id'));
|
||||
```
|
||||
|
||||
For the above example, the SQL injection part is fixed with the patches provided in this release, but an attacker may still be able to search
|
||||
records by different condition than a primary key search and violate your application business logic. So passing user input directly like this can cause problems and should be avoided.
|
||||
|
||||
|
||||
Upgrade from Yii 2.0.13
|
||||
-----------------------
|
||||
|
||||
* Constants `IPV6_ADDRESS_LENGTH`, `IPV4_ADDRESS_LENGTH` were moved from `yii\validators\IpValidator` to `yii\helpers\IpHelper`.
|
||||
If your application relies on these constants, make sure to update your code to follow the changes.
|
||||
|
||||
* `yii\base\Security::compareString()` is now throwing `yii\base\InvalidArgumentException` in case non-strings are compared.
|
||||
|
||||
* `yii\db\ExpressionInterface` has been introduced to represent a wider range of SQL expressions. In case you check for
|
||||
`instanceof yii\db\Expression` in your code, you might consider changing that to checking for the interface and use the newly
|
||||
introduced methods to retrieve the expression content.
|
||||
|
||||
* Added JSON support for PostgreSQL and MySQL as well as Arrays support for PostgreSQL in ActiveRecord layer.
|
||||
In case you already implemented such support yourself, please switch to Yii implementation.
|
||||
* For MySQL JSON and PgSQL JSON & JSONB columns Active Record will return decoded JSON (that can be either array or scalar) after data population
|
||||
and expects arrays or scalars to be assigned for further saving them into a database.
|
||||
* For PgSQL Array columns Active Record will return `yii\db\ArrayExpression` object that acts as an array
|
||||
(it implements `ArrayAccess`, `Traversable` and `Countable` interfaces) and expects array or `yii\db\ArrayExpression` to be
|
||||
assigned for further saving it into the database.
|
||||
|
||||
In case this change makes the upgrade process to Yii 2.0.14 too hard in your project, you can [switch off the described behavior](https://github.com/yiisoft/yii2/issues/15716#issuecomment-368143206)
|
||||
Then you can take your time to change your code and then re-enable arrays or JSON support.
|
||||
|
||||
* `yii\db\PdoValue` class has been introduced to replace a special syntax that was used to declare PDO parameter type
|
||||
when binding parameters to an SQL command, for example: `['value', \PDO::PARAM_STR]`.
|
||||
You should use `new PdoValue('value', \PDO::PARAM_STR)` instead. Old syntax will be removed in Yii 2.1.
|
||||
|
||||
* `yii\db\QueryBuilder::conditionBuilders` property and method-based condition builders are no longer used.
|
||||
Class-based conditions and builders are introduced instead to provide more flexibility, extensibility and
|
||||
space to customization. In case you rely on that property or override any of default condition builders, follow the
|
||||
special [guide article](http://www.yiiframework.com/doc-2.0/guide-db-query-builder.html#adding-custom-conditions-and-expressions)
|
||||
to update your code.
|
||||
|
||||
* Protected method `yii\db\ActiveQueryTrait::createModels()` does not apply indexes as defined in `indexBy` property anymore.
|
||||
In case you override default ActiveQuery implementation and relied on that behavior, call `yii\db\Query::populate()`
|
||||
method instead to index query results according to the `indexBy` parameter.
|
||||
|
||||
* Log targets (like `yii\log\EmailTarget`) are now throwing `yii\log\LogRuntimeException` in case log can not be properly exported.
|
||||
|
||||
* You can start preparing your application for Yii 2.1 by doing the following:
|
||||
|
||||
- Replace `::className()` calls with `::class` (if you’re running PHP 5.5+).
|
||||
- Replace usages of `yii\base\InvalidParamException` with `yii\base\InvalidArgumentException`.
|
||||
- Replace calls to `Yii::trace()` with `Yii::debug()`.
|
||||
- Remove calls to `yii\BaseYii::powered()`.
|
||||
- If you are using XCache or Zend data cache, those are going away in 2.1 so you might want to start looking for an alternative.
|
||||
|
||||
Upgrade from Yii 2.0.12
|
||||
-----------------------
|
||||
|
||||
* The `yii\web\Request` class allowed to determine the value of `getIsSecureConnection()` form the
|
||||
`X-Forwarded-Proto` header if the connection was made via a normal HTTP request. This behavior
|
||||
was insecure as the header could have been set by a malicious client on a non-HTTPS connection.
|
||||
With 2.0.13 Yii adds support for configuring trusted proxies. If your application runs behind a reverse proxy and relies on
|
||||
`getIsSecureConnection()` to return the value form the `X-Forwarded-Proto` header you need to explicitly allow
|
||||
this in the Request configuration. See the [guide](http://www.yiiframework.com/doc-2.0/guide-runtime-requests.html#trusted-proxies) for more information.
|
||||
|
||||
This setting also affects you when Yii is running on IIS webserver, which sets the `X-Rewrite-Url` header.
|
||||
This header is now filtered by default and must be listed in trusted hosts to be detected by Yii:
|
||||
|
||||
```php
|
||||
[ // accept X-Rewrite-Url from all hosts, as it will be set by IIS
|
||||
'/.*/' => ['X-Rewrite-Url'],
|
||||
]
|
||||
```
|
||||
|
||||
* For compatibiliy with [PHP 7.2 which does not allow classes to be named `Object` anymore](https://wiki.php.net/rfc/object-typehint),
|
||||
we needed to rename `yii\base\Object` to `yii\base\BaseObject`.
|
||||
|
||||
`yii\base\Object` still exists for backwards compatibility and will be loaded if needed in projects that are
|
||||
running on PHP <7.2. The compatibility class `yii\base\Object` extends from `yii\base\BaseObject` so if you
|
||||
have classes that extend from `yii\base\Object` these would still work.
|
||||
|
||||
What does not work however will be code that relies on `instanceof` checks or `is_subclass_of()` calls
|
||||
for `yii\base\Object` on framework classes as these do not extend `yii\base\Object` anymore but only
|
||||
extend from `yii\base\BaseObject`. In general such a check is not needed as there is a `yii\base\Configurable`
|
||||
interface you should check against instead.
|
||||
|
||||
Here is a visualisation of the change (`a < b` means "b extends a"):
|
||||
|
||||
```
|
||||
Before:
|
||||
|
||||
yii\base\Object < Framework Classes
|
||||
yii\base\Object < Application Classes
|
||||
|
||||
After Upgrade:
|
||||
|
||||
yii\base\BaseObject < Framework Classes
|
||||
yii\base\BaseObject < yii\base\Object < Application Classes
|
||||
|
||||
```
|
||||
|
||||
If you want to upgrade PHP to version 7.2 in your project you need to remove all cases that extend `yii\base\Object`
|
||||
and extend from `yii\base\BaseObject` instead:
|
||||
|
||||
```
|
||||
yii\base\BaseObject < Framework Classes
|
||||
yii\base\BaseObject < Application Classes
|
||||
```
|
||||
|
||||
For extensions that have classes extending from `yii\base\Object`, to be compatible with PHP 7.2, you need to
|
||||
require `"yiisoft/yii2": "~2.0.13"` in composer.json and change affected classes to extend from `yii\base\BaseObject`
|
||||
instead. It is not possible to allow Yii versions `<2.0.13` and be compatible with PHP 7.2 or higher.
|
||||
|
||||
* A new method `public static function instance($refresh = false);` has been added to the `yii\db\ActiveRecordInterface` via a new
|
||||
`yii\base\StaticInstanceInterface`. This change may affect your application in the following ways:
|
||||
|
||||
- If you have an `instance()` method defined in an `ActiveRecord` or `Model` class, you need to check whether the behavior is
|
||||
compatible with the method added by Yii.
|
||||
- Otherwise this method is implemented in the `yii\base\Model`, so the change only affects your code if you implement `ActiveRecordInterface`
|
||||
in a class that does not extend `Model`. You may use `yii\base\StaticInstanceTrait` to implement it.
|
||||
|
||||
* Fixed built-in validator creating when model has a method with the same name.
|
||||
|
||||
It is documented, that for the validation rules declared in model by `yii\base\Model::rules()`, validator can be either
|
||||
a built-in validator name, a method name of the model class, an anonymous function, or a validator class name.
|
||||
Before this change behavior was inconsistent with the documentation: method in the model had higher priority, than
|
||||
a built-in validator. In case you have relied on this behavior, make sure to fix it.
|
||||
|
||||
* Behavior was changed for methods `yii\base\Module::get()` and `yii\base\Module::has()` so in case when the requested
|
||||
component was not found in the current module, the parent ones will be checked for this component hierarchically.
|
||||
Considering that the root parent module is usually an application, this change can reduce calls to global `Yii::$app->get()`,
|
||||
and replace them with module-scope calls to `get()`, making code more reliable and easier to test.
|
||||
However, this change may affect your application if you have code that uses method `yii\base\Module::has()` in order
|
||||
to check existence of the component exactly in this specific module. In this case make sure the logic is not corrupted.
|
||||
|
||||
* If you are using "asset" command to compress assets and your web applicaiton `assetManager` has `linkAssets` turned on,
|
||||
make sure that "asset" command config has `linkAssets` turned on as well.
|
||||
|
||||
|
||||
Upgrade from Yii 2.0.11
|
||||
-----------------------
|
||||
|
||||
* `yii\i18n\Formatter::normalizeDatetimeValue()` returns now array with additional third boolean element
|
||||
indicating whether the timestamp has date information or it is just time value.
|
||||
|
||||
* `yii\grid\DataColumn` filter is now automatically generated as dropdown list with localized `Yes` and `No` strings
|
||||
in case of `format` being set to `boolean`.
|
||||
|
||||
* The signature of `yii\db\QueryBuilder::prepareInsertSelectSubQuery()` was changed. The method has got an extra optional parameter
|
||||
`$params`.
|
||||
|
||||
* The signature of `yii\cache\Cache::getOrSet()` has been adjusted to also accept a callable and not only `Closure`.
|
||||
If you extend this method, make sure to adjust your code.
|
||||
|
||||
* `yii\web\UrlManager` now checks if rules implement `getCreateUrlStatus()` method in order to decide whether to use
|
||||
internal cache for `createUrl()` calls. Ensure that all your custom rules implement this method in order to fully
|
||||
benefit from the acceleration provided by this cache.
|
||||
|
||||
* `yii\filters\AccessControl` now can be used without `user` component. This has two consequences:
|
||||
|
||||
1. If used without user component, `yii\filters\AccessControl::denyAccess()` throws `yii\web\ForbiddenHttpException` instead of redirecting to login page.
|
||||
2. If used without user component, using `AccessRule` matching a role throws `yii\base\InvalidConfigException`.
|
||||
|
||||
* Inputmask package name was changed from `jquery.inputmask` to `inputmask`. If you've configured path to
|
||||
assets manually, please adjust it.
|
||||
|
||||
Upgrade from Yii 2.0.10
|
||||
-----------------------
|
||||
|
||||
* A new method `public function emulateExecution($value = true);` has been added to the `yii\db\QueryInterace`.
|
||||
This method is implemented in the `yii\db\QueryTrait`, so this only affects your code if you implement QueryInterface
|
||||
in a class that does not use the trait.
|
||||
|
||||
* `yii\validators\FileValidator::getClientOptions()` and `yii\validators\ImageValidator::getClientOptions()` are now public.
|
||||
If you extend from these classes and override these methods, you must make them public as well.
|
||||
|
||||
* `yii\widgets\MaskedInput` inputmask dependency was updated to `~3.3.3`.
|
||||
[See its changelog for details](https://github.com/RobinHerbots/Inputmask/blob/3.x/CHANGELOG.md).
|
||||
|
||||
* PJAX: Auto generated IDs of the Pjax widget have been changed to use their own prefix to avoid conflicts.
|
||||
Auto generated IDs are now prefixed with `p` instead of `w`. This is defined by the `$autoIdPrefix`
|
||||
property of `yii\widgets\Pjax`. If you have any PHP or Javascript code that depends on autogenerated IDs
|
||||
you should update these to match this new value. It is not a good idea to rely on auto generated values anyway, so
|
||||
you better fix these cases by specifying an explicit ID.
|
||||
|
||||
|
||||
Upgrade from Yii 2.0.9
|
||||
----------------------
|
||||
|
||||
* RBAC: `getChildRoles()` method was added to `\yii\rbac\ManagerInterface`. If you've implemented your own RBAC manager
|
||||
you need to implement new method.
|
||||
|
||||
* Microsoft SQL `NTEXT` data type [was marked as deprecated](https://msdn.microsoft.com/en-us/library/ms187993.aspx) in MSSQL so
|
||||
`\yii\db\mssql\Schema::TYPE_TEXT` was changed from `'ntext'` to `'nvarchar(max)'
|
||||
|
||||
* Method `yii\web\Request::getBodyParams()` has been changed to pass full value of 'content-type' header to the second
|
||||
argument of `yii\web\RequestParserInterface::parse()`. If you create your own custom parser, which relies on `$contentType`
|
||||
argument, ensure to process it correctly as it may content additional data.
|
||||
|
||||
* `yii\rest\Serializer` has been changed to return a JSON array for collection data in all cases to be consistent among pages
|
||||
for data that is not indexed starting by 0. If your API relies on the Serializer to return data as JSON objects indexed by
|
||||
PHP array keys, you should set `yii\rest\Serializer::$preserveKeys` to `true`.
|
||||
|
||||
|
||||
Upgrade from Yii 2.0.8
|
||||
----------------------
|
||||
|
||||
* Part of code from `yii\web\User::loginByCookie()` method was moved to new `getIdentityAndDurationFromCookie()`
|
||||
and `removeIdentityCookie()` methods. If you override `loginByCookie()` method, update it in order use new methods.
|
||||
|
||||
* Fixture console command syntax was changed from `yii fixture "*" -User` to `yii fixture "*, -User"`. Upgrade your
|
||||
scripts if necessary.
|
||||
|
||||
Upgrade from Yii 2.0.7
|
||||
----------------------
|
||||
|
||||
* The signature of `yii\helpers\BaseArrayHelper::index()` was changed. The method has got an extra optional parameter
|
||||
`$groups`.
|
||||
|
||||
* `yii\helpers\BaseArrayHelper` methods `isIn()` and `isSubset()` throw `\yii\base\InvalidParamException`
|
||||
instead of `\InvalidArgumentException`. If you wrap calls of these methods in try/catch block, change expected
|
||||
exception class.
|
||||
|
||||
* `yii\rbac\ManagerInterface::canAddChild()` method was added. If you have custom backend for RBAC you need to implement
|
||||
it.
|
||||
|
||||
* The signature of `yii\web\User::loginRequired()` was changed. The method has got an extra optional parameter
|
||||
`$checkAcceptHeader`.
|
||||
|
||||
* The signature of `yii\db\ColumnSchemaBuilder::__construct()` was changed. The method has got an extra optional
|
||||
parameter `$db`. In case you are instantiating this class yourself and using the `$config` parameter, you will need to
|
||||
move it to the right by one.
|
||||
|
||||
* String types in the MSSQL column schema map were upgraded to Unicode storage types. This will have no effect on
|
||||
existing columns, but any new columns you generate via the migrations engine will now store data as Unicode.
|
||||
|
||||
* Output buffering was introduced in the pair of `yii\widgets\ActiveForm::init()` and `::run()`. If you override any of
|
||||
these methods, make sure that output buffer handling is not corrupted. If you call the parent implementation, when
|
||||
overriding, everything should work fine. You should be doing that anyway.
|
||||
|
||||
Upgrade from Yii 2.0.6
|
||||
----------------------
|
||||
|
||||
* Added new requirement: ICU Data version >= 49.1. Please, ensure that your environment has ICU data installed and
|
||||
up to date to prevent unexpected behavior or crashes. This may not be the case on older systems e.g. running Debian Wheezy.
|
||||
|
||||
> Tip: Use Yii 2 Requirements checker for easy and fast check. Look for `requirements.php` in root of Basic and Advanced
|
||||
templates (howto-comment is in head of the script).
|
||||
|
||||
* The signature of `yii\helpers\BaseInflector::transliterate()` was changed. The method is now public and has an
|
||||
extra optional parameter `$transliterator`.
|
||||
|
||||
* In `yii\web\UrlRule` the `pattern` matching group names are being replaced with the placeholders on class
|
||||
initialization to support wider range of allowed characters. Because of this change:
|
||||
|
||||
- You are required to flush your application cache to remove outdated `UrlRule` serialized objects.
|
||||
See the [Cache Flushing Guide](http://www.yiiframework.com/doc-2.0/guide-caching-data.html#cache-flushing)
|
||||
- If you implement `parseRequest()` or `createUrl()` and rely on parameter names, call `substitutePlaceholderNames()`
|
||||
in order to replace temporary IDs with parameter names after doing matching.
|
||||
|
||||
* The context of `yii.confirm` JavaScript function was changed from `yii` object to the DOM element which triggered
|
||||
the event.
|
||||
|
||||
- If you overrode the `yii.confirm` function and accessed the `yii` object through `this`, you must access it
|
||||
with global variable `yii` instead.
|
||||
|
||||
* Traversable objects are now formatted as arrays in XML response to support SPL objects and Generators. Previous
|
||||
behavior could be turned on by setting `XmlResponseFormatter::$useTraversableAsArray` to `false`.
|
||||
|
||||
* If you've implemented `yii\rbac\ManagerInterface` you need to implement additional method `getUserIdsByRole($roleName)`.
|
||||
|
||||
* If you're using ApcCache with APCu, set `useApcu` to `true` in the component config.
|
||||
|
||||
* The `yii\behaviors\SluggableBehavior` class has been refactored to make it more reusable.
|
||||
Added new `protected` methods:
|
||||
|
||||
- `isSlugNeeded()`
|
||||
- `makeUnique()`
|
||||
|
||||
The visibility of the following Methods has changed from `private` to `protected`:
|
||||
|
||||
- `validateSlug()`
|
||||
- `generateUniqueSlug()`
|
||||
|
||||
* The `yii\console\controllers\MessageController` class has been refactored to be better configurable and now also allows
|
||||
setting a lot of configuration options via command line. If you extend from this class, make sure it works as expected after
|
||||
these changes.
|
||||
|
||||
Upgrade from Yii 2.0.5
|
||||
----------------------
|
||||
|
||||
* The signature of the following methods in `yii\console\controllers\MessageController` has changed. They have an extra parameter `$markUnused`.
|
||||
- `saveMessagesToDb($messages, $db, $sourceMessageTable, $messageTable, $removeUnused, $languages, $markUnused)`
|
||||
- `saveMessagesToPHP($messages, $dirName, $overwrite, $removeUnused, $sort, $markUnused)`
|
||||
- `saveMessagesCategoryToPHP($messages, $fileName, $overwrite, $removeUnused, $sort, $category, $markUnused)`
|
||||
- `saveMessagesToPO($messages, $dirName, $overwrite, $removeUnused, $sort, $catalog, $markUnused)`
|
||||
|
||||
Upgrade from Yii 2.0.4
|
||||
----------------------
|
||||
|
||||
Upgrading from 2.0.4 to 2.0.5 does not require any changes.
|
||||
|
||||
Upgrade from Yii 2.0.3
|
||||
----------------------
|
||||
|
||||
* Updated dependency to `cebe/markdown` to version `1.1.x`.
|
||||
If you need stick with 1.0.x, you can specify that in your `composer.json` by
|
||||
adding the following line in the `require` section:
|
||||
|
||||
```json
|
||||
"cebe/markdown": "~1.0.0",
|
||||
```
|
||||
|
||||
Upgrade from Yii 2.0.2
|
||||
----------------------
|
||||
|
||||
Starting from version 2.0.3 Yii `Security` component relies on OpenSSL crypto lib instead of Mcrypt. The reason is that
|
||||
Mcrypt is abandoned and isn't maintained for years. Therefore your PHP should be compiled with OpenSSL support. Most
|
||||
probably there's nothing to worry because it is quite typical.
|
||||
|
||||
If you've extended `yii\base\Security` to override any of the config constants you have to update your code:
|
||||
|
||||
- `MCRYPT_CIPHER` — now encoded in `$cipher` (and hence `$allowedCiphers`).
|
||||
- `MCRYPT_MODE` — now encoded in `$cipher` (and hence `$allowedCiphers`).
|
||||
- `KEY_SIZE` — now encoded in `$cipher` (and hence `$allowedCiphers`).
|
||||
- `KDF_HASH` — now `$kdfHash`.
|
||||
- `MAC_HASH` — now `$macHash`.
|
||||
- `AUTH_KEY_INFO` — now `$authKeyInfo`.
|
||||
|
||||
Upgrade from Yii 2.0.0
|
||||
----------------------
|
||||
|
||||
* Upgraded Twitter Bootstrap to [version 3.3.x](http://blog.getbootstrap.com/2014/10/29/bootstrap-3-3-0-released/).
|
||||
If you need to use an older version (i.e. stick with 3.2.x) you can specify that in your `composer.json` by
|
||||
adding the following line in the `require` section:
|
||||
|
||||
```json
|
||||
"bower-asset/bootstrap": "3.2.*",
|
||||
```
|
||||
|
||||
Upgrade from Yii 2.0 RC
|
||||
-----------------------
|
||||
|
||||
* If you've implemented `yii\rbac\ManagerInterface` you need to add implementation for new method `removeChildren()`.
|
||||
|
||||
* The input dates for datetime formatting are now assumed to be in UTC unless a timezone is explicitly given.
|
||||
Before, the timezone assumed for input dates was the default timezone set by PHP which is the same as `Yii::$app->timeZone`.
|
||||
This causes trouble because the formatter uses `Yii::$app->timeZone` as the default values for output so no timezone conversion
|
||||
was possible. If your timestamps are stored in the database without a timezone identifier you have to ensure they are in UTC or
|
||||
add a timezone identifier explicitly.
|
||||
|
||||
* `yii\bootstrap\Collapse` is now encoding labels by default. `encode` item option and global `encodeLabels` property were
|
||||
introduced to disable it. Keys are no longer used as labels. You need to remove keys and use `label` item option instead.
|
||||
|
||||
* The `yii\base\View::beforeRender()` and `yii\base\View::afterRender()` methods have two extra parameters `$viewFile`
|
||||
and `$params`. If you are overriding these methods, you should adjust the method signature accordingly.
|
||||
|
||||
* If you've used `asImage` formatter i.e. `Yii::$app->formatter->asImage($value, $alt);` you should change it
|
||||
to `Yii::$app->formatter->asImage($value, ['alt' => $alt]);`.
|
||||
|
||||
* Yii now requires `cebe/markdown` 1.0.0 or higher, which includes breaking changes in its internal API. If you extend the markdown class
|
||||
you need to update your implementation. See <https://github.com/cebe/markdown/releases/tag/1.0.0-rc> for details.
|
||||
If you just used the markdown helper class there is no need to change anything.
|
||||
|
||||
* If you are using CUBRID DBMS, make sure to use at least version 9.3.0 as the server and also as the PDO extension.
|
||||
Quoting of values is broken in prior versions and Yii has no reliable way to work around this issue.
|
||||
A workaround that may have worked before has been removed in this release because it was not reliable.
|
||||
|
||||
Upgrade from Yii 2.0 Beta
|
||||
-------------------------
|
||||
|
||||
* If you are using Composer to upgrade Yii, you should run the following command first (once for all) to install
|
||||
the composer-asset-plugin, *before* you update your project:
|
||||
|
||||
```
|
||||
php composer.phar global require "fxp/composer-asset-plugin:~1.3.1"
|
||||
```
|
||||
|
||||
You also need to add the following code to your project's `composer.json` file:
|
||||
|
||||
```json
|
||||
"extra": {
|
||||
"asset-installer-paths": {
|
||||
"npm-asset-library": "vendor/npm",
|
||||
"bower-asset-library": "vendor/bower"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
It is also a good idea to upgrade composer itself to the latest version if you see any problems:
|
||||
|
||||
```
|
||||
composer self-update
|
||||
```
|
||||
|
||||
* If you used `clearAll()` or `clearAllAssignments()` of `yii\rbac\DbManager`, you should replace
|
||||
them with `removeAll()` and `removeAllAssignments()` respectively.
|
||||
|
||||
* If you created RBAC rule classes, you should modify their `execute()` method by adding `$user`
|
||||
as the first parameter: `execute($user, $item, $params)`. The `$user` parameter represents
|
||||
the ID of the user currently being access checked. Previously, this is passed via `$params['user']`.
|
||||
|
||||
* If you override `yii\grid\DataColumn::getDataCellValue()` with visibility `protected` you have
|
||||
to change visibility to `public` as visibility of the base method has changed.
|
||||
|
||||
* If you have classes implementing `yii\web\IdentityInterface` (very common), you should modify
|
||||
the signature of `findIdentityByAccessToken()` as
|
||||
`public static function findIdentityByAccessToken($token, $type = null)`. The new `$type` parameter
|
||||
will contain the type information about the access token. For example, if you use
|
||||
`yii\filters\auth\HttpBearerAuth` authentication method, the value of this parameter will be
|
||||
`yii\filters\auth\HttpBearerAuth`. This allows you to differentiate access tokens taken by
|
||||
different authentication methods.
|
||||
|
||||
* If you are sharing the same cache across different applications, you should configure
|
||||
the `keyPrefix` property of the cache component to use some unique string.
|
||||
Previously, this property was automatically assigned with a unique string.
|
||||
|
||||
* If you are using `dropDownList()`, `listBox()`, `activeDropDownList()`, or `activeListBox()`
|
||||
of `yii\helpers\Html`, and your list options use multiple blank spaces to format and align
|
||||
option label texts, you need to specify the option `encodeSpaces` to be true.
|
||||
|
||||
* If you are using `yii\grid\GridView` and have configured a data column to use a PHP callable
|
||||
to return cell values (via `yii\grid\DataColumn::value`), you may need to adjust the signature
|
||||
of the callable to be `function ($model, $key, $index, $widget)`. The `$key` parameter was newly added
|
||||
in this release.
|
||||
|
||||
* `yii\console\controllers\AssetController` is now using hashes instead of timestamps. Replace all `{ts}` with `{hash}`.
|
||||
|
||||
* The database table of the `yii\log\DbTarget` now needs a `prefix` column to store context information.
|
||||
You can add it with `ALTER TABLE log ADD COLUMN prefix TEXT AFTER log_time;`.
|
||||
|
||||
* The `fileinfo` PHP extension is now required by Yii. If you use `yii\helpers\FileHelper::getMimeType()`, make sure
|
||||
you have enabled this extension. This extension is [builtin](http://www.php.net/manual/en/fileinfo.installation.php) in php above `5.3`.
|
||||
|
||||
* Please update your main layout file by adding this line in the `<head>` section: `<?= Html::csrfMetaTags() ?>`.
|
||||
This change is needed because `yii\web\View` no longer automatically generates CSRF meta tags due to issue #3358.
|
||||
|
||||
* If your model code is using the `file` validation rule, you should rename its `types` option to `extensions`.
|
||||
|
||||
* `MailEvent` class has been moved to the `yii\mail` namespace. You have to adjust all references that may exist in your code.
|
||||
|
||||
* The behavior and signature of `ActiveRecord::afterSave()` has changed. `ActiveRecord::$isNewRecord` will now always be
|
||||
false in afterSave and also dirty attributes are not available. This change has been made to have a more consistent and
|
||||
expected behavior. The changed attributes are now available in the new parameter of afterSave() `$changedAttributes`.
|
||||
`$changedAttributes` contains the old values of attributes that had changed and were saved.
|
||||
|
||||
* `ActiveRecord::updateAttributes()` has been changed to not trigger events and not respect optimistic locking anymore to
|
||||
differentiate it more from calling `update(false)` and to ensure it can be used in `afterSave()` without triggering infinite
|
||||
loops.
|
||||
|
||||
* If you are developing RESTful APIs and using an authentication method such as `yii\filters\auth\HttpBasicAuth`,
|
||||
you should explicitly configure `yii\web\User::enableSession` in the application configuration to be false to avoid
|
||||
starting a session when authentication is performed. Previously this was done automatically by authentication method.
|
||||
|
||||
* `mail` component was renamed to `mailer`, `yii\log\EmailTarget::$mail` was renamed to `yii\log\EmailTarget::$mailer`.
|
||||
Please update all references in the code and config files.
|
||||
|
||||
* `yii\caching\GroupDependency` was renamed to `TagDependency`. You should create such a dependency using the code
|
||||
`new \yii\caching\TagDependency(['tags' => 'TagName'])`, where `TagName` is similar to the group name that you
|
||||
previously used.
|
||||
|
||||
* If you are using the constant `YII_PATH` in your code, you should rename it to `YII2_PATH` now.
|
||||
|
||||
* You must explicitly configure `yii\web\Request::cookieValidationKey` with a secret key. Previously this is done automatically.
|
||||
To do so, modify your application configuration like the following:
|
||||
|
||||
```php
|
||||
return [
|
||||
// ...
|
||||
'components' => [
|
||||
'request' => [
|
||||
'cookieValidationKey' => 'your secret key here',
|
||||
],
|
||||
],
|
||||
];
|
||||
```
|
||||
|
||||
> Note: If you are using the `Advanced Project Template` you should not add this configuration to `common/config`
|
||||
or `console/config` because the console application doesn't have to deal with CSRF and uses its own request that
|
||||
doesn't have `cookieValidationKey` property.
|
||||
|
||||
* `yii\rbac\PhpManager` now stores data in three separate files instead of one. In order to convert old file to
|
||||
new ones save the following code as `convert.php` that should be placed in the same directory your `rbac.php` is in:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$oldFile = 'rbac.php';
|
||||
$itemsFile = 'items.php';
|
||||
$assignmentsFile = 'assignments.php';
|
||||
$rulesFile = 'rules.php';
|
||||
|
||||
$oldData = include $oldFile;
|
||||
|
||||
function saveToFile($data, $fileName) {
|
||||
$out = var_export($data, true);
|
||||
$out = "<?php\nreturn " . $out . ';';
|
||||
$out = str_replace(['array (', ')'], ['[', ']'], $out);
|
||||
file_put_contents($fileName, $out, LOCK_EX);
|
||||
}
|
||||
|
||||
$items = [];
|
||||
$assignments = [];
|
||||
if (isset($oldData['items'])) {
|
||||
foreach ($oldData['items'] as $name => $data) {
|
||||
if (isset($data['assignments'])) {
|
||||
foreach ($data['assignments'] as $userId => $assignmentData) {
|
||||
$assignments[$userId][] = $assignmentData['roleName'];
|
||||
}
|
||||
unset($data['assignments']);
|
||||
}
|
||||
$items[$name] = $data;
|
||||
}
|
||||
}
|
||||
|
||||
$rules = [];
|
||||
if (isset($oldData['rules'])) {
|
||||
$rules = $oldData['rules'];
|
||||
}
|
||||
|
||||
saveToFile($items, $itemsFile);
|
||||
saveToFile($assignments, $assignmentsFile);
|
||||
saveToFile($rules, $rulesFile);
|
||||
|
||||
echo "Done!\n";
|
||||
```
|
||||
|
||||
Run it once, delete `rbac.php`. If you've configured `authFile` property, remove the line from config and instead
|
||||
configure `itemFile`, `assignmentFile` and `ruleFile`.
|
||||
|
||||
* Static helper `yii\helpers\Security` has been converted into an application component. You should change all usage of
|
||||
its methods to a new syntax, for example: instead of `yii\helpers\Security::hashData()` use `Yii::$app->getSecurity()->hashData()`.
|
||||
The `generateRandomKey()` method now produces not an ASCII compatible output. Use `generateRandomString()` instead.
|
||||
Default encryption and hash parameters has been upgraded. If you need to decrypt/validate data that was encrypted/hashed
|
||||
before, use the following configuration of the 'security' component:
|
||||
|
||||
```php
|
||||
return [
|
||||
'components' => [
|
||||
'security' => [
|
||||
'derivationIterations' => 1000,
|
||||
],
|
||||
// ...
|
||||
],
|
||||
// ...
|
||||
];
|
||||
```
|
||||
|
||||
* If you are using query caching, you should modify your relevant code as follows, as `beginCache()` and `endCache()` are
|
||||
replaced by `cache()`:
|
||||
|
||||
```php
|
||||
$db->cache(function ($db) {
|
||||
|
||||
// ... SQL queries that need to use query caching
|
||||
|
||||
}, $duration, $dependency);
|
||||
```
|
||||
|
||||
* Due to significant changes to security you need to upgrade your code to use `\yii\base\Security` component instead of
|
||||
helper. If you have any data encrypted it should be re-encrypted. In order to do so you can use old security helper
|
||||
[as explained by @docsolver at github](https://github.com/yiisoft/yii2/issues/4461#issuecomment-50237807).
|
||||
|
||||
* [[yii\helpers\Url::to()]] will no longer prefix base URL to relative URLs. For example, `Url::to('images/logo.png')`
|
||||
will return `images/logo.png` directly. If you want a relative URL to be prefix with base URL, you should make use
|
||||
of the alias `@web`. For example, `Url::to('@web/images/logo.png')` will return `/BaseUrl/images/logo.png`.
|
||||
|
||||
* The following properties are now taking `false` instead of `null` for "don't use" case:
|
||||
- `yii\bootstrap\NavBar::$brandLabel`.
|
||||
- `yii\bootstrap\NavBar::$brandUrl`.
|
||||
- `yii\bootstrap\Modal::$closeButton`.
|
||||
- `yii\bootstrap\Modal::$toggleButton`.
|
||||
- `yii\bootstrap\Alert::$closeButton`.
|
||||
- `yii\widgets\LinkPager::$nextPageLabel`.
|
||||
- `yii\widgets\LinkPager::$prevPageLabel`.
|
||||
- `yii\widgets\LinkPager::$firstPageLabel`.
|
||||
- `yii\widgets\LinkPager::$lastPageLabel`.
|
||||
|
||||
* The format of the Faker fixture template is changed. For an example, please refer to the file
|
||||
`apps/advanced/common/tests/templates/fixtures/user.php`.
|
||||
|
||||
* The signature of all file downloading methods in `yii\web\Response` is changed, as summarized below:
|
||||
- `sendFile($filePath, $attachmentName = null, $options = [])`
|
||||
- `sendContentAsFile($content, $attachmentName, $options = [])`
|
||||
- `sendStreamAsFile($handle, $attachmentName, $options = [])`
|
||||
- `xSendFile($filePath, $attachmentName = null, $options = [])`
|
||||
|
||||
* The signature of callbacks used in `yii\base\ArrayableTrait::fields()` is changed from `function ($field, $model) {`
|
||||
to `function ($model, $field) {`.
|
||||
|
||||
* `Html::radio()`, `Html::checkbox()`, `Html::radioList()`, `Html::checkboxList()` no longer generate the container
|
||||
tag around each radio/checkbox when you specify labels for them. You should manually render such container tags,
|
||||
or set the `item` option for `Html::radioList()`, `Html::checkboxList()` to generate the container tags.
|
||||
|
||||
* The formatter class has been refactored to have only one class regardless whether PHP intl extension is installed or not.
|
||||
Functionality of `yii\base\Formatter` has been merged into `yii\i18n\Formatter` and `yii\base\Formatter` has been
|
||||
removed so you have to replace all usage of `yii\base\Formatter` with `yii\i18n\Formatter` in your code.
|
||||
Also the API of the Formatter class has changed in many ways.
|
||||
The signature of the following Methods has changed:
|
||||
|
||||
- `asDate`
|
||||
- `asTime`
|
||||
- `asDatetime`
|
||||
- `asSize` has been split up into `asSize` and `asShortSize`
|
||||
- `asCurrency`
|
||||
- `asDecimal`
|
||||
- `asPercent`
|
||||
- `asScientific`
|
||||
|
||||
The following methods have been removed, this also means that the corresponding format which may be used by a
|
||||
GridView or DetailView is not available anymore:
|
||||
|
||||
- `asNumber`
|
||||
- `asDouble`
|
||||
|
||||
Also due to these changes some formatting defaults have changes so you have to check all your GridView and DetailView
|
||||
configuration and make sure the formatting is displayed correctly.
|
||||
|
||||
The configuration for `asSize()` has changed. It now uses the configuration for the number formatting from intl
|
||||
and only the base is configured using `$sizeFormatBase`.
|
||||
|
||||
The specification of the date and time formats is now using the ICU pattern format even if PHP intl extension is not installed.
|
||||
You can prefix a date format with `php:` to use the old format of the PHP `date()`-function.
|
||||
|
||||
* The DateValidator has been refactored to use the same format as the Formatter class now (see previous change).
|
||||
When you use the DateValidator and did not specify a format it will now be what is configured in the formatter class instead of 'Y-m-d'.
|
||||
To get the old behavior of the DateValidator you have to set the format explicitly in your validation rule:
|
||||
|
||||
```php
|
||||
['attributeName', 'date', 'format' => 'php:Y-m-d'],
|
||||
```
|
||||
|
||||
* `beforeValidate()`, `beforeValidateAll()`, `afterValidate()`, `afterValidateAll()`, `ajaxBeforeSend()` and `ajaxComplete()`
|
||||
are removed from `ActiveForm`. The same functionality is now achieved via JavaScript event mechanism like the following:
|
||||
|
||||
```js
|
||||
$('#myform').on('beforeValidate', function (event, messages, deferreds) {
|
||||
// called when the validation is triggered by submitting the form
|
||||
// return false if you want to cancel the validation for the whole form
|
||||
}).on('beforeValidateAttribute', function (event, attribute, messages, deferreds) {
|
||||
// before validating an attribute
|
||||
// return false if you want to cancel the validation for the attribute
|
||||
}).on('afterValidateAttribute', function (event, attribute, messages) {
|
||||
// ...
|
||||
}).on('afterValidate', function (event, messages) {
|
||||
// ...
|
||||
}).on('beforeSubmit', function () {
|
||||
// after all validations have passed
|
||||
// you can do ajax form submission here
|
||||
// return false if you want to stop form submission
|
||||
});
|
||||
```
|
||||
|
||||
* The signature of `View::registerJsFile()` and `View::registerCssFile()` has changed. The `$depends` and `$position`
|
||||
paramaters have been merged into `$options`. The new signatures are as follows:
|
||||
|
||||
- `registerJsFile($url, $options = [], $key = null)`
|
||||
- `registerCssFile($url, $options = [], $key = null)`
|
||||
25
vendor/yiisoft/yii2/Yii.php
vendored
Normal file
25
vendor/yiisoft/yii2/Yii.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
require __DIR__ . '/BaseYii.php';
|
||||
|
||||
/**
|
||||
* Yii is a helper class serving common framework functionalities.
|
||||
*
|
||||
* It extends from [[\yii\BaseYii]] which provides the actual implementation.
|
||||
* By writing your own Yii class, you can customize some functionalities of [[\yii\BaseYii]].
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class Yii extends \yii\BaseYii
|
||||
{
|
||||
}
|
||||
|
||||
spl_autoload_register(['Yii', 'autoload'], true, true);
|
||||
Yii::$classMap = require __DIR__ . '/classes.php';
|
||||
Yii::$container = new yii\di\Container();
|
||||
799
vendor/yiisoft/yii2/assets/yii.activeForm.js
vendored
Normal file
799
vendor/yiisoft/yii2/assets/yii.activeForm.js
vendored
Normal file
@@ -0,0 +1,799 @@
|
||||
/**
|
||||
* Yii form widget.
|
||||
*
|
||||
* This is the JavaScript widget used by the yii\widgets\ActiveForm widget.
|
||||
*
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
(function ($) {
|
||||
|
||||
$.fn.yiiActiveForm = function (method) {
|
||||
if (methods[method]) {
|
||||
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
|
||||
} else if (typeof method === 'object' || !method) {
|
||||
return methods.init.apply(this, arguments);
|
||||
} else {
|
||||
$.error('Method ' + method + ' does not exist on jQuery.yiiActiveForm');
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
var events = {
|
||||
/**
|
||||
* beforeValidate event is triggered before validating the whole form.
|
||||
* The signature of the event handler should be:
|
||||
* function (event, messages, deferreds)
|
||||
* where
|
||||
* - event: an Event object.
|
||||
* - messages: an associative array with keys being attribute IDs and values being error message arrays
|
||||
* for the corresponding attributes.
|
||||
* - deferreds: an array of Deferred objects. You can use deferreds.add(callback) to add a new deferred validation.
|
||||
*
|
||||
* If the handler returns a boolean false, it will stop further form validation after this event. And as
|
||||
* a result, afterValidate event will not be triggered.
|
||||
*/
|
||||
beforeValidate: 'beforeValidate',
|
||||
/**
|
||||
* afterValidate event is triggered after validating the whole form.
|
||||
* The signature of the event handler should be:
|
||||
* function (event, messages, errorAttributes)
|
||||
* where
|
||||
* - event: an Event object.
|
||||
* - messages: an associative array with keys being attribute IDs and values being error message arrays
|
||||
* for the corresponding attributes.
|
||||
* - errorAttributes: an array of attributes that have validation errors. Please refer to attributeDefaults for the structure of this parameter.
|
||||
*/
|
||||
afterValidate: 'afterValidate',
|
||||
/**
|
||||
* beforeValidateAttribute event is triggered before validating an attribute.
|
||||
* The signature of the event handler should be:
|
||||
* function (event, attribute, messages, deferreds)
|
||||
* where
|
||||
* - event: an Event object.
|
||||
* - attribute: the attribute to be validated. Please refer to attributeDefaults for the structure of this parameter.
|
||||
* - messages: an array to which you can add validation error messages for the specified attribute.
|
||||
* - deferreds: an array of Deferred objects. You can use deferreds.add(callback) to add a new deferred validation.
|
||||
*
|
||||
* If the handler returns a boolean false, it will stop further validation of the specified attribute.
|
||||
* And as a result, afterValidateAttribute event will not be triggered.
|
||||
*/
|
||||
beforeValidateAttribute: 'beforeValidateAttribute',
|
||||
/**
|
||||
* afterValidateAttribute event is triggered after validating the whole form and each attribute.
|
||||
* The signature of the event handler should be:
|
||||
* function (event, attribute, messages)
|
||||
* where
|
||||
* - event: an Event object.
|
||||
* - attribute: the attribute being validated. Please refer to attributeDefaults for the structure of this parameter.
|
||||
* - messages: an array to which you can add additional validation error messages for the specified attribute.
|
||||
*/
|
||||
afterValidateAttribute: 'afterValidateAttribute',
|
||||
/**
|
||||
* beforeSubmit event is triggered before submitting the form after all validations have passed.
|
||||
* The signature of the event handler should be:
|
||||
* function (event)
|
||||
* where event is an Event object.
|
||||
*
|
||||
* If the handler returns a boolean false, it will stop form submission.
|
||||
*/
|
||||
beforeSubmit: 'beforeSubmit',
|
||||
/**
|
||||
* ajaxBeforeSend event is triggered before sending an AJAX request for AJAX-based validation.
|
||||
* The signature of the event handler should be:
|
||||
* function (event, jqXHR, settings)
|
||||
* where
|
||||
* - event: an Event object.
|
||||
* - jqXHR: a jqXHR object
|
||||
* - settings: the settings for the AJAX request
|
||||
*/
|
||||
ajaxBeforeSend: 'ajaxBeforeSend',
|
||||
/**
|
||||
* ajaxComplete event is triggered after completing an AJAX request for AJAX-based validation.
|
||||
* The signature of the event handler should be:
|
||||
* function (event, jqXHR, textStatus)
|
||||
* where
|
||||
* - event: an Event object.
|
||||
* - jqXHR: a jqXHR object
|
||||
* - textStatus: the status of the request ("success", "notmodified", "error", "timeout", "abort", or "parsererror").
|
||||
*/
|
||||
ajaxComplete: 'ajaxComplete',
|
||||
/**
|
||||
* afterInit event is triggered after yii activeForm init.
|
||||
* The signature of the event handler should be:
|
||||
* function (event)
|
||||
* where
|
||||
* - event: an Event object.
|
||||
*/
|
||||
afterInit: 'afterInit'
|
||||
};
|
||||
|
||||
// NOTE: If you change any of these defaults, make sure you update yii\widgets\ActiveForm::getClientOptions() as well
|
||||
var defaults = {
|
||||
// whether to encode the error summary
|
||||
encodeErrorSummary: true,
|
||||
// the jQuery selector for the error summary
|
||||
errorSummary: '.error-summary',
|
||||
// whether to perform validation before submitting the form.
|
||||
validateOnSubmit: true,
|
||||
// the container CSS class representing the corresponding attribute has validation error
|
||||
errorCssClass: 'has-error',
|
||||
// the container CSS class representing the corresponding attribute passes validation
|
||||
successCssClass: 'has-success',
|
||||
// the container CSS class representing the corresponding attribute is being validated
|
||||
validatingCssClass: 'validating',
|
||||
// the GET parameter name indicating an AJAX-based validation
|
||||
ajaxParam: 'ajax',
|
||||
// the type of data that you're expecting back from the server
|
||||
ajaxDataType: 'json',
|
||||
// the URL for performing AJAX-based validation. If not set, it will use the the form's action
|
||||
validationUrl: undefined,
|
||||
// whether to scroll to first visible error after validation.
|
||||
scrollToError: true,
|
||||
// offset in pixels that should be added when scrolling to the first error.
|
||||
scrollToErrorOffset: 0,
|
||||
// where to add validation class: container or input
|
||||
validationStateOn: 'container'
|
||||
};
|
||||
|
||||
// NOTE: If you change any of these defaults, make sure you update yii\widgets\ActiveField::getClientOptions() as well
|
||||
var attributeDefaults = {
|
||||
// a unique ID identifying an attribute (e.g. "loginform-username") in a form
|
||||
id: undefined,
|
||||
// attribute name or expression (e.g. "[0]content" for tabular input)
|
||||
name: undefined,
|
||||
// the jQuery selector of the container of the input field
|
||||
container: undefined,
|
||||
// the jQuery selector of the input field under the context of the form
|
||||
input: undefined,
|
||||
// the jQuery selector of the error tag under the context of the container
|
||||
error: '.help-block',
|
||||
// whether to encode the error
|
||||
encodeError: true,
|
||||
// whether to perform validation when a change is detected on the input
|
||||
validateOnChange: true,
|
||||
// whether to perform validation when the input loses focus
|
||||
validateOnBlur: true,
|
||||
// whether to perform validation when the user is typing.
|
||||
validateOnType: false,
|
||||
// number of milliseconds that the validation should be delayed when a user is typing in the input field.
|
||||
validationDelay: 500,
|
||||
// whether to enable AJAX-based validation.
|
||||
enableAjaxValidation: false,
|
||||
// function (attribute, value, messages, deferred, $form), the client-side validation function.
|
||||
validate: undefined,
|
||||
// status of the input field, 0: empty, not entered before, 1: validated, 2: pending validation, 3: validating
|
||||
status: 0,
|
||||
// whether the validation is cancelled by beforeValidateAttribute event handler
|
||||
cancelled: false,
|
||||
// the value of the input
|
||||
value: undefined,
|
||||
// whether to update aria-invalid attribute after validation
|
||||
updateAriaInvalid: true
|
||||
};
|
||||
|
||||
|
||||
var submitDefer;
|
||||
|
||||
var setSubmitFinalizeDefer = function($form) {
|
||||
submitDefer = $.Deferred();
|
||||
$form.data('yiiSubmitFinalizePromise', submitDefer.promise());
|
||||
};
|
||||
|
||||
// finalize yii.js $form.submit
|
||||
var submitFinalize = function($form) {
|
||||
if(submitDefer) {
|
||||
submitDefer.resolve();
|
||||
submitDefer = undefined;
|
||||
$form.removeData('yiiSubmitFinalizePromise');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var methods = {
|
||||
init: function (attributes, options) {
|
||||
return this.each(function () {
|
||||
var $form = $(this);
|
||||
if ($form.data('yiiActiveForm')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var settings = $.extend({}, defaults, options || {});
|
||||
if (settings.validationUrl === undefined) {
|
||||
settings.validationUrl = $form.attr('action');
|
||||
}
|
||||
|
||||
$.each(attributes, function (i) {
|
||||
attributes[i] = $.extend({value: getValue($form, this)}, attributeDefaults, this);
|
||||
watchAttribute($form, attributes[i]);
|
||||
});
|
||||
|
||||
$form.data('yiiActiveForm', {
|
||||
settings: settings,
|
||||
attributes: attributes,
|
||||
submitting: false,
|
||||
validated: false,
|
||||
options: getFormOptions($form)
|
||||
});
|
||||
|
||||
/**
|
||||
* Clean up error status when the form is reset.
|
||||
* Note that $form.on('reset', ...) does work because the "reset" event does not bubble on IE.
|
||||
*/
|
||||
$form.on('reset.yiiActiveForm', methods.resetForm);
|
||||
|
||||
if (settings.validateOnSubmit) {
|
||||
$form.on('mouseup.yiiActiveForm keyup.yiiActiveForm', ':submit', function () {
|
||||
$form.data('yiiActiveForm').submitObject = $(this);
|
||||
});
|
||||
$form.on('submit.yiiActiveForm', methods.submitForm);
|
||||
}
|
||||
var event = $.Event(events.afterInit);
|
||||
$form.trigger(event);
|
||||
});
|
||||
},
|
||||
|
||||
// add a new attribute to the form dynamically.
|
||||
// please refer to attributeDefaults for the structure of attribute
|
||||
add: function (attribute) {
|
||||
var $form = $(this);
|
||||
attribute = $.extend({value: getValue($form, attribute)}, attributeDefaults, attribute);
|
||||
$form.data('yiiActiveForm').attributes.push(attribute);
|
||||
watchAttribute($form, attribute);
|
||||
},
|
||||
|
||||
// remove the attribute with the specified ID from the form
|
||||
remove: function (id) {
|
||||
var $form = $(this),
|
||||
attributes = $form.data('yiiActiveForm').attributes,
|
||||
index = -1,
|
||||
attribute = undefined;
|
||||
$.each(attributes, function (i) {
|
||||
if (attributes[i]['id'] == id) {
|
||||
index = i;
|
||||
attribute = attributes[i];
|
||||
return false;
|
||||
}
|
||||
});
|
||||
if (index >= 0) {
|
||||
attributes.splice(index, 1);
|
||||
unwatchAttribute($form, attribute);
|
||||
}
|
||||
|
||||
return attribute;
|
||||
},
|
||||
|
||||
// manually trigger the validation of the attribute with the specified ID
|
||||
validateAttribute: function (id) {
|
||||
var attribute = methods.find.call(this, id);
|
||||
if (attribute != undefined) {
|
||||
validateAttribute($(this), attribute, true);
|
||||
}
|
||||
},
|
||||
|
||||
// find an attribute config based on the specified attribute ID
|
||||
find: function (id) {
|
||||
var attributes = $(this).data('yiiActiveForm').attributes,
|
||||
result = undefined;
|
||||
$.each(attributes, function (i) {
|
||||
if (attributes[i]['id'] == id) {
|
||||
result = attributes[i];
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
return this.each(function () {
|
||||
$(this).off('.yiiActiveForm');
|
||||
$(this).removeData('yiiActiveForm');
|
||||
});
|
||||
},
|
||||
|
||||
data: function () {
|
||||
return this.data('yiiActiveForm');
|
||||
},
|
||||
|
||||
// validate all applicable inputs in the form
|
||||
validate: function (forceValidate) {
|
||||
if (forceValidate) {
|
||||
$(this).data('yiiActiveForm').submitting = true;
|
||||
}
|
||||
|
||||
var $form = $(this),
|
||||
data = $form.data('yiiActiveForm'),
|
||||
needAjaxValidation = false,
|
||||
messages = {},
|
||||
deferreds = deferredArray(),
|
||||
submitting = data.submitting;
|
||||
|
||||
if (submitting) {
|
||||
var event = $.Event(events.beforeValidate);
|
||||
$form.trigger(event, [messages, deferreds]);
|
||||
|
||||
if (event.result === false) {
|
||||
data.submitting = false;
|
||||
submitFinalize($form);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// client-side validation
|
||||
$.each(data.attributes, function () {
|
||||
this.$form = $form;
|
||||
if (!$(this.input).is(":disabled")) {
|
||||
this.cancelled = false;
|
||||
// perform validation only if the form is being submitted or if an attribute is pending validation
|
||||
if (data.submitting || this.status === 2 || this.status === 3) {
|
||||
var msg = messages[this.id];
|
||||
if (msg === undefined) {
|
||||
msg = [];
|
||||
messages[this.id] = msg;
|
||||
}
|
||||
var event = $.Event(events.beforeValidateAttribute);
|
||||
$form.trigger(event, [this, msg, deferreds]);
|
||||
if (event.result !== false) {
|
||||
if (this.validate) {
|
||||
this.validate(this, getValue($form, this), msg, deferreds, $form);
|
||||
}
|
||||
if (this.enableAjaxValidation) {
|
||||
needAjaxValidation = true;
|
||||
}
|
||||
} else {
|
||||
this.cancelled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// ajax validation
|
||||
$.when.apply(this, deferreds).always(function() {
|
||||
// Remove empty message arrays
|
||||
for (var i in messages) {
|
||||
if (0 === messages[i].length) {
|
||||
delete messages[i];
|
||||
}
|
||||
}
|
||||
if (needAjaxValidation && ($.isEmptyObject(messages) || data.submitting)) {
|
||||
var $button = data.submitObject,
|
||||
extData = '&' + data.settings.ajaxParam + '=' + $form.attr('id');
|
||||
if ($button && $button.length && $button.attr('name')) {
|
||||
extData += '&' + $button.attr('name') + '=' + $button.attr('value');
|
||||
}
|
||||
$.ajax({
|
||||
url: data.settings.validationUrl,
|
||||
type: $form.attr('method'),
|
||||
data: $form.serialize() + extData,
|
||||
dataType: data.settings.ajaxDataType,
|
||||
complete: function (jqXHR, textStatus) {
|
||||
$form.trigger(events.ajaxComplete, [jqXHR, textStatus]);
|
||||
},
|
||||
beforeSend: function (jqXHR, settings) {
|
||||
$form.trigger(events.ajaxBeforeSend, [jqXHR, settings]);
|
||||
},
|
||||
success: function (msgs) {
|
||||
if (msgs !== null && typeof msgs === 'object') {
|
||||
$.each(data.attributes, function () {
|
||||
if (!this.enableAjaxValidation || this.cancelled) {
|
||||
delete msgs[this.id];
|
||||
}
|
||||
});
|
||||
updateInputs($form, $.extend(messages, msgs), submitting);
|
||||
} else {
|
||||
updateInputs($form, messages, submitting);
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
data.submitting = false;
|
||||
submitFinalize($form);
|
||||
}
|
||||
});
|
||||
} else if (data.submitting) {
|
||||
// delay callback so that the form can be submitted without problem
|
||||
window.setTimeout(function () {
|
||||
updateInputs($form, messages, submitting);
|
||||
}, 200);
|
||||
} else {
|
||||
updateInputs($form, messages, submitting);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
submitForm: function () {
|
||||
var $form = $(this),
|
||||
data = $form.data('yiiActiveForm');
|
||||
|
||||
if (data.validated) {
|
||||
// Second submit's call (from validate/updateInputs)
|
||||
data.submitting = false;
|
||||
var event = $.Event(events.beforeSubmit);
|
||||
$form.trigger(event);
|
||||
if (event.result === false) {
|
||||
data.validated = false;
|
||||
submitFinalize($form);
|
||||
return false;
|
||||
}
|
||||
updateHiddenButton($form);
|
||||
return true; // continue submitting the form since validation passes
|
||||
} else {
|
||||
// First submit's call (from yii.js/handleAction) - execute validating
|
||||
setSubmitFinalizeDefer($form);
|
||||
|
||||
if (data.settings.timer !== undefined) {
|
||||
clearTimeout(data.settings.timer);
|
||||
}
|
||||
data.submitting = true;
|
||||
methods.validate.call($form);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
resetForm: function () {
|
||||
var $form = $(this);
|
||||
var data = $form.data('yiiActiveForm');
|
||||
// Because we bind directly to a form reset event instead of a reset button (that may not exist),
|
||||
// when this function is executed form input values have not been reset yet.
|
||||
// Therefore we do the actual reset work through setTimeout.
|
||||
window.setTimeout(function () {
|
||||
$.each(data.attributes, function () {
|
||||
// Without setTimeout() we would get the input values that are not reset yet.
|
||||
this.value = getValue($form, this);
|
||||
this.status = 0;
|
||||
var $container = $form.find(this.container),
|
||||
$input = findInput($form, this),
|
||||
$errorElement = data.settings.validationStateOn === 'input' ? $input : $container;
|
||||
|
||||
$errorElement.removeClass(
|
||||
data.settings.validatingCssClass + ' ' +
|
||||
data.settings.errorCssClass + ' ' +
|
||||
data.settings.successCssClass
|
||||
);
|
||||
$container.find(this.error).html('');
|
||||
});
|
||||
$form.find(data.settings.errorSummary).hide().find('ul').html('');
|
||||
}, 1);
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates error messages, input containers, and optionally summary as well.
|
||||
* If an attribute is missing from messages, it is considered valid.
|
||||
* @param messages array the validation error messages, indexed by attribute IDs
|
||||
* @param summary whether to update summary as well.
|
||||
*/
|
||||
updateMessages: function (messages, summary) {
|
||||
var $form = $(this);
|
||||
var data = $form.data('yiiActiveForm');
|
||||
$.each(data.attributes, function () {
|
||||
updateInput($form, this, messages);
|
||||
});
|
||||
if (summary) {
|
||||
updateSummary($form, messages);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates error messages and input container of a single attribute.
|
||||
* If messages is empty, the attribute is considered valid.
|
||||
* @param id attribute ID
|
||||
* @param messages array with error messages
|
||||
*/
|
||||
updateAttribute: function(id, messages) {
|
||||
var attribute = methods.find.call(this, id);
|
||||
if (attribute != undefined) {
|
||||
var msg = {};
|
||||
msg[id] = messages;
|
||||
updateInput($(this), attribute, msg);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
var watchAttribute = function ($form, attribute) {
|
||||
var $input = findInput($form, attribute);
|
||||
if (attribute.validateOnChange) {
|
||||
$input.on('change.yiiActiveForm', function () {
|
||||
validateAttribute($form, attribute, false);
|
||||
});
|
||||
}
|
||||
if (attribute.validateOnBlur) {
|
||||
$input.on('blur.yiiActiveForm', function () {
|
||||
if (attribute.status == 0 || attribute.status == 1) {
|
||||
validateAttribute($form, attribute, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (attribute.validateOnType) {
|
||||
$input.on('keyup.yiiActiveForm', function (e) {
|
||||
if ($.inArray(e.which, [16, 17, 18, 37, 38, 39, 40]) !== -1 ) {
|
||||
return;
|
||||
}
|
||||
if (attribute.value !== getValue($form, attribute)) {
|
||||
validateAttribute($form, attribute, false, attribute.validationDelay);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var unwatchAttribute = function ($form, attribute) {
|
||||
findInput($form, attribute).off('.yiiActiveForm');
|
||||
};
|
||||
|
||||
var validateAttribute = function ($form, attribute, forceValidate, validationDelay) {
|
||||
var data = $form.data('yiiActiveForm');
|
||||
|
||||
if (forceValidate) {
|
||||
attribute.status = 2;
|
||||
}
|
||||
$.each(data.attributes, function () {
|
||||
if (this.value !== getValue($form, this)) {
|
||||
this.status = 2;
|
||||
forceValidate = true;
|
||||
}
|
||||
});
|
||||
if (!forceValidate) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.settings.timer !== undefined) {
|
||||
clearTimeout(data.settings.timer);
|
||||
}
|
||||
data.settings.timer = window.setTimeout(function () {
|
||||
if (data.submitting || $form.is(':hidden')) {
|
||||
return;
|
||||
}
|
||||
$.each(data.attributes, function () {
|
||||
if (this.status === 2) {
|
||||
this.status = 3;
|
||||
$form.find(this.container).addClass(data.settings.validatingCssClass);
|
||||
}
|
||||
});
|
||||
methods.validate.call($form);
|
||||
}, validationDelay ? validationDelay : 200);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an array prototype with a shortcut method for adding a new deferred.
|
||||
* The context of the callback will be the deferred object so it can be resolved like ```this.resolve()```
|
||||
* @returns Array
|
||||
*/
|
||||
var deferredArray = function () {
|
||||
var array = [];
|
||||
array.add = function(callback) {
|
||||
this.push(new $.Deferred(callback));
|
||||
};
|
||||
return array;
|
||||
};
|
||||
|
||||
var buttonOptions = ['action', 'target', 'method', 'enctype'];
|
||||
|
||||
/**
|
||||
* Returns current form options
|
||||
* @param $form
|
||||
* @returns object Object with button of form options
|
||||
*/
|
||||
var getFormOptions = function ($form) {
|
||||
var attributes = {};
|
||||
for (var i = 0; i < buttonOptions.length; i++) {
|
||||
attributes[buttonOptions[i]] = $form.attr(buttonOptions[i]);
|
||||
}
|
||||
|
||||
return attributes;
|
||||
};
|
||||
|
||||
/**
|
||||
* Applies temporary form options related to submit button
|
||||
* @param $form the form jQuery object
|
||||
* @param $button the button jQuery object
|
||||
*/
|
||||
var applyButtonOptions = function ($form, $button) {
|
||||
for (var i = 0; i < buttonOptions.length; i++) {
|
||||
var value = $button.attr('form' + buttonOptions[i]);
|
||||
if (value) {
|
||||
$form.attr(buttonOptions[i], value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Restores original form options
|
||||
* @param $form the form jQuery object
|
||||
*/
|
||||
var restoreButtonOptions = function ($form) {
|
||||
var data = $form.data('yiiActiveForm');
|
||||
|
||||
for (var i = 0; i < buttonOptions.length; i++) {
|
||||
$form.attr(buttonOptions[i], data.options[buttonOptions[i]] || null);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the error messages and the input containers for all applicable attributes
|
||||
* @param $form the form jQuery object
|
||||
* @param messages array the validation error messages
|
||||
* @param submitting whether this method is called after validation triggered by form submission
|
||||
*/
|
||||
var updateInputs = function ($form, messages, submitting) {
|
||||
var data = $form.data('yiiActiveForm');
|
||||
|
||||
if (data === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (submitting) {
|
||||
var errorAttributes = [];
|
||||
$.each(data.attributes, function () {
|
||||
if (!$(this.input).is(":disabled") && !this.cancelled && updateInput($form, this, messages)) {
|
||||
errorAttributes.push(this);
|
||||
}
|
||||
});
|
||||
|
||||
$form.trigger(events.afterValidate, [messages, errorAttributes]);
|
||||
|
||||
updateSummary($form, messages);
|
||||
|
||||
if (errorAttributes.length) {
|
||||
if (data.settings.scrollToError) {
|
||||
var top = $form.find($.map(errorAttributes, function(attribute) {
|
||||
return attribute.input;
|
||||
}).join(',')).first().closest(':visible').offset().top - data.settings.scrollToErrorOffset;
|
||||
if (top < 0) {
|
||||
top = 0;
|
||||
} else if (top > $(document).height()) {
|
||||
top = $(document).height();
|
||||
}
|
||||
var wtop = $(window).scrollTop();
|
||||
if (top < wtop || top > wtop + $(window).height()) {
|
||||
$(window).scrollTop(top);
|
||||
}
|
||||
}
|
||||
data.submitting = false;
|
||||
} else {
|
||||
data.validated = true;
|
||||
if (data.submitObject) {
|
||||
applyButtonOptions($form, data.submitObject);
|
||||
}
|
||||
$form.submit();
|
||||
if (data.submitObject) {
|
||||
restoreButtonOptions($form);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$.each(data.attributes, function () {
|
||||
if (!this.cancelled && (this.status === 2 || this.status === 3)) {
|
||||
updateInput($form, this, messages);
|
||||
}
|
||||
});
|
||||
}
|
||||
submitFinalize($form);
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates hidden field that represents clicked submit button.
|
||||
* @param $form the form jQuery object.
|
||||
*/
|
||||
var updateHiddenButton = function ($form) {
|
||||
var data = $form.data('yiiActiveForm');
|
||||
var $button = data.submitObject || $form.find(':submit:first');
|
||||
// TODO: if the submission is caused by "change" event, it will not work
|
||||
if ($button.length && $button.attr('type') == 'submit' && $button.attr('name')) {
|
||||
// simulate button input value
|
||||
var $hiddenButton = $('input[type="hidden"][name="' + $button.attr('name') + '"]', $form);
|
||||
if (!$hiddenButton.length) {
|
||||
$('<input>').attr({
|
||||
type: 'hidden',
|
||||
name: $button.attr('name'),
|
||||
value: $button.attr('value')
|
||||
}).appendTo($form);
|
||||
} else {
|
||||
$hiddenButton.attr('value', $button.attr('value'));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the error message and the input container for a particular attribute.
|
||||
* @param $form the form jQuery object
|
||||
* @param attribute object the configuration for a particular attribute.
|
||||
* @param messages array the validation error messages
|
||||
* @return boolean whether there is a validation error for the specified attribute
|
||||
*/
|
||||
var updateInput = function ($form, attribute, messages) {
|
||||
var data = $form.data('yiiActiveForm'),
|
||||
$input = findInput($form, attribute),
|
||||
hasError = false;
|
||||
|
||||
if (!$.isArray(messages[attribute.id])) {
|
||||
messages[attribute.id] = [];
|
||||
}
|
||||
|
||||
attribute.status = 1;
|
||||
if ($input.length) {
|
||||
hasError = messages[attribute.id].length > 0;
|
||||
var $container = $form.find(attribute.container);
|
||||
var $error = $container.find(attribute.error);
|
||||
updateAriaInvalid($form, attribute, hasError);
|
||||
|
||||
var $errorElement = data.settings.validationStateOn === 'input' ? $input : $container;
|
||||
|
||||
if (hasError) {
|
||||
if (attribute.encodeError) {
|
||||
$error.text(messages[attribute.id][0]);
|
||||
} else {
|
||||
$error.html(messages[attribute.id][0]);
|
||||
}
|
||||
$errorElement.removeClass(data.settings.validatingCssClass + ' ' + data.settings.successCssClass)
|
||||
.addClass(data.settings.errorCssClass);
|
||||
} else {
|
||||
$error.empty();
|
||||
$errorElement.removeClass(data.settings.validatingCssClass + ' ' + data.settings.errorCssClass + ' ')
|
||||
.addClass(data.settings.successCssClass);
|
||||
}
|
||||
attribute.value = getValue($form, attribute);
|
||||
}
|
||||
|
||||
$form.trigger(events.afterValidateAttribute, [attribute, messages[attribute.id]]);
|
||||
|
||||
return hasError;
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the error summary.
|
||||
* @param $form the form jQuery object
|
||||
* @param messages array the validation error messages
|
||||
*/
|
||||
var updateSummary = function ($form, messages) {
|
||||
var data = $form.data('yiiActiveForm'),
|
||||
$summary = $form.find(data.settings.errorSummary),
|
||||
$ul = $summary.find('ul').empty();
|
||||
|
||||
if ($summary.length && messages) {
|
||||
$.each(data.attributes, function () {
|
||||
if ($.isArray(messages[this.id]) && messages[this.id].length) {
|
||||
var error = $('<li/>');
|
||||
if (data.settings.encodeErrorSummary) {
|
||||
error.text(messages[this.id][0]);
|
||||
} else {
|
||||
error.html(messages[this.id][0]);
|
||||
}
|
||||
$ul.append(error);
|
||||
}
|
||||
});
|
||||
$summary.toggle($ul.find('li').length > 0);
|
||||
}
|
||||
};
|
||||
|
||||
var getValue = function ($form, attribute) {
|
||||
var $input = findInput($form, attribute);
|
||||
var type = $input.attr('type');
|
||||
if (type === 'checkbox' || type === 'radio') {
|
||||
var $realInput = $input.filter(':checked');
|
||||
if (!$realInput.length) {
|
||||
$realInput = $form.find('input[type=hidden][name="' + $input.attr('name') + '"]');
|
||||
}
|
||||
|
||||
return $realInput.val();
|
||||
} else {
|
||||
return $input.val();
|
||||
}
|
||||
};
|
||||
|
||||
var findInput = function ($form, attribute) {
|
||||
var $input = $form.find(attribute.input);
|
||||
if ($input.length && $input[0].tagName.toLowerCase() === 'div') {
|
||||
// checkbox list or radio list
|
||||
return $input.find('input');
|
||||
} else {
|
||||
return $input;
|
||||
}
|
||||
};
|
||||
|
||||
var updateAriaInvalid = function ($form, attribute, hasError) {
|
||||
if (attribute.updateAriaInvalid) {
|
||||
$form.find(attribute.input).attr('aria-invalid', hasError ? 'true' : 'false');
|
||||
}
|
||||
}
|
||||
})(window.jQuery);
|
||||
69
vendor/yiisoft/yii2/assets/yii.captcha.js
vendored
Normal file
69
vendor/yiisoft/yii2/assets/yii.captcha.js
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Yii Captcha widget.
|
||||
*
|
||||
* This is the JavaScript widget used by the yii\captcha\Captcha widget.
|
||||
*
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
(function ($) {
|
||||
$.fn.yiiCaptcha = function (method) {
|
||||
if (methods[method]) {
|
||||
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
|
||||
} else if (typeof method === 'object' || !method) {
|
||||
return methods.init.apply(this, arguments);
|
||||
} else {
|
||||
$.error('Method ' + method + ' does not exist in jQuery.yiiCaptcha');
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
var defaults = {
|
||||
refreshUrl: undefined,
|
||||
hashKey: undefined
|
||||
};
|
||||
|
||||
var methods = {
|
||||
init: function (options) {
|
||||
return this.each(function () {
|
||||
var $e = $(this);
|
||||
var settings = $.extend({}, defaults, options || {});
|
||||
$e.data('yiiCaptcha', {
|
||||
settings: settings
|
||||
});
|
||||
|
||||
$e.on('click.yiiCaptcha', function () {
|
||||
methods.refresh.apply($e);
|
||||
return false;
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
refresh: function () {
|
||||
var $e = this,
|
||||
settings = this.data('yiiCaptcha').settings;
|
||||
$.ajax({
|
||||
url: $e.data('yiiCaptcha').settings.refreshUrl,
|
||||
dataType: 'json',
|
||||
cache: false,
|
||||
success: function (data) {
|
||||
$e.attr('src', data.url);
|
||||
$('body').data(settings.hashKey, [data.hash1, data.hash2]);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
this.off('.yiiCaptcha');
|
||||
this.removeData('yiiCaptcha');
|
||||
return this;
|
||||
},
|
||||
|
||||
data: function () {
|
||||
return this.data('yiiCaptcha');
|
||||
}
|
||||
};
|
||||
})(window.jQuery);
|
||||
254
vendor/yiisoft/yii2/assets/yii.gridView.js
vendored
Normal file
254
vendor/yiisoft/yii2/assets/yii.gridView.js
vendored
Normal file
@@ -0,0 +1,254 @@
|
||||
/**
|
||||
* Yii GridView widget.
|
||||
*
|
||||
* This is the JavaScript widget used by the yii\grid\GridView widget.
|
||||
*
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
(function ($) {
|
||||
$.fn.yiiGridView = function (method) {
|
||||
if (methods[method]) {
|
||||
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
|
||||
} else if (typeof method === 'object' || !method) {
|
||||
return methods.init.apply(this, arguments);
|
||||
} else {
|
||||
$.error('Method ' + method + ' does not exist in jQuery.yiiGridView');
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
var defaults = {
|
||||
filterUrl: undefined,
|
||||
filterSelector: undefined
|
||||
};
|
||||
|
||||
var gridData = {};
|
||||
|
||||
var gridEvents = {
|
||||
/**
|
||||
* beforeFilter event is triggered before filtering the grid.
|
||||
* The signature of the event handler should be:
|
||||
* function (event)
|
||||
* where
|
||||
* - event: an Event object.
|
||||
*
|
||||
* If the handler returns a boolean false, it will stop filter form submission after this event. As
|
||||
* a result, afterFilter event will not be triggered.
|
||||
*/
|
||||
beforeFilter: 'beforeFilter',
|
||||
/**
|
||||
* afterFilter event is triggered after filtering the grid and filtered results are fetched.
|
||||
* The signature of the event handler should be:
|
||||
* function (event)
|
||||
* where
|
||||
* - event: an Event object.
|
||||
*/
|
||||
afterFilter: 'afterFilter'
|
||||
};
|
||||
|
||||
/**
|
||||
* Used for storing active event handlers and removing them later.
|
||||
* The structure of single event handler is:
|
||||
*
|
||||
* {
|
||||
* gridViewId: {
|
||||
* type: {
|
||||
* event: '...',
|
||||
* selector: '...'
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* Used types:
|
||||
*
|
||||
* - filter, used for filtering grid with elements found by filterSelector
|
||||
* - checkRow, used for checking single row
|
||||
* - checkAllRows, used for checking all rows with according "Check all" checkbox
|
||||
*
|
||||
* event is the name of event, for example: 'change.yiiGridView'
|
||||
* selector is a jQuery selector for finding elements
|
||||
*
|
||||
* @type {{}}
|
||||
*/
|
||||
var gridEventHandlers = {};
|
||||
|
||||
var methods = {
|
||||
init: function (options) {
|
||||
return this.each(function () {
|
||||
var $e = $(this);
|
||||
var settings = $.extend({}, defaults, options || {});
|
||||
var id = $e.attr('id');
|
||||
if (gridData[id] === undefined) {
|
||||
gridData[id] = {};
|
||||
}
|
||||
|
||||
gridData[id] = $.extend(gridData[id], {settings: settings});
|
||||
|
||||
var filterEvents = 'change.yiiGridView keydown.yiiGridView';
|
||||
var enterPressed = false;
|
||||
initEventHandler($e, 'filter', filterEvents, settings.filterSelector, function (event) {
|
||||
if (event.type === 'keydown') {
|
||||
if (event.keyCode !== 13) {
|
||||
return; // only react to enter key
|
||||
} else {
|
||||
enterPressed = true;
|
||||
}
|
||||
} else {
|
||||
// prevent processing for both keydown and change events
|
||||
if (enterPressed) {
|
||||
enterPressed = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
methods.applyFilter.apply($e);
|
||||
|
||||
return false;
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
applyFilter: function () {
|
||||
var $grid = $(this);
|
||||
var settings = gridData[$grid.attr('id')].settings;
|
||||
var data = {};
|
||||
$.each($(settings.filterSelector).serializeArray(), function () {
|
||||
if (!(this.name in data)) {
|
||||
data[this.name] = [];
|
||||
}
|
||||
data[this.name].push(this.value);
|
||||
});
|
||||
|
||||
var namesInFilter = Object.keys(data);
|
||||
|
||||
$.each(yii.getQueryParams(settings.filterUrl), function (name, value) {
|
||||
if (namesInFilter.indexOf(name) === -1 && namesInFilter.indexOf(name.replace(/\[\d*\]$/, '')) === -1) {
|
||||
if (!$.isArray(value)) {
|
||||
value = [value];
|
||||
}
|
||||
if (!(name in data)) {
|
||||
data[name] = value;
|
||||
} else {
|
||||
$.each(value, function (i, val) {
|
||||
if ($.inArray(val, data[name])) {
|
||||
data[name].push(val);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var pos = settings.filterUrl.indexOf('?');
|
||||
var url = pos < 0 ? settings.filterUrl : settings.filterUrl.substring(0, pos);
|
||||
var hashPos = settings.filterUrl.indexOf('#');
|
||||
if (pos >= 0 && hashPos >= 0) {
|
||||
url += settings.filterUrl.substring(hashPos);
|
||||
}
|
||||
|
||||
$grid.find('form.gridview-filter-form').remove();
|
||||
var $form = $('<form/>', {
|
||||
action: url,
|
||||
method: 'get',
|
||||
'class': 'gridview-filter-form',
|
||||
style: 'display:none',
|
||||
'data-pjax': ''
|
||||
}).appendTo($grid);
|
||||
$.each(data, function (name, values) {
|
||||
$.each(values, function (index, value) {
|
||||
$form.append($('<input/>').attr({type: 'hidden', name: name, value: value}));
|
||||
});
|
||||
});
|
||||
|
||||
var event = $.Event(gridEvents.beforeFilter);
|
||||
$grid.trigger(event);
|
||||
if (event.result === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$form.submit();
|
||||
|
||||
$grid.trigger(gridEvents.afterFilter);
|
||||
},
|
||||
|
||||
setSelectionColumn: function (options) {
|
||||
var $grid = $(this);
|
||||
var id = $(this).attr('id');
|
||||
if (gridData[id] === undefined) {
|
||||
gridData[id] = {};
|
||||
}
|
||||
gridData[id].selectionColumn = options.name;
|
||||
if (!options.multiple || !options.checkAll) {
|
||||
return;
|
||||
}
|
||||
var checkAll = "#" + id + " input[name='" + options.checkAll + "']";
|
||||
var inputs = options['class'] ? "input." + options['class'] : "input[name='" + options.name + "']";
|
||||
var inputsEnabled = "#" + id + " " + inputs + ":enabled";
|
||||
initEventHandler($grid, 'checkAllRows', 'click.yiiGridView', checkAll, function () {
|
||||
$grid.find(inputs + ":enabled").prop('checked', this.checked);
|
||||
});
|
||||
initEventHandler($grid, 'checkRow', 'click.yiiGridView', inputsEnabled, function () {
|
||||
var all = $grid.find(inputs).length == $grid.find(inputs + ":checked").length;
|
||||
$grid.find("input[name='" + options.checkAll + "']").prop('checked', all);
|
||||
});
|
||||
},
|
||||
|
||||
getSelectedRows: function () {
|
||||
var $grid = $(this);
|
||||
var data = gridData[$grid.attr('id')];
|
||||
var keys = [];
|
||||
if (data.selectionColumn) {
|
||||
$grid.find("input[name='" + data.selectionColumn + "']:checked").each(function () {
|
||||
keys.push($(this).parent().closest('tr').data('key'));
|
||||
});
|
||||
}
|
||||
|
||||
return keys;
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
var events = ['.yiiGridView', gridEvents.beforeFilter, gridEvents.afterFilter].join(' ');
|
||||
this.off(events);
|
||||
|
||||
var id = $(this).attr('id');
|
||||
$.each(gridEventHandlers[id], function (type, data) {
|
||||
$(document).off(data.event, data.selector);
|
||||
});
|
||||
|
||||
delete gridData[id];
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
data: function () {
|
||||
var id = $(this).attr('id');
|
||||
return gridData[id];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Used for attaching event handler and prevent of duplicating them. With each call previously attached handler of
|
||||
* the same type is removed even selector was changed.
|
||||
* @param {jQuery} $gridView According jQuery grid view element
|
||||
* @param {string} type Type of the event which acts like a key
|
||||
* @param {string} event Event name, for example 'change.yiiGridView'
|
||||
* @param {string} selector jQuery selector
|
||||
* @param {function} callback The actual function to be executed with this event
|
||||
*/
|
||||
function initEventHandler($gridView, type, event, selector, callback) {
|
||||
var id = $gridView.attr('id');
|
||||
var prevHandler = gridEventHandlers[id];
|
||||
if (prevHandler !== undefined && prevHandler[type] !== undefined) {
|
||||
var data = prevHandler[type];
|
||||
$(document).off(data.event, data.selector);
|
||||
}
|
||||
if (prevHandler === undefined) {
|
||||
gridEventHandlers[id] = {};
|
||||
}
|
||||
$(document).on(event, selector, callback);
|
||||
gridEventHandlers[id][type] = {event: event, selector: selector};
|
||||
}
|
||||
})(window.jQuery);
|
||||
522
vendor/yiisoft/yii2/assets/yii.js
vendored
Normal file
522
vendor/yiisoft/yii2/assets/yii.js
vendored
Normal file
@@ -0,0 +1,522 @@
|
||||
/**
|
||||
* Yii JavaScript module.
|
||||
*
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* yii is the root module for all Yii JavaScript modules.
|
||||
* It implements a mechanism of organizing JavaScript code in modules through the function "yii.initModule()".
|
||||
*
|
||||
* Each module should be named as "x.y.z", where "x" stands for the root module (for the Yii core code, this is "yii").
|
||||
*
|
||||
* A module may be structured as follows:
|
||||
*
|
||||
* ```javascript
|
||||
* window.yii.sample = (function($) {
|
||||
* var pub = {
|
||||
* // whether this module is currently active. If false, init() will not be called for this module
|
||||
* // it will also not be called for all its child modules. If this property is undefined, it means true.
|
||||
* isActive: true,
|
||||
* init: function() {
|
||||
* // ... module initialization code goes here ...
|
||||
* },
|
||||
*
|
||||
* // ... other public functions and properties go here ...
|
||||
* };
|
||||
*
|
||||
* // ... private functions and properties go here ...
|
||||
*
|
||||
* return pub;
|
||||
* })(window.jQuery);
|
||||
* ```
|
||||
*
|
||||
* Using this structure, you can define public and private functions/properties for a module.
|
||||
* Private functions/properties are only visible within the module, while public functions/properties
|
||||
* may be accessed outside of the module. For example, you can access "yii.sample.isActive".
|
||||
*
|
||||
* You must call "yii.initModule()" once for the root module of all your modules.
|
||||
*/
|
||||
window.yii = (function ($) {
|
||||
var pub = {
|
||||
/**
|
||||
* List of JS or CSS URLs that can be loaded multiple times via AJAX requests.
|
||||
* Each item may be represented as either an absolute URL or a relative one.
|
||||
* Each item may contain a wildcard matching character `*`, that means one or more
|
||||
* any characters on the position. For example:
|
||||
* - `/css/*.css` will match any file ending with `.css` in the `css` directory of the current web site
|
||||
* - `http*://cdn.example.com/*` will match any files on domain `cdn.example.com`, loaded with HTTP or HTTPS
|
||||
* - `/js/myCustomScript.js?realm=*` will match file `/js/myCustomScript.js` with defined `realm` parameter
|
||||
*/
|
||||
reloadableScripts: [],
|
||||
/**
|
||||
* The selector for clickable elements that need to support confirmation and form submission.
|
||||
*/
|
||||
clickableSelector: 'a, button, input[type="submit"], input[type="button"], input[type="reset"], ' +
|
||||
'input[type="image"]',
|
||||
/**
|
||||
* The selector for changeable elements that need to support confirmation and form submission.
|
||||
*/
|
||||
changeableSelector: 'select, input, textarea',
|
||||
|
||||
/**
|
||||
* @return string|undefined the CSRF parameter name. Undefined is returned if CSRF validation is not enabled.
|
||||
*/
|
||||
getCsrfParam: function () {
|
||||
return $('meta[name=csrf-param]').attr('content');
|
||||
},
|
||||
|
||||
/**
|
||||
* @return string|undefined the CSRF token. Undefined is returned if CSRF validation is not enabled.
|
||||
*/
|
||||
getCsrfToken: function () {
|
||||
return $('meta[name=csrf-token]').attr('content');
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the CSRF token in the meta elements.
|
||||
* This method is provided so that you can update the CSRF token with the latest one you obtain from the server.
|
||||
* @param name the CSRF token name
|
||||
* @param value the CSRF token value
|
||||
*/
|
||||
setCsrfToken: function (name, value) {
|
||||
$('meta[name=csrf-param]').attr('content', name);
|
||||
$('meta[name=csrf-token]').attr('content', value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates all form CSRF input fields with the latest CSRF token.
|
||||
* This method is provided to avoid cached forms containing outdated CSRF tokens.
|
||||
*/
|
||||
refreshCsrfToken: function () {
|
||||
var token = pub.getCsrfToken();
|
||||
if (token) {
|
||||
$('form input[name="' + pub.getCsrfParam() + '"]').val(token);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays a confirmation dialog.
|
||||
* The default implementation simply displays a js confirmation dialog.
|
||||
* You may override this by setting `yii.confirm`.
|
||||
* @param message the confirmation message.
|
||||
* @param ok a callback to be called when the user confirms the message
|
||||
* @param cancel a callback to be called when the user cancels the confirmation
|
||||
*/
|
||||
confirm: function (message, ok, cancel) {
|
||||
if (window.confirm(message)) {
|
||||
!ok || ok();
|
||||
} else {
|
||||
!cancel || cancel();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the action triggered by user.
|
||||
* This method recognizes the `data-method` attribute of the element. If the attribute exists,
|
||||
* the method will submit the form containing this element. If there is no containing form, a form
|
||||
* will be created and submitted using the method given by this attribute value (e.g. "post", "put").
|
||||
* For hyperlinks, the form action will take the value of the "href" attribute of the link.
|
||||
* For other elements, either the containing form action or the current page URL will be used
|
||||
* as the form action URL.
|
||||
*
|
||||
* If the `data-method` attribute is not defined, the `href` attribute (if any) of the element
|
||||
* will be assigned to `window.location`.
|
||||
*
|
||||
* Starting from version 2.0.3, the `data-params` attribute is also recognized when you specify
|
||||
* `data-method`. The value of `data-params` should be a JSON representation of the data (name-value pairs)
|
||||
* that should be submitted as hidden inputs. For example, you may use the following code to generate
|
||||
* such a link:
|
||||
*
|
||||
* ```php
|
||||
* use yii\helpers\Html;
|
||||
* use yii\helpers\Json;
|
||||
*
|
||||
* echo Html::a('submit', ['site/foobar'], [
|
||||
* 'data' => [
|
||||
* 'method' => 'post',
|
||||
* 'params' => [
|
||||
* 'name1' => 'value1',
|
||||
* 'name2' => 'value2',
|
||||
* ],
|
||||
* ],
|
||||
* ]);
|
||||
* ```
|
||||
*
|
||||
* @param $e the jQuery representation of the element
|
||||
* @param event Related event
|
||||
*/
|
||||
handleAction: function ($e, event) {
|
||||
var $form = $e.attr('data-form') ? $('#' + $e.attr('data-form')) : $e.closest('form'),
|
||||
method = !$e.data('method') && $form ? $form.attr('method') : $e.data('method'),
|
||||
action = $e.attr('href'),
|
||||
isValidAction = action && action !== '#',
|
||||
params = $e.data('params'),
|
||||
areValidParams = params && $.isPlainObject(params),
|
||||
pjax = $e.data('pjax'),
|
||||
usePjax = pjax !== undefined && pjax !== 0 && $.support.pjax,
|
||||
pjaxContainer,
|
||||
pjaxOptions = {};
|
||||
|
||||
if (usePjax) {
|
||||
pjaxContainer = $e.data('pjax-container');
|
||||
if (pjaxContainer === undefined || !pjaxContainer.length) {
|
||||
pjaxContainer = $e.closest('[data-pjax-container]').attr('id')
|
||||
? ('#' + $e.closest('[data-pjax-container]').attr('id'))
|
||||
: '';
|
||||
}
|
||||
if (!pjaxContainer.length) {
|
||||
pjaxContainer = 'body';
|
||||
}
|
||||
pjaxOptions = {
|
||||
container: pjaxContainer,
|
||||
push: !!$e.data('pjax-push-state'),
|
||||
replace: !!$e.data('pjax-replace-state'),
|
||||
scrollTo: $e.data('pjax-scrollto'),
|
||||
pushRedirect: $e.data('pjax-push-redirect'),
|
||||
replaceRedirect: $e.data('pjax-replace-redirect'),
|
||||
skipOuterContainers: $e.data('pjax-skip-outer-containers'),
|
||||
timeout: $e.data('pjax-timeout'),
|
||||
originalEvent: event,
|
||||
originalTarget: $e
|
||||
};
|
||||
}
|
||||
|
||||
if (method === undefined) {
|
||||
if (isValidAction) {
|
||||
usePjax ? $.pjax.click(event, pjaxOptions) : window.location.assign(action);
|
||||
} else if ($e.is(':submit') && $form.length) {
|
||||
if (usePjax) {
|
||||
$form.on('submit', function (e) {
|
||||
$.pjax.submit(e, pjaxOptions);
|
||||
});
|
||||
}
|
||||
$form.trigger('submit');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var oldMethod,
|
||||
oldAction,
|
||||
newForm = !$form.length;
|
||||
if (!newForm) {
|
||||
oldMethod = $form.attr('method');
|
||||
$form.attr('method', method);
|
||||
if (isValidAction) {
|
||||
oldAction = $form.attr('action');
|
||||
$form.attr('action', action);
|
||||
}
|
||||
} else {
|
||||
if (!isValidAction) {
|
||||
action = pub.getCurrentUrl();
|
||||
}
|
||||
$form = $('<form/>', {method: method, action: action});
|
||||
var target = $e.attr('target');
|
||||
if (target) {
|
||||
$form.attr('target', target);
|
||||
}
|
||||
if (!/(get|post)/i.test(method)) {
|
||||
$form.append($('<input/>', {name: '_method', value: method, type: 'hidden'}));
|
||||
method = 'post';
|
||||
$form.attr('method', method);
|
||||
}
|
||||
if (/post/i.test(method)) {
|
||||
var csrfParam = pub.getCsrfParam();
|
||||
if (csrfParam) {
|
||||
$form.append($('<input/>', {name: csrfParam, value: pub.getCsrfToken(), type: 'hidden'}));
|
||||
}
|
||||
}
|
||||
$form.hide().appendTo('body');
|
||||
}
|
||||
|
||||
var activeFormData = $form.data('yiiActiveForm');
|
||||
if (activeFormData) {
|
||||
// Remember the element triggered the form submission. This is used by yii.activeForm.js.
|
||||
activeFormData.submitObject = $e;
|
||||
}
|
||||
|
||||
if (areValidParams) {
|
||||
$.each(params, function (name, value) {
|
||||
$form.append($('<input/>').attr({name: name, value: value, type: 'hidden'}));
|
||||
});
|
||||
}
|
||||
|
||||
if (usePjax) {
|
||||
$form.on('submit', function (e) {
|
||||
$.pjax.submit(e, pjaxOptions);
|
||||
});
|
||||
}
|
||||
|
||||
$form.trigger('submit');
|
||||
|
||||
$.when($form.data('yiiSubmitFinalizePromise')).done(function () {
|
||||
if (newForm) {
|
||||
$form.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldAction !== undefined) {
|
||||
$form.attr('action', oldAction);
|
||||
}
|
||||
$form.attr('method', oldMethod);
|
||||
|
||||
if (areValidParams) {
|
||||
$.each(params, function (name) {
|
||||
$('input[name="' + name + '"]', $form).remove();
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getQueryParams: function (url) {
|
||||
var pos = url.indexOf('?');
|
||||
if (pos < 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
var pairs = $.grep(url.substring(pos + 1).split('#')[0].split('&'), function (value) {
|
||||
return value !== '';
|
||||
});
|
||||
var params = {};
|
||||
|
||||
for (var i = 0, len = pairs.length; i < len; i++) {
|
||||
var pair = pairs[i].split('=');
|
||||
var name = decodeURIComponent(pair[0].replace(/\+/g, '%20'));
|
||||
var value = decodeURIComponent(pair[1].replace(/\+/g, '%20'));
|
||||
if (!name.length) {
|
||||
continue;
|
||||
}
|
||||
if (params[name] === undefined) {
|
||||
params[name] = value || '';
|
||||
} else {
|
||||
if (!$.isArray(params[name])) {
|
||||
params[name] = [params[name]];
|
||||
}
|
||||
params[name].push(value || '');
|
||||
}
|
||||
}
|
||||
|
||||
return params;
|
||||
},
|
||||
|
||||
initModule: function (module) {
|
||||
if (module.isActive !== undefined && !module.isActive) {
|
||||
return;
|
||||
}
|
||||
if ($.isFunction(module.init)) {
|
||||
module.init();
|
||||
}
|
||||
$.each(module, function () {
|
||||
if ($.isPlainObject(this)) {
|
||||
pub.initModule(this);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
init: function () {
|
||||
initCsrfHandler();
|
||||
initRedirectHandler();
|
||||
initAssetFilters();
|
||||
initDataMethods();
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the URL of the current page without params and trailing slash. Separated and made public for testing.
|
||||
* @returns {string}
|
||||
*/
|
||||
getBaseCurrentUrl: function () {
|
||||
return window.location.protocol + '//' + window.location.host;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the URL of the current page. Used for testing, you can always call `window.location.href` manually
|
||||
* instead.
|
||||
* @returns {string}
|
||||
*/
|
||||
getCurrentUrl: function () {
|
||||
return window.location.href;
|
||||
}
|
||||
};
|
||||
|
||||
function initCsrfHandler() {
|
||||
// automatically send CSRF token for all AJAX requests
|
||||
$.ajaxPrefilter(function (options, originalOptions, xhr) {
|
||||
if (!options.crossDomain && pub.getCsrfParam()) {
|
||||
xhr.setRequestHeader('X-CSRF-Token', pub.getCsrfToken());
|
||||
}
|
||||
});
|
||||
pub.refreshCsrfToken();
|
||||
}
|
||||
|
||||
function initRedirectHandler() {
|
||||
// handle AJAX redirection
|
||||
$(document).ajaxComplete(function (event, xhr) {
|
||||
var url = xhr && xhr.getResponseHeader('X-Redirect');
|
||||
if (url) {
|
||||
window.location.assign(url);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function initAssetFilters() {
|
||||
/**
|
||||
* Used for storing loaded scripts and information about loading each script if it's in the process of loading.
|
||||
* A single script can have one of the following values:
|
||||
*
|
||||
* - `undefined` - script was not loaded at all before or was loaded with error last time.
|
||||
* - `true` (boolean) - script was successfully loaded.
|
||||
* - object - script is currently loading.
|
||||
*
|
||||
* In case of a value being an object the properties are:
|
||||
* - `xhrList` - represents a queue of XHR requests sent to the same URL (related with this script) in the same
|
||||
* small period of time.
|
||||
* - `xhrDone` - boolean, acts like a locking mechanism. When one of the XHR requests in the queue is
|
||||
* successfully completed, it will abort the rest of concurrent requests to the same URL until cleanup is done
|
||||
* to prevent possible errors and race conditions.
|
||||
* @type {{}}
|
||||
*/
|
||||
var loadedScripts = {};
|
||||
|
||||
$('script[src]').each(function () {
|
||||
var url = getAbsoluteUrl(this.src);
|
||||
loadedScripts[url] = true;
|
||||
});
|
||||
|
||||
$.ajaxPrefilter('script', function (options, originalOptions, xhr) {
|
||||
if (options.dataType == 'jsonp') {
|
||||
return;
|
||||
}
|
||||
|
||||
var url = getAbsoluteUrl(options.url),
|
||||
forbiddenRepeatedLoad = loadedScripts[url] === true && !isReloadableAsset(url),
|
||||
cleanupRunning = loadedScripts[url] !== undefined && loadedScripts[url]['xhrDone'] === true;
|
||||
|
||||
if (forbiddenRepeatedLoad || cleanupRunning) {
|
||||
xhr.abort();
|
||||
return;
|
||||
}
|
||||
|
||||
if (loadedScripts[url] === undefined || loadedScripts[url] === true) {
|
||||
loadedScripts[url] = {
|
||||
xhrList: [],
|
||||
xhrDone: false
|
||||
};
|
||||
}
|
||||
|
||||
xhr.done(function (data, textStatus, jqXHR) {
|
||||
// If multiple requests were successfully loaded, perform cleanup only once
|
||||
if (loadedScripts[jqXHR.yiiUrl]['xhrDone'] === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadedScripts[jqXHR.yiiUrl]['xhrDone'] = true;
|
||||
|
||||
for (var i = 0, len = loadedScripts[jqXHR.yiiUrl]['xhrList'].length; i < len; i++) {
|
||||
var singleXhr = loadedScripts[jqXHR.yiiUrl]['xhrList'][i];
|
||||
if (singleXhr && singleXhr.readyState !== XMLHttpRequest.DONE) {
|
||||
singleXhr.abort();
|
||||
}
|
||||
}
|
||||
|
||||
loadedScripts[jqXHR.yiiUrl] = true;
|
||||
}).fail(function (jqXHR, textStatus) {
|
||||
if (textStatus === 'abort') {
|
||||
return;
|
||||
}
|
||||
|
||||
delete loadedScripts[jqXHR.yiiUrl]['xhrList'][jqXHR.yiiIndex];
|
||||
|
||||
var allFailed = true;
|
||||
for (var i = 0, len = loadedScripts[jqXHR.yiiUrl]['xhrList'].length; i < len; i++) {
|
||||
if (loadedScripts[jqXHR.yiiUrl]['xhrList'][i]) {
|
||||
allFailed = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (allFailed) {
|
||||
delete loadedScripts[jqXHR.yiiUrl];
|
||||
}
|
||||
});
|
||||
// Use prefix for custom XHR properties to avoid possible conflicts with existing properties
|
||||
xhr.yiiIndex = loadedScripts[url]['xhrList'].length;
|
||||
xhr.yiiUrl = url;
|
||||
|
||||
loadedScripts[url]['xhrList'][xhr.yiiIndex] = xhr;
|
||||
});
|
||||
|
||||
$(document).ajaxComplete(function () {
|
||||
var styleSheets = [];
|
||||
$('link[rel=stylesheet]').each(function () {
|
||||
var url = getAbsoluteUrl(this.href);
|
||||
if (isReloadableAsset(url)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$.inArray(url, styleSheets) === -1 ? styleSheets.push(url) : $(this).remove();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function initDataMethods() {
|
||||
var handler = function (event) {
|
||||
var $this = $(this),
|
||||
method = $this.data('method'),
|
||||
message = $this.data('confirm'),
|
||||
form = $this.data('form');
|
||||
|
||||
if (method === undefined && message === undefined && form === undefined) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (message !== undefined) {
|
||||
$.proxy(pub.confirm, this)(message, function () {
|
||||
pub.handleAction($this, event);
|
||||
});
|
||||
} else {
|
||||
pub.handleAction($this, event);
|
||||
}
|
||||
event.stopImmediatePropagation();
|
||||
return false;
|
||||
};
|
||||
|
||||
// handle data-confirm and data-method for clickable and changeable elements
|
||||
$(document).on('click.yii', pub.clickableSelector, handler)
|
||||
.on('change.yii', pub.changeableSelector, handler);
|
||||
}
|
||||
|
||||
function isReloadableAsset(url) {
|
||||
for (var i = 0; i < pub.reloadableScripts.length; i++) {
|
||||
var rule = getAbsoluteUrl(pub.reloadableScripts[i]);
|
||||
var match = new RegExp("^" + escapeRegExp(rule).split('\\*').join('.+') + "$").test(url);
|
||||
if (match === true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
|
||||
function escapeRegExp(str) {
|
||||
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns absolute URL based on the given URL
|
||||
* @param {string} url Initial URL
|
||||
* @returns {string}
|
||||
*/
|
||||
function getAbsoluteUrl(url) {
|
||||
return url.charAt(0) === '/' ? pub.getBaseCurrentUrl() + url : url;
|
||||
}
|
||||
|
||||
return pub;
|
||||
})(window.jQuery);
|
||||
|
||||
window.jQuery(function () {
|
||||
window.yii.initModule(window.yii);
|
||||
});
|
||||
452
vendor/yiisoft/yii2/assets/yii.validation.js
vendored
Normal file
452
vendor/yiisoft/yii2/assets/yii.validation.js
vendored
Normal file
@@ -0,0 +1,452 @@
|
||||
/**
|
||||
* Yii validation module.
|
||||
*
|
||||
* This JavaScript module provides the validation methods for the built-in validators.
|
||||
*
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
|
||||
yii.validation = (function ($) {
|
||||
var pub = {
|
||||
isEmpty: function (value) {
|
||||
return value === null || value === undefined || ($.isArray(value) && value.length === 0) || value === '';
|
||||
},
|
||||
|
||||
addMessage: function (messages, message, value) {
|
||||
messages.push(message.replace(/\{value\}/g, value));
|
||||
},
|
||||
|
||||
required: function (value, messages, options) {
|
||||
var valid = false;
|
||||
if (options.requiredValue === undefined) {
|
||||
var isString = typeof value == 'string' || value instanceof String;
|
||||
if (options.strict && value !== undefined || !options.strict && !pub.isEmpty(isString ? $.trim(value) : value)) {
|
||||
valid = true;
|
||||
}
|
||||
} else if (!options.strict && value == options.requiredValue || options.strict && value === options.requiredValue) {
|
||||
valid = true;
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
pub.addMessage(messages, options.message, value);
|
||||
}
|
||||
},
|
||||
|
||||
// "boolean" is a reserved keyword in older versions of ES so it's quoted for IE < 9 support
|
||||
'boolean': function (value, messages, options) {
|
||||
if (options.skipOnEmpty && pub.isEmpty(value)) {
|
||||
return;
|
||||
}
|
||||
var valid = !options.strict && (value == options.trueValue || value == options.falseValue)
|
||||
|| options.strict && (value === options.trueValue || value === options.falseValue);
|
||||
|
||||
if (!valid) {
|
||||
pub.addMessage(messages, options.message, value);
|
||||
}
|
||||
},
|
||||
|
||||
string: function (value, messages, options) {
|
||||
if (options.skipOnEmpty && pub.isEmpty(value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof value !== 'string') {
|
||||
pub.addMessage(messages, options.message, value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.is !== undefined && value.length != options.is) {
|
||||
pub.addMessage(messages, options.notEqual, value);
|
||||
return;
|
||||
}
|
||||
if (options.min !== undefined && value.length < options.min) {
|
||||
pub.addMessage(messages, options.tooShort, value);
|
||||
}
|
||||
if (options.max !== undefined && value.length > options.max) {
|
||||
pub.addMessage(messages, options.tooLong, value);
|
||||
}
|
||||
},
|
||||
|
||||
file: function (attribute, messages, options) {
|
||||
var files = getUploadedFiles(attribute, messages, options);
|
||||
$.each(files, function (i, file) {
|
||||
validateFile(file, messages, options);
|
||||
});
|
||||
},
|
||||
|
||||
image: function (attribute, messages, options, deferredList) {
|
||||
var files = getUploadedFiles(attribute, messages, options);
|
||||
$.each(files, function (i, file) {
|
||||
validateFile(file, messages, options);
|
||||
|
||||
// Skip image validation if FileReader API is not available
|
||||
if (typeof FileReader === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
var deferred = $.Deferred();
|
||||
pub.validateImage(file, messages, options, deferred, new FileReader(), new Image());
|
||||
deferredList.push(deferred);
|
||||
});
|
||||
},
|
||||
|
||||
validateImage: function (file, messages, options, deferred, fileReader, image) {
|
||||
image.onload = function() {
|
||||
validateImageSize(file, image, messages, options);
|
||||
deferred.resolve();
|
||||
};
|
||||
|
||||
image.onerror = function () {
|
||||
messages.push(options.notImage.replace(/\{file\}/g, file.name));
|
||||
deferred.resolve();
|
||||
};
|
||||
|
||||
fileReader.onload = function () {
|
||||
image.src = this.result;
|
||||
};
|
||||
|
||||
// Resolve deferred if there was error while reading data
|
||||
fileReader.onerror = function () {
|
||||
deferred.resolve();
|
||||
};
|
||||
|
||||
fileReader.readAsDataURL(file);
|
||||
},
|
||||
|
||||
number: function (value, messages, options) {
|
||||
if (options.skipOnEmpty && pub.isEmpty(value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof value === 'string' && !options.pattern.test(value)) {
|
||||
pub.addMessage(messages, options.message, value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.min !== undefined && value < options.min) {
|
||||
pub.addMessage(messages, options.tooSmall, value);
|
||||
}
|
||||
if (options.max !== undefined && value > options.max) {
|
||||
pub.addMessage(messages, options.tooBig, value);
|
||||
}
|
||||
},
|
||||
|
||||
range: function (value, messages, options) {
|
||||
if (options.skipOnEmpty && pub.isEmpty(value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!options.allowArray && $.isArray(value)) {
|
||||
pub.addMessage(messages, options.message, value);
|
||||
return;
|
||||
}
|
||||
|
||||
var inArray = true;
|
||||
|
||||
$.each($.isArray(value) ? value : [value], function (i, v) {
|
||||
if ($.inArray(v, options.range) == -1) {
|
||||
inArray = false;
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
if (options.not === undefined) {
|
||||
options.not = false;
|
||||
}
|
||||
|
||||
if (options.not === inArray) {
|
||||
pub.addMessage(messages, options.message, value);
|
||||
}
|
||||
},
|
||||
|
||||
regularExpression: function (value, messages, options) {
|
||||
if (options.skipOnEmpty && pub.isEmpty(value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!options.not && !options.pattern.test(value) || options.not && options.pattern.test(value)) {
|
||||
pub.addMessage(messages, options.message, value);
|
||||
}
|
||||
},
|
||||
|
||||
email: function (value, messages, options) {
|
||||
if (options.skipOnEmpty && pub.isEmpty(value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var valid = true,
|
||||
regexp = /^((?:"?([^"]*)"?\s)?)(?:\s+)?(?:(<?)((.+)@([^>]+))(>?))$/,
|
||||
matches = regexp.exec(value);
|
||||
|
||||
if (matches === null) {
|
||||
valid = false;
|
||||
} else {
|
||||
var localPart = matches[5],
|
||||
domain = matches[6];
|
||||
|
||||
if (options.enableIDN) {
|
||||
localPart = punycode.toASCII(localPart);
|
||||
domain = punycode.toASCII(domain);
|
||||
|
||||
value = matches[1] + matches[3] + localPart + '@' + domain + matches[7];
|
||||
}
|
||||
|
||||
if (localPart.length > 64) {
|
||||
valid = false;
|
||||
} else if ((localPart + '@' + domain).length > 254) {
|
||||
valid = false;
|
||||
} else {
|
||||
valid = options.pattern.test(value) || (options.allowName && options.fullPattern.test(value));
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
pub.addMessage(messages, options.message, value);
|
||||
}
|
||||
},
|
||||
|
||||
url: function (value, messages, options) {
|
||||
if (options.skipOnEmpty && pub.isEmpty(value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.defaultScheme && !/:\/\//.test(value)) {
|
||||
value = options.defaultScheme + '://' + value;
|
||||
}
|
||||
|
||||
var valid = true;
|
||||
|
||||
if (options.enableIDN) {
|
||||
var matches = /^([^:]+):\/\/([^\/]+)(.*)$/.exec(value);
|
||||
if (matches === null) {
|
||||
valid = false;
|
||||
} else {
|
||||
value = matches[1] + '://' + punycode.toASCII(matches[2]) + matches[3];
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid || !options.pattern.test(value)) {
|
||||
pub.addMessage(messages, options.message, value);
|
||||
}
|
||||
},
|
||||
|
||||
trim: function ($form, attribute, options) {
|
||||
var $input = $form.find(attribute.input);
|
||||
var value = $input.val();
|
||||
if (!options.skipOnEmpty || !pub.isEmpty(value)) {
|
||||
value = $.trim(value);
|
||||
$input.val(value);
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
|
||||
captcha: function (value, messages, options) {
|
||||
if (options.skipOnEmpty && pub.isEmpty(value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// CAPTCHA may be updated via AJAX and the updated hash is stored in body data
|
||||
var hash = $('body').data(options.hashKey);
|
||||
hash = hash == null ? options.hash : hash[options.caseSensitive ? 0 : 1];
|
||||
var v = options.caseSensitive ? value : value.toLowerCase();
|
||||
for (var i = v.length - 1, h = 0; i >= 0; --i) {
|
||||
h += v.charCodeAt(i);
|
||||
}
|
||||
if (h != hash) {
|
||||
pub.addMessage(messages, options.message, value);
|
||||
}
|
||||
},
|
||||
|
||||
compare: function (value, messages, options, $form) {
|
||||
if (options.skipOnEmpty && pub.isEmpty(value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var compareValue,
|
||||
valid = true;
|
||||
if (options.compareAttribute === undefined) {
|
||||
compareValue = options.compareValue;
|
||||
} else {
|
||||
var attributes = $form.data('yiiActiveForm').attributes
|
||||
for (var i = attributes.length - 1; i >= 0; i--) {
|
||||
if (attributes[i].id === options.compareAttribute) {
|
||||
compareValue = $(attributes[i].input).val();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (options.type === 'number') {
|
||||
value = parseFloat(value);
|
||||
compareValue = parseFloat(compareValue);
|
||||
}
|
||||
switch (options.operator) {
|
||||
case '==':
|
||||
valid = value == compareValue;
|
||||
break;
|
||||
case '===':
|
||||
valid = value === compareValue;
|
||||
break;
|
||||
case '!=':
|
||||
valid = value != compareValue;
|
||||
break;
|
||||
case '!==':
|
||||
valid = value !== compareValue;
|
||||
break;
|
||||
case '>':
|
||||
valid = value > compareValue;
|
||||
break;
|
||||
case '>=':
|
||||
valid = value >= compareValue;
|
||||
break;
|
||||
case '<':
|
||||
valid = value < compareValue;
|
||||
break;
|
||||
case '<=':
|
||||
valid = value <= compareValue;
|
||||
break;
|
||||
default:
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
pub.addMessage(messages, options.message, value);
|
||||
}
|
||||
},
|
||||
|
||||
ip: function (value, messages, options) {
|
||||
if (options.skipOnEmpty && pub.isEmpty(value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var negation = null,
|
||||
cidr = null,
|
||||
matches = new RegExp(options.ipParsePattern).exec(value);
|
||||
if (matches) {
|
||||
negation = matches[1] || null;
|
||||
value = matches[2];
|
||||
cidr = matches[4] || null;
|
||||
}
|
||||
|
||||
if (options.subnet === true && cidr === null) {
|
||||
pub.addMessage(messages, options.messages.noSubnet, value);
|
||||
return;
|
||||
}
|
||||
if (options.subnet === false && cidr !== null) {
|
||||
pub.addMessage(messages, options.messages.hasSubnet, value);
|
||||
return;
|
||||
}
|
||||
if (options.negation === false && negation !== null) {
|
||||
pub.addMessage(messages, options.messages.message, value);
|
||||
return;
|
||||
}
|
||||
|
||||
var ipVersion = value.indexOf(':') === -1 ? 4 : 6;
|
||||
if (ipVersion == 6) {
|
||||
if (!(new RegExp(options.ipv6Pattern)).test(value)) {
|
||||
pub.addMessage(messages, options.messages.message, value);
|
||||
}
|
||||
if (!options.ipv6) {
|
||||
pub.addMessage(messages, options.messages.ipv6NotAllowed, value);
|
||||
}
|
||||
} else {
|
||||
if (!(new RegExp(options.ipv4Pattern)).test(value)) {
|
||||
pub.addMessage(messages, options.messages.message, value);
|
||||
}
|
||||
if (!options.ipv4) {
|
||||
pub.addMessage(messages, options.messages.ipv4NotAllowed, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function getUploadedFiles(attribute, messages, options) {
|
||||
// Skip validation if File API is not available
|
||||
if (typeof File === "undefined") {
|
||||
return [];
|
||||
}
|
||||
|
||||
var files = $(attribute.input, attribute.$form).get(0).files;
|
||||
if (!files) {
|
||||
messages.push(options.message);
|
||||
return [];
|
||||
}
|
||||
|
||||
if (files.length === 0) {
|
||||
if (!options.skipOnEmpty) {
|
||||
messages.push(options.uploadRequired);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
if (options.maxFiles && options.maxFiles < files.length) {
|
||||
messages.push(options.tooMany);
|
||||
return [];
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
function validateFile(file, messages, options) {
|
||||
if (options.extensions && options.extensions.length > 0) {
|
||||
var index = file.name.lastIndexOf('.');
|
||||
var ext = !~index ? '' : file.name.substr(index + 1, file.name.length).toLowerCase();
|
||||
|
||||
if (!~options.extensions.indexOf(ext)) {
|
||||
messages.push(options.wrongExtension.replace(/\{file\}/g, file.name));
|
||||
}
|
||||
}
|
||||
|
||||
if (options.mimeTypes && options.mimeTypes.length > 0) {
|
||||
if (!validateMimeType(options.mimeTypes, file.type)) {
|
||||
messages.push(options.wrongMimeType.replace(/\{file\}/g, file.name));
|
||||
}
|
||||
}
|
||||
|
||||
if (options.maxSize && options.maxSize < file.size) {
|
||||
messages.push(options.tooBig.replace(/\{file\}/g, file.name));
|
||||
}
|
||||
|
||||
if (options.minSize && options.minSize > file.size) {
|
||||
messages.push(options.tooSmall.replace(/\{file\}/g, file.name));
|
||||
}
|
||||
}
|
||||
|
||||
function validateMimeType(mimeTypes, fileType) {
|
||||
for (var i = 0, len = mimeTypes.length; i < len; i++) {
|
||||
if (new RegExp(mimeTypes[i]).test(fileType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function validateImageSize(file, image, messages, options) {
|
||||
if (options.minWidth && image.width < options.minWidth) {
|
||||
messages.push(options.underWidth.replace(/\{file\}/g, file.name));
|
||||
}
|
||||
|
||||
if (options.maxWidth && image.width > options.maxWidth) {
|
||||
messages.push(options.overWidth.replace(/\{file\}/g, file.name));
|
||||
}
|
||||
|
||||
if (options.minHeight && image.height < options.minHeight) {
|
||||
messages.push(options.underHeight.replace(/\{file\}/g, file.name));
|
||||
}
|
||||
|
||||
if (options.maxHeight && image.height > options.maxHeight) {
|
||||
messages.push(options.overHeight.replace(/\{file\}/g, file.name));
|
||||
}
|
||||
}
|
||||
|
||||
return pub;
|
||||
})(jQuery);
|
||||
122
vendor/yiisoft/yii2/base/Action.php
vendored
Normal file
122
vendor/yiisoft/yii2/base/Action.php
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
use Yii;
|
||||
|
||||
/**
|
||||
* Action is the base class for all controller action classes.
|
||||
*
|
||||
* Action provides a way to reuse action method code. An action method in an Action
|
||||
* class can be used in multiple controllers or in different projects.
|
||||
*
|
||||
* Derived classes must implement a method named `run()`. This method
|
||||
* will be invoked by the controller when the action is requested.
|
||||
* The `run()` method can have parameters which will be filled up
|
||||
* with user input values automatically according to their names.
|
||||
* For example, if the `run()` method is declared as follows:
|
||||
*
|
||||
* ```php
|
||||
* public function run($id, $type = 'book') { ... }
|
||||
* ```
|
||||
*
|
||||
* And the parameters provided for the action are: `['id' => 1]`.
|
||||
* Then the `run()` method will be invoked as `run(1)` automatically.
|
||||
*
|
||||
* For more details and usage information on Action, see the [guide article on actions](guide:structure-controllers).
|
||||
*
|
||||
* @property string $uniqueId The unique ID of this action among the whole application. This property is
|
||||
* read-only.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class Action extends Component
|
||||
{
|
||||
/**
|
||||
* @var string ID of the action
|
||||
*/
|
||||
public $id;
|
||||
/**
|
||||
* @var Controller|\yii\web\Controller|\yii\console\Controller the controller that owns this action
|
||||
*/
|
||||
public $controller;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $id the ID of this action
|
||||
* @param Controller $controller the controller that owns this action
|
||||
* @param array $config name-value pairs that will be used to initialize the object properties
|
||||
*/
|
||||
public function __construct($id, $controller, $config = [])
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->controller = $controller;
|
||||
parent::__construct($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique ID of this action among the whole application.
|
||||
*
|
||||
* @return string the unique ID of this action among the whole application.
|
||||
*/
|
||||
public function getUniqueId()
|
||||
{
|
||||
return $this->controller->getUniqueId() . '/' . $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs this action with the specified parameters.
|
||||
* This method is mainly invoked by the controller.
|
||||
*
|
||||
* @param array $params the parameters to be bound to the action's run() method.
|
||||
* @return mixed the result of the action
|
||||
* @throws InvalidConfigException if the action class does not have a run() method
|
||||
*/
|
||||
public function runWithParams($params)
|
||||
{
|
||||
if (!method_exists($this, 'run')) {
|
||||
throw new InvalidConfigException(get_class($this) . ' must define a "run()" method.');
|
||||
}
|
||||
$args = $this->controller->bindActionParams($this, $params);
|
||||
Yii::debug('Running action: ' . get_class($this) . '::run()', __METHOD__);
|
||||
if (Yii::$app->requestedParams === null) {
|
||||
Yii::$app->requestedParams = $args;
|
||||
}
|
||||
if ($this->beforeRun()) {
|
||||
$result = call_user_func_array([$this, 'run'], $args);
|
||||
$this->afterRun();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called right before `run()` is executed.
|
||||
* You may override this method to do preparation work for the action run.
|
||||
* If the method returns false, it will cancel the action.
|
||||
*
|
||||
* @return bool whether to run the action.
|
||||
*/
|
||||
protected function beforeRun()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called right after `run()` is executed.
|
||||
* You may override this method to do post-processing work for the action run.
|
||||
*/
|
||||
protected function afterRun()
|
||||
{
|
||||
}
|
||||
}
|
||||
46
vendor/yiisoft/yii2/base/ActionEvent.php
vendored
Normal file
46
vendor/yiisoft/yii2/base/ActionEvent.php
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* ActionEvent represents the event parameter used for an action event.
|
||||
*
|
||||
* By setting the [[isValid]] property, one may control whether to continue running the action.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class ActionEvent extends Event
|
||||
{
|
||||
/**
|
||||
* @var Action the action currently being executed
|
||||
*/
|
||||
public $action;
|
||||
/**
|
||||
* @var mixed the action result. Event handlers may modify this property to change the action result.
|
||||
*/
|
||||
public $result;
|
||||
/**
|
||||
* @var bool whether to continue running the action. Event handlers of
|
||||
* [[Controller::EVENT_BEFORE_ACTION]] may set this property to decide whether
|
||||
* to continue running the current action.
|
||||
*/
|
||||
public $isValid = true;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param Action $action the action associated with this action event.
|
||||
* @param array $config name-value pairs that will be used to initialize the object properties
|
||||
*/
|
||||
public function __construct($action, $config = [])
|
||||
{
|
||||
$this->action = $action;
|
||||
parent::__construct($config);
|
||||
}
|
||||
}
|
||||
171
vendor/yiisoft/yii2/base/ActionFilter.php
vendored
Normal file
171
vendor/yiisoft/yii2/base/ActionFilter.php
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
use yii\helpers\StringHelper;
|
||||
|
||||
/**
|
||||
* ActionFilter is the base class for action filters.
|
||||
*
|
||||
* An action filter will participate in the action execution workflow by responding to
|
||||
* the `beforeAction` and `afterAction` events triggered by modules and controllers.
|
||||
*
|
||||
* Check implementation of [[\yii\filters\AccessControl]], [[\yii\filters\PageCache]] and [[\yii\filters\HttpCache]] as examples on how to use it.
|
||||
*
|
||||
* For more details and usage information on ActionFilter, see the [guide article on filters](guide:structure-filters).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class ActionFilter extends Behavior
|
||||
{
|
||||
/**
|
||||
* @var array list of action IDs that this filter should apply to. If this property is not set,
|
||||
* then the filter applies to all actions, unless they are listed in [[except]].
|
||||
* If an action ID appears in both [[only]] and [[except]], this filter will NOT apply to it.
|
||||
*
|
||||
* Note that if the filter is attached to a module, the action IDs should also include child module IDs (if any)
|
||||
* and controller IDs.
|
||||
*
|
||||
* Since version 2.0.9 action IDs can be specified as wildcards, e.g. `site/*`.
|
||||
*
|
||||
* @see except
|
||||
*/
|
||||
public $only;
|
||||
/**
|
||||
* @var array list of action IDs that this filter should not apply to.
|
||||
* @see only
|
||||
*/
|
||||
public $except = [];
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function attach($owner)
|
||||
{
|
||||
$this->owner = $owner;
|
||||
$owner->on(Controller::EVENT_BEFORE_ACTION, [$this, 'beforeFilter']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function detach()
|
||||
{
|
||||
if ($this->owner) {
|
||||
$this->owner->off(Controller::EVENT_BEFORE_ACTION, [$this, 'beforeFilter']);
|
||||
$this->owner->off(Controller::EVENT_AFTER_ACTION, [$this, 'afterFilter']);
|
||||
$this->owner = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ActionEvent $event
|
||||
*/
|
||||
public function beforeFilter($event)
|
||||
{
|
||||
if (!$this->isActive($event->action)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$event->isValid = $this->beforeAction($event->action);
|
||||
if ($event->isValid) {
|
||||
// call afterFilter only if beforeFilter succeeds
|
||||
// beforeFilter and afterFilter should be properly nested
|
||||
$this->owner->on(Controller::EVENT_AFTER_ACTION, [$this, 'afterFilter'], null, false);
|
||||
} else {
|
||||
$event->handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ActionEvent $event
|
||||
*/
|
||||
public function afterFilter($event)
|
||||
{
|
||||
$event->result = $this->afterAction($event->action, $event->result);
|
||||
$this->owner->off(Controller::EVENT_AFTER_ACTION, [$this, 'afterFilter']);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is invoked right before an action is to be executed (after all possible filters.)
|
||||
* You may override this method to do last-minute preparation for the action.
|
||||
* @param Action $action the action to be executed.
|
||||
* @return bool whether the action should continue to be executed.
|
||||
*/
|
||||
public function beforeAction($action)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is invoked right after an action is executed.
|
||||
* You may override this method to do some postprocessing for the action.
|
||||
* @param Action $action the action just executed.
|
||||
* @param mixed $result the action execution result
|
||||
* @return mixed the processed action result.
|
||||
*/
|
||||
public function afterAction($action, $result)
|
||||
{
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an action ID by converting [[Action::$uniqueId]] into an ID relative to the module.
|
||||
* @param Action $action
|
||||
* @return string
|
||||
* @since 2.0.7
|
||||
*/
|
||||
protected function getActionId($action)
|
||||
{
|
||||
if ($this->owner instanceof Module) {
|
||||
$mid = $this->owner->getUniqueId();
|
||||
$id = $action->getUniqueId();
|
||||
if ($mid !== '' && strpos($id, $mid) === 0) {
|
||||
$id = substr($id, strlen($mid) + 1);
|
||||
}
|
||||
} else {
|
||||
$id = $action->id;
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value indicating whether the filter is active for the given action.
|
||||
* @param Action $action the action being filtered
|
||||
* @return bool whether the filter is active for the given action.
|
||||
*/
|
||||
protected function isActive($action)
|
||||
{
|
||||
$id = $this->getActionId($action);
|
||||
|
||||
if (empty($this->only)) {
|
||||
$onlyMatch = true;
|
||||
} else {
|
||||
$onlyMatch = false;
|
||||
foreach ($this->only as $pattern) {
|
||||
if (StringHelper::matchWildcard($pattern, $id)) {
|
||||
$onlyMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$exceptMatch = false;
|
||||
foreach ($this->except as $pattern) {
|
||||
if (StringHelper::matchWildcard($pattern, $id)) {
|
||||
$exceptMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return !$exceptMatch && $onlyMatch;
|
||||
}
|
||||
}
|
||||
676
vendor/yiisoft/yii2/base/Application.php
vendored
Normal file
676
vendor/yiisoft/yii2/base/Application.php
vendored
Normal file
@@ -0,0 +1,676 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
use Yii;
|
||||
|
||||
/**
|
||||
* Application is the base class for all application classes.
|
||||
*
|
||||
* For more details and usage information on Application, see the [guide article on applications](guide:structure-applications).
|
||||
*
|
||||
* @property \yii\web\AssetManager $assetManager The asset manager application component. This property is
|
||||
* read-only.
|
||||
* @property \yii\rbac\ManagerInterface $authManager The auth manager application component. Null is returned
|
||||
* if auth manager is not configured. This property is read-only.
|
||||
* @property string $basePath The root directory of the application.
|
||||
* @property \yii\caching\CacheInterface $cache The cache application component. Null if the component is not
|
||||
* enabled. This property is read-only.
|
||||
* @property array $container Values given in terms of name-value pairs. This property is write-only.
|
||||
* @property \yii\db\Connection $db The database connection. This property is read-only.
|
||||
* @property \yii\web\ErrorHandler|\yii\console\ErrorHandler $errorHandler The error handler application
|
||||
* component. This property is read-only.
|
||||
* @property \yii\i18n\Formatter $formatter The formatter application component. This property is read-only.
|
||||
* @property \yii\i18n\I18N $i18n The internationalization application component. This property is read-only.
|
||||
* @property \yii\log\Dispatcher $log The log dispatcher application component. This property is read-only.
|
||||
* @property \yii\mail\MailerInterface $mailer The mailer application component. This property is read-only.
|
||||
* @property \yii\web\Request|\yii\console\Request $request The request component. This property is read-only.
|
||||
* @property \yii\web\Response|\yii\console\Response $response The response component. This property is
|
||||
* read-only.
|
||||
* @property string $runtimePath The directory that stores runtime files. Defaults to the "runtime"
|
||||
* subdirectory under [[basePath]].
|
||||
* @property \yii\base\Security $security The security application component. This property is read-only.
|
||||
* @property string $timeZone The time zone used by this application.
|
||||
* @property string $uniqueId The unique ID of the module. This property is read-only.
|
||||
* @property \yii\web\UrlManager $urlManager The URL manager for this application. This property is read-only.
|
||||
* @property string $vendorPath The directory that stores vendor files. Defaults to "vendor" directory under
|
||||
* [[basePath]].
|
||||
* @property View|\yii\web\View $view The view application component that is used to render various view
|
||||
* files. This property is read-only.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
abstract class Application extends Module
|
||||
{
|
||||
/**
|
||||
* @event Event an event raised before the application starts to handle a request.
|
||||
*/
|
||||
const EVENT_BEFORE_REQUEST = 'beforeRequest';
|
||||
/**
|
||||
* @event Event an event raised after the application successfully handles a request (before the response is sent out).
|
||||
*/
|
||||
const EVENT_AFTER_REQUEST = 'afterRequest';
|
||||
/**
|
||||
* Application state used by [[state]]: application just started.
|
||||
*/
|
||||
const STATE_BEGIN = 0;
|
||||
/**
|
||||
* Application state used by [[state]]: application is initializing.
|
||||
*/
|
||||
const STATE_INIT = 1;
|
||||
/**
|
||||
* Application state used by [[state]]: application is triggering [[EVENT_BEFORE_REQUEST]].
|
||||
*/
|
||||
const STATE_BEFORE_REQUEST = 2;
|
||||
/**
|
||||
* Application state used by [[state]]: application is handling the request.
|
||||
*/
|
||||
const STATE_HANDLING_REQUEST = 3;
|
||||
/**
|
||||
* Application state used by [[state]]: application is triggering [[EVENT_AFTER_REQUEST]]..
|
||||
*/
|
||||
const STATE_AFTER_REQUEST = 4;
|
||||
/**
|
||||
* Application state used by [[state]]: application is about to send response.
|
||||
*/
|
||||
const STATE_SENDING_RESPONSE = 5;
|
||||
/**
|
||||
* Application state used by [[state]]: application has ended.
|
||||
*/
|
||||
const STATE_END = 6;
|
||||
|
||||
/**
|
||||
* @var string the namespace that controller classes are located in.
|
||||
* This namespace will be used to load controller classes by prepending it to the controller class name.
|
||||
* The default namespace is `app\controllers`.
|
||||
*
|
||||
* Please refer to the [guide about class autoloading](guide:concept-autoloading.md) for more details.
|
||||
*/
|
||||
public $controllerNamespace = 'app\\controllers';
|
||||
/**
|
||||
* @var string the application name.
|
||||
*/
|
||||
public $name = 'My Application';
|
||||
/**
|
||||
* @var string the charset currently used for the application.
|
||||
*/
|
||||
public $charset = 'UTF-8';
|
||||
/**
|
||||
* @var string the language that is meant to be used for end users. It is recommended that you
|
||||
* use [IETF language tags](http://en.wikipedia.org/wiki/IETF_language_tag). For example, `en` stands
|
||||
* for English, while `en-US` stands for English (United States).
|
||||
* @see sourceLanguage
|
||||
*/
|
||||
public $language = 'en-US';
|
||||
/**
|
||||
* @var string the language that the application is written in. This mainly refers to
|
||||
* the language that the messages and view files are written in.
|
||||
* @see language
|
||||
*/
|
||||
public $sourceLanguage = 'en-US';
|
||||
/**
|
||||
* @var Controller the currently active controller instance
|
||||
*/
|
||||
public $controller;
|
||||
/**
|
||||
* @var string|bool the layout that should be applied for views in this application. Defaults to 'main'.
|
||||
* If this is false, layout will be disabled.
|
||||
*/
|
||||
public $layout = 'main';
|
||||
/**
|
||||
* @var string the requested route
|
||||
*/
|
||||
public $requestedRoute;
|
||||
/**
|
||||
* @var Action the requested Action. If null, it means the request cannot be resolved into an action.
|
||||
*/
|
||||
public $requestedAction;
|
||||
/**
|
||||
* @var array the parameters supplied to the requested action.
|
||||
*/
|
||||
public $requestedParams;
|
||||
/**
|
||||
* @var array list of installed Yii extensions. Each array element represents a single extension
|
||||
* with the following structure:
|
||||
*
|
||||
* ```php
|
||||
* [
|
||||
* 'name' => 'extension name',
|
||||
* 'version' => 'version number',
|
||||
* 'bootstrap' => 'BootstrapClassName', // optional, may also be a configuration array
|
||||
* 'alias' => [
|
||||
* '@alias1' => 'to/path1',
|
||||
* '@alias2' => 'to/path2',
|
||||
* ],
|
||||
* ]
|
||||
* ```
|
||||
*
|
||||
* The "bootstrap" class listed above will be instantiated during the application
|
||||
* [[bootstrap()|bootstrapping process]]. If the class implements [[BootstrapInterface]],
|
||||
* its [[BootstrapInterface::bootstrap()|bootstrap()]] method will be also be called.
|
||||
*
|
||||
* If not set explicitly in the application config, this property will be populated with the contents of
|
||||
* `@vendor/yiisoft/extensions.php`.
|
||||
*/
|
||||
public $extensions;
|
||||
/**
|
||||
* @var array list of components that should be run during the application [[bootstrap()|bootstrapping process]].
|
||||
*
|
||||
* Each component may be specified in one of the following formats:
|
||||
*
|
||||
* - an application component ID as specified via [[components]].
|
||||
* - a module ID as specified via [[modules]].
|
||||
* - a class name.
|
||||
* - a configuration array.
|
||||
* - a Closure
|
||||
*
|
||||
* During the bootstrapping process, each component will be instantiated. If the component class
|
||||
* implements [[BootstrapInterface]], its [[BootstrapInterface::bootstrap()|bootstrap()]] method
|
||||
* will be also be called.
|
||||
*/
|
||||
public $bootstrap = [];
|
||||
/**
|
||||
* @var int the current application state during a request handling life cycle.
|
||||
* This property is managed by the application. Do not modify this property.
|
||||
*/
|
||||
public $state;
|
||||
/**
|
||||
* @var array list of loaded modules indexed by their class names.
|
||||
*/
|
||||
public $loadedModules = [];
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param array $config name-value pairs that will be used to initialize the object properties.
|
||||
* Note that the configuration must contain both [[id]] and [[basePath]].
|
||||
* @throws InvalidConfigException if either [[id]] or [[basePath]] configuration is missing.
|
||||
*/
|
||||
public function __construct($config = [])
|
||||
{
|
||||
Yii::$app = $this;
|
||||
static::setInstance($this);
|
||||
|
||||
$this->state = self::STATE_BEGIN;
|
||||
|
||||
$this->preInit($config);
|
||||
|
||||
$this->registerErrorHandler($config);
|
||||
|
||||
Component::__construct($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-initializes the application.
|
||||
* This method is called at the beginning of the application constructor.
|
||||
* It initializes several important application properties.
|
||||
* If you override this method, please make sure you call the parent implementation.
|
||||
* @param array $config the application configuration
|
||||
* @throws InvalidConfigException if either [[id]] or [[basePath]] configuration is missing.
|
||||
*/
|
||||
public function preInit(&$config)
|
||||
{
|
||||
if (!isset($config['id'])) {
|
||||
throw new InvalidConfigException('The "id" configuration for the Application is required.');
|
||||
}
|
||||
if (isset($config['basePath'])) {
|
||||
$this->setBasePath($config['basePath']);
|
||||
unset($config['basePath']);
|
||||
} else {
|
||||
throw new InvalidConfigException('The "basePath" configuration for the Application is required.');
|
||||
}
|
||||
|
||||
if (isset($config['vendorPath'])) {
|
||||
$this->setVendorPath($config['vendorPath']);
|
||||
unset($config['vendorPath']);
|
||||
} else {
|
||||
// set "@vendor"
|
||||
$this->getVendorPath();
|
||||
}
|
||||
if (isset($config['runtimePath'])) {
|
||||
$this->setRuntimePath($config['runtimePath']);
|
||||
unset($config['runtimePath']);
|
||||
} else {
|
||||
// set "@runtime"
|
||||
$this->getRuntimePath();
|
||||
}
|
||||
|
||||
if (isset($config['timeZone'])) {
|
||||
$this->setTimeZone($config['timeZone']);
|
||||
unset($config['timeZone']);
|
||||
} elseif (!ini_get('date.timezone')) {
|
||||
$this->setTimeZone('UTC');
|
||||
}
|
||||
|
||||
if (isset($config['container'])) {
|
||||
$this->setContainer($config['container']);
|
||||
|
||||
unset($config['container']);
|
||||
}
|
||||
|
||||
// merge core components with custom components
|
||||
foreach ($this->coreComponents() as $id => $component) {
|
||||
if (!isset($config['components'][$id])) {
|
||||
$config['components'][$id] = $component;
|
||||
} elseif (is_array($config['components'][$id]) && !isset($config['components'][$id]['class'])) {
|
||||
$config['components'][$id]['class'] = $component['class'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->state = self::STATE_INIT;
|
||||
$this->bootstrap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes extensions and executes bootstrap components.
|
||||
* This method is called by [[init()]] after the application has been fully configured.
|
||||
* If you override this method, make sure you also call the parent implementation.
|
||||
*/
|
||||
protected function bootstrap()
|
||||
{
|
||||
if ($this->extensions === null) {
|
||||
$file = Yii::getAlias('@vendor/yiisoft/extensions.php');
|
||||
$this->extensions = is_file($file) ? include $file : [];
|
||||
}
|
||||
foreach ($this->extensions as $extension) {
|
||||
if (!empty($extension['alias'])) {
|
||||
foreach ($extension['alias'] as $name => $path) {
|
||||
Yii::setAlias($name, $path);
|
||||
}
|
||||
}
|
||||
if (isset($extension['bootstrap'])) {
|
||||
$component = Yii::createObject($extension['bootstrap']);
|
||||
if ($component instanceof BootstrapInterface) {
|
||||
Yii::debug('Bootstrap with ' . get_class($component) . '::bootstrap()', __METHOD__);
|
||||
$component->bootstrap($this);
|
||||
} else {
|
||||
Yii::debug('Bootstrap with ' . get_class($component), __METHOD__);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->bootstrap as $mixed) {
|
||||
$component = null;
|
||||
if ($mixed instanceof \Closure) {
|
||||
Yii::debug('Bootstrap with Closure', __METHOD__);
|
||||
if (!$component = call_user_func($mixed, $this)) {
|
||||
continue;
|
||||
}
|
||||
} elseif (is_string($mixed)) {
|
||||
if ($this->has($mixed)) {
|
||||
$component = $this->get($mixed);
|
||||
} elseif ($this->hasModule($mixed)) {
|
||||
$component = $this->getModule($mixed);
|
||||
} elseif (strpos($mixed, '\\') === false) {
|
||||
throw new InvalidConfigException("Unknown bootstrapping component ID: $mixed");
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($component)) {
|
||||
$component = Yii::createObject($mixed);
|
||||
}
|
||||
|
||||
if ($component instanceof BootstrapInterface) {
|
||||
Yii::debug('Bootstrap with ' . get_class($component) . '::bootstrap()', __METHOD__);
|
||||
$component->bootstrap($this);
|
||||
} else {
|
||||
Yii::debug('Bootstrap with ' . get_class($component), __METHOD__);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the errorHandler component as a PHP error handler.
|
||||
* @param array $config application config
|
||||
*/
|
||||
protected function registerErrorHandler(&$config)
|
||||
{
|
||||
if (YII_ENABLE_ERROR_HANDLER) {
|
||||
if (!isset($config['components']['errorHandler']['class'])) {
|
||||
echo "Error: no errorHandler component is configured.\n";
|
||||
exit(1);
|
||||
}
|
||||
$this->set('errorHandler', $config['components']['errorHandler']);
|
||||
unset($config['components']['errorHandler']);
|
||||
$this->getErrorHandler()->register();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ID that uniquely identifies this module among all modules within the current application.
|
||||
* Since this is an application instance, it will always return an empty string.
|
||||
* @return string the unique ID of the module.
|
||||
*/
|
||||
public function getUniqueId()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the root directory of the application and the @app alias.
|
||||
* This method can only be invoked at the beginning of the constructor.
|
||||
* @param string $path the root directory of the application.
|
||||
* @property string the root directory of the application.
|
||||
* @throws InvalidArgumentException if the directory does not exist.
|
||||
*/
|
||||
public function setBasePath($path)
|
||||
{
|
||||
parent::setBasePath($path);
|
||||
Yii::setAlias('@app', $this->getBasePath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the application.
|
||||
* This is the main entrance of an application.
|
||||
* @return int the exit status (0 means normal, non-zero values mean abnormal)
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
try {
|
||||
$this->state = self::STATE_BEFORE_REQUEST;
|
||||
$this->trigger(self::EVENT_BEFORE_REQUEST);
|
||||
|
||||
$this->state = self::STATE_HANDLING_REQUEST;
|
||||
$response = $this->handleRequest($this->getRequest());
|
||||
|
||||
$this->state = self::STATE_AFTER_REQUEST;
|
||||
$this->trigger(self::EVENT_AFTER_REQUEST);
|
||||
|
||||
$this->state = self::STATE_SENDING_RESPONSE;
|
||||
$response->send();
|
||||
|
||||
$this->state = self::STATE_END;
|
||||
|
||||
return $response->exitStatus;
|
||||
} catch (ExitException $e) {
|
||||
$this->end($e->statusCode, isset($response) ? $response : null);
|
||||
return $e->statusCode;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the specified request.
|
||||
*
|
||||
* This method should return an instance of [[Response]] or its child class
|
||||
* which represents the handling result of the request.
|
||||
*
|
||||
* @param Request $request the request to be handled
|
||||
* @return Response the resulting response
|
||||
*/
|
||||
abstract public function handleRequest($request);
|
||||
|
||||
private $_runtimePath;
|
||||
|
||||
/**
|
||||
* Returns the directory that stores runtime files.
|
||||
* @return string the directory that stores runtime files.
|
||||
* Defaults to the "runtime" subdirectory under [[basePath]].
|
||||
*/
|
||||
public function getRuntimePath()
|
||||
{
|
||||
if ($this->_runtimePath === null) {
|
||||
$this->setRuntimePath($this->getBasePath() . DIRECTORY_SEPARATOR . 'runtime');
|
||||
}
|
||||
|
||||
return $this->_runtimePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the directory that stores runtime files.
|
||||
* @param string $path the directory that stores runtime files.
|
||||
*/
|
||||
public function setRuntimePath($path)
|
||||
{
|
||||
$this->_runtimePath = Yii::getAlias($path);
|
||||
Yii::setAlias('@runtime', $this->_runtimePath);
|
||||
}
|
||||
|
||||
private $_vendorPath;
|
||||
|
||||
/**
|
||||
* Returns the directory that stores vendor files.
|
||||
* @return string the directory that stores vendor files.
|
||||
* Defaults to "vendor" directory under [[basePath]].
|
||||
*/
|
||||
public function getVendorPath()
|
||||
{
|
||||
if ($this->_vendorPath === null) {
|
||||
$this->setVendorPath($this->getBasePath() . DIRECTORY_SEPARATOR . 'vendor');
|
||||
}
|
||||
|
||||
return $this->_vendorPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the directory that stores vendor files.
|
||||
* @param string $path the directory that stores vendor files.
|
||||
*/
|
||||
public function setVendorPath($path)
|
||||
{
|
||||
$this->_vendorPath = Yii::getAlias($path);
|
||||
Yii::setAlias('@vendor', $this->_vendorPath);
|
||||
Yii::setAlias('@bower', $this->_vendorPath . DIRECTORY_SEPARATOR . 'bower');
|
||||
Yii::setAlias('@npm', $this->_vendorPath . DIRECTORY_SEPARATOR . 'npm');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time zone used by this application.
|
||||
* This is a simple wrapper of PHP function date_default_timezone_get().
|
||||
* If time zone is not configured in php.ini or application config,
|
||||
* it will be set to UTC by default.
|
||||
* @return string the time zone used by this application.
|
||||
* @see http://php.net/manual/en/function.date-default-timezone-get.php
|
||||
*/
|
||||
public function getTimeZone()
|
||||
{
|
||||
return date_default_timezone_get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time zone used by this application.
|
||||
* This is a simple wrapper of PHP function date_default_timezone_set().
|
||||
* Refer to the [php manual](http://www.php.net/manual/en/timezones.php) for available timezones.
|
||||
* @param string $value the time zone used by this application.
|
||||
* @see http://php.net/manual/en/function.date-default-timezone-set.php
|
||||
*/
|
||||
public function setTimeZone($value)
|
||||
{
|
||||
date_default_timezone_set($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the database connection component.
|
||||
* @return \yii\db\Connection the database connection.
|
||||
*/
|
||||
public function getDb()
|
||||
{
|
||||
return $this->get('db');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the log dispatcher component.
|
||||
* @return \yii\log\Dispatcher the log dispatcher application component.
|
||||
*/
|
||||
public function getLog()
|
||||
{
|
||||
return $this->get('log');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error handler component.
|
||||
* @return \yii\web\ErrorHandler|\yii\console\ErrorHandler the error handler application component.
|
||||
*/
|
||||
public function getErrorHandler()
|
||||
{
|
||||
return $this->get('errorHandler');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cache component.
|
||||
* @return \yii\caching\CacheInterface the cache application component. Null if the component is not enabled.
|
||||
*/
|
||||
public function getCache()
|
||||
{
|
||||
return $this->get('cache', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the formatter component.
|
||||
* @return \yii\i18n\Formatter the formatter application component.
|
||||
*/
|
||||
public function getFormatter()
|
||||
{
|
||||
return $this->get('formatter');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request component.
|
||||
* @return \yii\web\Request|\yii\console\Request the request component.
|
||||
*/
|
||||
public function getRequest()
|
||||
{
|
||||
return $this->get('request');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the response component.
|
||||
* @return \yii\web\Response|\yii\console\Response the response component.
|
||||
*/
|
||||
public function getResponse()
|
||||
{
|
||||
return $this->get('response');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the view object.
|
||||
* @return View|\yii\web\View the view application component that is used to render various view files.
|
||||
*/
|
||||
public function getView()
|
||||
{
|
||||
return $this->get('view');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL manager for this application.
|
||||
* @return \yii\web\UrlManager the URL manager for this application.
|
||||
*/
|
||||
public function getUrlManager()
|
||||
{
|
||||
return $this->get('urlManager');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the internationalization (i18n) component.
|
||||
* @return \yii\i18n\I18N the internationalization application component.
|
||||
*/
|
||||
public function getI18n()
|
||||
{
|
||||
return $this->get('i18n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mailer component.
|
||||
* @return \yii\mail\MailerInterface the mailer application component.
|
||||
*/
|
||||
public function getMailer()
|
||||
{
|
||||
return $this->get('mailer');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the auth manager for this application.
|
||||
* @return \yii\rbac\ManagerInterface the auth manager application component.
|
||||
* Null is returned if auth manager is not configured.
|
||||
*/
|
||||
public function getAuthManager()
|
||||
{
|
||||
return $this->get('authManager', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the asset manager.
|
||||
* @return \yii\web\AssetManager the asset manager application component.
|
||||
*/
|
||||
public function getAssetManager()
|
||||
{
|
||||
return $this->get('assetManager');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the security component.
|
||||
* @return \yii\base\Security the security application component.
|
||||
*/
|
||||
public function getSecurity()
|
||||
{
|
||||
return $this->get('security');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configuration of core application components.
|
||||
* @see set()
|
||||
*/
|
||||
public function coreComponents()
|
||||
{
|
||||
return [
|
||||
'log' => ['class' => 'yii\log\Dispatcher'],
|
||||
'view' => ['class' => 'yii\web\View'],
|
||||
'formatter' => ['class' => 'yii\i18n\Formatter'],
|
||||
'i18n' => ['class' => 'yii\i18n\I18N'],
|
||||
'mailer' => ['class' => 'yii\swiftmailer\Mailer'],
|
||||
'urlManager' => ['class' => 'yii\web\UrlManager'],
|
||||
'assetManager' => ['class' => 'yii\web\AssetManager'],
|
||||
'security' => ['class' => 'yii\base\Security'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminates the application.
|
||||
* This method replaces the `exit()` function by ensuring the application life cycle is completed
|
||||
* before terminating the application.
|
||||
* @param int $status the exit status (value 0 means normal exit while other values mean abnormal exit).
|
||||
* @param Response $response the response to be sent. If not set, the default application [[response]] component will be used.
|
||||
* @throws ExitException if the application is in testing mode
|
||||
*/
|
||||
public function end($status = 0, $response = null)
|
||||
{
|
||||
if ($this->state === self::STATE_BEFORE_REQUEST || $this->state === self::STATE_HANDLING_REQUEST) {
|
||||
$this->state = self::STATE_AFTER_REQUEST;
|
||||
$this->trigger(self::EVENT_AFTER_REQUEST);
|
||||
}
|
||||
|
||||
if ($this->state !== self::STATE_SENDING_RESPONSE && $this->state !== self::STATE_END) {
|
||||
$this->state = self::STATE_END;
|
||||
$response = $response ?: $this->getResponse();
|
||||
$response->send();
|
||||
}
|
||||
|
||||
if (YII_ENV_TEST) {
|
||||
throw new ExitException($status);
|
||||
}
|
||||
|
||||
exit($status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures [[Yii::$container]] with the $config.
|
||||
*
|
||||
* @param array $config values given in terms of name-value pairs
|
||||
* @since 2.0.11
|
||||
*/
|
||||
public function setContainer($config)
|
||||
{
|
||||
Yii::configure(Yii::$container, $config);
|
||||
}
|
||||
}
|
||||
82
vendor/yiisoft/yii2/base/ArrayAccessTrait.php
vendored
Normal file
82
vendor/yiisoft/yii2/base/ArrayAccessTrait.php
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* ArrayAccessTrait provides the implementation for [[\IteratorAggregate]], [[\ArrayAccess]] and [[\Countable]].
|
||||
*
|
||||
* Note that ArrayAccessTrait requires the class using it contain a property named `data` which should be an array.
|
||||
* The data will be exposed by ArrayAccessTrait to support accessing the class object like an array.
|
||||
*
|
||||
* @property array $data
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
trait ArrayAccessTrait
|
||||
{
|
||||
/**
|
||||
* Returns an iterator for traversing the data.
|
||||
* This method is required by the SPL interface [[\IteratorAggregate]].
|
||||
* It will be implicitly called when you use `foreach` to traverse the collection.
|
||||
* @return \ArrayIterator an iterator for traversing the cookies in the collection.
|
||||
*/
|
||||
public function getIterator()
|
||||
{
|
||||
return new \ArrayIterator($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of data items.
|
||||
* This method is required by Countable interface.
|
||||
* @return int number of data elements.
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return count($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is required by the interface [[\ArrayAccess]].
|
||||
* @param mixed $offset the offset to check on
|
||||
* @return bool
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return isset($this->data[$offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is required by the interface [[\ArrayAccess]].
|
||||
* @param int $offset the offset to retrieve element.
|
||||
* @return mixed the element at the offset, null if no element is found at the offset
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return isset($this->data[$offset]) ? $this->data[$offset] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is required by the interface [[\ArrayAccess]].
|
||||
* @param int $offset the offset to set element
|
||||
* @param mixed $item the element value
|
||||
*/
|
||||
public function offsetSet($offset, $item)
|
||||
{
|
||||
$this->data[$offset] = $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is required by the interface [[\ArrayAccess]].
|
||||
* @param mixed $offset the offset to unset element
|
||||
*/
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
unset($this->data[$offset]);
|
||||
}
|
||||
}
|
||||
92
vendor/yiisoft/yii2/base/Arrayable.php
vendored
Normal file
92
vendor/yiisoft/yii2/base/Arrayable.php
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* Arrayable is the interface that should be implemented by classes who want to support customizable representation of their instances.
|
||||
*
|
||||
* For example, if a class implements Arrayable, by calling [[toArray()]], an instance of this class
|
||||
* can be turned into an array (including all its embedded objects) which can then be further transformed easily
|
||||
* into other formats, such as JSON, XML.
|
||||
*
|
||||
* The methods [[fields()]] and [[extraFields()]] allow the implementing classes to customize how and which of their data
|
||||
* should be formatted and put into the result of [[toArray()]].
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
interface Arrayable
|
||||
{
|
||||
/**
|
||||
* Returns the list of fields that should be returned by default by [[toArray()]] when no specific fields are specified.
|
||||
*
|
||||
* A field is a named element in the returned array by [[toArray()]].
|
||||
*
|
||||
* This method should return an array of field names or field definitions.
|
||||
* If the former, the field name will be treated as an object property name whose value will be used
|
||||
* as the field value. If the latter, the array key should be the field name while the array value should be
|
||||
* the corresponding field definition which can be either an object property name or a PHP callable
|
||||
* returning the corresponding field value. The signature of the callable should be:
|
||||
*
|
||||
* ```php
|
||||
* function ($model, $field) {
|
||||
* // return field value
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* For example, the following code declares four fields:
|
||||
*
|
||||
* - `email`: the field name is the same as the property name `email`;
|
||||
* - `firstName` and `lastName`: the field names are `firstName` and `lastName`, and their
|
||||
* values are obtained from the `first_name` and `last_name` properties;
|
||||
* - `fullName`: the field name is `fullName`. Its value is obtained by concatenating `first_name`
|
||||
* and `last_name`.
|
||||
*
|
||||
* ```php
|
||||
* return [
|
||||
* 'email',
|
||||
* 'firstName' => 'first_name',
|
||||
* 'lastName' => 'last_name',
|
||||
* 'fullName' => function ($model) {
|
||||
* return $model->first_name . ' ' . $model->last_name;
|
||||
* },
|
||||
* ];
|
||||
* ```
|
||||
*
|
||||
* @return array the list of field names or field definitions.
|
||||
* @see toArray()
|
||||
*/
|
||||
public function fields();
|
||||
|
||||
/**
|
||||
* Returns the list of additional fields that can be returned by [[toArray()]] in addition to those listed in [[fields()]].
|
||||
*
|
||||
* This method is similar to [[fields()]] except that the list of fields declared
|
||||
* by this method are not returned by default by [[toArray()]]. Only when a field in the list
|
||||
* is explicitly requested, will it be included in the result of [[toArray()]].
|
||||
*
|
||||
* @return array the list of expandable field names or field definitions. Please refer
|
||||
* to [[fields()]] on the format of the return value.
|
||||
* @see toArray()
|
||||
* @see fields()
|
||||
*/
|
||||
public function extraFields();
|
||||
|
||||
/**
|
||||
* Converts the object into an array.
|
||||
*
|
||||
* @param array $fields the fields that the output array should contain. Fields not specified
|
||||
* in [[fields()]] will be ignored. If this parameter is empty, all fields as specified in [[fields()]] will be returned.
|
||||
* @param array $expand the additional fields that the output array should contain.
|
||||
* Fields not specified in [[extraFields()]] will be ignored. If this parameter is empty, no extra fields
|
||||
* will be returned.
|
||||
* @param bool $recursive whether to recursively return array representation of embedded objects.
|
||||
* @return array the array representation of the object
|
||||
*/
|
||||
public function toArray(array $fields = [], array $expand = [], $recursive = true);
|
||||
}
|
||||
242
vendor/yiisoft/yii2/base/ArrayableTrait.php
vendored
Normal file
242
vendor/yiisoft/yii2/base/ArrayableTrait.php
vendored
Normal file
@@ -0,0 +1,242 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
use Yii;
|
||||
use yii\helpers\ArrayHelper;
|
||||
use yii\web\Link;
|
||||
use yii\web\Linkable;
|
||||
|
||||
/**
|
||||
* ArrayableTrait provides a common implementation of the [[Arrayable]] interface.
|
||||
*
|
||||
* ArrayableTrait implements [[toArray()]] by respecting the field definitions as declared
|
||||
* in [[fields()]] and [[extraFields()]].
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
trait ArrayableTrait
|
||||
{
|
||||
/**
|
||||
* Returns the list of fields that should be returned by default by [[toArray()]] when no specific fields are specified.
|
||||
*
|
||||
* A field is a named element in the returned array by [[toArray()]].
|
||||
*
|
||||
* This method should return an array of field names or field definitions.
|
||||
* If the former, the field name will be treated as an object property name whose value will be used
|
||||
* as the field value. If the latter, the array key should be the field name while the array value should be
|
||||
* the corresponding field definition which can be either an object property name or a PHP callable
|
||||
* returning the corresponding field value. The signature of the callable should be:
|
||||
*
|
||||
* ```php
|
||||
* function ($model, $field) {
|
||||
* // return field value
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* For example, the following code declares four fields:
|
||||
*
|
||||
* - `email`: the field name is the same as the property name `email`;
|
||||
* - `firstName` and `lastName`: the field names are `firstName` and `lastName`, and their
|
||||
* values are obtained from the `first_name` and `last_name` properties;
|
||||
* - `fullName`: the field name is `fullName`. Its value is obtained by concatenating `first_name`
|
||||
* and `last_name`.
|
||||
*
|
||||
* ```php
|
||||
* return [
|
||||
* 'email',
|
||||
* 'firstName' => 'first_name',
|
||||
* 'lastName' => 'last_name',
|
||||
* 'fullName' => function () {
|
||||
* return $this->first_name . ' ' . $this->last_name;
|
||||
* },
|
||||
* ];
|
||||
* ```
|
||||
*
|
||||
* In this method, you may also want to return different lists of fields based on some context
|
||||
* information. For example, depending on the privilege of the current application user,
|
||||
* you may return different sets of visible fields or filter out some fields.
|
||||
*
|
||||
* The default implementation of this method returns the public object member variables indexed by themselves.
|
||||
*
|
||||
* @return array the list of field names or field definitions.
|
||||
* @see toArray()
|
||||
*/
|
||||
public function fields()
|
||||
{
|
||||
$fields = array_keys(Yii::getObjectVars($this));
|
||||
return array_combine($fields, $fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of fields that can be expanded further and returned by [[toArray()]].
|
||||
*
|
||||
* This method is similar to [[fields()]] except that the list of fields returned
|
||||
* by this method are not returned by default by [[toArray()]]. Only when field names
|
||||
* to be expanded are explicitly specified when calling [[toArray()]], will their values
|
||||
* be exported.
|
||||
*
|
||||
* The default implementation returns an empty array.
|
||||
*
|
||||
* You may override this method to return a list of expandable fields based on some context information
|
||||
* (e.g. the current application user).
|
||||
*
|
||||
* @return array the list of expandable field names or field definitions. Please refer
|
||||
* to [[fields()]] on the format of the return value.
|
||||
* @see toArray()
|
||||
* @see fields()
|
||||
*/
|
||||
public function extraFields()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the model into an array.
|
||||
*
|
||||
* This method will first identify which fields to be included in the resulting array by calling [[resolveFields()]].
|
||||
* It will then turn the model into an array with these fields. If `$recursive` is true,
|
||||
* any embedded objects will also be converted into arrays.
|
||||
* When embeded objects are [[Arrayable]], their respective nested fields will be extracted and passed to [[toArray()]].
|
||||
*
|
||||
* If the model implements the [[Linkable]] interface, the resulting array will also have a `_link` element
|
||||
* which refers to a list of links as specified by the interface.
|
||||
*
|
||||
* @param array $fields the fields being requested.
|
||||
* If empty or if it contains '*', all fields as specified by [[fields()]] will be returned.
|
||||
* Fields can be nested, separated with dots (.). e.g.: item.field.sub-field
|
||||
* `$recursive` must be true for nested fields to be extracted. If `$recursive` is false, only the root fields will be extracted.
|
||||
* @param array $expand the additional fields being requested for exporting. Only fields declared in [[extraFields()]]
|
||||
* will be considered.
|
||||
* Expand can also be nested, separated with dots (.). e.g.: item.expand1.expand2
|
||||
* `$recursive` must be true for nested expands to be extracted. If `$recursive` is false, only the root expands will be extracted.
|
||||
* @param bool $recursive whether to recursively return array representation of embedded objects.
|
||||
* @return array the array representation of the object
|
||||
*/
|
||||
public function toArray(array $fields = [], array $expand = [], $recursive = true)
|
||||
{
|
||||
$data = [];
|
||||
foreach ($this->resolveFields($fields, $expand) as $field => $definition) {
|
||||
$attribute = is_string($definition) ? $this->$definition : $definition($this, $field);
|
||||
|
||||
if ($recursive) {
|
||||
$nestedFields = $this->extractFieldsFor($fields, $field);
|
||||
$nestedExpand = $this->extractFieldsFor($expand, $field);
|
||||
if ($attribute instanceof Arrayable) {
|
||||
$attribute = $attribute->toArray($nestedFields, $nestedExpand);
|
||||
} elseif (is_array($attribute)) {
|
||||
$attribute = array_map(
|
||||
function ($item) use ($nestedFields, $nestedExpand) {
|
||||
if ($item instanceof Arrayable) {
|
||||
return $item->toArray($nestedFields, $nestedExpand);
|
||||
}
|
||||
return $item;
|
||||
},
|
||||
$attribute
|
||||
);
|
||||
}
|
||||
}
|
||||
$data[$field] = $attribute;
|
||||
}
|
||||
|
||||
if ($this instanceof Linkable) {
|
||||
$data['_links'] = Link::serialize($this->getLinks());
|
||||
}
|
||||
|
||||
return $recursive ? ArrayHelper::toArray($data) : $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the root field names from nested fields.
|
||||
* Nested fields are separated with dots (.). e.g: "item.id"
|
||||
* The previous example would extract "item".
|
||||
*
|
||||
* @param array $fields The fields requested for extraction
|
||||
* @return array root fields extracted from the given nested fields
|
||||
* @since 2.0.14
|
||||
*/
|
||||
protected function extractRootFields(array $fields)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach ($fields as $field) {
|
||||
$result[] = current(explode('.', $field, 2));
|
||||
}
|
||||
|
||||
if (in_array('*', $result, true)) {
|
||||
$result = [];
|
||||
}
|
||||
|
||||
return array_unique($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract nested fields from a fields collection for a given root field
|
||||
* Nested fields are separated with dots (.). e.g: "item.id"
|
||||
* The previous example would extract "id".
|
||||
*
|
||||
* @param array $fields The fields requested for extraction
|
||||
* @param string $rootField The root field for which we want to extract the nested fields
|
||||
* @return array nested fields extracted for the given field
|
||||
* @since 2.0.14
|
||||
*/
|
||||
protected function extractFieldsFor(array $fields, $rootField)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach ($fields as $field) {
|
||||
if (0 === strpos($field, "{$rootField}.")) {
|
||||
$result[] = preg_replace('/^' . preg_quote($rootField, '/') . '\./i', '', $field);
|
||||
}
|
||||
}
|
||||
|
||||
return array_unique($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which fields can be returned by [[toArray()]].
|
||||
* This method will first extract the root fields from the given fields.
|
||||
* Then it will check the requested root fields against those declared in [[fields()]] and [[extraFields()]]
|
||||
* to determine which fields can be returned.
|
||||
* @param array $fields the fields being requested for exporting
|
||||
* @param array $expand the additional fields being requested for exporting
|
||||
* @return array the list of fields to be exported. The array keys are the field names, and the array values
|
||||
* are the corresponding object property names or PHP callables returning the field values.
|
||||
*/
|
||||
protected function resolveFields(array $fields, array $expand)
|
||||
{
|
||||
$fields = $this->extractRootFields($fields);
|
||||
$expand = $this->extractRootFields($expand);
|
||||
$result = [];
|
||||
|
||||
foreach ($this->fields() as $field => $definition) {
|
||||
if (is_int($field)) {
|
||||
$field = $definition;
|
||||
}
|
||||
if (empty($fields) || in_array($field, $fields, true)) {
|
||||
$result[$field] = $definition;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($expand)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
foreach ($this->extraFields() as $field => $definition) {
|
||||
if (is_int($field)) {
|
||||
$field = $definition;
|
||||
}
|
||||
if (in_array($field, $expand, true)) {
|
||||
$result[$field] = $definition;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
295
vendor/yiisoft/yii2/base/BaseObject.php
vendored
Normal file
295
vendor/yiisoft/yii2/base/BaseObject.php
vendored
Normal file
@@ -0,0 +1,295 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
use Yii;
|
||||
|
||||
/**
|
||||
* BaseObject is the base class that implements the *property* feature.
|
||||
*
|
||||
* A property is defined by a getter method (e.g. `getLabel`), and/or a setter method (e.g. `setLabel`). For example,
|
||||
* the following getter and setter methods define a property named `label`:
|
||||
*
|
||||
* ```php
|
||||
* private $_label;
|
||||
*
|
||||
* public function getLabel()
|
||||
* {
|
||||
* return $this->_label;
|
||||
* }
|
||||
*
|
||||
* public function setLabel($value)
|
||||
* {
|
||||
* $this->_label = $value;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Property names are *case-insensitive*.
|
||||
*
|
||||
* A property can be accessed like a member variable of an object. Reading or writing a property will cause the invocation
|
||||
* of the corresponding getter or setter method. For example,
|
||||
*
|
||||
* ```php
|
||||
* // equivalent to $label = $object->getLabel();
|
||||
* $label = $object->label;
|
||||
* // equivalent to $object->setLabel('abc');
|
||||
* $object->label = 'abc';
|
||||
* ```
|
||||
*
|
||||
* If a property has only a getter method and has no setter method, it is considered as *read-only*. In this case, trying
|
||||
* to modify the property value will cause an exception.
|
||||
*
|
||||
* One can call [[hasProperty()]], [[canGetProperty()]] and/or [[canSetProperty()]] to check the existence of a property.
|
||||
*
|
||||
* Besides the property feature, BaseObject also introduces an important object initialization life cycle. In particular,
|
||||
* creating an new instance of BaseObject or its derived class will involve the following life cycles sequentially:
|
||||
*
|
||||
* 1. the class constructor is invoked;
|
||||
* 2. object properties are initialized according to the given configuration;
|
||||
* 3. the `init()` method is invoked.
|
||||
*
|
||||
* In the above, both Step 2 and 3 occur at the end of the class constructor. It is recommended that
|
||||
* you perform object initialization in the `init()` method because at that stage, the object configuration
|
||||
* is already applied.
|
||||
*
|
||||
* In order to ensure the above life cycles, if a child class of BaseObject needs to override the constructor,
|
||||
* it should be done like the following:
|
||||
*
|
||||
* ```php
|
||||
* public function __construct($param1, $param2, ..., $config = [])
|
||||
* {
|
||||
* ...
|
||||
* parent::__construct($config);
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* That is, a `$config` parameter (defaults to `[]`) should be declared as the last parameter
|
||||
* of the constructor, and the parent implementation should be called at the end of the constructor.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0.13
|
||||
*/
|
||||
class BaseObject implements Configurable
|
||||
{
|
||||
/**
|
||||
* Returns the fully qualified name of this class.
|
||||
* @return string the fully qualified name of this class.
|
||||
* @deprecated since 2.0.14. On PHP >=5.5, use `::class` instead.
|
||||
*/
|
||||
public static function className()
|
||||
{
|
||||
return get_called_class();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* The default implementation does two things:
|
||||
*
|
||||
* - Initializes the object with the given configuration `$config`.
|
||||
* - Call [[init()]].
|
||||
*
|
||||
* If this method is overridden in a child class, it is recommended that
|
||||
*
|
||||
* - the last parameter of the constructor is a configuration array, like `$config` here.
|
||||
* - call the parent implementation at the end of the constructor.
|
||||
*
|
||||
* @param array $config name-value pairs that will be used to initialize the object properties
|
||||
*/
|
||||
public function __construct($config = [])
|
||||
{
|
||||
if (!empty($config)) {
|
||||
Yii::configure($this, $config);
|
||||
}
|
||||
$this->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the object.
|
||||
* This method is invoked at the end of the constructor after the object is initialized with the
|
||||
* given configuration.
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of an object property.
|
||||
*
|
||||
* Do not call this method directly as it is a PHP magic method that
|
||||
* will be implicitly called when executing `$value = $object->property;`.
|
||||
* @param string $name the property name
|
||||
* @return mixed the property value
|
||||
* @throws UnknownPropertyException if the property is not defined
|
||||
* @throws InvalidCallException if the property is write-only
|
||||
* @see __set()
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
$getter = 'get' . $name;
|
||||
if (method_exists($this, $getter)) {
|
||||
return $this->$getter();
|
||||
} elseif (method_exists($this, 'set' . $name)) {
|
||||
throw new InvalidCallException('Getting write-only property: ' . get_class($this) . '::' . $name);
|
||||
}
|
||||
|
||||
throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets value of an object property.
|
||||
*
|
||||
* Do not call this method directly as it is a PHP magic method that
|
||||
* will be implicitly called when executing `$object->property = $value;`.
|
||||
* @param string $name the property name or the event name
|
||||
* @param mixed $value the property value
|
||||
* @throws UnknownPropertyException if the property is not defined
|
||||
* @throws InvalidCallException if the property is read-only
|
||||
* @see __get()
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
$setter = 'set' . $name;
|
||||
if (method_exists($this, $setter)) {
|
||||
$this->$setter($value);
|
||||
} elseif (method_exists($this, 'get' . $name)) {
|
||||
throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '::' . $name);
|
||||
} else {
|
||||
throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '::' . $name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a property is set, i.e. defined and not null.
|
||||
*
|
||||
* Do not call this method directly as it is a PHP magic method that
|
||||
* will be implicitly called when executing `isset($object->property)`.
|
||||
*
|
||||
* Note that if the property is not defined, false will be returned.
|
||||
* @param string $name the property name or the event name
|
||||
* @return bool whether the named property is set (not null).
|
||||
* @see http://php.net/manual/en/function.isset.php
|
||||
*/
|
||||
public function __isset($name)
|
||||
{
|
||||
$getter = 'get' . $name;
|
||||
if (method_exists($this, $getter)) {
|
||||
return $this->$getter() !== null;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an object property to null.
|
||||
*
|
||||
* Do not call this method directly as it is a PHP magic method that
|
||||
* will be implicitly called when executing `unset($object->property)`.
|
||||
*
|
||||
* Note that if the property is not defined, this method will do nothing.
|
||||
* If the property is read-only, it will throw an exception.
|
||||
* @param string $name the property name
|
||||
* @throws InvalidCallException if the property is read only.
|
||||
* @see http://php.net/manual/en/function.unset.php
|
||||
*/
|
||||
public function __unset($name)
|
||||
{
|
||||
$setter = 'set' . $name;
|
||||
if (method_exists($this, $setter)) {
|
||||
$this->$setter(null);
|
||||
} elseif (method_exists($this, 'get' . $name)) {
|
||||
throw new InvalidCallException('Unsetting read-only property: ' . get_class($this) . '::' . $name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the named method which is not a class method.
|
||||
*
|
||||
* Do not call this method directly as it is a PHP magic method that
|
||||
* will be implicitly called when an unknown method is being invoked.
|
||||
* @param string $name the method name
|
||||
* @param array $params method parameters
|
||||
* @throws UnknownMethodException when calling unknown method
|
||||
* @return mixed the method return value
|
||||
*/
|
||||
public function __call($name, $params)
|
||||
{
|
||||
throw new UnknownMethodException('Calling unknown method: ' . get_class($this) . "::$name()");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value indicating whether a property is defined.
|
||||
*
|
||||
* A property is defined if:
|
||||
*
|
||||
* - the class has a getter or setter method associated with the specified name
|
||||
* (in this case, property name is case-insensitive);
|
||||
* - the class has a member variable with the specified name (when `$checkVars` is true);
|
||||
*
|
||||
* @param string $name the property name
|
||||
* @param bool $checkVars whether to treat member variables as properties
|
||||
* @return bool whether the property is defined
|
||||
* @see canGetProperty()
|
||||
* @see canSetProperty()
|
||||
*/
|
||||
public function hasProperty($name, $checkVars = true)
|
||||
{
|
||||
return $this->canGetProperty($name, $checkVars) || $this->canSetProperty($name, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value indicating whether a property can be read.
|
||||
*
|
||||
* A property is readable if:
|
||||
*
|
||||
* - the class has a getter method associated with the specified name
|
||||
* (in this case, property name is case-insensitive);
|
||||
* - the class has a member variable with the specified name (when `$checkVars` is true);
|
||||
*
|
||||
* @param string $name the property name
|
||||
* @param bool $checkVars whether to treat member variables as properties
|
||||
* @return bool whether the property can be read
|
||||
* @see canSetProperty()
|
||||
*/
|
||||
public function canGetProperty($name, $checkVars = true)
|
||||
{
|
||||
return method_exists($this, 'get' . $name) || $checkVars && property_exists($this, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value indicating whether a property can be set.
|
||||
*
|
||||
* A property is writable if:
|
||||
*
|
||||
* - the class has a setter method associated with the specified name
|
||||
* (in this case, property name is case-insensitive);
|
||||
* - the class has a member variable with the specified name (when `$checkVars` is true);
|
||||
*
|
||||
* @param string $name the property name
|
||||
* @param bool $checkVars whether to treat member variables as properties
|
||||
* @return bool whether the property can be written
|
||||
* @see canGetProperty()
|
||||
*/
|
||||
public function canSetProperty($name, $checkVars = true)
|
||||
{
|
||||
return method_exists($this, 'set' . $name) || $checkVars && property_exists($this, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value indicating whether a method is defined.
|
||||
*
|
||||
* The default implementation is a call to php function `method_exists()`.
|
||||
* You may override this method when you implemented the php magic method `__call()`.
|
||||
* @param string $name the method name
|
||||
* @return bool whether the method is defined
|
||||
*/
|
||||
public function hasMethod($name)
|
||||
{
|
||||
return method_exists($this, $name);
|
||||
}
|
||||
}
|
||||
94
vendor/yiisoft/yii2/base/Behavior.php
vendored
Normal file
94
vendor/yiisoft/yii2/base/Behavior.php
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* Behavior is the base class for all behavior classes.
|
||||
*
|
||||
* A behavior can be used to enhance the functionality of an existing component without modifying its code.
|
||||
* In particular, it can "inject" its own methods and properties into the component
|
||||
* and make them directly accessible via the component. It can also respond to the events triggered in the component
|
||||
* and thus intercept the normal code execution.
|
||||
*
|
||||
* For more details and usage information on Behavior, see the [guide article on behaviors](guide:concept-behaviors).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class Behavior extends BaseObject
|
||||
{
|
||||
/**
|
||||
* @var Component|null the owner of this behavior
|
||||
*/
|
||||
public $owner;
|
||||
|
||||
|
||||
/**
|
||||
* Declares event handlers for the [[owner]]'s events.
|
||||
*
|
||||
* Child classes may override this method to declare what PHP callbacks should
|
||||
* be attached to the events of the [[owner]] component.
|
||||
*
|
||||
* The callbacks will be attached to the [[owner]]'s events when the behavior is
|
||||
* attached to the owner; and they will be detached from the events when
|
||||
* the behavior is detached from the component.
|
||||
*
|
||||
* The callbacks can be any of the following:
|
||||
*
|
||||
* - method in this behavior: `'handleClick'`, equivalent to `[$this, 'handleClick']`
|
||||
* - object method: `[$object, 'handleClick']`
|
||||
* - static method: `['Page', 'handleClick']`
|
||||
* - anonymous function: `function ($event) { ... }`
|
||||
*
|
||||
* The following is an example:
|
||||
*
|
||||
* ```php
|
||||
* [
|
||||
* Model::EVENT_BEFORE_VALIDATE => 'myBeforeValidate',
|
||||
* Model::EVENT_AFTER_VALIDATE => 'myAfterValidate',
|
||||
* ]
|
||||
* ```
|
||||
*
|
||||
* @return array events (array keys) and the corresponding event handler methods (array values).
|
||||
*/
|
||||
public function events()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches the behavior object to the component.
|
||||
* The default implementation will set the [[owner]] property
|
||||
* and attach event handlers as declared in [[events]].
|
||||
* Make sure you call the parent implementation if you override this method.
|
||||
* @param Component $owner the component that this behavior is to be attached to.
|
||||
*/
|
||||
public function attach($owner)
|
||||
{
|
||||
$this->owner = $owner;
|
||||
foreach ($this->events() as $event => $handler) {
|
||||
$owner->on($event, is_string($handler) ? [$this, $handler] : $handler);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detaches the behavior object from the component.
|
||||
* The default implementation will unset the [[owner]] property
|
||||
* and detach event handlers declared in [[events]].
|
||||
* Make sure you call the parent implementation if you override this method.
|
||||
*/
|
||||
public function detach()
|
||||
{
|
||||
if ($this->owner) {
|
||||
foreach ($this->events() as $event => $handler) {
|
||||
$this->owner->off($event, is_string($handler) ? [$this, $handler] : $handler);
|
||||
}
|
||||
$this->owner = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
62
vendor/yiisoft/yii2/base/BootstrapInterface.php
vendored
Normal file
62
vendor/yiisoft/yii2/base/BootstrapInterface.php
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* BootstrapInterface is the interface that should be implemented by classes who want to participate in the application bootstrap process.
|
||||
*
|
||||
* The main method [[bootstrap()]] will be invoked by an application at the beginning of its `init()` method.
|
||||
*
|
||||
* Bootstrapping classes can be registered in two approaches.
|
||||
*
|
||||
* The first approach is mainly used by extensions and is managed by the Composer installation process.
|
||||
* You mainly need to list the bootstrapping class of your extension in the `composer.json` file like following,
|
||||
*
|
||||
* ```json
|
||||
* {
|
||||
* // ...
|
||||
* "extra": {
|
||||
* "bootstrap": "path\\to\\MyBootstrapClass"
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* If the extension is installed, the bootstrap information will be saved in [[Application::extensions]].
|
||||
*
|
||||
* The second approach is used by application code which needs to register some code to be run during
|
||||
* the bootstrap process. This is done by configuring the [[Application::bootstrap]] property:
|
||||
*
|
||||
* ```php
|
||||
* return [
|
||||
* // ...
|
||||
* 'bootstrap' => [
|
||||
* "path\\to\\MyBootstrapClass1",
|
||||
* [
|
||||
* 'class' => "path\\to\\MyBootstrapClass2",
|
||||
* 'prop1' => 'value1',
|
||||
* 'prop2' => 'value2',
|
||||
* ],
|
||||
* ],
|
||||
* ];
|
||||
* ```
|
||||
*
|
||||
* As you can see, you can register a bootstrapping class in terms of either a class name or a configuration class.
|
||||
*
|
||||
* For more details and usage information on BootstrapInterface, see the [guide article on bootstrapping applications](guide:structure-applications).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
interface BootstrapInterface
|
||||
{
|
||||
/**
|
||||
* Bootstrap method to be called during application bootstrap stage.
|
||||
* @param Application $app the application currently running
|
||||
*/
|
||||
public function bootstrap($app);
|
||||
}
|
||||
765
vendor/yiisoft/yii2/base/Component.php
vendored
Normal file
765
vendor/yiisoft/yii2/base/Component.php
vendored
Normal file
@@ -0,0 +1,765 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
use Yii;
|
||||
use yii\helpers\StringHelper;
|
||||
|
||||
/**
|
||||
* Component is the base class that implements the *property*, *event* and *behavior* features.
|
||||
*
|
||||
* Component provides the *event* and *behavior* features, in addition to the *property* feature which is implemented in
|
||||
* its parent class [[\yii\base\BaseObject|BaseObject]].
|
||||
*
|
||||
* Event is a way to "inject" custom code into existing code at certain places. For example, a comment object can trigger
|
||||
* an "add" event when the user adds a comment. We can write custom code and attach it to this event so that when the event
|
||||
* is triggered (i.e. comment will be added), our custom code will be executed.
|
||||
*
|
||||
* An event is identified by a name that should be unique within the class it is defined at. Event names are *case-sensitive*.
|
||||
*
|
||||
* One or multiple PHP callbacks, called *event handlers*, can be attached to an event. You can call [[trigger()]] to
|
||||
* raise an event. When an event is raised, the event handlers will be invoked automatically in the order they were
|
||||
* attached.
|
||||
*
|
||||
* To attach an event handler to an event, call [[on()]]:
|
||||
*
|
||||
* ```php
|
||||
* $post->on('update', function ($event) {
|
||||
* // send email notification
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* In the above, an anonymous function is attached to the "update" event of the post. You may attach
|
||||
* the following types of event handlers:
|
||||
*
|
||||
* - anonymous function: `function ($event) { ... }`
|
||||
* - object method: `[$object, 'handleAdd']`
|
||||
* - static class method: `['Page', 'handleAdd']`
|
||||
* - global function: `'handleAdd'`
|
||||
*
|
||||
* The signature of an event handler should be like the following:
|
||||
*
|
||||
* ```php
|
||||
* function foo($event)
|
||||
* ```
|
||||
*
|
||||
* where `$event` is an [[Event]] object which includes parameters associated with the event.
|
||||
*
|
||||
* You can also attach a handler to an event when configuring a component with a configuration array.
|
||||
* The syntax is like the following:
|
||||
*
|
||||
* ```php
|
||||
* [
|
||||
* 'on add' => function ($event) { ... }
|
||||
* ]
|
||||
* ```
|
||||
*
|
||||
* where `on add` stands for attaching an event to the `add` event.
|
||||
*
|
||||
* Sometimes, you may want to associate extra data with an event handler when you attach it to an event
|
||||
* and then access it when the handler is invoked. You may do so by
|
||||
*
|
||||
* ```php
|
||||
* $post->on('update', function ($event) {
|
||||
* // the data can be accessed via $event->data
|
||||
* }, $data);
|
||||
* ```
|
||||
*
|
||||
* A behavior is an instance of [[Behavior]] or its child class. A component can be attached with one or multiple
|
||||
* behaviors. When a behavior is attached to a component, its public properties and methods can be accessed via the
|
||||
* component directly, as if the component owns those properties and methods.
|
||||
*
|
||||
* To attach a behavior to a component, declare it in [[behaviors()]], or explicitly call [[attachBehavior]]. Behaviors
|
||||
* declared in [[behaviors()]] are automatically attached to the corresponding component.
|
||||
*
|
||||
* One can also attach a behavior to a component when configuring it with a configuration array. The syntax is like the
|
||||
* following:
|
||||
*
|
||||
* ```php
|
||||
* [
|
||||
* 'as tree' => [
|
||||
* 'class' => 'Tree',
|
||||
* ],
|
||||
* ]
|
||||
* ```
|
||||
*
|
||||
* where `as tree` stands for attaching a behavior named `tree`, and the array will be passed to [[\Yii::createObject()]]
|
||||
* to create the behavior object.
|
||||
*
|
||||
* For more details and usage information on Component, see the [guide article on components](guide:concept-components).
|
||||
*
|
||||
* @property Behavior[] $behaviors List of behaviors attached to this component. This property is read-only.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class Component extends BaseObject
|
||||
{
|
||||
/**
|
||||
* @var array the attached event handlers (event name => handlers)
|
||||
*/
|
||||
private $_events = [];
|
||||
/**
|
||||
* @var array the event handlers attached for wildcard patterns (event name wildcard => handlers)
|
||||
* @since 2.0.14
|
||||
*/
|
||||
private $_eventWildcards = [];
|
||||
/**
|
||||
* @var Behavior[]|null the attached behaviors (behavior name => behavior). This is `null` when not initialized.
|
||||
*/
|
||||
private $_behaviors;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the value of a component property.
|
||||
*
|
||||
* This method will check in the following order and act accordingly:
|
||||
*
|
||||
* - a property defined by a getter: return the getter result
|
||||
* - a property of a behavior: return the behavior property value
|
||||
*
|
||||
* Do not call this method directly as it is a PHP magic method that
|
||||
* will be implicitly called when executing `$value = $component->property;`.
|
||||
* @param string $name the property name
|
||||
* @return mixed the property value or the value of a behavior's property
|
||||
* @throws UnknownPropertyException if the property is not defined
|
||||
* @throws InvalidCallException if the property is write-only.
|
||||
* @see __set()
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
$getter = 'get' . $name;
|
||||
if (method_exists($this, $getter)) {
|
||||
// read property, e.g. getName()
|
||||
return $this->$getter();
|
||||
}
|
||||
|
||||
// behavior property
|
||||
$this->ensureBehaviors();
|
||||
foreach ($this->_behaviors as $behavior) {
|
||||
if ($behavior->canGetProperty($name)) {
|
||||
return $behavior->$name;
|
||||
}
|
||||
}
|
||||
|
||||
if (method_exists($this, 'set' . $name)) {
|
||||
throw new InvalidCallException('Getting write-only property: ' . get_class($this) . '::' . $name);
|
||||
}
|
||||
|
||||
throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a component property.
|
||||
*
|
||||
* This method will check in the following order and act accordingly:
|
||||
*
|
||||
* - a property defined by a setter: set the property value
|
||||
* - an event in the format of "on xyz": attach the handler to the event "xyz"
|
||||
* - a behavior in the format of "as xyz": attach the behavior named as "xyz"
|
||||
* - a property of a behavior: set the behavior property value
|
||||
*
|
||||
* Do not call this method directly as it is a PHP magic method that
|
||||
* will be implicitly called when executing `$component->property = $value;`.
|
||||
* @param string $name the property name or the event name
|
||||
* @param mixed $value the property value
|
||||
* @throws UnknownPropertyException if the property is not defined
|
||||
* @throws InvalidCallException if the property is read-only.
|
||||
* @see __get()
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
$setter = 'set' . $name;
|
||||
if (method_exists($this, $setter)) {
|
||||
// set property
|
||||
$this->$setter($value);
|
||||
|
||||
return;
|
||||
} elseif (strncmp($name, 'on ', 3) === 0) {
|
||||
// on event: attach event handler
|
||||
$this->on(trim(substr($name, 3)), $value);
|
||||
|
||||
return;
|
||||
} elseif (strncmp($name, 'as ', 3) === 0) {
|
||||
// as behavior: attach behavior
|
||||
$name = trim(substr($name, 3));
|
||||
$this->attachBehavior($name, $value instanceof Behavior ? $value : Yii::createObject($value));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// behavior property
|
||||
$this->ensureBehaviors();
|
||||
foreach ($this->_behaviors as $behavior) {
|
||||
if ($behavior->canSetProperty($name)) {
|
||||
$behavior->$name = $value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (method_exists($this, 'get' . $name)) {
|
||||
throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '::' . $name);
|
||||
}
|
||||
|
||||
throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '::' . $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a property is set, i.e. defined and not null.
|
||||
*
|
||||
* This method will check in the following order and act accordingly:
|
||||
*
|
||||
* - a property defined by a setter: return whether the property is set
|
||||
* - a property of a behavior: return whether the property is set
|
||||
* - return `false` for non existing properties
|
||||
*
|
||||
* Do not call this method directly as it is a PHP magic method that
|
||||
* will be implicitly called when executing `isset($component->property)`.
|
||||
* @param string $name the property name or the event name
|
||||
* @return bool whether the named property is set
|
||||
* @see http://php.net/manual/en/function.isset.php
|
||||
*/
|
||||
public function __isset($name)
|
||||
{
|
||||
$getter = 'get' . $name;
|
||||
if (method_exists($this, $getter)) {
|
||||
return $this->$getter() !== null;
|
||||
}
|
||||
|
||||
// behavior property
|
||||
$this->ensureBehaviors();
|
||||
foreach ($this->_behaviors as $behavior) {
|
||||
if ($behavior->canGetProperty($name)) {
|
||||
return $behavior->$name !== null;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a component property to be null.
|
||||
*
|
||||
* This method will check in the following order and act accordingly:
|
||||
*
|
||||
* - a property defined by a setter: set the property value to be null
|
||||
* - a property of a behavior: set the property value to be null
|
||||
*
|
||||
* Do not call this method directly as it is a PHP magic method that
|
||||
* will be implicitly called when executing `unset($component->property)`.
|
||||
* @param string $name the property name
|
||||
* @throws InvalidCallException if the property is read only.
|
||||
* @see http://php.net/manual/en/function.unset.php
|
||||
*/
|
||||
public function __unset($name)
|
||||
{
|
||||
$setter = 'set' . $name;
|
||||
if (method_exists($this, $setter)) {
|
||||
$this->$setter(null);
|
||||
return;
|
||||
}
|
||||
|
||||
// behavior property
|
||||
$this->ensureBehaviors();
|
||||
foreach ($this->_behaviors as $behavior) {
|
||||
if ($behavior->canSetProperty($name)) {
|
||||
$behavior->$name = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidCallException('Unsetting an unknown or read-only property: ' . get_class($this) . '::' . $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the named method which is not a class method.
|
||||
*
|
||||
* This method will check if any attached behavior has
|
||||
* the named method and will execute it if available.
|
||||
*
|
||||
* Do not call this method directly as it is a PHP magic method that
|
||||
* will be implicitly called when an unknown method is being invoked.
|
||||
* @param string $name the method name
|
||||
* @param array $params method parameters
|
||||
* @return mixed the method return value
|
||||
* @throws UnknownMethodException when calling unknown method
|
||||
*/
|
||||
public function __call($name, $params)
|
||||
{
|
||||
$this->ensureBehaviors();
|
||||
foreach ($this->_behaviors as $object) {
|
||||
if ($object->hasMethod($name)) {
|
||||
return call_user_func_array([$object, $name], $params);
|
||||
}
|
||||
}
|
||||
throw new UnknownMethodException('Calling unknown method: ' . get_class($this) . "::$name()");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called after the object is created by cloning an existing one.
|
||||
* It removes all behaviors because they are attached to the old object.
|
||||
*/
|
||||
public function __clone()
|
||||
{
|
||||
$this->_events = [];
|
||||
$this->_eventWildcards = [];
|
||||
$this->_behaviors = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value indicating whether a property is defined for this component.
|
||||
*
|
||||
* A property is defined if:
|
||||
*
|
||||
* - the class has a getter or setter method associated with the specified name
|
||||
* (in this case, property name is case-insensitive);
|
||||
* - the class has a member variable with the specified name (when `$checkVars` is true);
|
||||
* - an attached behavior has a property of the given name (when `$checkBehaviors` is true).
|
||||
*
|
||||
* @param string $name the property name
|
||||
* @param bool $checkVars whether to treat member variables as properties
|
||||
* @param bool $checkBehaviors whether to treat behaviors' properties as properties of this component
|
||||
* @return bool whether the property is defined
|
||||
* @see canGetProperty()
|
||||
* @see canSetProperty()
|
||||
*/
|
||||
public function hasProperty($name, $checkVars = true, $checkBehaviors = true)
|
||||
{
|
||||
return $this->canGetProperty($name, $checkVars, $checkBehaviors) || $this->canSetProperty($name, false, $checkBehaviors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value indicating whether a property can be read.
|
||||
*
|
||||
* A property can be read if:
|
||||
*
|
||||
* - the class has a getter method associated with the specified name
|
||||
* (in this case, property name is case-insensitive);
|
||||
* - the class has a member variable with the specified name (when `$checkVars` is true);
|
||||
* - an attached behavior has a readable property of the given name (when `$checkBehaviors` is true).
|
||||
*
|
||||
* @param string $name the property name
|
||||
* @param bool $checkVars whether to treat member variables as properties
|
||||
* @param bool $checkBehaviors whether to treat behaviors' properties as properties of this component
|
||||
* @return bool whether the property can be read
|
||||
* @see canSetProperty()
|
||||
*/
|
||||
public function canGetProperty($name, $checkVars = true, $checkBehaviors = true)
|
||||
{
|
||||
if (method_exists($this, 'get' . $name) || $checkVars && property_exists($this, $name)) {
|
||||
return true;
|
||||
} elseif ($checkBehaviors) {
|
||||
$this->ensureBehaviors();
|
||||
foreach ($this->_behaviors as $behavior) {
|
||||
if ($behavior->canGetProperty($name, $checkVars)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value indicating whether a property can be set.
|
||||
*
|
||||
* A property can be written if:
|
||||
*
|
||||
* - the class has a setter method associated with the specified name
|
||||
* (in this case, property name is case-insensitive);
|
||||
* - the class has a member variable with the specified name (when `$checkVars` is true);
|
||||
* - an attached behavior has a writable property of the given name (when `$checkBehaviors` is true).
|
||||
*
|
||||
* @param string $name the property name
|
||||
* @param bool $checkVars whether to treat member variables as properties
|
||||
* @param bool $checkBehaviors whether to treat behaviors' properties as properties of this component
|
||||
* @return bool whether the property can be written
|
||||
* @see canGetProperty()
|
||||
*/
|
||||
public function canSetProperty($name, $checkVars = true, $checkBehaviors = true)
|
||||
{
|
||||
if (method_exists($this, 'set' . $name) || $checkVars && property_exists($this, $name)) {
|
||||
return true;
|
||||
} elseif ($checkBehaviors) {
|
||||
$this->ensureBehaviors();
|
||||
foreach ($this->_behaviors as $behavior) {
|
||||
if ($behavior->canSetProperty($name, $checkVars)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value indicating whether a method is defined.
|
||||
*
|
||||
* A method is defined if:
|
||||
*
|
||||
* - the class has a method with the specified name
|
||||
* - an attached behavior has a method with the given name (when `$checkBehaviors` is true).
|
||||
*
|
||||
* @param string $name the property name
|
||||
* @param bool $checkBehaviors whether to treat behaviors' methods as methods of this component
|
||||
* @return bool whether the method is defined
|
||||
*/
|
||||
public function hasMethod($name, $checkBehaviors = true)
|
||||
{
|
||||
if (method_exists($this, $name)) {
|
||||
return true;
|
||||
} elseif ($checkBehaviors) {
|
||||
$this->ensureBehaviors();
|
||||
foreach ($this->_behaviors as $behavior) {
|
||||
if ($behavior->hasMethod($name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of behaviors that this component should behave as.
|
||||
*
|
||||
* Child classes may override this method to specify the behaviors they want to behave as.
|
||||
*
|
||||
* The return value of this method should be an array of behavior objects or configurations
|
||||
* indexed by behavior names. A behavior configuration can be either a string specifying
|
||||
* the behavior class or an array of the following structure:
|
||||
*
|
||||
* ```php
|
||||
* 'behaviorName' => [
|
||||
* 'class' => 'BehaviorClass',
|
||||
* 'property1' => 'value1',
|
||||
* 'property2' => 'value2',
|
||||
* ]
|
||||
* ```
|
||||
*
|
||||
* Note that a behavior class must extend from [[Behavior]]. Behaviors can be attached using a name or anonymously.
|
||||
* When a name is used as the array key, using this name, the behavior can later be retrieved using [[getBehavior()]]
|
||||
* or be detached using [[detachBehavior()]]. Anonymous behaviors can not be retrieved or detached.
|
||||
*
|
||||
* Behaviors declared in this method will be attached to the component automatically (on demand).
|
||||
*
|
||||
* @return array the behavior configurations.
|
||||
*/
|
||||
public function behaviors()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value indicating whether there is any handler attached to the named event.
|
||||
* @param string $name the event name
|
||||
* @return bool whether there is any handler attached to the event.
|
||||
*/
|
||||
public function hasEventHandlers($name)
|
||||
{
|
||||
$this->ensureBehaviors();
|
||||
|
||||
foreach ($this->_eventWildcards as $wildcard => $handlers) {
|
||||
if (!empty($handlers) && StringHelper::matchWildcard($wildcard, $name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return !empty($this->_events[$name]) || Event::hasHandlers($this, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches an event handler to an event.
|
||||
*
|
||||
* The event handler must be a valid PHP callback. The following are
|
||||
* some examples:
|
||||
*
|
||||
* ```
|
||||
* function ($event) { ... } // anonymous function
|
||||
* [$object, 'handleClick'] // $object->handleClick()
|
||||
* ['Page', 'handleClick'] // Page::handleClick()
|
||||
* 'handleClick' // global function handleClick()
|
||||
* ```
|
||||
*
|
||||
* The event handler must be defined with the following signature,
|
||||
*
|
||||
* ```
|
||||
* function ($event)
|
||||
* ```
|
||||
*
|
||||
* where `$event` is an [[Event]] object which includes parameters associated with the event.
|
||||
*
|
||||
* Since 2.0.14 you can specify event name as a wildcard pattern:
|
||||
*
|
||||
* ```php
|
||||
* $component->on('event.group.*', function ($event) {
|
||||
* Yii::trace($event->name . ' is triggered.');
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @param string $name the event name
|
||||
* @param callable $handler the event handler
|
||||
* @param mixed $data the data to be passed to the event handler when the event is triggered.
|
||||
* When the event handler is invoked, this data can be accessed via [[Event::data]].
|
||||
* @param bool $append whether to append new event handler to the end of the existing
|
||||
* handler list. If false, the new handler will be inserted at the beginning of the existing
|
||||
* handler list.
|
||||
* @see off()
|
||||
*/
|
||||
public function on($name, $handler, $data = null, $append = true)
|
||||
{
|
||||
$this->ensureBehaviors();
|
||||
|
||||
if (strpos($name, '*') !== false) {
|
||||
if ($append || empty($this->_eventWildcards[$name])) {
|
||||
$this->_eventWildcards[$name][] = [$handler, $data];
|
||||
} else {
|
||||
array_unshift($this->_eventWildcards[$name], [$handler, $data]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ($append || empty($this->_events[$name])) {
|
||||
$this->_events[$name][] = [$handler, $data];
|
||||
} else {
|
||||
array_unshift($this->_events[$name], [$handler, $data]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detaches an existing event handler from this component.
|
||||
*
|
||||
* This method is the opposite of [[on()]].
|
||||
*
|
||||
* Note: in case wildcard pattern is passed for event name, only the handlers registered with this
|
||||
* wildcard will be removed, while handlers registered with plain names matching this wildcard will remain.
|
||||
*
|
||||
* @param string $name event name
|
||||
* @param callable $handler the event handler to be removed.
|
||||
* If it is null, all handlers attached to the named event will be removed.
|
||||
* @return bool if a handler is found and detached
|
||||
* @see on()
|
||||
*/
|
||||
public function off($name, $handler = null)
|
||||
{
|
||||
$this->ensureBehaviors();
|
||||
if (empty($this->_events[$name]) && empty($this->_eventWildcards[$name])) {
|
||||
return false;
|
||||
}
|
||||
if ($handler === null) {
|
||||
unset($this->_events[$name], $this->_eventWildcards[$name]);
|
||||
return true;
|
||||
}
|
||||
|
||||
$removed = false;
|
||||
// plain event names
|
||||
if (isset($this->_events[$name])) {
|
||||
foreach ($this->_events[$name] as $i => $event) {
|
||||
if ($event[0] === $handler) {
|
||||
unset($this->_events[$name][$i]);
|
||||
$removed = true;
|
||||
}
|
||||
}
|
||||
if ($removed) {
|
||||
$this->_events[$name] = array_values($this->_events[$name]);
|
||||
return $removed;
|
||||
}
|
||||
}
|
||||
|
||||
// wildcard event names
|
||||
if (isset($this->_eventWildcards[$name])) {
|
||||
foreach ($this->_eventWildcards[$name] as $i => $event) {
|
||||
if ($event[0] === $handler) {
|
||||
unset($this->_eventWildcards[$name][$i]);
|
||||
$removed = true;
|
||||
}
|
||||
}
|
||||
if ($removed) {
|
||||
$this->_eventWildcards[$name] = array_values($this->_eventWildcards[$name]);
|
||||
// remove empty wildcards to save future redundant regex checks:
|
||||
if (empty($this->_eventWildcards[$name])) {
|
||||
unset($this->_eventWildcards[$name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $removed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers an event.
|
||||
* This method represents the happening of an event. It invokes
|
||||
* all attached handlers for the event including class-level handlers.
|
||||
* @param string $name the event name
|
||||
* @param Event $event the event parameter. If not set, a default [[Event]] object will be created.
|
||||
*/
|
||||
public function trigger($name, Event $event = null)
|
||||
{
|
||||
$this->ensureBehaviors();
|
||||
|
||||
$eventHandlers = [];
|
||||
foreach ($this->_eventWildcards as $wildcard => $handlers) {
|
||||
if (StringHelper::matchWildcard($wildcard, $name)) {
|
||||
$eventHandlers = array_merge($eventHandlers, $handlers);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($this->_events[$name])) {
|
||||
$eventHandlers = array_merge($eventHandlers, $this->_events[$name]);
|
||||
}
|
||||
|
||||
if (!empty($eventHandlers)) {
|
||||
if ($event === null) {
|
||||
$event = new Event();
|
||||
}
|
||||
if ($event->sender === null) {
|
||||
$event->sender = $this;
|
||||
}
|
||||
$event->handled = false;
|
||||
$event->name = $name;
|
||||
foreach ($eventHandlers as $handler) {
|
||||
$event->data = $handler[1];
|
||||
call_user_func($handler[0], $event);
|
||||
// stop further handling if the event is handled
|
||||
if ($event->handled) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// invoke class-level attached handlers
|
||||
Event::trigger($this, $name, $event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the named behavior object.
|
||||
* @param string $name the behavior name
|
||||
* @return null|Behavior the behavior object, or null if the behavior does not exist
|
||||
*/
|
||||
public function getBehavior($name)
|
||||
{
|
||||
$this->ensureBehaviors();
|
||||
return isset($this->_behaviors[$name]) ? $this->_behaviors[$name] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all behaviors attached to this component.
|
||||
* @return Behavior[] list of behaviors attached to this component
|
||||
*/
|
||||
public function getBehaviors()
|
||||
{
|
||||
$this->ensureBehaviors();
|
||||
return $this->_behaviors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches a behavior to this component.
|
||||
* This method will create the behavior object based on the given
|
||||
* configuration. After that, the behavior object will be attached to
|
||||
* this component by calling the [[Behavior::attach()]] method.
|
||||
* @param string $name the name of the behavior.
|
||||
* @param string|array|Behavior $behavior the behavior configuration. This can be one of the following:
|
||||
*
|
||||
* - a [[Behavior]] object
|
||||
* - a string specifying the behavior class
|
||||
* - an object configuration array that will be passed to [[Yii::createObject()]] to create the behavior object.
|
||||
*
|
||||
* @return Behavior the behavior object
|
||||
* @see detachBehavior()
|
||||
*/
|
||||
public function attachBehavior($name, $behavior)
|
||||
{
|
||||
$this->ensureBehaviors();
|
||||
return $this->attachBehaviorInternal($name, $behavior);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches a list of behaviors to the component.
|
||||
* Each behavior is indexed by its name and should be a [[Behavior]] object,
|
||||
* a string specifying the behavior class, or an configuration array for creating the behavior.
|
||||
* @param array $behaviors list of behaviors to be attached to the component
|
||||
* @see attachBehavior()
|
||||
*/
|
||||
public function attachBehaviors($behaviors)
|
||||
{
|
||||
$this->ensureBehaviors();
|
||||
foreach ($behaviors as $name => $behavior) {
|
||||
$this->attachBehaviorInternal($name, $behavior);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detaches a behavior from the component.
|
||||
* The behavior's [[Behavior::detach()]] method will be invoked.
|
||||
* @param string $name the behavior's name.
|
||||
* @return null|Behavior the detached behavior. Null if the behavior does not exist.
|
||||
*/
|
||||
public function detachBehavior($name)
|
||||
{
|
||||
$this->ensureBehaviors();
|
||||
if (isset($this->_behaviors[$name])) {
|
||||
$behavior = $this->_behaviors[$name];
|
||||
unset($this->_behaviors[$name]);
|
||||
$behavior->detach();
|
||||
return $behavior;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detaches all behaviors from the component.
|
||||
*/
|
||||
public function detachBehaviors()
|
||||
{
|
||||
$this->ensureBehaviors();
|
||||
foreach ($this->_behaviors as $name => $behavior) {
|
||||
$this->detachBehavior($name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure that the behaviors declared in [[behaviors()]] are attached to this component.
|
||||
*/
|
||||
public function ensureBehaviors()
|
||||
{
|
||||
if ($this->_behaviors === null) {
|
||||
$this->_behaviors = [];
|
||||
foreach ($this->behaviors() as $name => $behavior) {
|
||||
$this->attachBehaviorInternal($name, $behavior);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches a behavior to this component.
|
||||
* @param string|int $name the name of the behavior. If this is an integer, it means the behavior
|
||||
* is an anonymous one. Otherwise, the behavior is a named one and any existing behavior with the same name
|
||||
* will be detached first.
|
||||
* @param string|array|Behavior $behavior the behavior to be attached
|
||||
* @return Behavior the attached behavior.
|
||||
*/
|
||||
private function attachBehaviorInternal($name, $behavior)
|
||||
{
|
||||
if (!($behavior instanceof Behavior)) {
|
||||
$behavior = Yii::createObject($behavior);
|
||||
}
|
||||
if (is_int($name)) {
|
||||
$behavior->attach($this);
|
||||
$this->_behaviors[] = $behavior;
|
||||
} else {
|
||||
if (isset($this->_behaviors[$name])) {
|
||||
$this->_behaviors[$name]->detach();
|
||||
}
|
||||
$behavior->attach($this);
|
||||
$this->_behaviors[$name] = $behavior;
|
||||
}
|
||||
|
||||
return $behavior;
|
||||
}
|
||||
}
|
||||
33
vendor/yiisoft/yii2/base/Configurable.php
vendored
Normal file
33
vendor/yiisoft/yii2/base/Configurable.php
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* Configurable is the interface that should be implemented by classes who support configuring
|
||||
* its properties through the last parameter to its constructor.
|
||||
*
|
||||
* The interface does not declare any method. Classes implementing this interface must declare their constructors
|
||||
* like the following:
|
||||
*
|
||||
* ```php
|
||||
* public function __constructor($param1, $param2, ..., $config = [])
|
||||
* ```
|
||||
*
|
||||
* That is, the last parameter of the constructor must accept a configuration array.
|
||||
*
|
||||
* This interface is mainly used by [[\yii\di\Container]] so that it can pass object configuration as the
|
||||
* last parameter to the implementing class' constructor.
|
||||
*
|
||||
* For more details and usage information on Configurable, see the [guide article on configurations](guide:concept-configurations).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0.3
|
||||
*/
|
||||
interface Configurable
|
||||
{
|
||||
}
|
||||
524
vendor/yiisoft/yii2/base/Controller.php
vendored
Normal file
524
vendor/yiisoft/yii2/base/Controller.php
vendored
Normal file
@@ -0,0 +1,524 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
use Yii;
|
||||
|
||||
/**
|
||||
* Controller is the base class for classes containing controller logic.
|
||||
*
|
||||
* For more details and usage information on Controller, see the [guide article on controllers](guide:structure-controllers).
|
||||
*
|
||||
* @property Module[] $modules All ancestor modules that this controller is located within. This property is
|
||||
* read-only.
|
||||
* @property string $route The route (module ID, controller ID and action ID) of the current request. This
|
||||
* property is read-only.
|
||||
* @property string $uniqueId The controller ID that is prefixed with the module ID (if any). This property is
|
||||
* read-only.
|
||||
* @property View|\yii\web\View $view The view object that can be used to render views or view files.
|
||||
* @property string $viewPath The directory containing the view files for this controller.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class Controller extends Component implements ViewContextInterface
|
||||
{
|
||||
/**
|
||||
* @event ActionEvent an event raised right before executing a controller action.
|
||||
* You may set [[ActionEvent::isValid]] to be false to cancel the action execution.
|
||||
*/
|
||||
const EVENT_BEFORE_ACTION = 'beforeAction';
|
||||
/**
|
||||
* @event ActionEvent an event raised right after executing a controller action.
|
||||
*/
|
||||
const EVENT_AFTER_ACTION = 'afterAction';
|
||||
|
||||
/**
|
||||
* @var string the ID of this controller.
|
||||
*/
|
||||
public $id;
|
||||
/**
|
||||
* @var Module the module that this controller belongs to.
|
||||
*/
|
||||
public $module;
|
||||
/**
|
||||
* @var string the ID of the action that is used when the action ID is not specified
|
||||
* in the request. Defaults to 'index'.
|
||||
*/
|
||||
public $defaultAction = 'index';
|
||||
/**
|
||||
* @var null|string|false the name of the layout to be applied to this controller's views.
|
||||
* This property mainly affects the behavior of [[render()]].
|
||||
* Defaults to null, meaning the actual layout value should inherit that from [[module]]'s layout value.
|
||||
* If false, no layout will be applied.
|
||||
*/
|
||||
public $layout;
|
||||
/**
|
||||
* @var Action the action that is currently being executed. This property will be set
|
||||
* by [[run()]] when it is called by [[Application]] to run an action.
|
||||
*/
|
||||
public $action;
|
||||
|
||||
/**
|
||||
* @var View the view object that can be used to render views or view files.
|
||||
*/
|
||||
private $_view;
|
||||
/**
|
||||
* @var string the root directory that contains view files for this controller.
|
||||
*/
|
||||
private $_viewPath;
|
||||
|
||||
|
||||
/**
|
||||
* @param string $id the ID of this controller.
|
||||
* @param Module $module the module that this controller belongs to.
|
||||
* @param array $config name-value pairs that will be used to initialize the object properties.
|
||||
*/
|
||||
public function __construct($id, $module, $config = [])
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->module = $module;
|
||||
parent::__construct($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Declares external actions for the controller.
|
||||
*
|
||||
* This method is meant to be overwritten to declare external actions for the controller.
|
||||
* It should return an array, with array keys being action IDs, and array values the corresponding
|
||||
* action class names or action configuration arrays. For example,
|
||||
*
|
||||
* ```php
|
||||
* return [
|
||||
* 'action1' => 'app\components\Action1',
|
||||
* 'action2' => [
|
||||
* 'class' => 'app\components\Action2',
|
||||
* 'property1' => 'value1',
|
||||
* 'property2' => 'value2',
|
||||
* ],
|
||||
* ];
|
||||
* ```
|
||||
*
|
||||
* [[\Yii::createObject()]] will be used later to create the requested action
|
||||
* using the configuration provided here.
|
||||
*/
|
||||
public function actions()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs an action within this controller with the specified action ID and parameters.
|
||||
* If the action ID is empty, the method will use [[defaultAction]].
|
||||
* @param string $id the ID of the action to be executed.
|
||||
* @param array $params the parameters (name-value pairs) to be passed to the action.
|
||||
* @return mixed the result of the action.
|
||||
* @throws InvalidRouteException if the requested action ID cannot be resolved into an action successfully.
|
||||
* @see createAction()
|
||||
*/
|
||||
public function runAction($id, $params = [])
|
||||
{
|
||||
$action = $this->createAction($id);
|
||||
if ($action === null) {
|
||||
throw new InvalidRouteException('Unable to resolve the request: ' . $this->getUniqueId() . '/' . $id);
|
||||
}
|
||||
|
||||
Yii::debug('Route to run: ' . $action->getUniqueId(), __METHOD__);
|
||||
|
||||
if (Yii::$app->requestedAction === null) {
|
||||
Yii::$app->requestedAction = $action;
|
||||
}
|
||||
|
||||
$oldAction = $this->action;
|
||||
$this->action = $action;
|
||||
|
||||
$modules = [];
|
||||
$runAction = true;
|
||||
|
||||
// call beforeAction on modules
|
||||
foreach ($this->getModules() as $module) {
|
||||
if ($module->beforeAction($action)) {
|
||||
array_unshift($modules, $module);
|
||||
} else {
|
||||
$runAction = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$result = null;
|
||||
|
||||
if ($runAction && $this->beforeAction($action)) {
|
||||
// run the action
|
||||
$result = $action->runWithParams($params);
|
||||
|
||||
$result = $this->afterAction($action, $result);
|
||||
|
||||
// call afterAction on modules
|
||||
foreach ($modules as $module) {
|
||||
/* @var $module Module */
|
||||
$result = $module->afterAction($action, $result);
|
||||
}
|
||||
}
|
||||
|
||||
if ($oldAction !== null) {
|
||||
$this->action = $oldAction;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a request specified in terms of a route.
|
||||
* The route can be either an ID of an action within this controller or a complete route consisting
|
||||
* of module IDs, controller ID and action ID. If the route starts with a slash '/', the parsing of
|
||||
* the route will start from the application; otherwise, it will start from the parent module of this controller.
|
||||
* @param string $route the route to be handled, e.g., 'view', 'comment/view', '/admin/comment/view'.
|
||||
* @param array $params the parameters to be passed to the action.
|
||||
* @return mixed the result of the action.
|
||||
* @see runAction()
|
||||
*/
|
||||
public function run($route, $params = [])
|
||||
{
|
||||
$pos = strpos($route, '/');
|
||||
if ($pos === false) {
|
||||
return $this->runAction($route, $params);
|
||||
} elseif ($pos > 0) {
|
||||
return $this->module->runAction($route, $params);
|
||||
}
|
||||
|
||||
return Yii::$app->runAction(ltrim($route, '/'), $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the parameters to the action.
|
||||
* This method is invoked by [[Action]] when it begins to run with the given parameters.
|
||||
* @param Action $action the action to be bound with parameters.
|
||||
* @param array $params the parameters to be bound to the action.
|
||||
* @return array the valid parameters that the action can run with.
|
||||
*/
|
||||
public function bindActionParams($action, $params)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an action based on the given action ID.
|
||||
* The method first checks if the action ID has been declared in [[actions()]]. If so,
|
||||
* it will use the configuration declared there to create the action object.
|
||||
* If not, it will look for a controller method whose name is in the format of `actionXyz`
|
||||
* where `Xyz` stands for the action ID. If found, an [[InlineAction]] representing that
|
||||
* method will be created and returned.
|
||||
* @param string $id the action ID.
|
||||
* @return Action|null the newly created action instance. Null if the ID doesn't resolve into any action.
|
||||
*/
|
||||
public function createAction($id)
|
||||
{
|
||||
if ($id === '') {
|
||||
$id = $this->defaultAction;
|
||||
}
|
||||
|
||||
$actionMap = $this->actions();
|
||||
if (isset($actionMap[$id])) {
|
||||
return Yii::createObject($actionMap[$id], [$id, $this]);
|
||||
} elseif (preg_match('/^[a-z0-9\\-_]+$/', $id) && strpos($id, '--') === false && trim($id, '-') === $id) {
|
||||
$methodName = 'action' . str_replace(' ', '', ucwords(implode(' ', explode('-', $id))));
|
||||
if (method_exists($this, $methodName)) {
|
||||
$method = new \ReflectionMethod($this, $methodName);
|
||||
if ($method->isPublic() && $method->getName() === $methodName) {
|
||||
return new InlineAction($id, $this, $methodName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is invoked right before an action is executed.
|
||||
*
|
||||
* The method will trigger the [[EVENT_BEFORE_ACTION]] event. The return value of the method
|
||||
* will determine whether the action should continue to run.
|
||||
*
|
||||
* In case the action should not run, the request should be handled inside of the `beforeAction` code
|
||||
* by either providing the necessary output or redirecting the request. Otherwise the response will be empty.
|
||||
*
|
||||
* If you override this method, your code should look like the following:
|
||||
*
|
||||
* ```php
|
||||
* public function beforeAction($action)
|
||||
* {
|
||||
* // your custom code here, if you want the code to run before action filters,
|
||||
* // which are triggered on the [[EVENT_BEFORE_ACTION]] event, e.g. PageCache or AccessControl
|
||||
*
|
||||
* if (!parent::beforeAction($action)) {
|
||||
* return false;
|
||||
* }
|
||||
*
|
||||
* // other custom code here
|
||||
*
|
||||
* return true; // or false to not run the action
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param Action $action the action to be executed.
|
||||
* @return bool whether the action should continue to run.
|
||||
*/
|
||||
public function beforeAction($action)
|
||||
{
|
||||
$event = new ActionEvent($action);
|
||||
$this->trigger(self::EVENT_BEFORE_ACTION, $event);
|
||||
return $event->isValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is invoked right after an action is executed.
|
||||
*
|
||||
* The method will trigger the [[EVENT_AFTER_ACTION]] event. The return value of the method
|
||||
* will be used as the action return value.
|
||||
*
|
||||
* If you override this method, your code should look like the following:
|
||||
*
|
||||
* ```php
|
||||
* public function afterAction($action, $result)
|
||||
* {
|
||||
* $result = parent::afterAction($action, $result);
|
||||
* // your custom code here
|
||||
* return $result;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param Action $action the action just executed.
|
||||
* @param mixed $result the action return result.
|
||||
* @return mixed the processed action result.
|
||||
*/
|
||||
public function afterAction($action, $result)
|
||||
{
|
||||
$event = new ActionEvent($action);
|
||||
$event->result = $result;
|
||||
$this->trigger(self::EVENT_AFTER_ACTION, $event);
|
||||
return $event->result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all ancestor modules of this controller.
|
||||
* The first module in the array is the outermost one (i.e., the application instance),
|
||||
* while the last is the innermost one.
|
||||
* @return Module[] all ancestor modules that this controller is located within.
|
||||
*/
|
||||
public function getModules()
|
||||
{
|
||||
$modules = [$this->module];
|
||||
$module = $this->module;
|
||||
while ($module->module !== null) {
|
||||
array_unshift($modules, $module->module);
|
||||
$module = $module->module;
|
||||
}
|
||||
|
||||
return $modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique ID of the controller.
|
||||
* @return string the controller ID that is prefixed with the module ID (if any).
|
||||
*/
|
||||
public function getUniqueId()
|
||||
{
|
||||
return $this->module instanceof Application ? $this->id : $this->module->getUniqueId() . '/' . $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the route of the current request.
|
||||
* @return string the route (module ID, controller ID and action ID) of the current request.
|
||||
*/
|
||||
public function getRoute()
|
||||
{
|
||||
return $this->action !== null ? $this->action->getUniqueId() : $this->getUniqueId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a view and applies layout if available.
|
||||
*
|
||||
* The view to be rendered can be specified in one of the following formats:
|
||||
*
|
||||
* - [path alias](guide:concept-aliases) (e.g. "@app/views/site/index");
|
||||
* - absolute path within application (e.g. "//site/index"): the view name starts with double slashes.
|
||||
* The actual view file will be looked for under the [[Application::viewPath|view path]] of the application.
|
||||
* - absolute path within module (e.g. "/site/index"): the view name starts with a single slash.
|
||||
* The actual view file will be looked for under the [[Module::viewPath|view path]] of [[module]].
|
||||
* - relative path (e.g. "index"): the actual view file will be looked for under [[viewPath]].
|
||||
*
|
||||
* To determine which layout should be applied, the following two steps are conducted:
|
||||
*
|
||||
* 1. In the first step, it determines the layout name and the context module:
|
||||
*
|
||||
* - If [[layout]] is specified as a string, use it as the layout name and [[module]] as the context module;
|
||||
* - If [[layout]] is null, search through all ancestor modules of this controller and find the first
|
||||
* module whose [[Module::layout|layout]] is not null. The layout and the corresponding module
|
||||
* are used as the layout name and the context module, respectively. If such a module is not found
|
||||
* or the corresponding layout is not a string, it will return false, meaning no applicable layout.
|
||||
*
|
||||
* 2. In the second step, it determines the actual layout file according to the previously found layout name
|
||||
* and context module. The layout name can be:
|
||||
*
|
||||
* - a [path alias](guide:concept-aliases) (e.g. "@app/views/layouts/main");
|
||||
* - an absolute path (e.g. "/main"): the layout name starts with a slash. The actual layout file will be
|
||||
* looked for under the [[Application::layoutPath|layout path]] of the application;
|
||||
* - a relative path (e.g. "main"): the actual layout file will be looked for under the
|
||||
* [[Module::layoutPath|layout path]] of the context module.
|
||||
*
|
||||
* If the layout name does not contain a file extension, it will use the default one `.php`.
|
||||
*
|
||||
* @param string $view the view name.
|
||||
* @param array $params the parameters (name-value pairs) that should be made available in the view.
|
||||
* These parameters will not be available in the layout.
|
||||
* @return string the rendering result.
|
||||
* @throws InvalidArgumentException if the view file or the layout file does not exist.
|
||||
*/
|
||||
public function render($view, $params = [])
|
||||
{
|
||||
$content = $this->getView()->render($view, $params, $this);
|
||||
return $this->renderContent($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a static string by applying a layout.
|
||||
* @param string $content the static string being rendered
|
||||
* @return string the rendering result of the layout with the given static string as the `$content` variable.
|
||||
* If the layout is disabled, the string will be returned back.
|
||||
* @since 2.0.1
|
||||
*/
|
||||
public function renderContent($content)
|
||||
{
|
||||
$layoutFile = $this->findLayoutFile($this->getView());
|
||||
if ($layoutFile !== false) {
|
||||
return $this->getView()->renderFile($layoutFile, ['content' => $content], $this);
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a view without applying layout.
|
||||
* This method differs from [[render()]] in that it does not apply any layout.
|
||||
* @param string $view the view name. Please refer to [[render()]] on how to specify a view name.
|
||||
* @param array $params the parameters (name-value pairs) that should be made available in the view.
|
||||
* @return string the rendering result.
|
||||
* @throws InvalidArgumentException if the view file does not exist.
|
||||
*/
|
||||
public function renderPartial($view, $params = [])
|
||||
{
|
||||
return $this->getView()->render($view, $params, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a view file.
|
||||
* @param string $file the view file to be rendered. This can be either a file path or a [path alias](guide:concept-aliases).
|
||||
* @param array $params the parameters (name-value pairs) that should be made available in the view.
|
||||
* @return string the rendering result.
|
||||
* @throws InvalidArgumentException if the view file does not exist.
|
||||
*/
|
||||
public function renderFile($file, $params = [])
|
||||
{
|
||||
return $this->getView()->renderFile($file, $params, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the view object that can be used to render views or view files.
|
||||
* The [[render()]], [[renderPartial()]] and [[renderFile()]] methods will use
|
||||
* this view object to implement the actual view rendering.
|
||||
* If not set, it will default to the "view" application component.
|
||||
* @return View|\yii\web\View the view object that can be used to render views or view files.
|
||||
*/
|
||||
public function getView()
|
||||
{
|
||||
if ($this->_view === null) {
|
||||
$this->_view = Yii::$app->getView();
|
||||
}
|
||||
|
||||
return $this->_view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the view object to be used by this controller.
|
||||
* @param View|\yii\web\View $view the view object that can be used to render views or view files.
|
||||
*/
|
||||
public function setView($view)
|
||||
{
|
||||
$this->_view = $view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the directory containing view files for this controller.
|
||||
* The default implementation returns the directory named as controller [[id]] under the [[module]]'s
|
||||
* [[viewPath]] directory.
|
||||
* @return string the directory containing the view files for this controller.
|
||||
*/
|
||||
public function getViewPath()
|
||||
{
|
||||
if ($this->_viewPath === null) {
|
||||
$this->_viewPath = $this->module->getViewPath() . DIRECTORY_SEPARATOR . $this->id;
|
||||
}
|
||||
|
||||
return $this->_viewPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the directory that contains the view files.
|
||||
* @param string $path the root directory of view files.
|
||||
* @throws InvalidArgumentException if the directory is invalid
|
||||
* @since 2.0.7
|
||||
*/
|
||||
public function setViewPath($path)
|
||||
{
|
||||
$this->_viewPath = Yii::getAlias($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the applicable layout file.
|
||||
* @param View $view the view object to render the layout file.
|
||||
* @return string|bool the layout file path, or false if layout is not needed.
|
||||
* Please refer to [[render()]] on how to specify this parameter.
|
||||
* @throws InvalidArgumentException if an invalid path alias is used to specify the layout.
|
||||
*/
|
||||
public function findLayoutFile($view)
|
||||
{
|
||||
$module = $this->module;
|
||||
if (is_string($this->layout)) {
|
||||
$layout = $this->layout;
|
||||
} elseif ($this->layout === null) {
|
||||
while ($module !== null && $module->layout === null) {
|
||||
$module = $module->module;
|
||||
}
|
||||
if ($module !== null && is_string($module->layout)) {
|
||||
$layout = $module->layout;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($layout)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strncmp($layout, '@', 1) === 0) {
|
||||
$file = Yii::getAlias($layout);
|
||||
} elseif (strncmp($layout, '/', 1) === 0) {
|
||||
$file = Yii::$app->getLayoutPath() . DIRECTORY_SEPARATOR . substr($layout, 1);
|
||||
} else {
|
||||
$file = $module->getLayoutPath() . DIRECTORY_SEPARATOR . $layout;
|
||||
}
|
||||
|
||||
if (pathinfo($file, PATHINFO_EXTENSION) !== '') {
|
||||
return $file;
|
||||
}
|
||||
$path = $file . '.' . $view->defaultExtension;
|
||||
if ($view->defaultExtension !== 'php' && !is_file($path)) {
|
||||
$path = $file . '.php';
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
40
vendor/yiisoft/yii2/base/DynamicContentAwareInterface.php
vendored
Normal file
40
vendor/yiisoft/yii2/base/DynamicContentAwareInterface.php
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* DynamicContentAwareInterface is the interface that should be implemented by classes
|
||||
* which support a [[View]] dynamic content feature.
|
||||
*
|
||||
* @author Sergey Makinen <sergey@makinen.ru>
|
||||
* @since 2.0.14
|
||||
*/
|
||||
interface DynamicContentAwareInterface
|
||||
{
|
||||
/**
|
||||
* Returns a list of placeholders for dynamic content. This method
|
||||
* is used internally to implement the content caching feature.
|
||||
* @return array a list of placeholders.
|
||||
*/
|
||||
public function getDynamicPlaceholders();
|
||||
|
||||
/**
|
||||
* Sets a list of placeholders for dynamic content. This method
|
||||
* is used internally to implement the content caching feature.
|
||||
* @param array $placeholders a list of placeholders.
|
||||
*/
|
||||
public function setDynamicPlaceholders($placeholders);
|
||||
|
||||
/**
|
||||
* Adds a placeholder for dynamic content.
|
||||
* This method is used internally to implement the content caching feature.
|
||||
* @param string $name the placeholder name.
|
||||
* @param string $statements the PHP statements for generating the dynamic content.
|
||||
*/
|
||||
public function addDynamicPlaceholder($name, $statements);
|
||||
}
|
||||
83
vendor/yiisoft/yii2/base/DynamicContentAwareTrait.php
vendored
Normal file
83
vendor/yiisoft/yii2/base/DynamicContentAwareTrait.php
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* DynamicContentAwareTrait implements common methods for classes
|
||||
* which support a [[View]] dynamic content feature.
|
||||
*
|
||||
* @author Sergey Makinen <sergey@makinen.ru>
|
||||
* @since 2.0.14
|
||||
*/
|
||||
trait DynamicContentAwareTrait
|
||||
{
|
||||
/**
|
||||
* @var string[] a list of placeholders for dynamic content
|
||||
*/
|
||||
private $_dynamicPlaceholders;
|
||||
|
||||
/**
|
||||
* Returns the view object that can be used to render views or view files using dynamic contents.
|
||||
* @return View the view object that can be used to render views or view files.
|
||||
*/
|
||||
abstract protected function getView();
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDynamicPlaceholders()
|
||||
{
|
||||
return $this->_dynamicPlaceholders;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setDynamicPlaceholders($placeholders)
|
||||
{
|
||||
$this->_dynamicPlaceholders = $placeholders;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addDynamicPlaceholder($name, $statements)
|
||||
{
|
||||
$this->_dynamicPlaceholders[$name] = $statements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces placeholders in $content with results of evaluated dynamic statements.
|
||||
* @param string $content content to be parsed.
|
||||
* @param string[] $placeholders placeholders and their values.
|
||||
* @param bool $isRestoredFromCache whether content is going to be restored from cache.
|
||||
* @return string final content.
|
||||
*/
|
||||
protected function updateDynamicContent($content, $placeholders, $isRestoredFromCache = false)
|
||||
{
|
||||
if (empty($placeholders) || !is_array($placeholders)) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
if (count($this->getView()->getDynamicContents()) === 0) {
|
||||
// outermost cache: replace placeholder with dynamic content
|
||||
foreach ($placeholders as $name => $statements) {
|
||||
$placeholders[$name] = $this->getView()->evaluateDynamicContent($statements);
|
||||
}
|
||||
$content = strtr($content, $placeholders);
|
||||
}
|
||||
if ($isRestoredFromCache) {
|
||||
$view = $this->getView();
|
||||
foreach ($placeholders as $name => $statements) {
|
||||
$view->addDynamicPlaceholder($name, $statements);
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
202
vendor/yiisoft/yii2/base/DynamicModel.php
vendored
Normal file
202
vendor/yiisoft/yii2/base/DynamicModel.php
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
use yii\validators\Validator;
|
||||
|
||||
/**
|
||||
* DynamicModel is a model class primarily used to support ad hoc data validation.
|
||||
*
|
||||
* The typical usage of DynamicModel is as follows,
|
||||
*
|
||||
* ```php
|
||||
* public function actionSearch($name, $email)
|
||||
* {
|
||||
* $model = DynamicModel::validateData(compact('name', 'email'), [
|
||||
* [['name', 'email'], 'string', 'max' => 128],
|
||||
* ['email', 'email'],
|
||||
* ]);
|
||||
* if ($model->hasErrors()) {
|
||||
* // validation fails
|
||||
* } else {
|
||||
* // validation succeeds
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The above example shows how to validate `$name` and `$email` with the help of DynamicModel.
|
||||
* The [[validateData()]] method creates an instance of DynamicModel, defines the attributes
|
||||
* using the given data (`name` and `email` in this example), and then calls [[Model::validate()]].
|
||||
*
|
||||
* You can check the validation result by [[hasErrors()]], like you do with a normal model.
|
||||
* You may also access the dynamic attributes defined through the model instance, e.g.,
|
||||
* `$model->name` and `$model->email`.
|
||||
*
|
||||
* Alternatively, you may use the following more "classic" syntax to perform ad-hoc data validation:
|
||||
*
|
||||
* ```php
|
||||
* $model = new DynamicModel(compact('name', 'email'));
|
||||
* $model->addRule(['name', 'email'], 'string', ['max' => 128])
|
||||
* ->addRule('email', 'email')
|
||||
* ->validate();
|
||||
* ```
|
||||
*
|
||||
* DynamicModel implements the above ad-hoc data validation feature by supporting the so-called
|
||||
* "dynamic attributes". It basically allows an attribute to be defined dynamically through its constructor
|
||||
* or [[defineAttribute()]].
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class DynamicModel extends Model
|
||||
{
|
||||
private $_attributes = [];
|
||||
|
||||
|
||||
/**
|
||||
* Constructors.
|
||||
* @param array $attributes the dynamic attributes (name-value pairs, or names) being defined
|
||||
* @param array $config the configuration array to be applied to this object.
|
||||
*/
|
||||
public function __construct(array $attributes = [], $config = [])
|
||||
{
|
||||
foreach ($attributes as $name => $value) {
|
||||
if (is_int($name)) {
|
||||
$this->_attributes[$value] = null;
|
||||
} else {
|
||||
$this->_attributes[$name] = $value;
|
||||
}
|
||||
}
|
||||
parent::__construct($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
if (array_key_exists($name, $this->_attributes)) {
|
||||
return $this->_attributes[$name];
|
||||
}
|
||||
|
||||
return parent::__get($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
if (array_key_exists($name, $this->_attributes)) {
|
||||
$this->_attributes[$name] = $value;
|
||||
} else {
|
||||
parent::__set($name, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __isset($name)
|
||||
{
|
||||
if (array_key_exists($name, $this->_attributes)) {
|
||||
return isset($this->_attributes[$name]);
|
||||
}
|
||||
|
||||
return parent::__isset($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __unset($name)
|
||||
{
|
||||
if (array_key_exists($name, $this->_attributes)) {
|
||||
unset($this->_attributes[$name]);
|
||||
} else {
|
||||
parent::__unset($name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines an attribute.
|
||||
* @param string $name the attribute name
|
||||
* @param mixed $value the attribute value
|
||||
*/
|
||||
public function defineAttribute($name, $value = null)
|
||||
{
|
||||
$this->_attributes[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Undefines an attribute.
|
||||
* @param string $name the attribute name
|
||||
*/
|
||||
public function undefineAttribute($name)
|
||||
{
|
||||
unset($this->_attributes[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a validation rule to this model.
|
||||
* You can also directly manipulate [[validators]] to add or remove validation rules.
|
||||
* This method provides a shortcut.
|
||||
* @param string|array $attributes the attribute(s) to be validated by the rule
|
||||
* @param mixed $validator the validator for the rule.This can be a built-in validator name,
|
||||
* a method name of the model class, an anonymous function, or a validator class name.
|
||||
* @param array $options the options (name-value pairs) to be applied to the validator
|
||||
* @return $this the model itself
|
||||
*/
|
||||
public function addRule($attributes, $validator, $options = [])
|
||||
{
|
||||
$validators = $this->getValidators();
|
||||
$validators->append(Validator::createValidator($validator, $this, (array) $attributes, $options));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the given data with the specified validation rules.
|
||||
* This method will create a DynamicModel instance, populate it with the data to be validated,
|
||||
* create the specified validation rules, and then validate the data using these rules.
|
||||
* @param array $data the data (name-value pairs) to be validated
|
||||
* @param array $rules the validation rules. Please refer to [[Model::rules()]] on the format of this parameter.
|
||||
* @return static the model instance that contains the data being validated
|
||||
* @throws InvalidConfigException if a validation rule is not specified correctly.
|
||||
*/
|
||||
public static function validateData(array $data, $rules = [])
|
||||
{
|
||||
/* @var $model DynamicModel */
|
||||
$model = new static($data);
|
||||
if (!empty($rules)) {
|
||||
$validators = $model->getValidators();
|
||||
foreach ($rules as $rule) {
|
||||
if ($rule instanceof Validator) {
|
||||
$validators->append($rule);
|
||||
} elseif (is_array($rule) && isset($rule[0], $rule[1])) { // attributes, validator type
|
||||
$validator = Validator::createValidator($rule[1], $model, (array) $rule[0], array_slice($rule, 2));
|
||||
$validators->append($validator);
|
||||
} else {
|
||||
throw new InvalidConfigException('Invalid validation rule: a rule must specify both attribute names and validator type.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$model->validate();
|
||||
|
||||
return $model;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function attributes()
|
||||
{
|
||||
return array_keys($this->_attributes);
|
||||
}
|
||||
}
|
||||
114
vendor/yiisoft/yii2/base/ErrorException.php
vendored
Normal file
114
vendor/yiisoft/yii2/base/ErrorException.php
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
use Yii;
|
||||
|
||||
/**
|
||||
* ErrorException represents a PHP error.
|
||||
*
|
||||
* For more details and usage information on ErrorException, see the [guide article on handling errors](guide:runtime-handling-errors).
|
||||
*
|
||||
* @author Alexander Makarov <sam@rmcreative.ru>
|
||||
* @since 2.0
|
||||
*/
|
||||
class ErrorException extends \ErrorException
|
||||
{
|
||||
/**
|
||||
* This constant represents a fatal error in the HHVM engine.
|
||||
*
|
||||
* PHP Zend runtime won't call the error handler on fatals, HHVM will, with an error code of 16777217
|
||||
* We will handle fatal error a bit different on HHVM.
|
||||
* @see https://github.com/facebook/hhvm/blob/master/hphp/runtime/base/runtime-error.h#L62
|
||||
* @since 2.0.6
|
||||
*/
|
||||
const E_HHVM_FATAL_ERROR = 16777217; // E_ERROR | (1 << 24)
|
||||
|
||||
|
||||
/**
|
||||
* Constructs the exception.
|
||||
* @link http://php.net/manual/en/errorexception.construct.php
|
||||
* @param $message [optional]
|
||||
* @param $code [optional]
|
||||
* @param $severity [optional]
|
||||
* @param $filename [optional]
|
||||
* @param $lineno [optional]
|
||||
* @param $previous [optional]
|
||||
*/
|
||||
public function __construct($message = '', $code = 0, $severity = 1, $filename = __FILE__, $lineno = __LINE__, \Exception $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $severity, $filename, $lineno, $previous);
|
||||
|
||||
if (function_exists('xdebug_get_function_stack')) {
|
||||
// XDebug trace can't be modified and used directly with PHP 7
|
||||
// @see https://github.com/yiisoft/yii2/pull/11723
|
||||
$xDebugTrace = array_slice(array_reverse(xdebug_get_function_stack()), 3, -1);
|
||||
$trace = [];
|
||||
foreach ($xDebugTrace as $frame) {
|
||||
if (!isset($frame['function'])) {
|
||||
$frame['function'] = 'unknown';
|
||||
}
|
||||
|
||||
// XDebug < 2.1.1: http://bugs.xdebug.org/view.php?id=695
|
||||
if (!isset($frame['type']) || $frame['type'] === 'static') {
|
||||
$frame['type'] = '::';
|
||||
} elseif ($frame['type'] === 'dynamic') {
|
||||
$frame['type'] = '->';
|
||||
}
|
||||
|
||||
// XDebug has a different key name
|
||||
if (isset($frame['params']) && !isset($frame['args'])) {
|
||||
$frame['args'] = $frame['params'];
|
||||
}
|
||||
$trace[] = $frame;
|
||||
}
|
||||
|
||||
$ref = new \ReflectionProperty('Exception', 'trace');
|
||||
$ref->setAccessible(true);
|
||||
$ref->setValue($this, $trace);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if error is one of fatal type.
|
||||
*
|
||||
* @param array $error error got from error_get_last()
|
||||
* @return bool if error is one of fatal type
|
||||
*/
|
||||
public static function isFatalError($error)
|
||||
{
|
||||
return isset($error['type']) && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING, self::E_HHVM_FATAL_ERROR]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the user-friendly name of this exception
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
static $names = [
|
||||
E_COMPILE_ERROR => 'PHP Compile Error',
|
||||
E_COMPILE_WARNING => 'PHP Compile Warning',
|
||||
E_CORE_ERROR => 'PHP Core Error',
|
||||
E_CORE_WARNING => 'PHP Core Warning',
|
||||
E_DEPRECATED => 'PHP Deprecated Warning',
|
||||
E_ERROR => 'PHP Fatal Error',
|
||||
E_NOTICE => 'PHP Notice',
|
||||
E_PARSE => 'PHP Parse Error',
|
||||
E_RECOVERABLE_ERROR => 'PHP Recoverable Error',
|
||||
E_STRICT => 'PHP Strict Warning',
|
||||
E_USER_DEPRECATED => 'PHP User Deprecated Warning',
|
||||
E_USER_ERROR => 'PHP User Error',
|
||||
E_USER_NOTICE => 'PHP User Notice',
|
||||
E_USER_WARNING => 'PHP User Warning',
|
||||
E_WARNING => 'PHP Warning',
|
||||
self::E_HHVM_FATAL_ERROR => 'HHVM Fatal Error',
|
||||
];
|
||||
|
||||
return isset($names[$this->getCode()]) ? $names[$this->getCode()] : 'Error';
|
||||
}
|
||||
}
|
||||
360
vendor/yiisoft/yii2/base/ErrorHandler.php
vendored
Normal file
360
vendor/yiisoft/yii2/base/ErrorHandler.php
vendored
Normal file
@@ -0,0 +1,360 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
use Yii;
|
||||
use yii\helpers\VarDumper;
|
||||
use yii\web\HttpException;
|
||||
|
||||
/**
|
||||
* ErrorHandler handles uncaught PHP errors and exceptions.
|
||||
*
|
||||
* ErrorHandler is configured as an application component in [[\yii\base\Application]] by default.
|
||||
* You can access that instance via `Yii::$app->errorHandler`.
|
||||
*
|
||||
* For more details and usage information on ErrorHandler, see the [guide article on handling errors](guide:runtime-handling-errors).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @author Alexander Makarov <sam@rmcreative.ru>
|
||||
* @author Carsten Brandt <mail@cebe.cc>
|
||||
* @since 2.0
|
||||
*/
|
||||
abstract class ErrorHandler extends Component
|
||||
{
|
||||
/**
|
||||
* @var bool whether to discard any existing page output before error display. Defaults to true.
|
||||
*/
|
||||
public $discardExistingOutput = true;
|
||||
/**
|
||||
* @var int the size of the reserved memory. A portion of memory is pre-allocated so that
|
||||
* when an out-of-memory issue occurs, the error handler is able to handle the error with
|
||||
* the help of this reserved memory. If you set this value to be 0, no memory will be reserved.
|
||||
* Defaults to 256KB.
|
||||
*/
|
||||
public $memoryReserveSize = 262144;
|
||||
/**
|
||||
* @var \Exception|null the exception that is being handled currently.
|
||||
*/
|
||||
public $exception;
|
||||
|
||||
/**
|
||||
* @var string Used to reserve memory for fatal error handler.
|
||||
*/
|
||||
private $_memoryReserve;
|
||||
/**
|
||||
* @var \Exception from HHVM error that stores backtrace
|
||||
*/
|
||||
private $_hhvmException;
|
||||
|
||||
|
||||
/**
|
||||
* Register this error handler.
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
ini_set('display_errors', false);
|
||||
set_exception_handler([$this, 'handleException']);
|
||||
if (defined('HHVM_VERSION')) {
|
||||
set_error_handler([$this, 'handleHhvmError']);
|
||||
} else {
|
||||
set_error_handler([$this, 'handleError']);
|
||||
}
|
||||
if ($this->memoryReserveSize > 0) {
|
||||
$this->_memoryReserve = str_repeat('x', $this->memoryReserveSize);
|
||||
}
|
||||
register_shutdown_function([$this, 'handleFatalError']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters this error handler by restoring the PHP error and exception handlers.
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles uncaught PHP exceptions.
|
||||
*
|
||||
* This method is implemented as a PHP exception handler.
|
||||
*
|
||||
* @param \Exception $exception the exception that is not caught
|
||||
*/
|
||||
public function handleException($exception)
|
||||
{
|
||||
if ($exception instanceof ExitException) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->exception = $exception;
|
||||
|
||||
// disable error capturing to avoid recursive errors while handling exceptions
|
||||
$this->unregister();
|
||||
|
||||
// set preventive HTTP status code to 500 in case error handling somehow fails and headers are sent
|
||||
// HTTP exceptions will override this value in renderException()
|
||||
if (PHP_SAPI !== 'cli') {
|
||||
http_response_code(500);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->logException($exception);
|
||||
if ($this->discardExistingOutput) {
|
||||
$this->clearOutput();
|
||||
}
|
||||
$this->renderException($exception);
|
||||
if (!YII_ENV_TEST) {
|
||||
\Yii::getLogger()->flush(true);
|
||||
if (defined('HHVM_VERSION')) {
|
||||
flush();
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// an other exception could be thrown while displaying the exception
|
||||
$this->handleFallbackExceptionMessage($e, $exception);
|
||||
} catch (\Throwable $e) {
|
||||
// additional check for \Throwable introduced in PHP 7
|
||||
$this->handleFallbackExceptionMessage($e, $exception);
|
||||
}
|
||||
|
||||
$this->exception = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles exception thrown during exception processing in [[handleException()]].
|
||||
* @param \Exception|\Throwable $exception Exception that was thrown during main exception processing.
|
||||
* @param \Exception $previousException Main exception processed in [[handleException()]].
|
||||
* @since 2.0.11
|
||||
*/
|
||||
protected function handleFallbackExceptionMessage($exception, $previousException)
|
||||
{
|
||||
$msg = "An Error occurred while handling another error:\n";
|
||||
$msg .= (string) $exception;
|
||||
$msg .= "\nPrevious exception:\n";
|
||||
$msg .= (string) $previousException;
|
||||
if (YII_DEBUG) {
|
||||
if (PHP_SAPI === 'cli') {
|
||||
echo $msg . "\n";
|
||||
} else {
|
||||
echo '<pre>' . htmlspecialchars($msg, ENT_QUOTES, Yii::$app->charset) . '</pre>';
|
||||
}
|
||||
} else {
|
||||
echo 'An internal server error occurred.';
|
||||
}
|
||||
$msg .= "\n\$_SERVER = " . VarDumper::export($_SERVER);
|
||||
error_log($msg);
|
||||
if (defined('HHVM_VERSION')) {
|
||||
flush();
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles HHVM execution errors such as warnings and notices.
|
||||
*
|
||||
* This method is used as a HHVM error handler. It will store exception that will
|
||||
* be used in fatal error handler
|
||||
*
|
||||
* @param int $code the level of the error raised.
|
||||
* @param string $message the error message.
|
||||
* @param string $file the filename that the error was raised in.
|
||||
* @param int $line the line number the error was raised at.
|
||||
* @param mixed $context
|
||||
* @param mixed $backtrace trace of error
|
||||
* @return bool whether the normal error handler continues.
|
||||
*
|
||||
* @throws ErrorException
|
||||
* @since 2.0.6
|
||||
*/
|
||||
public function handleHhvmError($code, $message, $file, $line, $context, $backtrace)
|
||||
{
|
||||
if ($this->handleError($code, $message, $file, $line)) {
|
||||
return true;
|
||||
}
|
||||
if (E_ERROR & $code) {
|
||||
$exception = new ErrorException($message, $code, $code, $file, $line);
|
||||
$ref = new \ReflectionProperty('\Exception', 'trace');
|
||||
$ref->setAccessible(true);
|
||||
$ref->setValue($exception, $backtrace);
|
||||
$this->_hhvmException = $exception;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles PHP execution errors such as warnings and notices.
|
||||
*
|
||||
* This method is used as a PHP error handler. It will simply raise an [[ErrorException]].
|
||||
*
|
||||
* @param int $code the level of the error raised.
|
||||
* @param string $message the error message.
|
||||
* @param string $file the filename that the error was raised in.
|
||||
* @param int $line the line number the error was raised at.
|
||||
* @return bool whether the normal error handler continues.
|
||||
*
|
||||
* @throws ErrorException
|
||||
*/
|
||||
public function handleError($code, $message, $file, $line)
|
||||
{
|
||||
if (error_reporting() & $code) {
|
||||
// load ErrorException manually here because autoloading them will not work
|
||||
// when error occurs while autoloading a class
|
||||
if (!class_exists('yii\\base\\ErrorException', false)) {
|
||||
require_once __DIR__ . '/ErrorException.php';
|
||||
}
|
||||
$exception = new ErrorException($message, $code, $code, $file, $line);
|
||||
|
||||
// in case error appeared in __toString method we can't throw any exception
|
||||
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
array_shift($trace);
|
||||
foreach ($trace as $frame) {
|
||||
if ($frame['function'] === '__toString') {
|
||||
$this->handleException($exception);
|
||||
if (defined('HHVM_VERSION')) {
|
||||
flush();
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles fatal PHP errors.
|
||||
*/
|
||||
public function handleFatalError()
|
||||
{
|
||||
unset($this->_memoryReserve);
|
||||
|
||||
// load ErrorException manually here because autoloading them will not work
|
||||
// when error occurs while autoloading a class
|
||||
if (!class_exists('yii\\base\\ErrorException', false)) {
|
||||
require_once __DIR__ . '/ErrorException.php';
|
||||
}
|
||||
|
||||
$error = error_get_last();
|
||||
|
||||
if (ErrorException::isFatalError($error)) {
|
||||
if (!empty($this->_hhvmException)) {
|
||||
$exception = $this->_hhvmException;
|
||||
} else {
|
||||
$exception = new ErrorException($error['message'], $error['type'], $error['type'], $error['file'], $error['line']);
|
||||
}
|
||||
$this->exception = $exception;
|
||||
|
||||
$this->logException($exception);
|
||||
|
||||
if ($this->discardExistingOutput) {
|
||||
$this->clearOutput();
|
||||
}
|
||||
$this->renderException($exception);
|
||||
|
||||
// need to explicitly flush logs because exit() next will terminate the app immediately
|
||||
Yii::getLogger()->flush(true);
|
||||
if (defined('HHVM_VERSION')) {
|
||||
flush();
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the exception.
|
||||
* @param \Exception $exception the exception to be rendered.
|
||||
*/
|
||||
abstract protected function renderException($exception);
|
||||
|
||||
/**
|
||||
* Logs the given exception.
|
||||
* @param \Exception $exception the exception to be logged
|
||||
* @since 2.0.3 this method is now public.
|
||||
*/
|
||||
public function logException($exception)
|
||||
{
|
||||
$category = get_class($exception);
|
||||
if ($exception instanceof HttpException) {
|
||||
$category = 'yii\\web\\HttpException:' . $exception->statusCode;
|
||||
} elseif ($exception instanceof \ErrorException) {
|
||||
$category .= ':' . $exception->getSeverity();
|
||||
}
|
||||
Yii::error($exception, $category);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all output echoed before calling this method.
|
||||
*/
|
||||
public function clearOutput()
|
||||
{
|
||||
// the following manual level counting is to deal with zlib.output_compression set to On
|
||||
for ($level = ob_get_level(); $level > 0; --$level) {
|
||||
if (!@ob_end_clean()) {
|
||||
ob_clean();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an exception into a PHP error.
|
||||
*
|
||||
* This method can be used to convert exceptions inside of methods like `__toString()`
|
||||
* to PHP errors because exceptions cannot be thrown inside of them.
|
||||
* @param \Exception $exception the exception to convert to a PHP error.
|
||||
*/
|
||||
public static function convertExceptionToError($exception)
|
||||
{
|
||||
trigger_error(static::convertExceptionToString($exception), E_USER_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an exception into a simple string.
|
||||
* @param \Exception|\Error $exception the exception being converted
|
||||
* @return string the string representation of the exception.
|
||||
*/
|
||||
public static function convertExceptionToString($exception)
|
||||
{
|
||||
if ($exception instanceof UserException) {
|
||||
return "{$exception->getName()}: {$exception->getMessage()}";
|
||||
}
|
||||
|
||||
if (YII_DEBUG) {
|
||||
return static::convertExceptionToVerboseString($exception);
|
||||
}
|
||||
|
||||
return 'An internal server error occurred.';
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an exception into a string that has verbose information about the exception and its trace.
|
||||
* @param \Exception|\Error $exception the exception being converted
|
||||
* @return string the string representation of the exception.
|
||||
*
|
||||
* @since 2.0.14
|
||||
*/
|
||||
public static function convertExceptionToVerboseString($exception)
|
||||
{
|
||||
if ($exception instanceof Exception) {
|
||||
$message = "Exception ({$exception->getName()})";
|
||||
} elseif ($exception instanceof ErrorException) {
|
||||
$message = (string)$exception->getName();
|
||||
} else {
|
||||
$message = 'Exception';
|
||||
}
|
||||
$message .= " '" . get_class($exception) . "' with message '{$exception->getMessage()}' \n\nin "
|
||||
. $exception->getFile() . ':' . $exception->getLine() . "\n\n"
|
||||
. "Stack trace:\n" . $exception->getTraceAsString();
|
||||
|
||||
return $message;
|
||||
}
|
||||
}
|
||||
317
vendor/yiisoft/yii2/base/Event.php
vendored
Normal file
317
vendor/yiisoft/yii2/base/Event.php
vendored
Normal file
@@ -0,0 +1,317 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
use yii\helpers\StringHelper;
|
||||
|
||||
/**
|
||||
* Event is the base class for all event classes.
|
||||
*
|
||||
* It encapsulates the parameters associated with an event.
|
||||
* The [[sender]] property describes who raises the event.
|
||||
* And the [[handled]] property indicates if the event is handled.
|
||||
* If an event handler sets [[handled]] to be `true`, the rest of the
|
||||
* uninvoked handlers will no longer be called to handle the event.
|
||||
*
|
||||
* Additionally, when attaching an event handler, extra data may be passed
|
||||
* and be available via the [[data]] property when the event handler is invoked.
|
||||
*
|
||||
* For more details and usage information on Event, see the [guide article on events](guide:concept-events).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class Event extends BaseObject
|
||||
{
|
||||
/**
|
||||
* @var string the event name. This property is set by [[Component::trigger()]] and [[trigger()]].
|
||||
* Event handlers may use this property to check what event it is handling.
|
||||
*/
|
||||
public $name;
|
||||
/**
|
||||
* @var object the sender of this event. If not set, this property will be
|
||||
* set as the object whose `trigger()` method is called.
|
||||
* This property may also be a `null` when this event is a
|
||||
* class-level event which is triggered in a static context.
|
||||
*/
|
||||
public $sender;
|
||||
/**
|
||||
* @var bool whether the event is handled. Defaults to `false`.
|
||||
* When a handler sets this to be `true`, the event processing will stop and
|
||||
* ignore the rest of the uninvoked event handlers.
|
||||
*/
|
||||
public $handled = false;
|
||||
/**
|
||||
* @var mixed the data that is passed to [[Component::on()]] when attaching an event handler.
|
||||
* Note that this varies according to which event handler is currently executing.
|
||||
*/
|
||||
public $data;
|
||||
|
||||
/**
|
||||
* @var array contains all globally registered event handlers.
|
||||
*/
|
||||
private static $_events = [];
|
||||
/**
|
||||
* @var array the globally registered event handlers attached for wildcard patterns (event name wildcard => handlers)
|
||||
* @since 2.0.14
|
||||
*/
|
||||
private static $_eventWildcards = [];
|
||||
|
||||
|
||||
/**
|
||||
* Attaches an event handler to a class-level event.
|
||||
*
|
||||
* When a class-level event is triggered, event handlers attached
|
||||
* to that class and all parent classes will be invoked.
|
||||
*
|
||||
* For example, the following code attaches an event handler to `ActiveRecord`'s
|
||||
* `afterInsert` event:
|
||||
*
|
||||
* ```php
|
||||
* Event::on(ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT, function ($event) {
|
||||
* Yii::trace(get_class($event->sender) . ' is inserted.');
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* The handler will be invoked for EVERY successful ActiveRecord insertion.
|
||||
*
|
||||
* Since 2.0.14 you can specify either class name or event name as a wildcard pattern:
|
||||
*
|
||||
* ```php
|
||||
* Event::on('app\models\db\*', '*Insert', function ($event) {
|
||||
* Yii::trace(get_class($event->sender) . ' is inserted.');
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* For more details about how to declare an event handler, please refer to [[Component::on()]].
|
||||
*
|
||||
* @param string $class the fully qualified class name to which the event handler needs to attach.
|
||||
* @param string $name the event name.
|
||||
* @param callable $handler the event handler.
|
||||
* @param mixed $data the data to be passed to the event handler when the event is triggered.
|
||||
* When the event handler is invoked, this data can be accessed via [[Event::data]].
|
||||
* @param bool $append whether to append new event handler to the end of the existing
|
||||
* handler list. If `false`, the new handler will be inserted at the beginning of the existing
|
||||
* handler list.
|
||||
* @see off()
|
||||
*/
|
||||
public static function on($class, $name, $handler, $data = null, $append = true)
|
||||
{
|
||||
$class = ltrim($class, '\\');
|
||||
|
||||
if (strpos($class, '*') !== false || strpos($name, '*') !== false) {
|
||||
if ($append || empty(self::$_eventWildcards[$name][$class])) {
|
||||
self::$_eventWildcards[$name][$class][] = [$handler, $data];
|
||||
} else {
|
||||
array_unshift(self::$_eventWildcards[$name][$class], [$handler, $data]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ($append || empty(self::$_events[$name][$class])) {
|
||||
self::$_events[$name][$class][] = [$handler, $data];
|
||||
} else {
|
||||
array_unshift(self::$_events[$name][$class], [$handler, $data]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detaches an event handler from a class-level event.
|
||||
*
|
||||
* This method is the opposite of [[on()]].
|
||||
*
|
||||
* Note: in case wildcard pattern is passed for class name or event name, only the handlers registered with this
|
||||
* wildcard will be removed, while handlers registered with plain names matching this wildcard will remain.
|
||||
*
|
||||
* @param string $class the fully qualified class name from which the event handler needs to be detached.
|
||||
* @param string $name the event name.
|
||||
* @param callable $handler the event handler to be removed.
|
||||
* If it is `null`, all handlers attached to the named event will be removed.
|
||||
* @return bool whether a handler is found and detached.
|
||||
* @see on()
|
||||
*/
|
||||
public static function off($class, $name, $handler = null)
|
||||
{
|
||||
$class = ltrim($class, '\\');
|
||||
if (empty(self::$_events[$name][$class]) && empty(self::$_eventWildcards[$name][$class])) {
|
||||
return false;
|
||||
}
|
||||
if ($handler === null) {
|
||||
unset(self::$_events[$name][$class]);
|
||||
unset(self::$_eventWildcards[$name][$class]);
|
||||
return true;
|
||||
}
|
||||
|
||||
// plain event names
|
||||
if (isset(self::$_events[$name][$class])) {
|
||||
$removed = false;
|
||||
foreach (self::$_events[$name][$class] as $i => $event) {
|
||||
if ($event[0] === $handler) {
|
||||
unset(self::$_events[$name][$class][$i]);
|
||||
$removed = true;
|
||||
}
|
||||
}
|
||||
if ($removed) {
|
||||
self::$_events[$name][$class] = array_values(self::$_events[$name][$class]);
|
||||
return $removed;
|
||||
}
|
||||
}
|
||||
|
||||
// wildcard event names
|
||||
$removed = false;
|
||||
foreach (self::$_eventWildcards[$name][$class] as $i => $event) {
|
||||
if ($event[0] === $handler) {
|
||||
unset(self::$_eventWildcards[$name][$class][$i]);
|
||||
$removed = true;
|
||||
}
|
||||
}
|
||||
if ($removed) {
|
||||
self::$_eventWildcards[$name][$class] = array_values(self::$_eventWildcards[$name][$class]);
|
||||
// remove empty wildcards to save future redundant regex checks :
|
||||
if (empty(self::$_eventWildcards[$name][$class])) {
|
||||
unset(self::$_eventWildcards[$name][$class]);
|
||||
if (empty(self::$_eventWildcards[$name])) {
|
||||
unset(self::$_eventWildcards[$name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $removed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detaches all registered class-level event handlers.
|
||||
* @see on()
|
||||
* @see off()
|
||||
* @since 2.0.10
|
||||
*/
|
||||
public static function offAll()
|
||||
{
|
||||
self::$_events = [];
|
||||
self::$_eventWildcards = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value indicating whether there is any handler attached to the specified class-level event.
|
||||
* Note that this method will also check all parent classes to see if there is any handler attached
|
||||
* to the named event.
|
||||
* @param string|object $class the object or the fully qualified class name specifying the class-level event.
|
||||
* @param string $name the event name.
|
||||
* @return bool whether there is any handler attached to the event.
|
||||
*/
|
||||
public static function hasHandlers($class, $name)
|
||||
{
|
||||
if (empty(self::$_eventWildcards) && empty(self::$_events[$name])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_object($class)) {
|
||||
$class = get_class($class);
|
||||
} else {
|
||||
$class = ltrim($class, '\\');
|
||||
}
|
||||
|
||||
$classes = array_merge(
|
||||
[$class],
|
||||
class_parents($class, true),
|
||||
class_implements($class, true)
|
||||
);
|
||||
|
||||
// regular events
|
||||
foreach ($classes as $class) {
|
||||
if (!empty(self::$_events[$name][$class])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// wildcard events
|
||||
foreach (self::$_eventWildcards as $nameWildcard => $classHandlers) {
|
||||
if (!StringHelper::matchWildcard($nameWildcard, $name)) {
|
||||
continue;
|
||||
}
|
||||
foreach ($classHandlers as $classWildcard => $handlers) {
|
||||
if (empty($handlers)) {
|
||||
continue;
|
||||
}
|
||||
foreach ($classes as $class) {
|
||||
if (!StringHelper::matchWildcard($classWildcard, $class)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers a class-level event.
|
||||
* This method will cause invocation of event handlers that are attached to the named event
|
||||
* for the specified class and all its parent classes.
|
||||
* @param string|object $class the object or the fully qualified class name specifying the class-level event.
|
||||
* @param string $name the event name.
|
||||
* @param Event $event the event parameter. If not set, a default [[Event]] object will be created.
|
||||
*/
|
||||
public static function trigger($class, $name, $event = null)
|
||||
{
|
||||
$wildcardEventHandlers = [];
|
||||
foreach (self::$_eventWildcards as $nameWildcard => $classHandlers) {
|
||||
if (!StringHelper::matchWildcard($nameWildcard, $name)) {
|
||||
continue;
|
||||
}
|
||||
$wildcardEventHandlers = array_merge($wildcardEventHandlers, $classHandlers);
|
||||
}
|
||||
|
||||
if (empty(self::$_events[$name]) && empty($wildcardEventHandlers)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($event === null) {
|
||||
$event = new static();
|
||||
}
|
||||
$event->handled = false;
|
||||
$event->name = $name;
|
||||
|
||||
if (is_object($class)) {
|
||||
if ($event->sender === null) {
|
||||
$event->sender = $class;
|
||||
}
|
||||
$class = get_class($class);
|
||||
} else {
|
||||
$class = ltrim($class, '\\');
|
||||
}
|
||||
|
||||
$classes = array_merge(
|
||||
[$class],
|
||||
class_parents($class, true),
|
||||
class_implements($class, true)
|
||||
);
|
||||
|
||||
foreach ($classes as $class) {
|
||||
$eventHandlers = [];
|
||||
foreach ($wildcardEventHandlers as $classWildcard => $handlers) {
|
||||
if (StringHelper::matchWildcard($classWildcard, $class)) {
|
||||
$eventHandlers = array_merge($eventHandlers, $handlers);
|
||||
unset($wildcardEventHandlers[$classWildcard]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty(self::$_events[$name][$class])) {
|
||||
$eventHandlers = array_merge($eventHandlers, self::$_events[$name][$class]);
|
||||
}
|
||||
|
||||
foreach ($eventHandlers as $handler) {
|
||||
$event->data = $handler[1];
|
||||
call_user_func($handler[0], $event);
|
||||
if ($event->handled) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
27
vendor/yiisoft/yii2/base/Exception.php
vendored
Normal file
27
vendor/yiisoft/yii2/base/Exception.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* Exception represents a generic exception for all purposes.
|
||||
*
|
||||
* For more details and usage information on Exception, see the [guide article on handling errors](guide:runtime-handling-errors).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class Exception extends \Exception
|
||||
{
|
||||
/**
|
||||
* @return string the user-friendly name of this exception
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'Exception';
|
||||
}
|
||||
}
|
||||
38
vendor/yiisoft/yii2/base/ExitException.php
vendored
Normal file
38
vendor/yiisoft/yii2/base/ExitException.php
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* ExitException represents a normal termination of an application.
|
||||
*
|
||||
* Do not catch ExitException. Yii will handle this exception to terminate the application gracefully.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class ExitException extends \Exception
|
||||
{
|
||||
/**
|
||||
* @var int the exit status code
|
||||
*/
|
||||
public $statusCode;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param int $status the exit status code
|
||||
* @param string $message error message
|
||||
* @param int $code error code
|
||||
* @param \Exception $previous The previous exception used for the exception chaining.
|
||||
*/
|
||||
public function __construct($status = 0, $message = null, $code = 0, \Exception $previous = null)
|
||||
{
|
||||
$this->statusCode = $status;
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
||||
59
vendor/yiisoft/yii2/base/InlineAction.php
vendored
Normal file
59
vendor/yiisoft/yii2/base/InlineAction.php
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
use Yii;
|
||||
|
||||
/**
|
||||
* InlineAction represents an action that is defined as a controller method.
|
||||
*
|
||||
* The name of the controller method is available via [[actionMethod]] which
|
||||
* is set by the [[controller]] who creates this action.
|
||||
*
|
||||
* For more details and usage information on InlineAction, see the [guide article on actions](guide:structure-controllers).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class InlineAction extends Action
|
||||
{
|
||||
/**
|
||||
* @var string the controller method that this inline action is associated with
|
||||
*/
|
||||
public $actionMethod;
|
||||
|
||||
|
||||
/**
|
||||
* @param string $id the ID of this action
|
||||
* @param Controller $controller the controller that owns this action
|
||||
* @param string $actionMethod the controller method that this inline action is associated with
|
||||
* @param array $config name-value pairs that will be used to initialize the object properties
|
||||
*/
|
||||
public function __construct($id, $controller, $actionMethod, $config = [])
|
||||
{
|
||||
$this->actionMethod = $actionMethod;
|
||||
parent::__construct($id, $controller, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs this action with the specified parameters.
|
||||
* This method is mainly invoked by the controller.
|
||||
* @param array $params action parameters
|
||||
* @return mixed the result of the action
|
||||
*/
|
||||
public function runWithParams($params)
|
||||
{
|
||||
$args = $this->controller->bindActionParams($this, $params);
|
||||
Yii::debug('Running action: ' . get_class($this->controller) . '::' . $this->actionMethod . '()', __METHOD__);
|
||||
if (Yii::$app->requestedParams === null) {
|
||||
Yii::$app->requestedParams = $args;
|
||||
}
|
||||
|
||||
return call_user_func_array([$this->controller, $this->actionMethod], $args);
|
||||
}
|
||||
}
|
||||
25
vendor/yiisoft/yii2/base/InvalidArgumentException.php
vendored
Normal file
25
vendor/yiisoft/yii2/base/InvalidArgumentException.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* InvalidArgumentException represents an exception caused by invalid arguments passed to a method.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0.14
|
||||
*/
|
||||
class InvalidArgumentException extends InvalidParamException
|
||||
{
|
||||
/**
|
||||
* @return string the user-friendly name of this exception
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'Invalid Argument';
|
||||
}
|
||||
}
|
||||
25
vendor/yiisoft/yii2/base/InvalidCallException.php
vendored
Normal file
25
vendor/yiisoft/yii2/base/InvalidCallException.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* InvalidCallException represents an exception caused by calling a method in a wrong way.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class InvalidCallException extends \BadMethodCallException
|
||||
{
|
||||
/**
|
||||
* @return string the user-friendly name of this exception
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'Invalid Call';
|
||||
}
|
||||
}
|
||||
25
vendor/yiisoft/yii2/base/InvalidConfigException.php
vendored
Normal file
25
vendor/yiisoft/yii2/base/InvalidConfigException.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* InvalidConfigException represents an exception caused by incorrect object configuration.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class InvalidConfigException extends Exception
|
||||
{
|
||||
/**
|
||||
* @return string the user-friendly name of this exception
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'Invalid Configuration';
|
||||
}
|
||||
}
|
||||
26
vendor/yiisoft/yii2/base/InvalidParamException.php
vendored
Normal file
26
vendor/yiisoft/yii2/base/InvalidParamException.php
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* InvalidParamException represents an exception caused by invalid parameters passed to a method.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
* @deprecated since 2.0.14. Use [[InvalidArgumentException]] instead.
|
||||
*/
|
||||
class InvalidParamException extends \BadMethodCallException
|
||||
{
|
||||
/**
|
||||
* @return string the user-friendly name of this exception
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'Invalid Parameter';
|
||||
}
|
||||
}
|
||||
25
vendor/yiisoft/yii2/base/InvalidRouteException.php
vendored
Normal file
25
vendor/yiisoft/yii2/base/InvalidRouteException.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* InvalidRouteException represents an exception caused by an invalid route.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class InvalidRouteException extends UserException
|
||||
{
|
||||
/**
|
||||
* @return string the user-friendly name of this exception
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'Invalid Route';
|
||||
}
|
||||
}
|
||||
25
vendor/yiisoft/yii2/base/InvalidValueException.php
vendored
Normal file
25
vendor/yiisoft/yii2/base/InvalidValueException.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* InvalidValueException represents an exception caused by a function returning a value of unexpected type.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class InvalidValueException extends \UnexpectedValueException
|
||||
{
|
||||
/**
|
||||
* @return string the user-friendly name of this exception
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'Invalid Return Value';
|
||||
}
|
||||
}
|
||||
1002
vendor/yiisoft/yii2/base/Model.php
vendored
Normal file
1002
vendor/yiisoft/yii2/base/Model.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
23
vendor/yiisoft/yii2/base/ModelEvent.php
vendored
Normal file
23
vendor/yiisoft/yii2/base/ModelEvent.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* ModelEvent represents the parameter needed by [[Model]] events.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class ModelEvent extends Event
|
||||
{
|
||||
/**
|
||||
* @var bool whether the model is in valid status. Defaults to true.
|
||||
* A model is in valid status if it passes validations or certain checks.
|
||||
*/
|
||||
public $isValid = true;
|
||||
}
|
||||
762
vendor/yiisoft/yii2/base/Module.php
vendored
Normal file
762
vendor/yiisoft/yii2/base/Module.php
vendored
Normal file
@@ -0,0 +1,762 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
use Yii;
|
||||
use yii\di\ServiceLocator;
|
||||
|
||||
/**
|
||||
* Module is the base class for module and application classes.
|
||||
*
|
||||
* A module represents a sub-application which contains MVC elements by itself, such as
|
||||
* models, views, controllers, etc.
|
||||
*
|
||||
* A module may consist of [[modules|sub-modules]].
|
||||
*
|
||||
* [[components|Components]] may be registered with the module so that they are globally
|
||||
* accessible within the module.
|
||||
*
|
||||
* For more details and usage information on Module, see the [guide article on modules](guide:structure-modules).
|
||||
*
|
||||
* @property array $aliases List of path aliases to be defined. The array keys are alias names (must start
|
||||
* with `@`) and the array values are the corresponding paths or aliases. See [[setAliases()]] for an example.
|
||||
* This property is write-only.
|
||||
* @property string $basePath The root directory of the module.
|
||||
* @property string $controllerPath The directory that contains the controller classes. This property is
|
||||
* read-only.
|
||||
* @property string $layoutPath The root directory of layout files. Defaults to "[[viewPath]]/layouts".
|
||||
* @property array $modules The modules (indexed by their IDs).
|
||||
* @property string $uniqueId The unique ID of the module. This property is read-only.
|
||||
* @property string $version The version of this module. Note that the type of this property differs in getter
|
||||
* and setter. See [[getVersion()]] and [[setVersion()]] for details.
|
||||
* @property string $viewPath The root directory of view files. Defaults to "[[basePath]]/views".
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class Module extends ServiceLocator
|
||||
{
|
||||
/**
|
||||
* @event ActionEvent an event raised before executing a controller action.
|
||||
* You may set [[ActionEvent::isValid]] to be `false` to cancel the action execution.
|
||||
*/
|
||||
const EVENT_BEFORE_ACTION = 'beforeAction';
|
||||
/**
|
||||
* @event ActionEvent an event raised after executing a controller action.
|
||||
*/
|
||||
const EVENT_AFTER_ACTION = 'afterAction';
|
||||
|
||||
/**
|
||||
* @var array custom module parameters (name => value).
|
||||
*/
|
||||
public $params = [];
|
||||
/**
|
||||
* @var string an ID that uniquely identifies this module among other modules which have the same [[module|parent]].
|
||||
*/
|
||||
public $id;
|
||||
/**
|
||||
* @var Module the parent module of this module. `null` if this module does not have a parent.
|
||||
*/
|
||||
public $module;
|
||||
/**
|
||||
* @var string|bool the layout that should be applied for views within this module. This refers to a view name
|
||||
* relative to [[layoutPath]]. If this is not set, it means the layout value of the [[module|parent module]]
|
||||
* will be taken. If this is `false`, layout will be disabled within this module.
|
||||
*/
|
||||
public $layout;
|
||||
/**
|
||||
* @var array mapping from controller ID to controller configurations.
|
||||
* Each name-value pair specifies the configuration of a single controller.
|
||||
* A controller configuration can be either a string or an array.
|
||||
* If the former, the string should be the fully qualified class name of the controller.
|
||||
* If the latter, the array must contain a `class` element which specifies
|
||||
* the controller's fully qualified class name, and the rest of the name-value pairs
|
||||
* in the array are used to initialize the corresponding controller properties. For example,
|
||||
*
|
||||
* ```php
|
||||
* [
|
||||
* 'account' => 'app\controllers\UserController',
|
||||
* 'article' => [
|
||||
* 'class' => 'app\controllers\PostController',
|
||||
* 'pageTitle' => 'something new',
|
||||
* ],
|
||||
* ]
|
||||
* ```
|
||||
*/
|
||||
public $controllerMap = [];
|
||||
/**
|
||||
* @var string the namespace that controller classes are in.
|
||||
* This namespace will be used to load controller classes by prepending it to the controller
|
||||
* class name.
|
||||
*
|
||||
* If not set, it will use the `controllers` sub-namespace under the namespace of this module.
|
||||
* For example, if the namespace of this module is `foo\bar`, then the default
|
||||
* controller namespace would be `foo\bar\controllers`.
|
||||
*
|
||||
* See also the [guide section on autoloading](guide:concept-autoloading) to learn more about
|
||||
* defining namespaces and how classes are loaded.
|
||||
*/
|
||||
public $controllerNamespace;
|
||||
/**
|
||||
* @var string the default route of this module. Defaults to `default`.
|
||||
* The route may consist of child module ID, controller ID, and/or action ID.
|
||||
* For example, `help`, `post/create`, `admin/post/create`.
|
||||
* If action ID is not given, it will take the default value as specified in
|
||||
* [[Controller::defaultAction]].
|
||||
*/
|
||||
public $defaultRoute = 'default';
|
||||
|
||||
/**
|
||||
* @var string the root directory of the module.
|
||||
*/
|
||||
private $_basePath;
|
||||
/**
|
||||
* @var string the root directory that contains view files for this module
|
||||
*/
|
||||
private $_viewPath;
|
||||
/**
|
||||
* @var string the root directory that contains layout view files for this module.
|
||||
*/
|
||||
private $_layoutPath;
|
||||
/**
|
||||
* @var array child modules of this module
|
||||
*/
|
||||
private $_modules = [];
|
||||
/**
|
||||
* @var string|callable the version of this module.
|
||||
* Version can be specified as a PHP callback, which can accept module instance as an argument and should
|
||||
* return the actual version. For example:
|
||||
*
|
||||
* ```php
|
||||
* function (Module $module) {
|
||||
* //return string|int
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* If not set, [[defaultVersion()]] will be used to determine actual value.
|
||||
*
|
||||
* @since 2.0.11
|
||||
*/
|
||||
private $_version;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param string $id the ID of this module.
|
||||
* @param Module $parent the parent module (if any).
|
||||
* @param array $config name-value pairs that will be used to initialize the object properties.
|
||||
*/
|
||||
public function __construct($id, $parent = null, $config = [])
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->module = $parent;
|
||||
parent::__construct($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently requested instance of this module class.
|
||||
* If the module class is not currently requested, `null` will be returned.
|
||||
* This method is provided so that you access the module instance from anywhere within the module.
|
||||
* @return static|null the currently requested instance of this module class, or `null` if the module class is not requested.
|
||||
*/
|
||||
public static function getInstance()
|
||||
{
|
||||
$class = get_called_class();
|
||||
return isset(Yii::$app->loadedModules[$class]) ? Yii::$app->loadedModules[$class] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the currently requested instance of this module class.
|
||||
* @param Module|null $instance the currently requested instance of this module class.
|
||||
* If it is `null`, the instance of the calling class will be removed, if any.
|
||||
*/
|
||||
public static function setInstance($instance)
|
||||
{
|
||||
if ($instance === null) {
|
||||
unset(Yii::$app->loadedModules[get_called_class()]);
|
||||
} else {
|
||||
Yii::$app->loadedModules[get_class($instance)] = $instance;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the module.
|
||||
*
|
||||
* This method is called after the module is created and initialized with property values
|
||||
* given in configuration. The default implementation will initialize [[controllerNamespace]]
|
||||
* if it is not set.
|
||||
*
|
||||
* If you override this method, please make sure you call the parent implementation.
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
if ($this->controllerNamespace === null) {
|
||||
$class = get_class($this);
|
||||
if (($pos = strrpos($class, '\\')) !== false) {
|
||||
$this->controllerNamespace = substr($class, 0, $pos) . '\\controllers';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ID that uniquely identifies this module among all modules within the current application.
|
||||
* Note that if the module is an application, an empty string will be returned.
|
||||
* @return string the unique ID of the module.
|
||||
*/
|
||||
public function getUniqueId()
|
||||
{
|
||||
return $this->module ? ltrim($this->module->getUniqueId() . '/' . $this->id, '/') : $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the root directory of the module.
|
||||
* It defaults to the directory containing the module class file.
|
||||
* @return string the root directory of the module.
|
||||
*/
|
||||
public function getBasePath()
|
||||
{
|
||||
if ($this->_basePath === null) {
|
||||
$class = new \ReflectionClass($this);
|
||||
$this->_basePath = dirname($class->getFileName());
|
||||
}
|
||||
|
||||
return $this->_basePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the root directory of the module.
|
||||
* This method can only be invoked at the beginning of the constructor.
|
||||
* @param string $path the root directory of the module. This can be either a directory name or a [path alias](guide:concept-aliases).
|
||||
* @throws InvalidArgumentException if the directory does not exist.
|
||||
*/
|
||||
public function setBasePath($path)
|
||||
{
|
||||
$path = Yii::getAlias($path);
|
||||
$p = strncmp($path, 'phar://', 7) === 0 ? $path : realpath($path);
|
||||
if ($p !== false && is_dir($p)) {
|
||||
$this->_basePath = $p;
|
||||
} else {
|
||||
throw new InvalidArgumentException("The directory does not exist: $path");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the directory that contains the controller classes according to [[controllerNamespace]].
|
||||
* Note that in order for this method to return a value, you must define
|
||||
* an alias for the root namespace of [[controllerNamespace]].
|
||||
* @return string the directory that contains the controller classes.
|
||||
* @throws InvalidArgumentException if there is no alias defined for the root namespace of [[controllerNamespace]].
|
||||
*/
|
||||
public function getControllerPath()
|
||||
{
|
||||
return Yii::getAlias('@' . str_replace('\\', '/', $this->controllerNamespace));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the directory that contains the view files for this module.
|
||||
* @return string the root directory of view files. Defaults to "[[basePath]]/views".
|
||||
*/
|
||||
public function getViewPath()
|
||||
{
|
||||
if ($this->_viewPath === null) {
|
||||
$this->_viewPath = $this->getBasePath() . DIRECTORY_SEPARATOR . 'views';
|
||||
}
|
||||
|
||||
return $this->_viewPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the directory that contains the view files.
|
||||
* @param string $path the root directory of view files.
|
||||
* @throws InvalidArgumentException if the directory is invalid.
|
||||
*/
|
||||
public function setViewPath($path)
|
||||
{
|
||||
$this->_viewPath = Yii::getAlias($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the directory that contains layout view files for this module.
|
||||
* @return string the root directory of layout files. Defaults to "[[viewPath]]/layouts".
|
||||
*/
|
||||
public function getLayoutPath()
|
||||
{
|
||||
if ($this->_layoutPath === null) {
|
||||
$this->_layoutPath = $this->getViewPath() . DIRECTORY_SEPARATOR . 'layouts';
|
||||
}
|
||||
|
||||
return $this->_layoutPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the directory that contains the layout files.
|
||||
* @param string $path the root directory or [path alias](guide:concept-aliases) of layout files.
|
||||
* @throws InvalidArgumentException if the directory is invalid
|
||||
*/
|
||||
public function setLayoutPath($path)
|
||||
{
|
||||
$this->_layoutPath = Yii::getAlias($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current module version.
|
||||
* If version is not explicitly set, [[defaultVersion()]] method will be used to determine its value.
|
||||
* @return string the version of this module.
|
||||
* @since 2.0.11
|
||||
*/
|
||||
public function getVersion()
|
||||
{
|
||||
if ($this->_version === null) {
|
||||
$this->_version = $this->defaultVersion();
|
||||
} else {
|
||||
if (!is_scalar($this->_version)) {
|
||||
$this->_version = call_user_func($this->_version, $this);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets current module version.
|
||||
* @param string|callable $version the version of this module.
|
||||
* Version can be specified as a PHP callback, which can accept module instance as an argument and should
|
||||
* return the actual version. For example:
|
||||
*
|
||||
* ```php
|
||||
* function (Module $module) {
|
||||
* //return string
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @since 2.0.11
|
||||
*/
|
||||
public function setVersion($version)
|
||||
{
|
||||
$this->_version = $version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns default module version.
|
||||
* Child class may override this method to provide more specific version detection.
|
||||
* @return string the version of this module.
|
||||
* @since 2.0.11
|
||||
*/
|
||||
protected function defaultVersion()
|
||||
{
|
||||
if ($this->module === null) {
|
||||
return '1.0';
|
||||
}
|
||||
|
||||
return $this->module->getVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines path aliases.
|
||||
* This method calls [[Yii::setAlias()]] to register the path aliases.
|
||||
* This method is provided so that you can define path aliases when configuring a module.
|
||||
* @property array list of path aliases to be defined. The array keys are alias names
|
||||
* (must start with `@`) and the array values are the corresponding paths or aliases.
|
||||
* See [[setAliases()]] for an example.
|
||||
* @param array $aliases list of path aliases to be defined. The array keys are alias names
|
||||
* (must start with `@`) and the array values are the corresponding paths or aliases.
|
||||
* For example,
|
||||
*
|
||||
* ```php
|
||||
* [
|
||||
* '@models' => '@app/models', // an existing alias
|
||||
* '@backend' => __DIR__ . '/../backend', // a directory
|
||||
* ]
|
||||
* ```
|
||||
*/
|
||||
public function setAliases($aliases)
|
||||
{
|
||||
foreach ($aliases as $name => $alias) {
|
||||
Yii::setAlias($name, $alias);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the child module of the specified ID exists.
|
||||
* This method supports checking the existence of both child and grand child modules.
|
||||
* @param string $id module ID. For grand child modules, use ID path relative to this module (e.g. `admin/content`).
|
||||
* @return bool whether the named module exists. Both loaded and unloaded modules
|
||||
* are considered.
|
||||
*/
|
||||
public function hasModule($id)
|
||||
{
|
||||
if (($pos = strpos($id, '/')) !== false) {
|
||||
// sub-module
|
||||
$module = $this->getModule(substr($id, 0, $pos));
|
||||
|
||||
return $module === null ? false : $module->hasModule(substr($id, $pos + 1));
|
||||
}
|
||||
|
||||
return isset($this->_modules[$id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the child module of the specified ID.
|
||||
* This method supports retrieving both child modules and grand child modules.
|
||||
* @param string $id module ID (case-sensitive). To retrieve grand child modules,
|
||||
* use ID path relative to this module (e.g. `admin/content`).
|
||||
* @param bool $load whether to load the module if it is not yet loaded.
|
||||
* @return Module|null the module instance, `null` if the module does not exist.
|
||||
* @see hasModule()
|
||||
*/
|
||||
public function getModule($id, $load = true)
|
||||
{
|
||||
if (($pos = strpos($id, '/')) !== false) {
|
||||
// sub-module
|
||||
$module = $this->getModule(substr($id, 0, $pos));
|
||||
|
||||
return $module === null ? null : $module->getModule(substr($id, $pos + 1), $load);
|
||||
}
|
||||
|
||||
if (isset($this->_modules[$id])) {
|
||||
if ($this->_modules[$id] instanceof self) {
|
||||
return $this->_modules[$id];
|
||||
} elseif ($load) {
|
||||
Yii::debug("Loading module: $id", __METHOD__);
|
||||
/* @var $module Module */
|
||||
$module = Yii::createObject($this->_modules[$id], [$id, $this]);
|
||||
$module->setInstance($module);
|
||||
return $this->_modules[$id] = $module;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a sub-module to this module.
|
||||
* @param string $id module ID.
|
||||
* @param Module|array|null $module the sub-module to be added to this module. This can
|
||||
* be one of the following:
|
||||
*
|
||||
* - a [[Module]] object
|
||||
* - a configuration array: when [[getModule()]] is called initially, the array
|
||||
* will be used to instantiate the sub-module
|
||||
* - `null`: the named sub-module will be removed from this module
|
||||
*/
|
||||
public function setModule($id, $module)
|
||||
{
|
||||
if ($module === null) {
|
||||
unset($this->_modules[$id]);
|
||||
} else {
|
||||
$this->_modules[$id] = $module;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sub-modules in this module.
|
||||
* @param bool $loadedOnly whether to return the loaded sub-modules only. If this is set `false`,
|
||||
* then all sub-modules registered in this module will be returned, whether they are loaded or not.
|
||||
* Loaded modules will be returned as objects, while unloaded modules as configuration arrays.
|
||||
* @return array the modules (indexed by their IDs).
|
||||
*/
|
||||
public function getModules($loadedOnly = false)
|
||||
{
|
||||
if ($loadedOnly) {
|
||||
$modules = [];
|
||||
foreach ($this->_modules as $module) {
|
||||
if ($module instanceof self) {
|
||||
$modules[] = $module;
|
||||
}
|
||||
}
|
||||
|
||||
return $modules;
|
||||
}
|
||||
|
||||
return $this->_modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers sub-modules in the current module.
|
||||
*
|
||||
* Each sub-module should be specified as a name-value pair, where
|
||||
* name refers to the ID of the module and value the module or a configuration
|
||||
* array that can be used to create the module. In the latter case, [[Yii::createObject()]]
|
||||
* will be used to create the module.
|
||||
*
|
||||
* If a new sub-module has the same ID as an existing one, the existing one will be overwritten silently.
|
||||
*
|
||||
* The following is an example for registering two sub-modules:
|
||||
*
|
||||
* ```php
|
||||
* [
|
||||
* 'comment' => [
|
||||
* 'class' => 'app\modules\comment\CommentModule',
|
||||
* 'db' => 'db',
|
||||
* ],
|
||||
* 'booking' => ['class' => 'app\modules\booking\BookingModule'],
|
||||
* ]
|
||||
* ```
|
||||
*
|
||||
* @param array $modules modules (id => module configuration or instances).
|
||||
*/
|
||||
public function setModules($modules)
|
||||
{
|
||||
foreach ($modules as $id => $module) {
|
||||
$this->_modules[$id] = $module;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a controller action specified by a route.
|
||||
* This method parses the specified route and creates the corresponding child module(s), controller and action
|
||||
* instances. It then calls [[Controller::runAction()]] to run the action with the given parameters.
|
||||
* If the route is empty, the method will use [[defaultRoute]].
|
||||
* @param string $route the route that specifies the action.
|
||||
* @param array $params the parameters to be passed to the action
|
||||
* @return mixed the result of the action.
|
||||
* @throws InvalidRouteException if the requested route cannot be resolved into an action successfully.
|
||||
*/
|
||||
public function runAction($route, $params = [])
|
||||
{
|
||||
$parts = $this->createController($route);
|
||||
if (is_array($parts)) {
|
||||
/* @var $controller Controller */
|
||||
list($controller, $actionID) = $parts;
|
||||
$oldController = Yii::$app->controller;
|
||||
Yii::$app->controller = $controller;
|
||||
$result = $controller->runAction($actionID, $params);
|
||||
if ($oldController !== null) {
|
||||
Yii::$app->controller = $oldController;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
$id = $this->getUniqueId();
|
||||
throw new InvalidRouteException('Unable to resolve the request "' . ($id === '' ? $route : $id . '/' . $route) . '".');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a controller instance based on the given route.
|
||||
*
|
||||
* The route should be relative to this module. The method implements the following algorithm
|
||||
* to resolve the given route:
|
||||
*
|
||||
* 1. If the route is empty, use [[defaultRoute]];
|
||||
* 2. If the first segment of the route is a valid module ID as declared in [[modules]],
|
||||
* call the module's `createController()` with the rest part of the route;
|
||||
* 3. If the first segment of the route is found in [[controllerMap]], create a controller
|
||||
* based on the corresponding configuration found in [[controllerMap]];
|
||||
* 4. The given route is in the format of `abc/def/xyz`. Try either `abc\DefController`
|
||||
* or `abc\def\XyzController` class within the [[controllerNamespace|controller namespace]].
|
||||
*
|
||||
* If any of the above steps resolves into a controller, it is returned together with the rest
|
||||
* part of the route which will be treated as the action ID. Otherwise, `false` will be returned.
|
||||
*
|
||||
* @param string $route the route consisting of module, controller and action IDs.
|
||||
* @return array|bool If the controller is created successfully, it will be returned together
|
||||
* with the requested action ID. Otherwise `false` will be returned.
|
||||
* @throws InvalidConfigException if the controller class and its file do not match.
|
||||
*/
|
||||
public function createController($route)
|
||||
{
|
||||
if ($route === '') {
|
||||
$route = $this->defaultRoute;
|
||||
}
|
||||
|
||||
// double slashes or leading/ending slashes may cause substr problem
|
||||
$route = trim($route, '/');
|
||||
if (strpos($route, '//') !== false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strpos($route, '/') !== false) {
|
||||
list($id, $route) = explode('/', $route, 2);
|
||||
} else {
|
||||
$id = $route;
|
||||
$route = '';
|
||||
}
|
||||
|
||||
// module and controller map take precedence
|
||||
if (isset($this->controllerMap[$id])) {
|
||||
$controller = Yii::createObject($this->controllerMap[$id], [$id, $this]);
|
||||
return [$controller, $route];
|
||||
}
|
||||
$module = $this->getModule($id);
|
||||
if ($module !== null) {
|
||||
return $module->createController($route);
|
||||
}
|
||||
|
||||
if (($pos = strrpos($route, '/')) !== false) {
|
||||
$id .= '/' . substr($route, 0, $pos);
|
||||
$route = substr($route, $pos + 1);
|
||||
}
|
||||
|
||||
$controller = $this->createControllerByID($id);
|
||||
if ($controller === null && $route !== '') {
|
||||
$controller = $this->createControllerByID($id . '/' . $route);
|
||||
$route = '';
|
||||
}
|
||||
|
||||
return $controller === null ? false : [$controller, $route];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a controller based on the given controller ID.
|
||||
*
|
||||
* The controller ID is relative to this module. The controller class
|
||||
* should be namespaced under [[controllerNamespace]].
|
||||
*
|
||||
* Note that this method does not check [[modules]] or [[controllerMap]].
|
||||
*
|
||||
* @param string $id the controller ID.
|
||||
* @return Controller|null the newly created controller instance, or `null` if the controller ID is invalid.
|
||||
* @throws InvalidConfigException if the controller class and its file name do not match.
|
||||
* This exception is only thrown when in debug mode.
|
||||
*/
|
||||
public function createControllerByID($id)
|
||||
{
|
||||
$pos = strrpos($id, '/');
|
||||
if ($pos === false) {
|
||||
$prefix = '';
|
||||
$className = $id;
|
||||
} else {
|
||||
$prefix = substr($id, 0, $pos + 1);
|
||||
$className = substr($id, $pos + 1);
|
||||
}
|
||||
|
||||
if ($this->isIncorrectClassNameOrPrefix($className, $prefix)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$className = preg_replace_callback('%-([a-z0-9_])%i', function ($matches) {
|
||||
return ucfirst($matches[1]);
|
||||
}, ucfirst($className)) . 'Controller';
|
||||
$className = ltrim($this->controllerNamespace . '\\' . str_replace('/', '\\', $prefix) . $className, '\\');
|
||||
if (strpos($className, '-') !== false || !class_exists($className)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (is_subclass_of($className, 'yii\base\Controller')) {
|
||||
$controller = Yii::createObject($className, [$id, $this]);
|
||||
return get_class($controller) === $className ? $controller : null;
|
||||
} elseif (YII_DEBUG) {
|
||||
throw new InvalidConfigException('Controller class must extend from \\yii\\base\\Controller.');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if class name or prefix is incorrect
|
||||
*
|
||||
* @param string $className
|
||||
* @param string $prefix
|
||||
* @return bool
|
||||
*/
|
||||
private function isIncorrectClassNameOrPrefix($className, $prefix)
|
||||
{
|
||||
if (!preg_match('%^[a-z][a-z0-9\\-_]*$%', $className)) {
|
||||
return true;
|
||||
}
|
||||
if ($prefix !== '' && !preg_match('%^[a-z0-9_/]+$%i', $prefix)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is invoked right before an action within this module is executed.
|
||||
*
|
||||
* The method will trigger the [[EVENT_BEFORE_ACTION]] event. The return value of the method
|
||||
* will determine whether the action should continue to run.
|
||||
*
|
||||
* In case the action should not run, the request should be handled inside of the `beforeAction` code
|
||||
* by either providing the necessary output or redirecting the request. Otherwise the response will be empty.
|
||||
*
|
||||
* If you override this method, your code should look like the following:
|
||||
*
|
||||
* ```php
|
||||
* public function beforeAction($action)
|
||||
* {
|
||||
* if (!parent::beforeAction($action)) {
|
||||
* return false;
|
||||
* }
|
||||
*
|
||||
* // your custom code here
|
||||
*
|
||||
* return true; // or false to not run the action
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param Action $action the action to be executed.
|
||||
* @return bool whether the action should continue to be executed.
|
||||
*/
|
||||
public function beforeAction($action)
|
||||
{
|
||||
$event = new ActionEvent($action);
|
||||
$this->trigger(self::EVENT_BEFORE_ACTION, $event);
|
||||
return $event->isValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is invoked right after an action within this module is executed.
|
||||
*
|
||||
* The method will trigger the [[EVENT_AFTER_ACTION]] event. The return value of the method
|
||||
* will be used as the action return value.
|
||||
*
|
||||
* If you override this method, your code should look like the following:
|
||||
*
|
||||
* ```php
|
||||
* public function afterAction($action, $result)
|
||||
* {
|
||||
* $result = parent::afterAction($action, $result);
|
||||
* // your custom code here
|
||||
* return $result;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param Action $action the action just executed.
|
||||
* @param mixed $result the action return result.
|
||||
* @return mixed the processed action result.
|
||||
*/
|
||||
public function afterAction($action, $result)
|
||||
{
|
||||
$event = new ActionEvent($action);
|
||||
$event->result = $result;
|
||||
$this->trigger(self::EVENT_AFTER_ACTION, $event);
|
||||
return $event->result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Since version 2.0.13, if a component isn't defined in the module, it will be looked up in the parent module.
|
||||
* The parent module may be the application.
|
||||
*/
|
||||
public function get($id, $throwException = true)
|
||||
{
|
||||
if (!isset($this->module)) {
|
||||
return parent::get($id, $throwException);
|
||||
}
|
||||
|
||||
$component = parent::get($id, false);
|
||||
if ($component === null) {
|
||||
$component = $this->module->get($id, $throwException);
|
||||
}
|
||||
return $component;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Since version 2.0.13, if a component isn't defined in the module, it will be looked up in the parent module.
|
||||
* The parent module may be the application.
|
||||
*/
|
||||
public function has($id, $checkInstance = false)
|
||||
{
|
||||
return parent::has($id, $checkInstance) || (isset($this->module) && $this->module->has($id, $checkInstance));
|
||||
}
|
||||
}
|
||||
25
vendor/yiisoft/yii2/base/NotSupportedException.php
vendored
Normal file
25
vendor/yiisoft/yii2/base/NotSupportedException.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* NotSupportedException represents an exception caused by accessing features that are not supported.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class NotSupportedException extends Exception
|
||||
{
|
||||
/**
|
||||
* @return string the user-friendly name of this exception
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'Not Supported';
|
||||
}
|
||||
}
|
||||
30
vendor/yiisoft/yii2/base/Object.php
vendored
Normal file
30
vendor/yiisoft/yii2/base/Object.php
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
use Yii;
|
||||
|
||||
/**
|
||||
* Object is the base class that implements the *property* feature.
|
||||
*
|
||||
* It has been replaced by [[BaseObject]] in version 2.0.13 because `object` has become a reserved word which can not be
|
||||
* used as class name in PHP 7.2.
|
||||
*
|
||||
* Please refer to [[BaseObject]] for detailed documentation and to the
|
||||
* [UPGRADE notes](https://github.com/yiisoft/yii2/blob/2.0.13/framework/UPGRADE.md#upgrade-from-yii-2012)
|
||||
* on how to migrate your application to use [[BaseObject]] class to make your application compatible with PHP 7.2.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
* @deprecated since 2.0.13, the class name `Object` is invalid since PHP 7.2, use [[BaseObject]] instead.
|
||||
* @see https://wiki.php.net/rfc/object-typehint
|
||||
* @see https://github.com/yiisoft/yii2/issues/7936#issuecomment-315384669
|
||||
*/
|
||||
class Object extends BaseObject
|
||||
{
|
||||
}
|
||||
88
vendor/yiisoft/yii2/base/Request.php
vendored
Normal file
88
vendor/yiisoft/yii2/base/Request.php
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
use Yii;
|
||||
|
||||
/**
|
||||
* Request represents a request that is handled by an [[Application]].
|
||||
*
|
||||
* For more details and usage information on Request, see the [guide article on requests](guide:runtime-requests).
|
||||
*
|
||||
* @property bool $isConsoleRequest The value indicating whether the current request is made via console.
|
||||
* @property string $scriptFile Entry script file path (processed w/ realpath()).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
abstract class Request extends Component
|
||||
{
|
||||
private $_scriptFile;
|
||||
private $_isConsoleRequest;
|
||||
|
||||
|
||||
/**
|
||||
* Resolves the current request into a route and the associated parameters.
|
||||
* @return array the first element is the route, and the second is the associated parameters.
|
||||
*/
|
||||
abstract public function resolve();
|
||||
|
||||
/**
|
||||
* Returns a value indicating whether the current request is made via command line.
|
||||
* @return bool the value indicating whether the current request is made via console
|
||||
*/
|
||||
public function getIsConsoleRequest()
|
||||
{
|
||||
return $this->_isConsoleRequest !== null ? $this->_isConsoleRequest : PHP_SAPI === 'cli';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value indicating whether the current request is made via command line.
|
||||
* @param bool $value the value indicating whether the current request is made via command line
|
||||
*/
|
||||
public function setIsConsoleRequest($value)
|
||||
{
|
||||
$this->_isConsoleRequest = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns entry script file path.
|
||||
* @return string entry script file path (processed w/ realpath())
|
||||
* @throws InvalidConfigException if the entry script file path cannot be determined automatically.
|
||||
*/
|
||||
public function getScriptFile()
|
||||
{
|
||||
if ($this->_scriptFile === null) {
|
||||
if (isset($_SERVER['SCRIPT_FILENAME'])) {
|
||||
$this->setScriptFile($_SERVER['SCRIPT_FILENAME']);
|
||||
} else {
|
||||
throw new InvalidConfigException('Unable to determine the entry script file path.');
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_scriptFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the entry script file path.
|
||||
* The entry script file path can normally be determined based on the `SCRIPT_FILENAME` SERVER variable.
|
||||
* However, for some server configurations, this may not be correct or feasible.
|
||||
* This setter is provided so that the entry script file path can be manually specified.
|
||||
* @param string $value the entry script file path. This can be either a file path or a [path alias](guide:concept-aliases).
|
||||
* @throws InvalidConfigException if the provided entry script file path is invalid.
|
||||
*/
|
||||
public function setScriptFile($value)
|
||||
{
|
||||
$scriptFile = realpath(Yii::getAlias($value));
|
||||
if ($scriptFile !== false && is_file($scriptFile)) {
|
||||
$this->_scriptFile = $scriptFile;
|
||||
} else {
|
||||
throw new InvalidConfigException('Unable to determine the entry script file path.');
|
||||
}
|
||||
}
|
||||
}
|
||||
46
vendor/yiisoft/yii2/base/Response.php
vendored
Normal file
46
vendor/yiisoft/yii2/base/Response.php
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* Response represents the response of an [[Application]] to a [[Request]].
|
||||
*
|
||||
* For more details and usage information on Response, see the [guide article on responses](guide:runtime-responses).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class Response extends Component
|
||||
{
|
||||
/**
|
||||
* @var int the exit status. Exit statuses should be in the range 0 to 254.
|
||||
* The status 0 means the program terminates successfully.
|
||||
*/
|
||||
public $exitStatus = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Sends the response to client.
|
||||
*/
|
||||
public function send()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all existing output buffers.
|
||||
*/
|
||||
public function clearOutputBuffers()
|
||||
{
|
||||
// the following manual level counting is to deal with zlib.output_compression set to On
|
||||
for ($level = ob_get_level(); $level > 0; --$level) {
|
||||
if (!@ob_end_clean()) {
|
||||
ob_clean();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
761
vendor/yiisoft/yii2/base/Security.php
vendored
Normal file
761
vendor/yiisoft/yii2/base/Security.php
vendored
Normal file
@@ -0,0 +1,761 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
use Yii;
|
||||
use yii\helpers\StringHelper;
|
||||
|
||||
/**
|
||||
* Security provides a set of methods to handle common security-related tasks.
|
||||
*
|
||||
* In particular, Security supports the following features:
|
||||
*
|
||||
* - Encryption/decryption: [[encryptByKey()]], [[decryptByKey()]], [[encryptByPassword()]] and [[decryptByPassword()]]
|
||||
* - Key derivation using standard algorithms: [[pbkdf2()]] and [[hkdf()]]
|
||||
* - Data tampering prevention: [[hashData()]] and [[validateData()]]
|
||||
* - Password validation: [[generatePasswordHash()]] and [[validatePassword()]]
|
||||
*
|
||||
* > Note: this class requires 'OpenSSL' PHP extension for random key/string generation on Windows and
|
||||
* for encryption/decryption on all platforms. For the highest security level PHP version >= 5.5.0 is recommended.
|
||||
*
|
||||
* For more details and usage information on Security, see the [guide article on security](guide:security-overview).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @author Tom Worster <fsb@thefsb.org>
|
||||
* @author Klimov Paul <klimov.paul@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class Security extends Component
|
||||
{
|
||||
/**
|
||||
* @var string The cipher to use for encryption and decryption.
|
||||
*/
|
||||
public $cipher = 'AES-128-CBC';
|
||||
/**
|
||||
* @var array[] Look-up table of block sizes and key sizes for each supported OpenSSL cipher.
|
||||
*
|
||||
* In each element, the key is one of the ciphers supported by OpenSSL (@see openssl_get_cipher_methods()).
|
||||
* The value is an array of two integers, the first is the cipher's block size in bytes and the second is
|
||||
* the key size in bytes.
|
||||
*
|
||||
* > Warning: All OpenSSL ciphers that we recommend are in the default value, i.e. AES in CBC mode.
|
||||
*
|
||||
* > Note: Yii's encryption protocol uses the same size for cipher key, HMAC signature key and key
|
||||
* derivation salt.
|
||||
*/
|
||||
public $allowedCiphers = [
|
||||
'AES-128-CBC' => [16, 16],
|
||||
'AES-192-CBC' => [16, 24],
|
||||
'AES-256-CBC' => [16, 32],
|
||||
];
|
||||
/**
|
||||
* @var string Hash algorithm for key derivation. Recommend sha256, sha384 or sha512.
|
||||
* @see [hash_algos()](http://php.net/manual/en/function.hash-algos.php)
|
||||
*/
|
||||
public $kdfHash = 'sha256';
|
||||
/**
|
||||
* @var string Hash algorithm for message authentication. Recommend sha256, sha384 or sha512.
|
||||
* @see [hash_algos()](http://php.net/manual/en/function.hash-algos.php)
|
||||
*/
|
||||
public $macHash = 'sha256';
|
||||
/**
|
||||
* @var string HKDF info value for derivation of message authentication key.
|
||||
* @see hkdf()
|
||||
*/
|
||||
public $authKeyInfo = 'AuthorizationKey';
|
||||
/**
|
||||
* @var int derivation iterations count.
|
||||
* Set as high as possible to hinder dictionary password attacks.
|
||||
*/
|
||||
public $derivationIterations = 100000;
|
||||
/**
|
||||
* @var string strategy, which should be used to generate password hash.
|
||||
* Available strategies:
|
||||
* - 'password_hash' - use of PHP `password_hash()` function with PASSWORD_DEFAULT algorithm.
|
||||
* This option is recommended, but it requires PHP version >= 5.5.0
|
||||
* - 'crypt' - use PHP `crypt()` function.
|
||||
* @deprecated since version 2.0.7, [[generatePasswordHash()]] ignores [[passwordHashStrategy]] and
|
||||
* uses `password_hash()` when available or `crypt()` when not.
|
||||
*/
|
||||
public $passwordHashStrategy;
|
||||
/**
|
||||
* @var int Default cost used for password hashing.
|
||||
* Allowed value is between 4 and 31.
|
||||
* @see generatePasswordHash()
|
||||
* @since 2.0.6
|
||||
*/
|
||||
public $passwordHashCost = 13;
|
||||
|
||||
|
||||
/**
|
||||
* Encrypts data using a password.
|
||||
* Derives keys for encryption and authentication from the password using PBKDF2 and a random salt,
|
||||
* which is deliberately slow to protect against dictionary attacks. Use [[encryptByKey()]] to
|
||||
* encrypt fast using a cryptographic key rather than a password. Key derivation time is
|
||||
* determined by [[$derivationIterations]], which should be set as high as possible.
|
||||
* The encrypted data includes a keyed message authentication code (MAC) so there is no need
|
||||
* to hash input or output data.
|
||||
* > Note: Avoid encrypting with passwords wherever possible. Nothing can protect against
|
||||
* poor-quality or compromised passwords.
|
||||
* @param string $data the data to encrypt
|
||||
* @param string $password the password to use for encryption
|
||||
* @return string the encrypted data
|
||||
* @see decryptByPassword()
|
||||
* @see encryptByKey()
|
||||
*/
|
||||
public function encryptByPassword($data, $password)
|
||||
{
|
||||
return $this->encrypt($data, true, $password, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts data using a cryptographic key.
|
||||
* Derives keys for encryption and authentication from the input key using HKDF and a random salt,
|
||||
* which is very fast relative to [[encryptByPassword()]]. The input key must be properly
|
||||
* random -- use [[generateRandomKey()]] to generate keys.
|
||||
* The encrypted data includes a keyed message authentication code (MAC) so there is no need
|
||||
* to hash input or output data.
|
||||
* @param string $data the data to encrypt
|
||||
* @param string $inputKey the input to use for encryption and authentication
|
||||
* @param string $info optional context and application specific information, see [[hkdf()]]
|
||||
* @return string the encrypted data
|
||||
* @see decryptByKey()
|
||||
* @see encryptByPassword()
|
||||
*/
|
||||
public function encryptByKey($data, $inputKey, $info = null)
|
||||
{
|
||||
return $this->encrypt($data, false, $inputKey, $info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies and decrypts data encrypted with [[encryptByPassword()]].
|
||||
* @param string $data the encrypted data to decrypt
|
||||
* @param string $password the password to use for decryption
|
||||
* @return bool|string the decrypted data or false on authentication failure
|
||||
* @see encryptByPassword()
|
||||
*/
|
||||
public function decryptByPassword($data, $password)
|
||||
{
|
||||
return $this->decrypt($data, true, $password, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies and decrypts data encrypted with [[encryptByKey()]].
|
||||
* @param string $data the encrypted data to decrypt
|
||||
* @param string $inputKey the input to use for encryption and authentication
|
||||
* @param string $info optional context and application specific information, see [[hkdf()]]
|
||||
* @return bool|string the decrypted data or false on authentication failure
|
||||
* @see encryptByKey()
|
||||
*/
|
||||
public function decryptByKey($data, $inputKey, $info = null)
|
||||
{
|
||||
return $this->decrypt($data, false, $inputKey, $info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts data.
|
||||
*
|
||||
* @param string $data data to be encrypted
|
||||
* @param bool $passwordBased set true to use password-based key derivation
|
||||
* @param string $secret the encryption password or key
|
||||
* @param string|null $info context/application specific information, e.g. a user ID
|
||||
* See [RFC 5869 Section 3.2](https://tools.ietf.org/html/rfc5869#section-3.2) for more details.
|
||||
*
|
||||
* @return string the encrypted data
|
||||
* @throws InvalidConfigException on OpenSSL not loaded
|
||||
* @throws Exception on OpenSSL error
|
||||
* @see decrypt()
|
||||
*/
|
||||
protected function encrypt($data, $passwordBased, $secret, $info)
|
||||
{
|
||||
if (!extension_loaded('openssl')) {
|
||||
throw new InvalidConfigException('Encryption requires the OpenSSL PHP extension');
|
||||
}
|
||||
if (!isset($this->allowedCiphers[$this->cipher][0], $this->allowedCiphers[$this->cipher][1])) {
|
||||
throw new InvalidConfigException($this->cipher . ' is not an allowed cipher');
|
||||
}
|
||||
|
||||
list($blockSize, $keySize) = $this->allowedCiphers[$this->cipher];
|
||||
|
||||
$keySalt = $this->generateRandomKey($keySize);
|
||||
if ($passwordBased) {
|
||||
$key = $this->pbkdf2($this->kdfHash, $secret, $keySalt, $this->derivationIterations, $keySize);
|
||||
} else {
|
||||
$key = $this->hkdf($this->kdfHash, $secret, $keySalt, $info, $keySize);
|
||||
}
|
||||
|
||||
$iv = $this->generateRandomKey($blockSize);
|
||||
|
||||
$encrypted = openssl_encrypt($data, $this->cipher, $key, OPENSSL_RAW_DATA, $iv);
|
||||
if ($encrypted === false) {
|
||||
throw new \yii\base\Exception('OpenSSL failure on encryption: ' . openssl_error_string());
|
||||
}
|
||||
|
||||
$authKey = $this->hkdf($this->kdfHash, $key, null, $this->authKeyInfo, $keySize);
|
||||
$hashed = $this->hashData($iv . $encrypted, $authKey);
|
||||
|
||||
/*
|
||||
* Output: [keySalt][MAC][IV][ciphertext]
|
||||
* - keySalt is KEY_SIZE bytes long
|
||||
* - MAC: message authentication code, length same as the output of MAC_HASH
|
||||
* - IV: initialization vector, length $blockSize
|
||||
*/
|
||||
return $keySalt . $hashed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts data.
|
||||
*
|
||||
* @param string $data encrypted data to be decrypted.
|
||||
* @param bool $passwordBased set true to use password-based key derivation
|
||||
* @param string $secret the decryption password or key
|
||||
* @param string|null $info context/application specific information, @see encrypt()
|
||||
*
|
||||
* @return bool|string the decrypted data or false on authentication failure
|
||||
* @throws InvalidConfigException on OpenSSL not loaded
|
||||
* @throws Exception on OpenSSL error
|
||||
* @see encrypt()
|
||||
*/
|
||||
protected function decrypt($data, $passwordBased, $secret, $info)
|
||||
{
|
||||
if (!extension_loaded('openssl')) {
|
||||
throw new InvalidConfigException('Encryption requires the OpenSSL PHP extension');
|
||||
}
|
||||
if (!isset($this->allowedCiphers[$this->cipher][0], $this->allowedCiphers[$this->cipher][1])) {
|
||||
throw new InvalidConfigException($this->cipher . ' is not an allowed cipher');
|
||||
}
|
||||
|
||||
list($blockSize, $keySize) = $this->allowedCiphers[$this->cipher];
|
||||
|
||||
$keySalt = StringHelper::byteSubstr($data, 0, $keySize);
|
||||
if ($passwordBased) {
|
||||
$key = $this->pbkdf2($this->kdfHash, $secret, $keySalt, $this->derivationIterations, $keySize);
|
||||
} else {
|
||||
$key = $this->hkdf($this->kdfHash, $secret, $keySalt, $info, $keySize);
|
||||
}
|
||||
|
||||
$authKey = $this->hkdf($this->kdfHash, $key, null, $this->authKeyInfo, $keySize);
|
||||
$data = $this->validateData(StringHelper::byteSubstr($data, $keySize, null), $authKey);
|
||||
if ($data === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$iv = StringHelper::byteSubstr($data, 0, $blockSize);
|
||||
$encrypted = StringHelper::byteSubstr($data, $blockSize, null);
|
||||
|
||||
$decrypted = openssl_decrypt($encrypted, $this->cipher, $key, OPENSSL_RAW_DATA, $iv);
|
||||
if ($decrypted === false) {
|
||||
throw new \yii\base\Exception('OpenSSL failure on decryption: ' . openssl_error_string());
|
||||
}
|
||||
|
||||
return $decrypted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Derives a key from the given input key using the standard HKDF algorithm.
|
||||
* Implements HKDF specified in [RFC 5869](https://tools.ietf.org/html/rfc5869).
|
||||
* Recommend use one of the SHA-2 hash algorithms: sha224, sha256, sha384 or sha512.
|
||||
* @param string $algo a hash algorithm supported by `hash_hmac()`, e.g. 'SHA-256'
|
||||
* @param string $inputKey the source key
|
||||
* @param string $salt the random salt
|
||||
* @param string $info optional info to bind the derived key material to application-
|
||||
* and context-specific information, e.g. a user ID or API version, see
|
||||
* [RFC 5869](https://tools.ietf.org/html/rfc5869)
|
||||
* @param int $length length of the output key in bytes. If 0, the output key is
|
||||
* the length of the hash algorithm output.
|
||||
* @throws InvalidArgumentException when HMAC generation fails.
|
||||
* @return string the derived key
|
||||
*/
|
||||
public function hkdf($algo, $inputKey, $salt = null, $info = null, $length = 0)
|
||||
{
|
||||
if (function_exists('hash_hkdf')) {
|
||||
$outputKey = hash_hkdf($algo, $inputKey, $length, $info, $salt);
|
||||
if ($outputKey === false) {
|
||||
throw new InvalidArgumentException('Invalid parameters to hash_hkdf()');
|
||||
}
|
||||
|
||||
return $outputKey;
|
||||
}
|
||||
|
||||
$test = @hash_hmac($algo, '', '', true);
|
||||
if (!$test) {
|
||||
throw new InvalidArgumentException('Failed to generate HMAC with hash algorithm: ' . $algo);
|
||||
}
|
||||
$hashLength = StringHelper::byteLength($test);
|
||||
if (is_string($length) && preg_match('{^\d{1,16}$}', $length)) {
|
||||
$length = (int) $length;
|
||||
}
|
||||
if (!is_int($length) || $length < 0 || $length > 255 * $hashLength) {
|
||||
throw new InvalidArgumentException('Invalid length');
|
||||
}
|
||||
$blocks = $length !== 0 ? ceil($length / $hashLength) : 1;
|
||||
|
||||
if ($salt === null) {
|
||||
$salt = str_repeat("\0", $hashLength);
|
||||
}
|
||||
$prKey = hash_hmac($algo, $inputKey, $salt, true);
|
||||
|
||||
$hmac = '';
|
||||
$outputKey = '';
|
||||
for ($i = 1; $i <= $blocks; $i++) {
|
||||
$hmac = hash_hmac($algo, $hmac . $info . chr($i), $prKey, true);
|
||||
$outputKey .= $hmac;
|
||||
}
|
||||
|
||||
if ($length !== 0) {
|
||||
$outputKey = StringHelper::byteSubstr($outputKey, 0, $length);
|
||||
}
|
||||
|
||||
return $outputKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Derives a key from the given password using the standard PBKDF2 algorithm.
|
||||
* Implements HKDF2 specified in [RFC 2898](http://tools.ietf.org/html/rfc2898#section-5.2)
|
||||
* Recommend use one of the SHA-2 hash algorithms: sha224, sha256, sha384 or sha512.
|
||||
* @param string $algo a hash algorithm supported by `hash_hmac()`, e.g. 'SHA-256'
|
||||
* @param string $password the source password
|
||||
* @param string $salt the random salt
|
||||
* @param int $iterations the number of iterations of the hash algorithm. Set as high as
|
||||
* possible to hinder dictionary password attacks.
|
||||
* @param int $length length of the output key in bytes. If 0, the output key is
|
||||
* the length of the hash algorithm output.
|
||||
* @return string the derived key
|
||||
* @throws InvalidArgumentException when hash generation fails due to invalid params given.
|
||||
*/
|
||||
public function pbkdf2($algo, $password, $salt, $iterations, $length = 0)
|
||||
{
|
||||
if (function_exists('hash_pbkdf2')) {
|
||||
$outputKey = hash_pbkdf2($algo, $password, $salt, $iterations, $length, true);
|
||||
if ($outputKey === false) {
|
||||
throw new InvalidArgumentException('Invalid parameters to hash_pbkdf2()');
|
||||
}
|
||||
|
||||
return $outputKey;
|
||||
}
|
||||
|
||||
// todo: is there a nice way to reduce the code repetition in hkdf() and pbkdf2()?
|
||||
$test = @hash_hmac($algo, '', '', true);
|
||||
if (!$test) {
|
||||
throw new InvalidArgumentException('Failed to generate HMAC with hash algorithm: ' . $algo);
|
||||
}
|
||||
if (is_string($iterations) && preg_match('{^\d{1,16}$}', $iterations)) {
|
||||
$iterations = (int) $iterations;
|
||||
}
|
||||
if (!is_int($iterations) || $iterations < 1) {
|
||||
throw new InvalidArgumentException('Invalid iterations');
|
||||
}
|
||||
if (is_string($length) && preg_match('{^\d{1,16}$}', $length)) {
|
||||
$length = (int) $length;
|
||||
}
|
||||
if (!is_int($length) || $length < 0) {
|
||||
throw new InvalidArgumentException('Invalid length');
|
||||
}
|
||||
$hashLength = StringHelper::byteLength($test);
|
||||
$blocks = $length !== 0 ? ceil($length / $hashLength) : 1;
|
||||
|
||||
$outputKey = '';
|
||||
for ($j = 1; $j <= $blocks; $j++) {
|
||||
$hmac = hash_hmac($algo, $salt . pack('N', $j), $password, true);
|
||||
$xorsum = $hmac;
|
||||
for ($i = 1; $i < $iterations; $i++) {
|
||||
$hmac = hash_hmac($algo, $hmac, $password, true);
|
||||
$xorsum ^= $hmac;
|
||||
}
|
||||
$outputKey .= $xorsum;
|
||||
}
|
||||
|
||||
if ($length !== 0) {
|
||||
$outputKey = StringHelper::byteSubstr($outputKey, 0, $length);
|
||||
}
|
||||
|
||||
return $outputKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefixes data with a keyed hash value so that it can later be detected if it is tampered.
|
||||
* There is no need to hash inputs or outputs of [[encryptByKey()]] or [[encryptByPassword()]]
|
||||
* as those methods perform the task.
|
||||
* @param string $data the data to be protected
|
||||
* @param string $key the secret key to be used for generating hash. Should be a secure
|
||||
* cryptographic key.
|
||||
* @param bool $rawHash whether the generated hash value is in raw binary format. If false, lowercase
|
||||
* hex digits will be generated.
|
||||
* @return string the data prefixed with the keyed hash
|
||||
* @throws InvalidConfigException when HMAC generation fails.
|
||||
* @see validateData()
|
||||
* @see generateRandomKey()
|
||||
* @see hkdf()
|
||||
* @see pbkdf2()
|
||||
*/
|
||||
public function hashData($data, $key, $rawHash = false)
|
||||
{
|
||||
$hash = hash_hmac($this->macHash, $data, $key, $rawHash);
|
||||
if (!$hash) {
|
||||
throw new InvalidConfigException('Failed to generate HMAC with hash algorithm: ' . $this->macHash);
|
||||
}
|
||||
|
||||
return $hash . $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates if the given data is tampered.
|
||||
* @param string $data the data to be validated. The data must be previously
|
||||
* generated by [[hashData()]].
|
||||
* @param string $key the secret key that was previously used to generate the hash for the data in [[hashData()]].
|
||||
* function to see the supported hashing algorithms on your system. This must be the same
|
||||
* as the value passed to [[hashData()]] when generating the hash for the data.
|
||||
* @param bool $rawHash this should take the same value as when you generate the data using [[hashData()]].
|
||||
* It indicates whether the hash value in the data is in binary format. If false, it means the hash value consists
|
||||
* of lowercase hex digits only.
|
||||
* hex digits will be generated.
|
||||
* @return string|false the real data with the hash stripped off. False if the data is tampered.
|
||||
* @throws InvalidConfigException when HMAC generation fails.
|
||||
* @see hashData()
|
||||
*/
|
||||
public function validateData($data, $key, $rawHash = false)
|
||||
{
|
||||
$test = @hash_hmac($this->macHash, '', '', $rawHash);
|
||||
if (!$test) {
|
||||
throw new InvalidConfigException('Failed to generate HMAC with hash algorithm: ' . $this->macHash);
|
||||
}
|
||||
$hashLength = StringHelper::byteLength($test);
|
||||
if (StringHelper::byteLength($data) >= $hashLength) {
|
||||
$hash = StringHelper::byteSubstr($data, 0, $hashLength);
|
||||
$pureData = StringHelper::byteSubstr($data, $hashLength, null);
|
||||
|
||||
$calculatedHash = hash_hmac($this->macHash, $pureData, $key, $rawHash);
|
||||
|
||||
if ($this->compareString($hash, $calculatedHash)) {
|
||||
return $pureData;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private $_useLibreSSL;
|
||||
private $_randomFile;
|
||||
|
||||
/**
|
||||
* Generates specified number of random bytes.
|
||||
* Note that output may not be ASCII.
|
||||
* @see generateRandomString() if you need a string.
|
||||
*
|
||||
* @param int $length the number of bytes to generate
|
||||
* @return string the generated random bytes
|
||||
* @throws InvalidArgumentException if wrong length is specified
|
||||
* @throws Exception on failure.
|
||||
*/
|
||||
public function generateRandomKey($length = 32)
|
||||
{
|
||||
if (!is_int($length)) {
|
||||
throw new InvalidArgumentException('First parameter ($length) must be an integer');
|
||||
}
|
||||
|
||||
if ($length < 1) {
|
||||
throw new InvalidArgumentException('First parameter ($length) must be greater than 0');
|
||||
}
|
||||
|
||||
// always use random_bytes() if it is available
|
||||
if (function_exists('random_bytes')) {
|
||||
return random_bytes($length);
|
||||
}
|
||||
|
||||
// The recent LibreSSL RNGs are faster and likely better than /dev/urandom.
|
||||
// Parse OPENSSL_VERSION_TEXT because OPENSSL_VERSION_NUMBER is no use for LibreSSL.
|
||||
// https://bugs.php.net/bug.php?id=71143
|
||||
if ($this->_useLibreSSL === null) {
|
||||
$this->_useLibreSSL = defined('OPENSSL_VERSION_TEXT')
|
||||
&& preg_match('{^LibreSSL (\d\d?)\.(\d\d?)\.(\d\d?)$}', OPENSSL_VERSION_TEXT, $matches)
|
||||
&& (10000 * $matches[1]) + (100 * $matches[2]) + $matches[3] >= 20105;
|
||||
}
|
||||
|
||||
// Since 5.4.0, openssl_random_pseudo_bytes() reads from CryptGenRandom on Windows instead
|
||||
// of using OpenSSL library. LibreSSL is OK everywhere but don't use OpenSSL on non-Windows.
|
||||
if (function_exists('openssl_random_pseudo_bytes')
|
||||
&& ($this->_useLibreSSL
|
||||
|| (
|
||||
DIRECTORY_SEPARATOR !== '/'
|
||||
&& substr_compare(PHP_OS, 'win', 0, 3, true) === 0
|
||||
))
|
||||
) {
|
||||
$key = openssl_random_pseudo_bytes($length, $cryptoStrong);
|
||||
if ($cryptoStrong === false) {
|
||||
throw new Exception(
|
||||
'openssl_random_pseudo_bytes() set $crypto_strong false. Your PHP setup is insecure.'
|
||||
);
|
||||
}
|
||||
if ($key !== false && StringHelper::byteLength($key) === $length) {
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
|
||||
// mcrypt_create_iv() does not use libmcrypt. Since PHP 5.3.7 it directly reads
|
||||
// CryptGenRandom on Windows. Elsewhere it directly reads /dev/urandom.
|
||||
if (function_exists('mcrypt_create_iv')) {
|
||||
$key = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
|
||||
if (StringHelper::byteLength($key) === $length) {
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
|
||||
// If not on Windows, try to open a random device.
|
||||
if ($this->_randomFile === null && DIRECTORY_SEPARATOR === '/') {
|
||||
// urandom is a symlink to random on FreeBSD.
|
||||
$device = PHP_OS === 'FreeBSD' ? '/dev/random' : '/dev/urandom';
|
||||
// Check random device for special character device protection mode. Use lstat()
|
||||
// instead of stat() in case an attacker arranges a symlink to a fake device.
|
||||
$lstat = @lstat($device);
|
||||
if ($lstat !== false && ($lstat['mode'] & 0170000) === 020000) {
|
||||
$this->_randomFile = fopen($device, 'rb') ?: null;
|
||||
|
||||
if (is_resource($this->_randomFile)) {
|
||||
// Reduce PHP stream buffer from default 8192 bytes to optimize data
|
||||
// transfer from the random device for smaller values of $length.
|
||||
// This also helps to keep future randoms out of user memory space.
|
||||
$bufferSize = 8;
|
||||
|
||||
if (function_exists('stream_set_read_buffer')) {
|
||||
stream_set_read_buffer($this->_randomFile, $bufferSize);
|
||||
}
|
||||
// stream_set_read_buffer() isn't implemented on HHVM
|
||||
if (function_exists('stream_set_chunk_size')) {
|
||||
stream_set_chunk_size($this->_randomFile, $bufferSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_resource($this->_randomFile)) {
|
||||
$buffer = '';
|
||||
$stillNeed = $length;
|
||||
while ($stillNeed > 0) {
|
||||
$someBytes = fread($this->_randomFile, $stillNeed);
|
||||
if ($someBytes === false) {
|
||||
break;
|
||||
}
|
||||
$buffer .= $someBytes;
|
||||
$stillNeed -= StringHelper::byteLength($someBytes);
|
||||
if ($stillNeed === 0) {
|
||||
// Leaving file pointer open in order to make next generation faster by reusing it.
|
||||
return $buffer;
|
||||
}
|
||||
}
|
||||
fclose($this->_randomFile);
|
||||
$this->_randomFile = null;
|
||||
}
|
||||
|
||||
throw new Exception('Unable to generate a random key');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random string of specified length.
|
||||
* The string generated matches [A-Za-z0-9_-]+ and is transparent to URL-encoding.
|
||||
*
|
||||
* @param int $length the length of the key in characters
|
||||
* @return string the generated random key
|
||||
* @throws Exception on failure.
|
||||
*/
|
||||
public function generateRandomString($length = 32)
|
||||
{
|
||||
if (!is_int($length)) {
|
||||
throw new InvalidArgumentException('First parameter ($length) must be an integer');
|
||||
}
|
||||
|
||||
if ($length < 1) {
|
||||
throw new InvalidArgumentException('First parameter ($length) must be greater than 0');
|
||||
}
|
||||
|
||||
$bytes = $this->generateRandomKey($length);
|
||||
return substr(StringHelper::base64UrlEncode($bytes), 0, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a secure hash from a password and a random salt.
|
||||
*
|
||||
* The generated hash can be stored in database.
|
||||
* Later when a password needs to be validated, the hash can be fetched and passed
|
||||
* to [[validatePassword()]]. For example,
|
||||
*
|
||||
* ```php
|
||||
* // generates the hash (usually done during user registration or when the password is changed)
|
||||
* $hash = Yii::$app->getSecurity()->generatePasswordHash($password);
|
||||
* // ...save $hash in database...
|
||||
*
|
||||
* // during login, validate if the password entered is correct using $hash fetched from database
|
||||
* if (Yii::$app->getSecurity()->validatePassword($password, $hash)) {
|
||||
* // password is good
|
||||
* } else {
|
||||
* // password is bad
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param string $password The password to be hashed.
|
||||
* @param int $cost Cost parameter used by the Blowfish hash algorithm.
|
||||
* The higher the value of cost,
|
||||
* the longer it takes to generate the hash and to verify a password against it. Higher cost
|
||||
* therefore slows down a brute-force attack. For best protection against brute-force attacks,
|
||||
* set it to the highest value that is tolerable on production servers. The time taken to
|
||||
* compute the hash doubles for every increment by one of $cost.
|
||||
* @return string The password hash string. When [[passwordHashStrategy]] is set to 'crypt',
|
||||
* the output is always 60 ASCII characters, when set to 'password_hash' the output length
|
||||
* might increase in future versions of PHP (http://php.net/manual/en/function.password-hash.php)
|
||||
* @throws Exception on bad password parameter or cost parameter.
|
||||
* @see validatePassword()
|
||||
*/
|
||||
public function generatePasswordHash($password, $cost = null)
|
||||
{
|
||||
if ($cost === null) {
|
||||
$cost = $this->passwordHashCost;
|
||||
}
|
||||
|
||||
if (function_exists('password_hash')) {
|
||||
/* @noinspection PhpUndefinedConstantInspection */
|
||||
return password_hash($password, PASSWORD_DEFAULT, ['cost' => $cost]);
|
||||
}
|
||||
|
||||
$salt = $this->generateSalt($cost);
|
||||
$hash = crypt($password, $salt);
|
||||
// strlen() is safe since crypt() returns only ascii
|
||||
if (!is_string($hash) || strlen($hash) !== 60) {
|
||||
throw new Exception('Unknown error occurred while generating hash.');
|
||||
}
|
||||
|
||||
return $hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies a password against a hash.
|
||||
* @param string $password The password to verify.
|
||||
* @param string $hash The hash to verify the password against.
|
||||
* @return bool whether the password is correct.
|
||||
* @throws InvalidArgumentException on bad password/hash parameters or if crypt() with Blowfish hash is not available.
|
||||
* @see generatePasswordHash()
|
||||
*/
|
||||
public function validatePassword($password, $hash)
|
||||
{
|
||||
if (!is_string($password) || $password === '') {
|
||||
throw new InvalidArgumentException('Password must be a string and cannot be empty.');
|
||||
}
|
||||
|
||||
if (!preg_match('/^\$2[axy]\$(\d\d)\$[\.\/0-9A-Za-z]{22}/', $hash, $matches)
|
||||
|| $matches[1] < 4
|
||||
|| $matches[1] > 30
|
||||
) {
|
||||
throw new InvalidArgumentException('Hash is invalid.');
|
||||
}
|
||||
|
||||
if (function_exists('password_verify')) {
|
||||
return password_verify($password, $hash);
|
||||
}
|
||||
|
||||
$test = crypt($password, $hash);
|
||||
$n = strlen($test);
|
||||
if ($n !== 60) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->compareString($test, $hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a salt that can be used to generate a password hash.
|
||||
*
|
||||
* The PHP [crypt()](http://php.net/manual/en/function.crypt.php) built-in function
|
||||
* requires, for the Blowfish hash algorithm, a salt string in a specific format:
|
||||
* "$2a$", "$2x$" or "$2y$", a two digit cost parameter, "$", and 22 characters
|
||||
* from the alphabet "./0-9A-Za-z".
|
||||
*
|
||||
* @param int $cost the cost parameter
|
||||
* @return string the random salt value.
|
||||
* @throws InvalidArgumentException if the cost parameter is out of the range of 4 to 31.
|
||||
*/
|
||||
protected function generateSalt($cost = 13)
|
||||
{
|
||||
$cost = (int) $cost;
|
||||
if ($cost < 4 || $cost > 31) {
|
||||
throw new InvalidArgumentException('Cost must be between 4 and 31.');
|
||||
}
|
||||
|
||||
// Get a 20-byte random string
|
||||
$rand = $this->generateRandomKey(20);
|
||||
// Form the prefix that specifies Blowfish (bcrypt) algorithm and cost parameter.
|
||||
$salt = sprintf('$2y$%02d$', $cost);
|
||||
// Append the random salt data in the required base64 format.
|
||||
$salt .= str_replace('+', '.', substr(base64_encode($rand), 0, 22));
|
||||
|
||||
return $salt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs string comparison using timing attack resistant approach.
|
||||
* @see http://codereview.stackexchange.com/questions/13512
|
||||
* @param string $expected string to compare.
|
||||
* @param string $actual user-supplied string.
|
||||
* @return bool whether strings are equal.
|
||||
*/
|
||||
public function compareString($expected, $actual)
|
||||
{
|
||||
if (!is_string($expected)) {
|
||||
throw new InvalidArgumentException('Expected expected value to be a string, ' . gettype($expected) . ' given.');
|
||||
}
|
||||
|
||||
if (!is_string($actual)) {
|
||||
throw new InvalidArgumentException('Expected actual value to be a string, ' . gettype($actual) . ' given.');
|
||||
}
|
||||
|
||||
if (function_exists('hash_equals')) {
|
||||
return hash_equals($expected, $actual);
|
||||
}
|
||||
|
||||
$expected .= "\0";
|
||||
$actual .= "\0";
|
||||
$expectedLength = StringHelper::byteLength($expected);
|
||||
$actualLength = StringHelper::byteLength($actual);
|
||||
$diff = $expectedLength - $actualLength;
|
||||
for ($i = 0; $i < $actualLength; $i++) {
|
||||
$diff |= (ord($actual[$i]) ^ ord($expected[$i % $expectedLength]));
|
||||
}
|
||||
|
||||
return $diff === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Masks a token to make it uncompressible.
|
||||
* Applies a random mask to the token and prepends the mask used to the result making the string always unique.
|
||||
* Used to mitigate BREACH attack by randomizing how token is outputted on each request.
|
||||
* @param string $token An unmasked token.
|
||||
* @return string A masked token.
|
||||
* @since 2.0.12
|
||||
*/
|
||||
public function maskToken($token)
|
||||
{
|
||||
// The number of bytes in a mask is always equal to the number of bytes in a token.
|
||||
$mask = $this->generateRandomKey(StringHelper::byteLength($token));
|
||||
return StringHelper::base64UrlEncode($mask . ($mask ^ $token));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmasks a token previously masked by `maskToken`.
|
||||
* @param string $maskedToken A masked token.
|
||||
* @return string An unmasked token, or an empty string in case of token format is invalid.
|
||||
* @since 2.0.12
|
||||
*/
|
||||
public function unmaskToken($maskedToken)
|
||||
{
|
||||
$decoded = StringHelper::base64UrlDecode($maskedToken);
|
||||
$length = StringHelper::byteLength($decoded) / 2;
|
||||
// Check if the masked token has an even length.
|
||||
if (!is_int($length)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return StringHelper::byteSubstr($decoded, $length, $length) ^ StringHelper::byteSubstr($decoded, 0, $length);
|
||||
}
|
||||
}
|
||||
30
vendor/yiisoft/yii2/base/StaticInstanceInterface.php
vendored
Normal file
30
vendor/yiisoft/yii2/base/StaticInstanceInterface.php
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* StaticInstanceInterface is the interface for providing static instances to classes,
|
||||
* which can be used to obtain class meta information that can not be expressed in static methods.
|
||||
* For example: adjustments made by DI or behaviors reveal only at object level, but might be needed
|
||||
* at class (static) level as well.
|
||||
*
|
||||
* To implement the [[instance()]] method you may use [[StaticInstanceTrait]].
|
||||
*
|
||||
* @author Paul Klimov <klimov.paul@gmail.com>
|
||||
* @since 2.0.13
|
||||
* @see StaticInstanceTrait
|
||||
*/
|
||||
interface StaticInstanceInterface
|
||||
{
|
||||
/**
|
||||
* Returns static class instance, which can be used to obtain meta information.
|
||||
* @param bool $refresh whether to re-create static instance even, if it is already cached.
|
||||
* @return static class instance.
|
||||
*/
|
||||
public static function instance($refresh = false);
|
||||
}
|
||||
41
vendor/yiisoft/yii2/base/StaticInstanceTrait.php
vendored
Normal file
41
vendor/yiisoft/yii2/base/StaticInstanceTrait.php
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
use Yii;
|
||||
|
||||
/**
|
||||
* StaticInstanceTrait provides methods to satisfy [[StaticInstanceInterface]] interface.
|
||||
*
|
||||
* @see StaticInstanceInterface
|
||||
*
|
||||
* @author Paul Klimov <klimov.paul@gmail.com>
|
||||
* @since 2.0.13
|
||||
*/
|
||||
trait StaticInstanceTrait
|
||||
{
|
||||
/**
|
||||
* @var static[] static instances in format: `[className => object]`
|
||||
*/
|
||||
private static $_instances = [];
|
||||
|
||||
|
||||
/**
|
||||
* Returns static class instance, which can be used to obtain meta information.
|
||||
* @param bool $refresh whether to re-create static instance even, if it is already cached.
|
||||
* @return static class instance.
|
||||
*/
|
||||
public static function instance($refresh = false)
|
||||
{
|
||||
$className = get_called_class();
|
||||
if ($refresh || !isset(self::$_instances[$className])) {
|
||||
self::$_instances[$className] = Yii::createObject($className);
|
||||
}
|
||||
return self::$_instances[$className];
|
||||
}
|
||||
}
|
||||
189
vendor/yiisoft/yii2/base/Theme.php
vendored
Normal file
189
vendor/yiisoft/yii2/base/Theme.php
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
use Yii;
|
||||
use yii\helpers\FileHelper;
|
||||
|
||||
/**
|
||||
* Theme represents an application theme.
|
||||
*
|
||||
* When [[View]] renders a view file, it will check the [[View::theme|active theme]]
|
||||
* to see if there is a themed version of the view file exists. If so, the themed version will be rendered instead.
|
||||
*
|
||||
* A theme is a directory consisting of view files which are meant to replace their non-themed counterparts.
|
||||
*
|
||||
* Theme uses [[pathMap]] to achieve the view file replacement:
|
||||
*
|
||||
* 1. It first looks for a key in [[pathMap]] that is a substring of the given view file path;
|
||||
* 2. If such a key exists, the corresponding value will be used to replace the corresponding part
|
||||
* in the view file path;
|
||||
* 3. It will then check if the updated view file exists or not. If so, that file will be used
|
||||
* to replace the original view file.
|
||||
* 4. If Step 2 or 3 fails, the original view file will be used.
|
||||
*
|
||||
* For example, if [[pathMap]] is `['@app/views' => '@app/themes/basic']`,
|
||||
* then the themed version for a view file `@app/views/site/index.php` will be
|
||||
* `@app/themes/basic/site/index.php`.
|
||||
*
|
||||
* It is possible to map a single path to multiple paths. For example,
|
||||
*
|
||||
* ```php
|
||||
* 'pathMap' => [
|
||||
* '@app/views' => [
|
||||
* '@app/themes/christmas',
|
||||
* '@app/themes/basic',
|
||||
* ],
|
||||
* ]
|
||||
* ```
|
||||
*
|
||||
* In this case, the themed version could be either `@app/themes/christmas/site/index.php` or
|
||||
* `@app/themes/basic/site/index.php`. The former has precedence over the latter if both files exist.
|
||||
*
|
||||
* To use a theme, you should configure the [[View::theme|theme]] property of the "view" application
|
||||
* component like the following:
|
||||
*
|
||||
* ```php
|
||||
* 'view' => [
|
||||
* 'theme' => [
|
||||
* 'basePath' => '@app/themes/basic',
|
||||
* 'baseUrl' => '@web/themes/basic',
|
||||
* ],
|
||||
* ],
|
||||
* ```
|
||||
*
|
||||
* The above configuration specifies a theme located under the "themes/basic" directory of the Web folder
|
||||
* that contains the entry script of the application. If your theme is designed to handle modules,
|
||||
* you may configure the [[pathMap]] property like described above.
|
||||
*
|
||||
* For more details and usage information on Theme, see the [guide article on theming](guide:output-theming).
|
||||
*
|
||||
* @property string $basePath The root path of this theme. All resources of this theme are located under this
|
||||
* directory.
|
||||
* @property string $baseUrl The base URL (without ending slash) for this theme. All resources of this theme
|
||||
* are considered to be under this base URL.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class Theme extends Component
|
||||
{
|
||||
/**
|
||||
* @var array the mapping between view directories and their corresponding themed versions.
|
||||
* This property is used by [[applyTo()]] when a view is trying to apply the theme.
|
||||
* [Path aliases](guide:concept-aliases) can be used when specifying directories.
|
||||
* If this property is empty or not set, a mapping [[Application::basePath]] to [[basePath]] will be used.
|
||||
*/
|
||||
public $pathMap;
|
||||
|
||||
private $_baseUrl;
|
||||
|
||||
|
||||
/**
|
||||
* @return string the base URL (without ending slash) for this theme. All resources of this theme are considered
|
||||
* to be under this base URL.
|
||||
*/
|
||||
public function getBaseUrl()
|
||||
{
|
||||
return $this->_baseUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url the base URL or [path alias](guide:concept-aliases) for this theme. All resources of this theme are considered
|
||||
* to be under this base URL.
|
||||
*/
|
||||
public function setBaseUrl($url)
|
||||
{
|
||||
$this->_baseUrl = $url === null ? null : rtrim(Yii::getAlias($url), '/');
|
||||
}
|
||||
|
||||
private $_basePath;
|
||||
|
||||
/**
|
||||
* @return string the root path of this theme. All resources of this theme are located under this directory.
|
||||
* @see pathMap
|
||||
*/
|
||||
public function getBasePath()
|
||||
{
|
||||
return $this->_basePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path the root path or [path alias](guide:concept-aliases) of this theme. All resources of this theme are located
|
||||
* under this directory.
|
||||
* @see pathMap
|
||||
*/
|
||||
public function setBasePath($path)
|
||||
{
|
||||
$this->_basePath = Yii::getAlias($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a file to a themed file if possible.
|
||||
* If there is no corresponding themed file, the original file will be returned.
|
||||
* @param string $path the file to be themed
|
||||
* @return string the themed file, or the original file if the themed version is not available.
|
||||
* @throws InvalidConfigException if [[basePath]] is not set
|
||||
*/
|
||||
public function applyTo($path)
|
||||
{
|
||||
$pathMap = $this->pathMap;
|
||||
if (empty($pathMap)) {
|
||||
if (($basePath = $this->getBasePath()) === null) {
|
||||
throw new InvalidConfigException('The "basePath" property must be set.');
|
||||
}
|
||||
$pathMap = [Yii::$app->getBasePath() => [$basePath]];
|
||||
}
|
||||
$path = FileHelper::normalizePath($path);
|
||||
foreach ($pathMap as $from => $tos) {
|
||||
$from = FileHelper::normalizePath(Yii::getAlias($from)) . DIRECTORY_SEPARATOR;
|
||||
if (strpos($path, $from) === 0) {
|
||||
$n = strlen($from);
|
||||
foreach ((array) $tos as $to) {
|
||||
$to = FileHelper::normalizePath(Yii::getAlias($to)) . DIRECTORY_SEPARATOR;
|
||||
$file = $to . substr($path, $n);
|
||||
if (is_file($file)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a relative URL into an absolute URL using [[baseUrl]].
|
||||
* @param string $url the relative URL to be converted.
|
||||
* @return string the absolute URL
|
||||
* @throws InvalidConfigException if [[baseUrl]] is not set
|
||||
*/
|
||||
public function getUrl($url)
|
||||
{
|
||||
if (($baseUrl = $this->getBaseUrl()) !== null) {
|
||||
return $baseUrl . '/' . ltrim($url, '/');
|
||||
}
|
||||
|
||||
throw new InvalidConfigException('The "baseUrl" property must be set.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a relative file path into an absolute one using [[basePath]].
|
||||
* @param string $path the relative file path to be converted.
|
||||
* @return string the absolute file path
|
||||
* @throws InvalidConfigException if [[basePath]] is not set
|
||||
*/
|
||||
public function getPath($path)
|
||||
{
|
||||
if (($basePath = $this->getBasePath()) !== null) {
|
||||
return $basePath . DIRECTORY_SEPARATOR . ltrim($path, '/\\');
|
||||
}
|
||||
|
||||
throw new InvalidConfigException('The "basePath" property must be set.');
|
||||
}
|
||||
}
|
||||
25
vendor/yiisoft/yii2/base/UnknownClassException.php
vendored
Normal file
25
vendor/yiisoft/yii2/base/UnknownClassException.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* UnknownClassException represents an exception caused by using an unknown class.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class UnknownClassException extends Exception
|
||||
{
|
||||
/**
|
||||
* @return string the user-friendly name of this exception
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'Unknown Class';
|
||||
}
|
||||
}
|
||||
25
vendor/yiisoft/yii2/base/UnknownMethodException.php
vendored
Normal file
25
vendor/yiisoft/yii2/base/UnknownMethodException.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* UnknownMethodException represents an exception caused by accessing an unknown object method.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class UnknownMethodException extends \BadMethodCallException
|
||||
{
|
||||
/**
|
||||
* @return string the user-friendly name of this exception
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'Unknown Method';
|
||||
}
|
||||
}
|
||||
25
vendor/yiisoft/yii2/base/UnknownPropertyException.php
vendored
Normal file
25
vendor/yiisoft/yii2/base/UnknownPropertyException.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* UnknownPropertyException represents an exception caused by accessing unknown object properties.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class UnknownPropertyException extends Exception
|
||||
{
|
||||
/**
|
||||
* @return string the user-friendly name of this exception
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'Unknown Property';
|
||||
}
|
||||
}
|
||||
19
vendor/yiisoft/yii2/base/UserException.php
vendored
Normal file
19
vendor/yiisoft/yii2/base/UserException.php
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* UserException is the base class for exceptions that are meant to be shown to end users.
|
||||
* Such exceptions are often caused by mistakes of end users.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class UserException extends Exception
|
||||
{
|
||||
}
|
||||
574
vendor/yiisoft/yii2/base/View.php
vendored
Normal file
574
vendor/yiisoft/yii2/base/View.php
vendored
Normal file
@@ -0,0 +1,574 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
use Yii;
|
||||
use yii\helpers\FileHelper;
|
||||
use yii\widgets\Block;
|
||||
use yii\widgets\ContentDecorator;
|
||||
use yii\widgets\FragmentCache;
|
||||
|
||||
/**
|
||||
* View represents a view object in the MVC pattern.
|
||||
*
|
||||
* View provides a set of methods (e.g. [[render()]]) for rendering purpose.
|
||||
*
|
||||
* For more details and usage information on View, see the [guide article on views](guide:structure-views).
|
||||
*
|
||||
* @property string|bool $viewFile The view file currently being rendered. False if no view file is being
|
||||
* rendered. This property is read-only.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class View extends Component implements DynamicContentAwareInterface
|
||||
{
|
||||
/**
|
||||
* @event Event an event that is triggered by [[beginPage()]].
|
||||
*/
|
||||
const EVENT_BEGIN_PAGE = 'beginPage';
|
||||
/**
|
||||
* @event Event an event that is triggered by [[endPage()]].
|
||||
*/
|
||||
const EVENT_END_PAGE = 'endPage';
|
||||
/**
|
||||
* @event ViewEvent an event that is triggered by [[renderFile()]] right before it renders a view file.
|
||||
*/
|
||||
const EVENT_BEFORE_RENDER = 'beforeRender';
|
||||
/**
|
||||
* @event ViewEvent an event that is triggered by [[renderFile()]] right after it renders a view file.
|
||||
*/
|
||||
const EVENT_AFTER_RENDER = 'afterRender';
|
||||
|
||||
/**
|
||||
* @var ViewContextInterface the context under which the [[renderFile()]] method is being invoked.
|
||||
*/
|
||||
public $context;
|
||||
/**
|
||||
* @var mixed custom parameters that are shared among view templates.
|
||||
*/
|
||||
public $params = [];
|
||||
/**
|
||||
* @var array a list of available renderers indexed by their corresponding supported file extensions.
|
||||
* Each renderer may be a view renderer object or the configuration for creating the renderer object.
|
||||
* For example, the following configuration enables both Smarty and Twig view renderers:
|
||||
*
|
||||
* ```php
|
||||
* [
|
||||
* 'tpl' => ['class' => 'yii\smarty\ViewRenderer'],
|
||||
* 'twig' => ['class' => 'yii\twig\ViewRenderer'],
|
||||
* ]
|
||||
* ```
|
||||
*
|
||||
* If no renderer is available for the given view file, the view file will be treated as a normal PHP
|
||||
* and rendered via [[renderPhpFile()]].
|
||||
*/
|
||||
public $renderers;
|
||||
/**
|
||||
* @var string the default view file extension. This will be appended to view file names if they don't have file extensions.
|
||||
*/
|
||||
public $defaultExtension = 'php';
|
||||
/**
|
||||
* @var Theme|array|string the theme object or the configuration for creating the theme object.
|
||||
* If not set, it means theming is not enabled.
|
||||
*/
|
||||
public $theme;
|
||||
/**
|
||||
* @var array a list of named output blocks. The keys are the block names and the values
|
||||
* are the corresponding block content. You can call [[beginBlock()]] and [[endBlock()]]
|
||||
* to capture small fragments of a view. They can be later accessed somewhere else
|
||||
* through this property.
|
||||
*/
|
||||
public $blocks;
|
||||
/**
|
||||
* @var array|DynamicContentAwareInterface[] a list of currently active dynamic content class instances.
|
||||
* This property is used internally to implement the dynamic content caching feature. Do not modify it directly.
|
||||
* @internal
|
||||
* @deprecated Since 2.0.14. Do not use this property directly. Use methods [[getDynamicContents()]],
|
||||
* [[pushDynamicContent()]], [[popDynamicContent()]] instead.
|
||||
*/
|
||||
public $cacheStack = [];
|
||||
/**
|
||||
* @var array a list of placeholders for embedding dynamic contents. This property
|
||||
* is used internally to implement the content caching feature. Do not modify it directly.
|
||||
* @internal
|
||||
* @deprecated Since 2.0.14. Do not use this property directly. Use methods [[getDynamicPlaceholders()]],
|
||||
* [[setDynamicPlaceholders()]], [[addDynamicPlaceholder()]] instead.
|
||||
*/
|
||||
public $dynamicPlaceholders = [];
|
||||
|
||||
/**
|
||||
* @var array the view files currently being rendered. There may be multiple view files being
|
||||
* rendered at a moment because one view may be rendered within another.
|
||||
*/
|
||||
private $_viewFiles = [];
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the view component.
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
if (is_array($this->theme)) {
|
||||
if (!isset($this->theme['class'])) {
|
||||
$this->theme['class'] = 'yii\base\Theme';
|
||||
}
|
||||
$this->theme = Yii::createObject($this->theme);
|
||||
} elseif (is_string($this->theme)) {
|
||||
$this->theme = Yii::createObject($this->theme);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a view.
|
||||
*
|
||||
* The view to be rendered can be specified in one of the following formats:
|
||||
*
|
||||
* - [path alias](guide:concept-aliases) (e.g. "@app/views/site/index");
|
||||
* - absolute path within application (e.g. "//site/index"): the view name starts with double slashes.
|
||||
* The actual view file will be looked for under the [[Application::viewPath|view path]] of the application.
|
||||
* - absolute path within current module (e.g. "/site/index"): the view name starts with a single slash.
|
||||
* The actual view file will be looked for under the [[Module::viewPath|view path]] of the [[Controller::module|current module]].
|
||||
* - relative view (e.g. "index"): the view name does not start with `@` or `/`. The corresponding view file will be
|
||||
* looked for under the [[ViewContextInterface::getViewPath()|view path]] of the view `$context`.
|
||||
* If `$context` is not given, it will be looked for under the directory containing the view currently
|
||||
* being rendered (i.e., this happens when rendering a view within another view).
|
||||
*
|
||||
* @param string $view the view name.
|
||||
* @param array $params the parameters (name-value pairs) that will be extracted and made available in the view file.
|
||||
* @param object $context the context to be assigned to the view and can later be accessed via [[context]]
|
||||
* in the view. If the context implements [[ViewContextInterface]], it may also be used to locate
|
||||
* the view file corresponding to a relative view name.
|
||||
* @return string the rendering result
|
||||
* @throws ViewNotFoundException if the view file does not exist.
|
||||
* @throws InvalidCallException if the view cannot be resolved.
|
||||
* @see renderFile()
|
||||
*/
|
||||
public function render($view, $params = [], $context = null)
|
||||
{
|
||||
$viewFile = $this->findViewFile($view, $context);
|
||||
return $this->renderFile($viewFile, $params, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the view file based on the given view name.
|
||||
* @param string $view the view name or the [path alias](guide:concept-aliases) of the view file. Please refer to [[render()]]
|
||||
* on how to specify this parameter.
|
||||
* @param object $context the context to be assigned to the view and can later be accessed via [[context]]
|
||||
* in the view. If the context implements [[ViewContextInterface]], it may also be used to locate
|
||||
* the view file corresponding to a relative view name.
|
||||
* @return string the view file path. Note that the file may not exist.
|
||||
* @throws InvalidCallException if a relative view name is given while there is no active context to
|
||||
* determine the corresponding view file.
|
||||
*/
|
||||
protected function findViewFile($view, $context = null)
|
||||
{
|
||||
if (strncmp($view, '@', 1) === 0) {
|
||||
// e.g. "@app/views/main"
|
||||
$file = Yii::getAlias($view);
|
||||
} elseif (strncmp($view, '//', 2) === 0) {
|
||||
// e.g. "//layouts/main"
|
||||
$file = Yii::$app->getViewPath() . DIRECTORY_SEPARATOR . ltrim($view, '/');
|
||||
} elseif (strncmp($view, '/', 1) === 0) {
|
||||
// e.g. "/site/index"
|
||||
if (Yii::$app->controller !== null) {
|
||||
$file = Yii::$app->controller->module->getViewPath() . DIRECTORY_SEPARATOR . ltrim($view, '/');
|
||||
} else {
|
||||
throw new InvalidCallException("Unable to locate view file for view '$view': no active controller.");
|
||||
}
|
||||
} elseif ($context instanceof ViewContextInterface) {
|
||||
$file = $context->getViewPath() . DIRECTORY_SEPARATOR . $view;
|
||||
} elseif (($currentViewFile = $this->getViewFile()) !== false) {
|
||||
$file = dirname($currentViewFile) . DIRECTORY_SEPARATOR . $view;
|
||||
} else {
|
||||
throw new InvalidCallException("Unable to resolve view file for view '$view': no active view context.");
|
||||
}
|
||||
|
||||
if (pathinfo($file, PATHINFO_EXTENSION) !== '') {
|
||||
return $file;
|
||||
}
|
||||
$path = $file . '.' . $this->defaultExtension;
|
||||
if ($this->defaultExtension !== 'php' && !is_file($path)) {
|
||||
$path = $file . '.php';
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a view file.
|
||||
*
|
||||
* If [[theme]] is enabled (not null), it will try to render the themed version of the view file as long
|
||||
* as it is available.
|
||||
*
|
||||
* The method will call [[FileHelper::localize()]] to localize the view file.
|
||||
*
|
||||
* If [[renderers|renderer]] is enabled (not null), the method will use it to render the view file.
|
||||
* Otherwise, it will simply include the view file as a normal PHP file, capture its output and
|
||||
* return it as a string.
|
||||
*
|
||||
* @param string $viewFile the view file. This can be either an absolute file path or an alias of it.
|
||||
* @param array $params the parameters (name-value pairs) that will be extracted and made available in the view file.
|
||||
* @param object $context the context that the view should use for rendering the view. If null,
|
||||
* existing [[context]] will be used.
|
||||
* @return string the rendering result
|
||||
* @throws ViewNotFoundException if the view file does not exist
|
||||
*/
|
||||
public function renderFile($viewFile, $params = [], $context = null)
|
||||
{
|
||||
$viewFile = Yii::getAlias($viewFile);
|
||||
|
||||
if ($this->theme !== null) {
|
||||
$viewFile = $this->theme->applyTo($viewFile);
|
||||
}
|
||||
if (is_file($viewFile)) {
|
||||
$viewFile = FileHelper::localize($viewFile);
|
||||
} else {
|
||||
throw new ViewNotFoundException("The view file does not exist: $viewFile");
|
||||
}
|
||||
|
||||
$oldContext = $this->context;
|
||||
if ($context !== null) {
|
||||
$this->context = $context;
|
||||
}
|
||||
$output = '';
|
||||
$this->_viewFiles[] = $viewFile;
|
||||
|
||||
if ($this->beforeRender($viewFile, $params)) {
|
||||
Yii::debug("Rendering view file: $viewFile", __METHOD__);
|
||||
$ext = pathinfo($viewFile, PATHINFO_EXTENSION);
|
||||
if (isset($this->renderers[$ext])) {
|
||||
if (is_array($this->renderers[$ext]) || is_string($this->renderers[$ext])) {
|
||||
$this->renderers[$ext] = Yii::createObject($this->renderers[$ext]);
|
||||
}
|
||||
/* @var $renderer ViewRenderer */
|
||||
$renderer = $this->renderers[$ext];
|
||||
$output = $renderer->render($this, $viewFile, $params);
|
||||
} else {
|
||||
$output = $this->renderPhpFile($viewFile, $params);
|
||||
}
|
||||
$this->afterRender($viewFile, $params, $output);
|
||||
}
|
||||
|
||||
array_pop($this->_viewFiles);
|
||||
$this->context = $oldContext;
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|bool the view file currently being rendered. False if no view file is being rendered.
|
||||
*/
|
||||
public function getViewFile()
|
||||
{
|
||||
return end($this->_viewFiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is invoked right before [[renderFile()]] renders a view file.
|
||||
* The default implementation will trigger the [[EVENT_BEFORE_RENDER]] event.
|
||||
* If you override this method, make sure you call the parent implementation first.
|
||||
* @param string $viewFile the view file to be rendered.
|
||||
* @param array $params the parameter array passed to the [[render()]] method.
|
||||
* @return bool whether to continue rendering the view file.
|
||||
*/
|
||||
public function beforeRender($viewFile, $params)
|
||||
{
|
||||
$event = new ViewEvent([
|
||||
'viewFile' => $viewFile,
|
||||
'params' => $params,
|
||||
]);
|
||||
$this->trigger(self::EVENT_BEFORE_RENDER, $event);
|
||||
|
||||
return $event->isValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is invoked right after [[renderFile()]] renders a view file.
|
||||
* The default implementation will trigger the [[EVENT_AFTER_RENDER]] event.
|
||||
* If you override this method, make sure you call the parent implementation first.
|
||||
* @param string $viewFile the view file being rendered.
|
||||
* @param array $params the parameter array passed to the [[render()]] method.
|
||||
* @param string $output the rendering result of the view file. Updates to this parameter
|
||||
* will be passed back and returned by [[renderFile()]].
|
||||
*/
|
||||
public function afterRender($viewFile, $params, &$output)
|
||||
{
|
||||
if ($this->hasEventHandlers(self::EVENT_AFTER_RENDER)) {
|
||||
$event = new ViewEvent([
|
||||
'viewFile' => $viewFile,
|
||||
'params' => $params,
|
||||
'output' => $output,
|
||||
]);
|
||||
$this->trigger(self::EVENT_AFTER_RENDER, $event);
|
||||
$output = $event->output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a view file as a PHP script.
|
||||
*
|
||||
* This method treats the view file as a PHP script and includes the file.
|
||||
* It extracts the given parameters and makes them available in the view file.
|
||||
* The method captures the output of the included view file and returns it as a string.
|
||||
*
|
||||
* This method should mainly be called by view renderer or [[renderFile()]].
|
||||
*
|
||||
* @param string $_file_ the view file.
|
||||
* @param array $_params_ the parameters (name-value pairs) that will be extracted and made available in the view file.
|
||||
* @return string the rendering result
|
||||
* @throws \Exception
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function renderPhpFile($_file_, $_params_ = [])
|
||||
{
|
||||
$_obInitialLevel_ = ob_get_level();
|
||||
ob_start();
|
||||
ob_implicit_flush(false);
|
||||
extract($_params_, EXTR_OVERWRITE);
|
||||
try {
|
||||
require $_file_;
|
||||
return ob_get_clean();
|
||||
} catch (\Exception $e) {
|
||||
while (ob_get_level() > $_obInitialLevel_) {
|
||||
if (!@ob_end_clean()) {
|
||||
ob_clean();
|
||||
}
|
||||
}
|
||||
throw $e;
|
||||
} catch (\Throwable $e) {
|
||||
while (ob_get_level() > $_obInitialLevel_) {
|
||||
if (!@ob_end_clean()) {
|
||||
ob_clean();
|
||||
}
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders dynamic content returned by the given PHP statements.
|
||||
* This method is mainly used together with content caching (fragment caching and page caching)
|
||||
* when some portions of the content (called *dynamic content*) should not be cached.
|
||||
* The dynamic content must be returned by some PHP statements.
|
||||
* @param string $statements the PHP statements for generating the dynamic content.
|
||||
* @return string the placeholder of the dynamic content, or the dynamic content if there is no
|
||||
* active content cache currently.
|
||||
*/
|
||||
public function renderDynamic($statements)
|
||||
{
|
||||
if (!empty($this->cacheStack)) {
|
||||
$n = count($this->dynamicPlaceholders);
|
||||
$placeholder = "<![CDATA[YII-DYNAMIC-$n]]>";
|
||||
$this->addDynamicPlaceholder($placeholder, $statements);
|
||||
|
||||
return $placeholder;
|
||||
}
|
||||
|
||||
return $this->evaluateDynamicContent($statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDynamicPlaceholders()
|
||||
{
|
||||
return $this->dynamicPlaceholders;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setDynamicPlaceholders($placeholders)
|
||||
{
|
||||
$this->dynamicPlaceholders = $placeholders;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addDynamicPlaceholder($placeholder, $statements)
|
||||
{
|
||||
foreach ($this->cacheStack as $cache) {
|
||||
if ($cache instanceof DynamicContentAwareInterface) {
|
||||
$cache->addDynamicPlaceholder($placeholder, $statements);
|
||||
} else {
|
||||
// TODO: Remove in 2.1
|
||||
$cache->dynamicPlaceholders[$placeholder] = $statements;
|
||||
}
|
||||
}
|
||||
$this->dynamicPlaceholders[$placeholder] = $statements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the given PHP statements.
|
||||
* This method is mainly used internally to implement dynamic content feature.
|
||||
* @param string $statements the PHP statements to be evaluated.
|
||||
* @return mixed the return value of the PHP statements.
|
||||
*/
|
||||
public function evaluateDynamicContent($statements)
|
||||
{
|
||||
return eval($statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of currently active dynamic content class instances.
|
||||
* @return DynamicContentAwareInterface[] class instances supporting dynamic contents.
|
||||
* @since 2.0.14
|
||||
*/
|
||||
public function getDynamicContents()
|
||||
{
|
||||
return $this->cacheStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a class instance supporting dynamic contents to the end of a list of currently active
|
||||
* dynamic content class instances.
|
||||
* @param DynamicContentAwareInterface $instance class instance supporting dynamic contents.
|
||||
* @since 2.0.14
|
||||
*/
|
||||
public function pushDynamicContent(DynamicContentAwareInterface $instance)
|
||||
{
|
||||
$this->cacheStack[] = $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a last class instance supporting dynamic contents from a list of currently active
|
||||
* dynamic content class instances.
|
||||
* @since 2.0.14
|
||||
*/
|
||||
public function popDynamicContent()
|
||||
{
|
||||
array_pop($this->cacheStack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Begins recording a block.
|
||||
*
|
||||
* This method is a shortcut to beginning [[Block]].
|
||||
* @param string $id the block ID.
|
||||
* @param bool $renderInPlace whether to render the block content in place.
|
||||
* Defaults to false, meaning the captured block will not be displayed.
|
||||
* @return Block the Block widget instance
|
||||
*/
|
||||
public function beginBlock($id, $renderInPlace = false)
|
||||
{
|
||||
return Block::begin([
|
||||
'id' => $id,
|
||||
'renderInPlace' => $renderInPlace,
|
||||
'view' => $this,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends recording a block.
|
||||
*/
|
||||
public function endBlock()
|
||||
{
|
||||
Block::end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Begins the rendering of content that is to be decorated by the specified view.
|
||||
*
|
||||
* This method can be used to implement nested layout. For example, a layout can be embedded
|
||||
* in another layout file specified as '@app/views/layouts/base.php' like the following:
|
||||
*
|
||||
* ```php
|
||||
* <?php $this->beginContent('@app/views/layouts/base.php'); ?>
|
||||
* //...layout content here...
|
||||
* <?php $this->endContent(); ?>
|
||||
* ```
|
||||
*
|
||||
* @param string $viewFile the view file that will be used to decorate the content enclosed by this widget.
|
||||
* This can be specified as either the view file path or [path alias](guide:concept-aliases).
|
||||
* @param array $params the variables (name => value) to be extracted and made available in the decorative view.
|
||||
* @return ContentDecorator the ContentDecorator widget instance
|
||||
* @see ContentDecorator
|
||||
*/
|
||||
public function beginContent($viewFile, $params = [])
|
||||
{
|
||||
return ContentDecorator::begin([
|
||||
'viewFile' => $viewFile,
|
||||
'params' => $params,
|
||||
'view' => $this,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends the rendering of content.
|
||||
*/
|
||||
public function endContent()
|
||||
{
|
||||
ContentDecorator::end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Begins fragment caching.
|
||||
*
|
||||
* This method will display cached content if it is available.
|
||||
* If not, it will start caching and would expect an [[endCache()]]
|
||||
* call to end the cache and save the content into cache.
|
||||
* A typical usage of fragment caching is as follows,
|
||||
*
|
||||
* ```php
|
||||
* if ($this->beginCache($id)) {
|
||||
* // ...generate content here
|
||||
* $this->endCache();
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param string $id a unique ID identifying the fragment to be cached.
|
||||
* @param array $properties initial property values for [[FragmentCache]]
|
||||
* @return bool whether you should generate the content for caching.
|
||||
* False if the cached version is available.
|
||||
*/
|
||||
public function beginCache($id, $properties = [])
|
||||
{
|
||||
$properties['id'] = $id;
|
||||
$properties['view'] = $this;
|
||||
/* @var $cache FragmentCache */
|
||||
$cache = FragmentCache::begin($properties);
|
||||
if ($cache->getCachedContent() !== false) {
|
||||
$this->endCache();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends fragment caching.
|
||||
*/
|
||||
public function endCache()
|
||||
{
|
||||
FragmentCache::end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the beginning of a page.
|
||||
*/
|
||||
public function beginPage()
|
||||
{
|
||||
ob_start();
|
||||
ob_implicit_flush(false);
|
||||
|
||||
$this->trigger(self::EVENT_BEGIN_PAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the ending of a page.
|
||||
*/
|
||||
public function endPage()
|
||||
{
|
||||
$this->trigger(self::EVENT_END_PAGE);
|
||||
ob_end_flush();
|
||||
}
|
||||
}
|
||||
24
vendor/yiisoft/yii2/base/ViewContextInterface.php
vendored
Normal file
24
vendor/yiisoft/yii2/base/ViewContextInterface.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* ViewContextInterface is the interface that should implemented by classes who want to support relative view names.
|
||||
*
|
||||
* The method [[getViewPath()]] should be implemented to return the view path that may be prefixed to a relative view name.
|
||||
*
|
||||
* @author Paul Klimov <klimov.paul@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
interface ViewContextInterface
|
||||
{
|
||||
/**
|
||||
* @return string the view path that may be prefixed to a relative view name.
|
||||
*/
|
||||
public function getViewPath();
|
||||
}
|
||||
39
vendor/yiisoft/yii2/base/ViewEvent.php
vendored
Normal file
39
vendor/yiisoft/yii2/base/ViewEvent.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* ViewEvent represents events triggered by the [[View]] component.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class ViewEvent extends Event
|
||||
{
|
||||
/**
|
||||
* @var string the view file being rendered.
|
||||
*/
|
||||
public $viewFile;
|
||||
/**
|
||||
* @var array the parameter array passed to the [[View::render()]] method.
|
||||
*/
|
||||
public $params;
|
||||
/**
|
||||
* @var string the rendering result of [[View::renderFile()]].
|
||||
* Event handlers may modify this property and the modified output will be
|
||||
* returned by [[View::renderFile()]]. This property is only used
|
||||
* by [[View::EVENT_AFTER_RENDER]] event.
|
||||
*/
|
||||
public $output;
|
||||
/**
|
||||
* @var bool whether to continue rendering the view file. Event handlers of
|
||||
* [[View::EVENT_BEFORE_RENDER]] may set this property to decide whether
|
||||
* to continue rendering the current view file.
|
||||
*/
|
||||
public $isValid = true;
|
||||
}
|
||||
25
vendor/yiisoft/yii2/base/ViewNotFoundException.php
vendored
Normal file
25
vendor/yiisoft/yii2/base/ViewNotFoundException.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* ViewNotFoundException represents an exception caused by view file not found.
|
||||
*
|
||||
* @author Alexander Makarov
|
||||
* @since 2.0.10
|
||||
*/
|
||||
class ViewNotFoundException extends InvalidArgumentException
|
||||
{
|
||||
/**
|
||||
* @return string the user-friendly name of this exception
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'View not Found';
|
||||
}
|
||||
}
|
||||
30
vendor/yiisoft/yii2/base/ViewRenderer.php
vendored
Normal file
30
vendor/yiisoft/yii2/base/ViewRenderer.php
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* ViewRenderer is the base class for view renderer classes.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
abstract class ViewRenderer extends Component
|
||||
{
|
||||
/**
|
||||
* Renders a view file.
|
||||
*
|
||||
* This method is invoked by [[View]] whenever it tries to render a view.
|
||||
* Child classes must implement this method to render the given view file.
|
||||
*
|
||||
* @param View $view the view object used for rendering the file.
|
||||
* @param string $file the view file.
|
||||
* @param array $params the parameters to be passed to the view file.
|
||||
* @return string the rendering result
|
||||
*/
|
||||
abstract public function render($view, $file, $params);
|
||||
}
|
||||
322
vendor/yiisoft/yii2/base/Widget.php
vendored
Normal file
322
vendor/yiisoft/yii2/base/Widget.php
vendored
Normal file
@@ -0,0 +1,322 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
use ReflectionClass;
|
||||
use Yii;
|
||||
|
||||
/**
|
||||
* Widget is the base class for widgets.
|
||||
*
|
||||
* For more details and usage information on Widget, see the [guide article on widgets](guide:structure-widgets).
|
||||
*
|
||||
* @property string $id ID of the widget.
|
||||
* @property \yii\web\View $view The view object that can be used to render views or view files. Note that the
|
||||
* type of this property differs in getter and setter. See [[getView()]] and [[setView()]] for details.
|
||||
* @property string $viewPath The directory containing the view files for this widget. This property is
|
||||
* read-only.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class Widget extends Component implements ViewContextInterface
|
||||
{
|
||||
/**
|
||||
* @event Event an event that is triggered when the widget is initialized via [[init()]].
|
||||
* @since 2.0.11
|
||||
*/
|
||||
const EVENT_INIT = 'init';
|
||||
/**
|
||||
* @event WidgetEvent an event raised right before executing a widget.
|
||||
* You may set [[WidgetEvent::isValid]] to be false to cancel the widget execution.
|
||||
* @since 2.0.11
|
||||
*/
|
||||
const EVENT_BEFORE_RUN = 'beforeRun';
|
||||
/**
|
||||
* @event WidgetEvent an event raised right after executing a widget.
|
||||
* @since 2.0.11
|
||||
*/
|
||||
const EVENT_AFTER_RUN = 'afterRun';
|
||||
|
||||
/**
|
||||
* @var int a counter used to generate [[id]] for widgets.
|
||||
* @internal
|
||||
*/
|
||||
public static $counter = 0;
|
||||
/**
|
||||
* @var string the prefix to the automatically generated widget IDs.
|
||||
* @see getId()
|
||||
*/
|
||||
public static $autoIdPrefix = 'w';
|
||||
/**
|
||||
* @var Widget[] the widgets that are currently being rendered (not ended). This property
|
||||
* is maintained by [[begin()]] and [[end()]] methods.
|
||||
* @internal
|
||||
*/
|
||||
public static $stack = [];
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the object.
|
||||
* This method is called at the end of the constructor.
|
||||
* The default implementation will trigger an [[EVENT_INIT]] event.
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
$this->trigger(self::EVENT_INIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Begins a widget.
|
||||
* This method creates an instance of the calling class. It will apply the configuration
|
||||
* to the created instance. A matching [[end()]] call should be called later.
|
||||
* As some widgets may use output buffering, the [[end()]] call should be made in the same view
|
||||
* to avoid breaking the nesting of output buffers.
|
||||
* @param array $config name-value pairs that will be used to initialize the object properties
|
||||
* @return static the newly created widget instance
|
||||
* @see end()
|
||||
*/
|
||||
public static function begin($config = [])
|
||||
{
|
||||
$config['class'] = get_called_class();
|
||||
/* @var $widget Widget */
|
||||
$widget = Yii::createObject($config);
|
||||
static::$stack[] = $widget;
|
||||
|
||||
return $widget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends a widget.
|
||||
* Note that the rendering result of the widget is directly echoed out.
|
||||
* @return static the widget instance that is ended.
|
||||
* @throws InvalidCallException if [[begin()]] and [[end()]] calls are not properly nested
|
||||
* @see begin()
|
||||
*/
|
||||
public static function end()
|
||||
{
|
||||
if (!empty(static::$stack)) {
|
||||
$widget = array_pop(static::$stack);
|
||||
if (get_class($widget) === get_called_class()) {
|
||||
/* @var $widget Widget */
|
||||
if ($widget->beforeRun()) {
|
||||
$result = $widget->run();
|
||||
$result = $widget->afterRun($result);
|
||||
echo $result;
|
||||
}
|
||||
|
||||
return $widget;
|
||||
}
|
||||
|
||||
throw new InvalidCallException('Expecting end() of ' . get_class($widget) . ', found ' . get_called_class());
|
||||
}
|
||||
|
||||
throw new InvalidCallException('Unexpected ' . get_called_class() . '::end() call. A matching begin() is not found.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a widget instance and runs it.
|
||||
* The widget rendering result is returned by this method.
|
||||
* @param array $config name-value pairs that will be used to initialize the object properties
|
||||
* @return string the rendering result of the widget.
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function widget($config = [])
|
||||
{
|
||||
ob_start();
|
||||
ob_implicit_flush(false);
|
||||
try {
|
||||
/* @var $widget Widget */
|
||||
$config['class'] = get_called_class();
|
||||
$widget = Yii::createObject($config);
|
||||
$out = '';
|
||||
if ($widget->beforeRun()) {
|
||||
$result = $widget->run();
|
||||
$out = $widget->afterRun($result);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// close the output buffer opened above if it has not been closed already
|
||||
if (ob_get_level() > 0) {
|
||||
ob_end_clean();
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return ob_get_clean() . $out;
|
||||
}
|
||||
|
||||
private $_id;
|
||||
|
||||
/**
|
||||
* Returns the ID of the widget.
|
||||
* @param bool $autoGenerate whether to generate an ID if it is not set previously
|
||||
* @return string ID of the widget.
|
||||
*/
|
||||
public function getId($autoGenerate = true)
|
||||
{
|
||||
if ($autoGenerate && $this->_id === null) {
|
||||
$this->_id = static::$autoIdPrefix . static::$counter++;
|
||||
}
|
||||
|
||||
return $this->_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ID of the widget.
|
||||
* @param string $value id of the widget.
|
||||
*/
|
||||
public function setId($value)
|
||||
{
|
||||
$this->_id = $value;
|
||||
}
|
||||
|
||||
private $_view;
|
||||
|
||||
/**
|
||||
* Returns the view object that can be used to render views or view files.
|
||||
* The [[render()]] and [[renderFile()]] methods will use
|
||||
* this view object to implement the actual view rendering.
|
||||
* If not set, it will default to the "view" application component.
|
||||
* @return \yii\web\View the view object that can be used to render views or view files.
|
||||
*/
|
||||
public function getView()
|
||||
{
|
||||
if ($this->_view === null) {
|
||||
$this->_view = Yii::$app->getView();
|
||||
}
|
||||
|
||||
return $this->_view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the view object to be used by this widget.
|
||||
* @param View $view the view object that can be used to render views or view files.
|
||||
*/
|
||||
public function setView($view)
|
||||
{
|
||||
$this->_view = $view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the widget.
|
||||
* @return string the result of widget execution to be outputted.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a view.
|
||||
*
|
||||
* The view to be rendered can be specified in one of the following formats:
|
||||
*
|
||||
* - [path alias](guide:concept-aliases) (e.g. "@app/views/site/index");
|
||||
* - absolute path within application (e.g. "//site/index"): the view name starts with double slashes.
|
||||
* The actual view file will be looked for under the [[Application::viewPath|view path]] of the application.
|
||||
* - absolute path within module (e.g. "/site/index"): the view name starts with a single slash.
|
||||
* The actual view file will be looked for under the [[Module::viewPath|view path]] of the currently
|
||||
* active module.
|
||||
* - relative path (e.g. "index"): the actual view file will be looked for under [[viewPath]].
|
||||
*
|
||||
* If the view name does not contain a file extension, it will use the default one `.php`.
|
||||
*
|
||||
* @param string $view the view name.
|
||||
* @param array $params the parameters (name-value pairs) that should be made available in the view.
|
||||
* @return string the rendering result.
|
||||
* @throws InvalidArgumentException if the view file does not exist.
|
||||
*/
|
||||
public function render($view, $params = [])
|
||||
{
|
||||
return $this->getView()->render($view, $params, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a view file.
|
||||
* @param string $file the view file to be rendered. This can be either a file path or a [path alias](guide:concept-aliases).
|
||||
* @param array $params the parameters (name-value pairs) that should be made available in the view.
|
||||
* @return string the rendering result.
|
||||
* @throws InvalidArgumentException if the view file does not exist.
|
||||
*/
|
||||
public function renderFile($file, $params = [])
|
||||
{
|
||||
return $this->getView()->renderFile($file, $params, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the directory containing the view files for this widget.
|
||||
* The default implementation returns the 'views' subdirectory under the directory containing the widget class file.
|
||||
* @return string the directory containing the view files for this widget.
|
||||
*/
|
||||
public function getViewPath()
|
||||
{
|
||||
$class = new ReflectionClass($this);
|
||||
|
||||
return dirname($class->getFileName()) . DIRECTORY_SEPARATOR . 'views';
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is invoked right before the widget is executed.
|
||||
*
|
||||
* The method will trigger the [[EVENT_BEFORE_RUN]] event. The return value of the method
|
||||
* will determine whether the widget should continue to run.
|
||||
*
|
||||
* When overriding this method, make sure you call the parent implementation like the following:
|
||||
*
|
||||
* ```php
|
||||
* public function beforeRun()
|
||||
* {
|
||||
* if (!parent::beforeRun()) {
|
||||
* return false;
|
||||
* }
|
||||
*
|
||||
* // your custom code here
|
||||
*
|
||||
* return true; // or false to not run the widget
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @return bool whether the widget should continue to be executed.
|
||||
* @since 2.0.11
|
||||
*/
|
||||
public function beforeRun()
|
||||
{
|
||||
$event = new WidgetEvent();
|
||||
$this->trigger(self::EVENT_BEFORE_RUN, $event);
|
||||
return $event->isValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is invoked right after a widget is executed.
|
||||
*
|
||||
* The method will trigger the [[EVENT_AFTER_RUN]] event. The return value of the method
|
||||
* will be used as the widget return value.
|
||||
*
|
||||
* If you override this method, your code should look like the following:
|
||||
*
|
||||
* ```php
|
||||
* public function afterRun($result)
|
||||
* {
|
||||
* $result = parent::afterRun($result);
|
||||
* // your custom code here
|
||||
* return $result;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param mixed $result the widget return result.
|
||||
* @return mixed the processed widget result.
|
||||
* @since 2.0.11
|
||||
*/
|
||||
public function afterRun($result)
|
||||
{
|
||||
$event = new WidgetEvent();
|
||||
$event->result = $result;
|
||||
$this->trigger(self::EVENT_AFTER_RUN, $event);
|
||||
return $event->result;
|
||||
}
|
||||
}
|
||||
30
vendor/yiisoft/yii2/base/WidgetEvent.php
vendored
Normal file
30
vendor/yiisoft/yii2/base/WidgetEvent.php
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* WidgetEvent represents the event parameter used for a widget event.
|
||||
*
|
||||
* By setting the [[isValid]] property, one may control whether to continue running the widget.
|
||||
*
|
||||
* @author Petra Barus <petra.barus@gmail.com>
|
||||
* @since 2.0.11
|
||||
*/
|
||||
class WidgetEvent extends Event
|
||||
{
|
||||
/**
|
||||
* @var mixed the widget result. Event handlers may modify this property to change the widget result.
|
||||
*/
|
||||
public $result;
|
||||
/**
|
||||
* @var bool whether to continue running the widget. Event handlers of
|
||||
* [[Widget::EVENT_BEFORE_RUN]] may set this property to decide whether
|
||||
* to continue running the current widget.
|
||||
*/
|
||||
public $isValid = true;
|
||||
}
|
||||
149
vendor/yiisoft/yii2/behaviors/AttributeBehavior.php
vendored
Normal file
149
vendor/yiisoft/yii2/behaviors/AttributeBehavior.php
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\behaviors;
|
||||
|
||||
use Closure;
|
||||
use yii\base\Behavior;
|
||||
use yii\base\Event;
|
||||
use yii\db\ActiveRecord;
|
||||
|
||||
/**
|
||||
* AttributeBehavior automatically assigns a specified value to one or multiple attributes of an ActiveRecord
|
||||
* object when certain events happen.
|
||||
*
|
||||
* To use AttributeBehavior, configure the [[attributes]] property which should specify the list of attributes
|
||||
* that need to be updated and the corresponding events that should trigger the update. Then configure the
|
||||
* [[value]] property with a PHP callable whose return value will be used to assign to the current attribute(s).
|
||||
* For example,
|
||||
*
|
||||
* ```php
|
||||
* use yii\behaviors\AttributeBehavior;
|
||||
*
|
||||
* public function behaviors()
|
||||
* {
|
||||
* return [
|
||||
* [
|
||||
* 'class' => AttributeBehavior::className(),
|
||||
* 'attributes' => [
|
||||
* ActiveRecord::EVENT_BEFORE_INSERT => 'attribute1',
|
||||
* ActiveRecord::EVENT_BEFORE_UPDATE => 'attribute2',
|
||||
* ],
|
||||
* 'value' => function ($event) {
|
||||
* return 'some value';
|
||||
* },
|
||||
* ],
|
||||
* ];
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Because attribute values will be set automatically by this behavior, they are usually not user input and should therefore
|
||||
* not be validated, i.e. they should not appear in the [[\yii\base\Model::rules()|rules()]] method of the model.
|
||||
*
|
||||
* @author Luciano Baraglia <luciano.baraglia@gmail.com>
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class AttributeBehavior extends Behavior
|
||||
{
|
||||
/**
|
||||
* @var array list of attributes that are to be automatically filled with the value specified via [[value]].
|
||||
* The array keys are the ActiveRecord events upon which the attributes are to be updated,
|
||||
* and the array values are the corresponding attribute(s) to be updated. You can use a string to represent
|
||||
* a single attribute, or an array to represent a list of attributes. For example,
|
||||
*
|
||||
* ```php
|
||||
* [
|
||||
* ActiveRecord::EVENT_BEFORE_INSERT => ['attribute1', 'attribute2'],
|
||||
* ActiveRecord::EVENT_BEFORE_UPDATE => 'attribute2',
|
||||
* ]
|
||||
* ```
|
||||
*/
|
||||
public $attributes = [];
|
||||
/**
|
||||
* @var mixed the value that will be assigned to the current attributes. This can be an anonymous function,
|
||||
* callable in array format (e.g. `[$this, 'methodName']`), an [[\yii\db\Expression|Expression]] object representing a DB expression
|
||||
* (e.g. `new Expression('NOW()')`), scalar, string or an arbitrary value. If the former, the return value of the
|
||||
* function will be assigned to the attributes.
|
||||
* The signature of the function should be as follows,
|
||||
*
|
||||
* ```php
|
||||
* function ($event)
|
||||
* {
|
||||
* // return value will be assigned to the attribute
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
public $value;
|
||||
/**
|
||||
* @var bool whether to skip this behavior when the `$owner` has not been
|
||||
* modified
|
||||
* @since 2.0.8
|
||||
*/
|
||||
public $skipUpdateOnClean = true;
|
||||
/**
|
||||
* @var bool whether to preserve non-empty attribute values.
|
||||
* @since 2.0.13
|
||||
*/
|
||||
public $preserveNonEmptyValues = false;
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function events()
|
||||
{
|
||||
return array_fill_keys(
|
||||
array_keys($this->attributes),
|
||||
'evaluateAttributes'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the attribute value and assigns it to the current attributes.
|
||||
* @param Event $event
|
||||
*/
|
||||
public function evaluateAttributes($event)
|
||||
{
|
||||
if ($this->skipUpdateOnClean
|
||||
&& $event->name == ActiveRecord::EVENT_BEFORE_UPDATE
|
||||
&& empty($this->owner->dirtyAttributes)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!empty($this->attributes[$event->name])) {
|
||||
$attributes = (array) $this->attributes[$event->name];
|
||||
$value = $this->getValue($event);
|
||||
foreach ($attributes as $attribute) {
|
||||
// ignore attribute names which are not string (e.g. when set by TimestampBehavior::updatedAtAttribute)
|
||||
if (is_string($attribute)) {
|
||||
if ($this->preserveNonEmptyValues && !empty($this->owner->$attribute)) {
|
||||
continue;
|
||||
}
|
||||
$this->owner->$attribute = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value for the current attributes.
|
||||
* This method is called by [[evaluateAttributes()]]. Its return value will be assigned
|
||||
* to the attributes corresponding to the triggering event.
|
||||
* @param Event $event the event that triggers the current attribute updating.
|
||||
* @return mixed the attribute value
|
||||
*/
|
||||
protected function getValue($event)
|
||||
{
|
||||
if ($this->value instanceof Closure || (is_array($this->value) && is_callable($this->value))) {
|
||||
return call_user_func($this->value, $event);
|
||||
}
|
||||
|
||||
return $this->value;
|
||||
}
|
||||
}
|
||||
368
vendor/yiisoft/yii2/behaviors/AttributeTypecastBehavior.php
vendored
Normal file
368
vendor/yiisoft/yii2/behaviors/AttributeTypecastBehavior.php
vendored
Normal file
@@ -0,0 +1,368 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\behaviors;
|
||||
|
||||
use yii\base\Behavior;
|
||||
use yii\base\InvalidArgumentException;
|
||||
use yii\base\Model;
|
||||
use yii\db\BaseActiveRecord;
|
||||
use yii\helpers\StringHelper;
|
||||
use yii\validators\BooleanValidator;
|
||||
use yii\validators\NumberValidator;
|
||||
use yii\validators\StringValidator;
|
||||
|
||||
/**
|
||||
* AttributeTypecastBehavior provides an ability of automatic model attribute typecasting.
|
||||
* This behavior is very useful in case of usage of ActiveRecord for the schema-less databases like MongoDB or Redis.
|
||||
* It may also come in handy for regular [[\yii\db\ActiveRecord]] or even [[\yii\base\Model]], allowing to maintain
|
||||
* strict attribute types after model validation.
|
||||
*
|
||||
* This behavior should be attached to [[\yii\base\Model]] or [[\yii\db\BaseActiveRecord]] descendant.
|
||||
*
|
||||
* You should specify exact attribute types via [[attributeTypes]].
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* ```php
|
||||
* use yii\behaviors\AttributeTypecastBehavior;
|
||||
*
|
||||
* class Item extends \yii\db\ActiveRecord
|
||||
* {
|
||||
* public function behaviors()
|
||||
* {
|
||||
* return [
|
||||
* 'typecast' => [
|
||||
* 'class' => AttributeTypecastBehavior::className(),
|
||||
* 'attributeTypes' => [
|
||||
* 'amount' => AttributeTypecastBehavior::TYPE_INTEGER,
|
||||
* 'price' => AttributeTypecastBehavior::TYPE_FLOAT,
|
||||
* 'is_active' => AttributeTypecastBehavior::TYPE_BOOLEAN,
|
||||
* ],
|
||||
* 'typecastAfterValidate' => true,
|
||||
* 'typecastBeforeSave' => false,
|
||||
* 'typecastAfterFind' => false,
|
||||
* ],
|
||||
* ];
|
||||
* }
|
||||
*
|
||||
* // ...
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Tip: you may left [[attributeTypes]] blank - in this case its value will be detected
|
||||
* automatically based on owner validation rules.
|
||||
* Following example will automatically create same [[attributeTypes]] value as it was configured at the above one:
|
||||
*
|
||||
* ```php
|
||||
* use yii\behaviors\AttributeTypecastBehavior;
|
||||
*
|
||||
* class Item extends \yii\db\ActiveRecord
|
||||
* {
|
||||
*
|
||||
* public function rules()
|
||||
* {
|
||||
* return [
|
||||
* ['amount', 'integer'],
|
||||
* ['price', 'number'],
|
||||
* ['is_active', 'boolean'],
|
||||
* ];
|
||||
* }
|
||||
*
|
||||
* public function behaviors()
|
||||
* {
|
||||
* return [
|
||||
* 'typecast' => [
|
||||
* 'class' => AttributeTypecastBehavior::className(),
|
||||
* // 'attributeTypes' will be composed automatically according to `rules()`
|
||||
* ],
|
||||
* ];
|
||||
* }
|
||||
*
|
||||
* // ...
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* This behavior allows automatic attribute typecasting at following cases:
|
||||
*
|
||||
* - after successful model validation
|
||||
* - before model save (insert or update)
|
||||
* - after model find (found by query or refreshed)
|
||||
*
|
||||
* You may control automatic typecasting for particular case using fields [[typecastAfterValidate]],
|
||||
* [[typecastBeforeSave]] and [[typecastAfterFind]].
|
||||
* By default typecasting will be performed only after model validation.
|
||||
*
|
||||
* Note: you can manually trigger attribute typecasting anytime invoking [[typecastAttributes()]] method:
|
||||
*
|
||||
* ```php
|
||||
* $model = new Item();
|
||||
* $model->price = '38.5';
|
||||
* $model->is_active = 1;
|
||||
* $model->typecastAttributes();
|
||||
* ```
|
||||
*
|
||||
* @author Paul Klimov <klimov.paul@gmail.com>
|
||||
* @since 2.0.10
|
||||
*/
|
||||
class AttributeTypecastBehavior extends Behavior
|
||||
{
|
||||
const TYPE_INTEGER = 'integer';
|
||||
const TYPE_FLOAT = 'float';
|
||||
const TYPE_BOOLEAN = 'boolean';
|
||||
const TYPE_STRING = 'string';
|
||||
|
||||
/**
|
||||
* @var Model|BaseActiveRecord the owner of this behavior.
|
||||
*/
|
||||
public $owner;
|
||||
/**
|
||||
* @var array attribute typecast map in format: attributeName => type.
|
||||
* Type can be set via PHP callable, which accept raw value as an argument and should return
|
||||
* typecast result.
|
||||
* For example:
|
||||
*
|
||||
* ```php
|
||||
* [
|
||||
* 'amount' => 'integer',
|
||||
* 'price' => 'float',
|
||||
* 'is_active' => 'boolean',
|
||||
* 'date' => function ($value) {
|
||||
* return ($value instanceof \DateTime) ? $value->getTimestamp(): (int)$value;
|
||||
* },
|
||||
* ]
|
||||
* ```
|
||||
*
|
||||
* If not set, attribute type map will be composed automatically from the owner validation rules.
|
||||
*/
|
||||
public $attributeTypes;
|
||||
/**
|
||||
* @var bool whether to skip typecasting of `null` values.
|
||||
* If enabled attribute value which equals to `null` will not be type-casted (e.g. `null` remains `null`),
|
||||
* otherwise it will be converted according to the type configured at [[attributeTypes]].
|
||||
*/
|
||||
public $skipOnNull = true;
|
||||
/**
|
||||
* @var bool whether to perform typecasting after owner model validation.
|
||||
* Note that typecasting will be performed only if validation was successful, e.g.
|
||||
* owner model has no errors.
|
||||
* Note that changing this option value will have no effect after this behavior has been attached to the model.
|
||||
*/
|
||||
public $typecastAfterValidate = true;
|
||||
/**
|
||||
* @var bool whether to perform typecasting before saving owner model (insert or update).
|
||||
* This option may be disabled in order to achieve better performance.
|
||||
* For example, in case of [[\yii\db\ActiveRecord]] usage, typecasting before save
|
||||
* will grant no benefit an thus can be disabled.
|
||||
* Note that changing this option value will have no effect after this behavior has been attached to the model.
|
||||
*/
|
||||
public $typecastBeforeSave = false;
|
||||
/**
|
||||
* @var bool whether to perform typecasting after saving owner model (insert or update).
|
||||
* This option may be disabled in order to achieve better performance.
|
||||
* For example, in case of [[\yii\db\ActiveRecord]] usage, typecasting after save
|
||||
* will grant no benefit an thus can be disabled.
|
||||
* Note that changing this option value will have no effect after this behavior has been attached to the model.
|
||||
* @since 2.0.14
|
||||
*/
|
||||
public $typecastAfterSave = false;
|
||||
/**
|
||||
* @var bool whether to perform typecasting after retrieving owner model data from
|
||||
* the database (after find or refresh).
|
||||
* This option may be disabled in order to achieve better performance.
|
||||
* For example, in case of [[\yii\db\ActiveRecord]] usage, typecasting after find
|
||||
* will grant no benefit in most cases an thus can be disabled.
|
||||
* Note that changing this option value will have no effect after this behavior has been attached to the model.
|
||||
*/
|
||||
public $typecastAfterFind = false;
|
||||
|
||||
/**
|
||||
* @var array internal static cache for auto detected [[attributeTypes]] values
|
||||
* in format: ownerClassName => attributeTypes
|
||||
*/
|
||||
private static $autoDetectedAttributeTypes = [];
|
||||
|
||||
|
||||
/**
|
||||
* Clears internal static cache of auto detected [[attributeTypes]] values
|
||||
* over all affected owner classes.
|
||||
*/
|
||||
public static function clearAutoDetectedAttributeTypes()
|
||||
{
|
||||
self::$autoDetectedAttributeTypes = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function attach($owner)
|
||||
{
|
||||
parent::attach($owner);
|
||||
|
||||
if ($this->attributeTypes === null) {
|
||||
$ownerClass = get_class($this->owner);
|
||||
if (!isset(self::$autoDetectedAttributeTypes[$ownerClass])) {
|
||||
self::$autoDetectedAttributeTypes[$ownerClass] = $this->detectAttributeTypes();
|
||||
}
|
||||
$this->attributeTypes = self::$autoDetectedAttributeTypes[$ownerClass];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Typecast owner attributes according to [[attributeTypes]].
|
||||
* @param array $attributeNames list of attribute names that should be type-casted.
|
||||
* If this parameter is empty, it means any attribute listed in the [[attributeTypes]]
|
||||
* should be type-casted.
|
||||
*/
|
||||
public function typecastAttributes($attributeNames = null)
|
||||
{
|
||||
$attributeTypes = [];
|
||||
|
||||
if ($attributeNames === null) {
|
||||
$attributeTypes = $this->attributeTypes;
|
||||
} else {
|
||||
foreach ($attributeNames as $attribute) {
|
||||
if (!isset($this->attributeTypes[$attribute])) {
|
||||
throw new InvalidArgumentException("There is no type mapping for '{$attribute}'.");
|
||||
}
|
||||
$attributeTypes[$attribute] = $this->attributeTypes[$attribute];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($attributeTypes as $attribute => $type) {
|
||||
$value = $this->owner->{$attribute};
|
||||
if ($this->skipOnNull && $value === null) {
|
||||
continue;
|
||||
}
|
||||
$this->owner->{$attribute} = $this->typecastValue($value, $type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts the given value to the specified type.
|
||||
* @param mixed $value value to be type-casted.
|
||||
* @param string|callable $type type name or typecast callable.
|
||||
* @return mixed typecast result.
|
||||
*/
|
||||
protected function typecastValue($value, $type)
|
||||
{
|
||||
if (is_scalar($type)) {
|
||||
if (is_object($value) && method_exists($value, '__toString')) {
|
||||
$value = $value->__toString();
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case self::TYPE_INTEGER:
|
||||
return (int) $value;
|
||||
case self::TYPE_FLOAT:
|
||||
return (float) $value;
|
||||
case self::TYPE_BOOLEAN:
|
||||
return (bool) $value;
|
||||
case self::TYPE_STRING:
|
||||
if (is_float($value)) {
|
||||
return StringHelper::floatToString($value);
|
||||
}
|
||||
return (string) $value;
|
||||
default:
|
||||
throw new InvalidArgumentException("Unsupported type '{$type}'");
|
||||
}
|
||||
}
|
||||
|
||||
return call_user_func($type, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Composes default value for [[attributeTypes]] from the owner validation rules.
|
||||
* @return array attribute type map.
|
||||
*/
|
||||
protected function detectAttributeTypes()
|
||||
{
|
||||
$attributeTypes = [];
|
||||
foreach ($this->owner->getValidators() as $validator) {
|
||||
$type = null;
|
||||
if ($validator instanceof BooleanValidator) {
|
||||
$type = self::TYPE_BOOLEAN;
|
||||
} elseif ($validator instanceof NumberValidator) {
|
||||
$type = $validator->integerOnly ? self::TYPE_INTEGER : self::TYPE_FLOAT;
|
||||
} elseif ($validator instanceof StringValidator) {
|
||||
$type = self::TYPE_STRING;
|
||||
}
|
||||
|
||||
if ($type !== null) {
|
||||
foreach ((array) $validator->attributes as $attribute) {
|
||||
$attributeTypes[ltrim($attribute, '!')] = $type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $attributeTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function events()
|
||||
{
|
||||
$events = [];
|
||||
|
||||
if ($this->typecastAfterValidate) {
|
||||
$events[Model::EVENT_AFTER_VALIDATE] = 'afterValidate';
|
||||
}
|
||||
if ($this->typecastBeforeSave) {
|
||||
$events[BaseActiveRecord::EVENT_BEFORE_INSERT] = 'beforeSave';
|
||||
$events[BaseActiveRecord::EVENT_BEFORE_UPDATE] = 'beforeSave';
|
||||
}
|
||||
if ($this->typecastAfterSave) {
|
||||
$events[BaseActiveRecord::EVENT_AFTER_INSERT] = 'afterSave';
|
||||
$events[BaseActiveRecord::EVENT_AFTER_UPDATE] = 'afterSave';
|
||||
}
|
||||
if ($this->typecastAfterFind) {
|
||||
$events[BaseActiveRecord::EVENT_AFTER_FIND] = 'afterFind';
|
||||
}
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles owner 'afterValidate' event, ensuring attribute typecasting.
|
||||
* @param \yii\base\Event $event event instance.
|
||||
*/
|
||||
public function afterValidate($event)
|
||||
{
|
||||
if (!$this->owner->hasErrors()) {
|
||||
$this->typecastAttributes();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles owner 'beforeInsert' and 'beforeUpdate' events, ensuring attribute typecasting.
|
||||
* @param \yii\base\Event $event event instance.
|
||||
*/
|
||||
public function beforeSave($event)
|
||||
{
|
||||
$this->typecastAttributes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles owner 'afterInsert' and 'afterUpdate' events, ensuring attribute typecasting.
|
||||
* @param \yii\base\Event $event event instance.
|
||||
* @since 2.0.14
|
||||
*/
|
||||
public function afterSave($event)
|
||||
{
|
||||
$this->typecastAttributes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles owner 'afterFind' event, ensuring attribute typecasting.
|
||||
* @param \yii\base\Event $event event instance.
|
||||
*/
|
||||
public function afterFind($event)
|
||||
{
|
||||
$this->typecastAttributes();
|
||||
}
|
||||
}
|
||||
185
vendor/yiisoft/yii2/behaviors/AttributesBehavior.php
vendored
Normal file
185
vendor/yiisoft/yii2/behaviors/AttributesBehavior.php
vendored
Normal file
@@ -0,0 +1,185 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\behaviors;
|
||||
|
||||
use Closure;
|
||||
use yii\base\Behavior;
|
||||
use yii\base\Event;
|
||||
use yii\db\ActiveRecord;
|
||||
|
||||
/**
|
||||
* AttributesBehavior automatically assigns values specified to one or multiple attributes of an ActiveRecord
|
||||
* object when certain events happen.
|
||||
*
|
||||
* To use AttributesBehavior, configure the [[attributes]] property which should specify the list of attributes
|
||||
* that need to be updated and the corresponding events that should trigger the update. Then configure the
|
||||
* value of enclosed arrays with a PHP callable whose return value will be used to assign to the current attribute.
|
||||
* For example,
|
||||
*
|
||||
* ```php
|
||||
* use yii\behaviors\AttributesBehavior;
|
||||
*
|
||||
* public function behaviors()
|
||||
* {
|
||||
* return [
|
||||
* [
|
||||
* 'class' => AttributesBehavior::className(),
|
||||
* 'attributes' => [
|
||||
* 'attribute1' => [
|
||||
* ActiveRecord::EVENT_BEFORE_INSERT => new Expression('NOW()'),
|
||||
* ActiveRecord::EVENT_BEFORE_UPDATE => \Yii::$app->formatter->asDatetime('2017-07-13'),
|
||||
* ],
|
||||
* 'attribute2' => [
|
||||
* ActiveRecord::EVENT_BEFORE_VALIDATE => [$this, 'storeAttributes'],
|
||||
* ActiveRecord::EVENT_AFTER_VALIDATE => [$this, 'restoreAttributes'],
|
||||
* ],
|
||||
* 'attribute3' => [
|
||||
* ActiveRecord::EVENT_BEFORE_VALIDATE => $fn2 = [$this, 'getAttribute2'],
|
||||
* ActiveRecord::EVENT_AFTER_VALIDATE => $fn2,
|
||||
* ],
|
||||
* 'attribute4' => [
|
||||
* ActiveRecord::EVENT_BEFORE_DELETE => function ($event, $attribute) {
|
||||
* static::disabled() || $event->isValid = false;
|
||||
* },
|
||||
* ],
|
||||
* ],
|
||||
* ],
|
||||
* ];
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Because attribute values will be set automatically by this behavior, they are usually not user input and should therefore
|
||||
* not be validated, i.e. they should not appear in the [[\yii\base\Model::rules()|rules()]] method of the model.
|
||||
*
|
||||
* @author Luciano Baraglia <luciano.baraglia@gmail.com>
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @author Bogdan Stepanenko <bscheshirwork@gmail.com>
|
||||
* @since 2.0.13
|
||||
*/
|
||||
class AttributesBehavior extends Behavior
|
||||
{
|
||||
/**
|
||||
* @var array list of attributes that are to be automatically filled with the values specified via enclosed arrays.
|
||||
* The array keys are the ActiveRecord attributes upon which the events are to be updated,
|
||||
* and the array values are the array of corresponding events(s). For this enclosed array:
|
||||
* the array keys are the ActiveRecord events upon which the attributes are to be updated,
|
||||
* and the array values are the value that will be assigned to the current attributes. This can be an anonymous function,
|
||||
* callable in array format (e.g. `[$this, 'methodName']`), an [[\yii\db\Expression|Expression]] object representing a DB expression
|
||||
* (e.g. `new Expression('NOW()')`), scalar, string or an arbitrary value. If the former, the return value of the
|
||||
* function will be assigned to the attributes.
|
||||
*
|
||||
* ```php
|
||||
* [
|
||||
* 'attribute1' => [
|
||||
* ActiveRecord::EVENT_BEFORE_INSERT => new Expression('NOW()'),
|
||||
* ActiveRecord::EVENT_BEFORE_UPDATE => \Yii::$app->formatter->asDatetime('2017-07-13'),
|
||||
* ],
|
||||
* 'attribute2' => [
|
||||
* ActiveRecord::EVENT_BEFORE_VALIDATE => [$this, 'storeAttributes'],
|
||||
* ActiveRecord::EVENT_AFTER_VALIDATE => [$this, 'restoreAttributes'],
|
||||
* ],
|
||||
* 'attribute3' => [
|
||||
* ActiveRecord::EVENT_BEFORE_VALIDATE => $fn2 = [$this, 'getAttribute2'],
|
||||
* ActiveRecord::EVENT_AFTER_VALIDATE => $fn2,
|
||||
* ],
|
||||
* 'attribute4' => [
|
||||
* ActiveRecord::EVENT_BEFORE_DELETE => function ($event, $attribute) {
|
||||
* static::disabled() || $event->isValid = false;
|
||||
* },
|
||||
* ],
|
||||
* ]
|
||||
* ```
|
||||
*/
|
||||
public $attributes = [];
|
||||
/**
|
||||
* @var array list of order of attributes that are to be automatically filled with the event.
|
||||
* The array keys are the ActiveRecord events upon which the attributes are to be updated,
|
||||
* and the array values are represent the order corresponding attributes.
|
||||
* The rest of the attributes are processed at the end.
|
||||
* If the [[attributes]] for this attribute do not specify this event, it is ignored
|
||||
*
|
||||
* ```php
|
||||
* [
|
||||
* ActiveRecord::EVENT_BEFORE_VALIDATE => ['attribute1', 'attribute2'],
|
||||
* ActiveRecord::EVENT_AFTER_VALIDATE => ['attribute2', 'attribute1'],
|
||||
* ]
|
||||
* ```
|
||||
*/
|
||||
public $order = [];
|
||||
/**
|
||||
* @var bool whether to skip this behavior when the `$owner` has not been modified
|
||||
*/
|
||||
public $skipUpdateOnClean = true;
|
||||
/**
|
||||
* @var bool whether to preserve non-empty attribute values.
|
||||
*/
|
||||
public $preserveNonEmptyValues = false;
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function events()
|
||||
{
|
||||
return array_fill_keys(
|
||||
array_reduce($this->attributes, function ($carry, $item) {
|
||||
return array_merge($carry, array_keys($item));
|
||||
}, []),
|
||||
'evaluateAttributes'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the attributes values and assigns it to the current attributes.
|
||||
* @param Event $event
|
||||
*/
|
||||
public function evaluateAttributes($event)
|
||||
{
|
||||
if ($this->skipUpdateOnClean
|
||||
&& $event->name === ActiveRecord::EVENT_BEFORE_UPDATE
|
||||
&& empty($this->owner->dirtyAttributes)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
$attributes = array_keys(array_filter($this->attributes, function ($carry) use ($event) {
|
||||
return array_key_exists($event->name, $carry);
|
||||
}));
|
||||
if (!empty($this->order[$event->name])) {
|
||||
$attributes = array_merge(
|
||||
array_intersect((array) $this->order[$event->name], $attributes),
|
||||
array_diff($attributes, (array) $this->order[$event->name]));
|
||||
}
|
||||
foreach ($attributes as $attribute) {
|
||||
if ($this->preserveNonEmptyValues && !empty($this->owner->$attribute)) {
|
||||
continue;
|
||||
}
|
||||
$this->owner->$attribute = $this->getValue($attribute, $event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value for the current attributes.
|
||||
* This method is called by [[evaluateAttributes()]]. Its return value will be assigned
|
||||
* to the target attribute corresponding to the triggering event.
|
||||
* @param string $attribute target attribute name
|
||||
* @param Event $event the event that triggers the current attribute updating.
|
||||
* @return mixed the attribute value
|
||||
*/
|
||||
protected function getValue($attribute, $event)
|
||||
{
|
||||
if (!isset($this->attributes[$attribute][$event->name])) {
|
||||
return null;
|
||||
}
|
||||
$value = $this->attributes[$attribute][$event->name];
|
||||
if ($value instanceof Closure || (is_array($value) && is_callable($value))) {
|
||||
return $value($event, $attribute);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
130
vendor/yiisoft/yii2/behaviors/BlameableBehavior.php
vendored
Normal file
130
vendor/yiisoft/yii2/behaviors/BlameableBehavior.php
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\behaviors;
|
||||
|
||||
use Yii;
|
||||
use yii\db\BaseActiveRecord;
|
||||
|
||||
/**
|
||||
* BlameableBehavior automatically fills the specified attributes with the current user ID.
|
||||
*
|
||||
* To use BlameableBehavior, insert the following code to your ActiveRecord class:
|
||||
*
|
||||
* ```php
|
||||
* use yii\behaviors\BlameableBehavior;
|
||||
*
|
||||
* public function behaviors()
|
||||
* {
|
||||
* return [
|
||||
* BlameableBehavior::className(),
|
||||
* ];
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* By default, BlameableBehavior will fill the `created_by` and `updated_by` attributes with the current user ID
|
||||
* when the associated AR object is being inserted; it will fill the `updated_by` attribute
|
||||
* with the current user ID when the AR object is being updated.
|
||||
*
|
||||
* Because attribute values will be set automatically by this behavior, they are usually not user input and should therefore
|
||||
* not be validated, i.e. `created_by` and `updated_by` should not appear in the [[\yii\base\Model::rules()|rules()]] method of the model.
|
||||
*
|
||||
* If your attribute names are different, you may configure the [[createdByAttribute]] and [[updatedByAttribute]]
|
||||
* properties like the following:
|
||||
*
|
||||
* ```php
|
||||
* public function behaviors()
|
||||
* {
|
||||
* return [
|
||||
* [
|
||||
* 'class' => BlameableBehavior::className(),
|
||||
* 'createdByAttribute' => 'author_id',
|
||||
* 'updatedByAttribute' => 'updater_id',
|
||||
* ],
|
||||
* ];
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @author Luciano Baraglia <luciano.baraglia@gmail.com>
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @author Alexander Kochetov <creocoder@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class BlameableBehavior extends AttributeBehavior
|
||||
{
|
||||
/**
|
||||
* @var string the attribute that will receive current user ID value
|
||||
* Set this property to false if you do not want to record the creator ID.
|
||||
*/
|
||||
public $createdByAttribute = 'created_by';
|
||||
/**
|
||||
* @var string the attribute that will receive current user ID value
|
||||
* Set this property to false if you do not want to record the updater ID.
|
||||
*/
|
||||
public $updatedByAttribute = 'updated_by';
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* In case, when the property is `null`, the value of `Yii::$app->user->id` will be used as the value.
|
||||
*/
|
||||
public $value;
|
||||
/**
|
||||
* @var mixed Default value for cases when the user is guest
|
||||
* @since 2.0.14
|
||||
*/
|
||||
public $defaultValue;
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
|
||||
if (empty($this->attributes)) {
|
||||
$this->attributes = [
|
||||
BaseActiveRecord::EVENT_BEFORE_INSERT => [$this->createdByAttribute, $this->updatedByAttribute],
|
||||
BaseActiveRecord::EVENT_BEFORE_UPDATE => $this->updatedByAttribute,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* In case, when the [[value]] property is `null`, the value of [[defaultValue]] will be used as the value.
|
||||
*/
|
||||
protected function getValue($event)
|
||||
{
|
||||
if ($this->value === null && Yii::$app->has('user')) {
|
||||
$userId = Yii::$app->get('user')->id;
|
||||
if ($userId === null) {
|
||||
return $this->getDefaultValue($event);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
|
||||
return parent::getValue($event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default value
|
||||
* @param \yii\base\Event $event
|
||||
* @return array|mixed
|
||||
* @since 2.0.14
|
||||
*/
|
||||
protected function getDefaultValue($event)
|
||||
{
|
||||
if ($this->defaultValue instanceof \Closure || (is_array($this->defaultValue) && is_callable($this->defaultValue))) {
|
||||
return call_user_func($this->defaultValue, $event);
|
||||
}
|
||||
|
||||
return $this->defaultValue;
|
||||
}
|
||||
}
|
||||
197
vendor/yiisoft/yii2/behaviors/CacheableWidgetBehavior.php
vendored
Normal file
197
vendor/yiisoft/yii2/behaviors/CacheableWidgetBehavior.php
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\behaviors;
|
||||
|
||||
use yii\base\Behavior;
|
||||
use yii\base\InvalidConfigException;
|
||||
use yii\base\Widget;
|
||||
use yii\base\WidgetEvent;
|
||||
use yii\caching\CacheInterface;
|
||||
use yii\caching\Dependency;
|
||||
use yii\di\Instance;
|
||||
|
||||
/**
|
||||
* Cacheable widget behavior automatically caches widget contents according to duration and dependencies specified.
|
||||
*
|
||||
* The behavior may be used without any configuration if an application has `cache` component configured.
|
||||
* By default the widget will be cached for one minute.
|
||||
*
|
||||
* The following example will cache the posts widget for an indefinite duration until any post is modified.
|
||||
*
|
||||
* ```php
|
||||
* use yii\behaviors\CacheableWidgetBehavior;
|
||||
*
|
||||
* public function behaviors()
|
||||
* {
|
||||
* return [
|
||||
* [
|
||||
* 'class' => CacheableWidgetBehavior::className(),
|
||||
* 'cacheDuration' => 0,
|
||||
* 'cacheDependency' => [
|
||||
* 'class' => 'yii\caching\DbDependency',
|
||||
* 'sql' => 'SELECT MAX(updated_at) FROM posts',
|
||||
* ],
|
||||
* ],
|
||||
* ];
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @author Nikolay Oleynikov <oleynikovny@mail.ru>
|
||||
* @since 2.0.14
|
||||
*/
|
||||
class CacheableWidgetBehavior extends Behavior
|
||||
{
|
||||
/**
|
||||
* @var CacheInterface|string|array a cache object or a cache component ID
|
||||
* or a configuration array for creating a cache object.
|
||||
* Defaults to the `cache` application component.
|
||||
*/
|
||||
public $cache = 'cache';
|
||||
/**
|
||||
* @var int cache duration in seconds.
|
||||
* Set to `0` to indicate that the cached data will never expire.
|
||||
* Defaults to 60 seconds or 1 minute.
|
||||
*/
|
||||
public $cacheDuration = 60;
|
||||
/**
|
||||
* @var Dependency|array|null a cache dependency or a configuration array
|
||||
* for creating a cache dependency or `null` meaning no cache dependency.
|
||||
*
|
||||
* For example,
|
||||
*
|
||||
* ```php
|
||||
* [
|
||||
* 'class' => 'yii\caching\DbDependency',
|
||||
* 'sql' => 'SELECT MAX(updated_at) FROM posts',
|
||||
* ]
|
||||
* ```
|
||||
*
|
||||
* would make the widget cache depend on the last modified time of all posts.
|
||||
* If any post has its modification time changed, the cached content would be invalidated.
|
||||
*/
|
||||
public $cacheDependency;
|
||||
/**
|
||||
* @var string[]|string an array of strings or a single string which would cause
|
||||
* the variation of the content being cached (e.g. an application language, a GET parameter).
|
||||
*
|
||||
* The following variation setting will cause the content to be cached in different versions
|
||||
* according to the current application language:
|
||||
*
|
||||
* ```php
|
||||
* [
|
||||
* Yii::$app->language,
|
||||
* ]
|
||||
* ```
|
||||
*/
|
||||
public $cacheKeyVariations = [];
|
||||
/**
|
||||
* @var bool whether to enable caching or not. Allows to turn the widget caching
|
||||
* on and off according to specific conditions.
|
||||
* The following configuration will disable caching when a special GET parameter is passed:
|
||||
*
|
||||
* ```php
|
||||
* empty(Yii::$app->request->get('disable-caching'))
|
||||
* ```
|
||||
*/
|
||||
public $cacheEnabled = true;
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function attach($owner)
|
||||
{
|
||||
parent::attach($owner);
|
||||
|
||||
$this->initializeEventHandlers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Begins fragment caching. Prevents owner widget from execution
|
||||
* if its contents can be retrieved from the cache.
|
||||
*
|
||||
* @param WidgetEvent $event `Widget::EVENT_BEFORE_RUN` event.
|
||||
*/
|
||||
public function beforeRun($event)
|
||||
{
|
||||
$cacheKey = $this->getCacheKey();
|
||||
$fragmentCacheConfiguration = $this->getFragmentCacheConfiguration();
|
||||
|
||||
if (!$this->owner->view->beginCache($cacheKey, $fragmentCacheConfiguration)) {
|
||||
$event->isValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs widget contents and ends fragment caching.
|
||||
*
|
||||
* @param WidgetEvent $event `Widget::EVENT_AFTER_RUN` event.
|
||||
*/
|
||||
public function afterRun($event)
|
||||
{
|
||||
echo $event->result;
|
||||
$event->result = null;
|
||||
|
||||
$this->owner->view->endCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes widget event handlers.
|
||||
*/
|
||||
private function initializeEventHandlers()
|
||||
{
|
||||
$this->owner->on(Widget::EVENT_BEFORE_RUN, [$this, 'beforeRun']);
|
||||
$this->owner->on(Widget::EVENT_AFTER_RUN, [$this, 'afterRun']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cache instance.
|
||||
*
|
||||
* @return CacheInterface cache instance.
|
||||
* @throws InvalidConfigException if cache instance instantiation fails.
|
||||
*/
|
||||
private function getCacheInstance()
|
||||
{
|
||||
$cacheInterface = 'yii\caching\CacheInterface';
|
||||
return Instance::ensure($this->cache, $cacheInterface);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the widget cache key.
|
||||
*
|
||||
* @return string[] an array of strings representing the cache key.
|
||||
*/
|
||||
private function getCacheKey()
|
||||
{
|
||||
// `$cacheKeyVariations` may be a `string` and needs to be cast to an `array`.
|
||||
$cacheKey = array_merge(
|
||||
(array)get_class($this->owner),
|
||||
(array)$this->cacheKeyVariations
|
||||
);
|
||||
|
||||
return $cacheKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a fragment cache widget configuration array.
|
||||
*
|
||||
* @return array a fragment cache widget configuration array.
|
||||
*/
|
||||
private function getFragmentCacheConfiguration()
|
||||
{
|
||||
$cache = $this->getCacheInstance();
|
||||
$fragmentCacheConfiguration = [
|
||||
'cache' => $cache,
|
||||
'duration' => $this->cacheDuration,
|
||||
'dependency' => $this->cacheDependency,
|
||||
'enabled' => $this->cacheEnabled,
|
||||
];
|
||||
|
||||
return $fragmentCacheConfiguration;
|
||||
}
|
||||
}
|
||||
283
vendor/yiisoft/yii2/behaviors/SluggableBehavior.php
vendored
Normal file
283
vendor/yiisoft/yii2/behaviors/SluggableBehavior.php
vendored
Normal file
@@ -0,0 +1,283 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\behaviors;
|
||||
|
||||
use Yii;
|
||||
use yii\base\InvalidConfigException;
|
||||
use yii\db\BaseActiveRecord;
|
||||
use yii\helpers\ArrayHelper;
|
||||
use yii\helpers\Inflector;
|
||||
use yii\validators\UniqueValidator;
|
||||
|
||||
/**
|
||||
* SluggableBehavior automatically fills the specified attribute with a value that can be used a slug in a URL.
|
||||
*
|
||||
* To use SluggableBehavior, insert the following code to your ActiveRecord class:
|
||||
*
|
||||
* ```php
|
||||
* use yii\behaviors\SluggableBehavior;
|
||||
*
|
||||
* public function behaviors()
|
||||
* {
|
||||
* return [
|
||||
* [
|
||||
* 'class' => SluggableBehavior::className(),
|
||||
* 'attribute' => 'title',
|
||||
* // 'slugAttribute' => 'slug',
|
||||
* ],
|
||||
* ];
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* By default, SluggableBehavior will fill the `slug` attribute with a value that can be used a slug in a URL
|
||||
* when the associated AR object is being validated.
|
||||
*
|
||||
* Because attribute values will be set automatically by this behavior, they are usually not user input and should therefore
|
||||
* not be validated, i.e. the `slug` attribute should not appear in the [[\yii\base\Model::rules()|rules()]] method of the model.
|
||||
*
|
||||
* If your attribute name is different, you may configure the [[slugAttribute]] property like the following:
|
||||
*
|
||||
* ```php
|
||||
* public function behaviors()
|
||||
* {
|
||||
* return [
|
||||
* [
|
||||
* 'class' => SluggableBehavior::className(),
|
||||
* 'slugAttribute' => 'alias',
|
||||
* ],
|
||||
* ];
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @author Alexander Kochetov <creocoder@gmail.com>
|
||||
* @author Paul Klimov <klimov.paul@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class SluggableBehavior extends AttributeBehavior
|
||||
{
|
||||
/**
|
||||
* @var string the attribute that will receive the slug value
|
||||
*/
|
||||
public $slugAttribute = 'slug';
|
||||
/**
|
||||
* @var string|array|null the attribute or list of attributes whose value will be converted into a slug
|
||||
* or `null` meaning that the `$value` property will be used to generate a slug.
|
||||
*/
|
||||
public $attribute;
|
||||
/**
|
||||
* @var callable|string|null the value that will be used as a slug. This can be an anonymous function
|
||||
* or an arbitrary value or null. If the former, the return value of the function will be used as a slug.
|
||||
* If `null` then the `$attribute` property will be used to generate a slug.
|
||||
* The signature of the function should be as follows,
|
||||
*
|
||||
* ```php
|
||||
* function ($event)
|
||||
* {
|
||||
* // return slug
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
public $value;
|
||||
/**
|
||||
* @var bool whether to generate a new slug if it has already been generated before.
|
||||
* If true, the behavior will not generate a new slug even if [[attribute]] is changed.
|
||||
* @since 2.0.2
|
||||
*/
|
||||
public $immutable = false;
|
||||
/**
|
||||
* @var bool whether to ensure generated slug value to be unique among owner class records.
|
||||
* If enabled behavior will validate slug uniqueness automatically. If validation fails it will attempt
|
||||
* generating unique slug value from based one until success.
|
||||
*/
|
||||
public $ensureUnique = false;
|
||||
/**
|
||||
* @var bool whether to skip slug generation if [[attribute]] is null or an empty string.
|
||||
* If true, the behaviour will not generate a new slug if [[attribute]] is null or an empty string.
|
||||
* @since 2.0.13
|
||||
*/
|
||||
public $skipOnEmpty = false;
|
||||
/**
|
||||
* @var array configuration for slug uniqueness validator. Parameter 'class' may be omitted - by default
|
||||
* [[UniqueValidator]] will be used.
|
||||
* @see UniqueValidator
|
||||
*/
|
||||
public $uniqueValidator = [];
|
||||
/**
|
||||
* @var callable slug unique value generator. It is used in case [[ensureUnique]] enabled and generated
|
||||
* slug is not unique. This should be a PHP callable with following signature:
|
||||
*
|
||||
* ```php
|
||||
* function ($baseSlug, $iteration, $model)
|
||||
* {
|
||||
* // return uniqueSlug
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* If not set unique slug will be generated adding incrementing suffix to the base slug.
|
||||
*/
|
||||
public $uniqueSlugGenerator;
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
|
||||
if (empty($this->attributes)) {
|
||||
$this->attributes = [BaseActiveRecord::EVENT_BEFORE_VALIDATE => $this->slugAttribute];
|
||||
}
|
||||
|
||||
if ($this->attribute === null && $this->value === null) {
|
||||
throw new InvalidConfigException('Either "attribute" or "value" property must be specified.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getValue($event)
|
||||
{
|
||||
if (!$this->isNewSlugNeeded()) {
|
||||
return $this->owner->{$this->slugAttribute};
|
||||
}
|
||||
|
||||
if ($this->attribute !== null) {
|
||||
$slugParts = [];
|
||||
foreach ((array) $this->attribute as $attribute) {
|
||||
$part = ArrayHelper::getValue($this->owner, $attribute);
|
||||
if ($this->skipOnEmpty && $this->isEmpty($part)) {
|
||||
return $this->owner->{$this->slugAttribute};
|
||||
}
|
||||
$slugParts[] = $part;
|
||||
}
|
||||
$slug = $this->generateSlug($slugParts);
|
||||
} else {
|
||||
$slug = parent::getValue($event);
|
||||
}
|
||||
|
||||
return $this->ensureUnique ? $this->makeUnique($slug) : $slug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the new slug generation is needed
|
||||
* This method is called by [[getValue]] to check whether the new slug generation is needed.
|
||||
* You may override it to customize checking.
|
||||
* @return bool
|
||||
* @since 2.0.7
|
||||
*/
|
||||
protected function isNewSlugNeeded()
|
||||
{
|
||||
if (empty($this->owner->{$this->slugAttribute})) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->immutable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->attribute === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach ((array) $this->attribute as $attribute) {
|
||||
if ($this->owner->isAttributeChanged($attribute)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by [[getValue]] to generate the slug.
|
||||
* You may override it to customize slug generation.
|
||||
* The default implementation calls [[\yii\helpers\Inflector::slug()]] on the input strings
|
||||
* concatenated by dashes (`-`).
|
||||
* @param array $slugParts an array of strings that should be concatenated and converted to generate the slug value.
|
||||
* @return string the conversion result.
|
||||
*/
|
||||
protected function generateSlug($slugParts)
|
||||
{
|
||||
return Inflector::slug(implode('-', $slugParts));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by [[getValue]] when [[ensureUnique]] is true to generate the unique slug.
|
||||
* Calls [[generateUniqueSlug]] until generated slug is unique and returns it.
|
||||
* @param string $slug basic slug value
|
||||
* @return string unique slug
|
||||
* @see getValue
|
||||
* @see generateUniqueSlug
|
||||
* @since 2.0.7
|
||||
*/
|
||||
protected function makeUnique($slug)
|
||||
{
|
||||
$uniqueSlug = $slug;
|
||||
$iteration = 0;
|
||||
while (!$this->validateSlug($uniqueSlug)) {
|
||||
$iteration++;
|
||||
$uniqueSlug = $this->generateUniqueSlug($slug, $iteration);
|
||||
}
|
||||
|
||||
return $uniqueSlug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if given slug value is unique.
|
||||
* @param string $slug slug value
|
||||
* @return bool whether slug is unique.
|
||||
*/
|
||||
protected function validateSlug($slug)
|
||||
{
|
||||
/* @var $validator UniqueValidator */
|
||||
/* @var $model BaseActiveRecord */
|
||||
$validator = Yii::createObject(array_merge(
|
||||
[
|
||||
'class' => UniqueValidator::className(),
|
||||
],
|
||||
$this->uniqueValidator
|
||||
));
|
||||
|
||||
$model = clone $this->owner;
|
||||
$model->clearErrors();
|
||||
$model->{$this->slugAttribute} = $slug;
|
||||
|
||||
$validator->validateAttribute($model, $this->slugAttribute);
|
||||
return !$model->hasErrors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates slug using configured callback or increment of iteration.
|
||||
* @param string $baseSlug base slug value
|
||||
* @param int $iteration iteration number
|
||||
* @return string new slug value
|
||||
* @throws \yii\base\InvalidConfigException
|
||||
*/
|
||||
protected function generateUniqueSlug($baseSlug, $iteration)
|
||||
{
|
||||
if (is_callable($this->uniqueSlugGenerator)) {
|
||||
return call_user_func($this->uniqueSlugGenerator, $baseSlug, $iteration, $this->owner);
|
||||
}
|
||||
|
||||
return $baseSlug . '-' . ($iteration + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if $slugPart is empty string or null.
|
||||
*
|
||||
* @param string $slugPart One of attributes that is used for slug generation.
|
||||
* @return bool whether $slugPart empty or not.
|
||||
* @since 2.0.13
|
||||
*/
|
||||
protected function isEmpty($slugPart)
|
||||
{
|
||||
return $slugPart === null || $slugPart === '';
|
||||
}
|
||||
}
|
||||
141
vendor/yiisoft/yii2/behaviors/TimestampBehavior.php
vendored
Normal file
141
vendor/yiisoft/yii2/behaviors/TimestampBehavior.php
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\behaviors;
|
||||
|
||||
use yii\base\InvalidCallException;
|
||||
use yii\db\BaseActiveRecord;
|
||||
|
||||
/**
|
||||
* TimestampBehavior automatically fills the specified attributes with the current timestamp.
|
||||
*
|
||||
* To use TimestampBehavior, insert the following code to your ActiveRecord class:
|
||||
*
|
||||
* ```php
|
||||
* use yii\behaviors\TimestampBehavior;
|
||||
*
|
||||
* public function behaviors()
|
||||
* {
|
||||
* return [
|
||||
* TimestampBehavior::className(),
|
||||
* ];
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* By default, TimestampBehavior will fill the `created_at` and `updated_at` attributes with the current timestamp
|
||||
* when the associated AR object is being inserted; it will fill the `updated_at` attribute
|
||||
* with the timestamp when the AR object is being updated. The timestamp value is obtained by `time()`.
|
||||
*
|
||||
* Because attribute values will be set automatically by this behavior, they are usually not user input and should therefore
|
||||
* not be validated, i.e. `created_at` and `updated_at` should not appear in the [[\yii\base\Model::rules()|rules()]] method of the model.
|
||||
*
|
||||
* For the above implementation to work with MySQL database, please declare the columns(`created_at`, `updated_at`) as int(11) for being UNIX timestamp.
|
||||
*
|
||||
* If your attribute names are different or you want to use a different way of calculating the timestamp,
|
||||
* you may configure the [[createdAtAttribute]], [[updatedAtAttribute]] and [[value]] properties like the following:
|
||||
*
|
||||
* ```php
|
||||
* use yii\db\Expression;
|
||||
*
|
||||
* public function behaviors()
|
||||
* {
|
||||
* return [
|
||||
* [
|
||||
* 'class' => TimestampBehavior::className(),
|
||||
* 'createdAtAttribute' => 'create_time',
|
||||
* 'updatedAtAttribute' => 'update_time',
|
||||
* 'value' => new Expression('NOW()'),
|
||||
* ],
|
||||
* ];
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* In case you use an [[\yii\db\Expression]] object as in the example above, the attribute will not hold the timestamp value, but
|
||||
* the Expression object itself after the record has been saved. If you need the value from DB afterwards you should call
|
||||
* the [[\yii\db\ActiveRecord::refresh()|refresh()]] method of the record.
|
||||
*
|
||||
* TimestampBehavior also provides a method named [[touch()]] that allows you to assign the current
|
||||
* timestamp to the specified attribute(s) and save them to the database. For example,
|
||||
*
|
||||
* ```php
|
||||
* $model->touch('creation_time');
|
||||
* ```
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @author Alexander Kochetov <creocoder@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class TimestampBehavior extends AttributeBehavior
|
||||
{
|
||||
/**
|
||||
* @var string the attribute that will receive timestamp value
|
||||
* Set this property to false if you do not want to record the creation time.
|
||||
*/
|
||||
public $createdAtAttribute = 'created_at';
|
||||
/**
|
||||
* @var string the attribute that will receive timestamp value.
|
||||
* Set this property to false if you do not want to record the update time.
|
||||
*/
|
||||
public $updatedAtAttribute = 'updated_at';
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* In case, when the value is `null`, the result of the PHP function [time()](http://php.net/manual/en/function.time.php)
|
||||
* will be used as value.
|
||||
*/
|
||||
public $value;
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
|
||||
if (empty($this->attributes)) {
|
||||
$this->attributes = [
|
||||
BaseActiveRecord::EVENT_BEFORE_INSERT => [$this->createdAtAttribute, $this->updatedAtAttribute],
|
||||
BaseActiveRecord::EVENT_BEFORE_UPDATE => $this->updatedAtAttribute,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* In case, when the [[value]] is `null`, the result of the PHP function [time()](http://php.net/manual/en/function.time.php)
|
||||
* will be used as value.
|
||||
*/
|
||||
protected function getValue($event)
|
||||
{
|
||||
if ($this->value === null) {
|
||||
return time();
|
||||
}
|
||||
|
||||
return parent::getValue($event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a timestamp attribute to the current timestamp.
|
||||
*
|
||||
* ```php
|
||||
* $model->touch('lastVisit');
|
||||
* ```
|
||||
* @param string $attribute the name of the attribute to update.
|
||||
* @throws InvalidCallException if owner is a new record (since version 2.0.6).
|
||||
*/
|
||||
public function touch($attribute)
|
||||
{
|
||||
/* @var $owner BaseActiveRecord */
|
||||
$owner = $this->owner;
|
||||
if ($owner->getIsNewRecord()) {
|
||||
throw new InvalidCallException('Updating the timestamp is not possible on a new record.');
|
||||
}
|
||||
$owner->updateAttributes(array_fill_keys((array) $attribute, $this->getValue(null)));
|
||||
}
|
||||
}
|
||||
163
vendor/yiisoft/yii2/caching/ApcCache.php
vendored
Normal file
163
vendor/yiisoft/yii2/caching/ApcCache.php
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\caching;
|
||||
|
||||
use yii\base\InvalidConfigException;
|
||||
|
||||
/**
|
||||
* ApcCache provides APC caching in terms of an application component.
|
||||
*
|
||||
* To use this application component, the [APC PHP extension](http://www.php.net/apc) must be loaded.
|
||||
* Alternatively [APCu PHP extension](http://www.php.net/apcu) could be used via setting `useApcu` to `true`.
|
||||
* In order to enable APC or APCu for CLI you should add "apc.enable_cli = 1" to your php.ini.
|
||||
*
|
||||
* See [[Cache]] for common cache operations that ApcCache supports.
|
||||
*
|
||||
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class ApcCache extends Cache
|
||||
{
|
||||
/**
|
||||
* @var bool whether to use apcu or apc as the underlying caching extension.
|
||||
* If true, [apcu](http://pecl.php.net/package/apcu) will be used.
|
||||
* If false, [apc](http://pecl.php.net/package/apc) will be used.
|
||||
* Defaults to false.
|
||||
* @since 2.0.7
|
||||
*/
|
||||
public $useApcu = false;
|
||||
|
||||
|
||||
/**
|
||||
* Initializes this application component.
|
||||
* It checks if extension required is loaded.
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
$extension = $this->useApcu ? 'apcu' : 'apc';
|
||||
if (!extension_loaded($extension)) {
|
||||
throw new InvalidConfigException("ApcCache requires PHP $extension extension to be loaded.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a specified key exists in the cache.
|
||||
* This can be faster than getting the value from the cache if the data is big.
|
||||
* Note that this method does not check whether the dependency associated
|
||||
* with the cached data, if there is any, has changed. So a call to [[get]]
|
||||
* may return false while exists returns true.
|
||||
* @param mixed $key a key identifying the cached value. This can be a simple string or
|
||||
* a complex data structure consisting of factors representing the key.
|
||||
* @return bool true if a value exists in cache, false if the value is not in the cache or expired.
|
||||
*/
|
||||
public function exists($key)
|
||||
{
|
||||
$key = $this->buildKey($key);
|
||||
|
||||
return $this->useApcu ? apcu_exists($key) : apc_exists($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a value from cache with a specified key.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
* @param string $key a unique key identifying the cached value
|
||||
* @return mixed|false the value stored in cache, false if the value is not in the cache or expired.
|
||||
*/
|
||||
protected function getValue($key)
|
||||
{
|
||||
return $this->useApcu ? apcu_fetch($key) : apc_fetch($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves multiple values from cache with the specified keys.
|
||||
* @param array $keys a list of keys identifying the cached values
|
||||
* @return array a list of cached values indexed by the keys
|
||||
*/
|
||||
protected function getValues($keys)
|
||||
{
|
||||
$values = $this->useApcu ? apcu_fetch($keys) : apc_fetch($keys);
|
||||
return is_array($values) ? $values : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a value identified by a key in cache.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
*
|
||||
* @param string $key the key identifying the value to be cached
|
||||
* @param mixed $value the value to be cached. Most often it's a string. If you have disabled [[serializer]],
|
||||
* it could be something else.
|
||||
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
|
||||
* @return bool true if the value is successfully stored into cache, false otherwise.
|
||||
*/
|
||||
protected function setValue($key, $value, $duration)
|
||||
{
|
||||
return $this->useApcu ? apcu_store($key, $value, $duration) : apc_store($key, $value, $duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores multiple key-value pairs in cache.
|
||||
* @param array $data array where key corresponds to cache key while value
|
||||
* @param int $duration the number of seconds in which the cached values will expire. 0 means never expire.
|
||||
* @return array array of failed keys
|
||||
*/
|
||||
protected function setValues($data, $duration)
|
||||
{
|
||||
$result = $this->useApcu ? apcu_store($data, null, $duration) : apc_store($data, null, $duration);
|
||||
return is_array($result) ? array_keys($result) : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a value identified by a key into cache if the cache does not contain this key.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
* @param string $key the key identifying the value to be cached
|
||||
* @param mixed $value the value to be cached. Most often it's a string. If you have disabled [[serializer]],
|
||||
* it could be something else.
|
||||
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
|
||||
* @return bool true if the value is successfully stored into cache, false otherwise
|
||||
*/
|
||||
protected function addValue($key, $value, $duration)
|
||||
{
|
||||
return $this->useApcu ? apcu_add($key, $value, $duration) : apc_add($key, $value, $duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds multiple key-value pairs to cache.
|
||||
* @param array $data array where key corresponds to cache key while value is the value stored
|
||||
* @param int $duration the number of seconds in which the cached values will expire. 0 means never expire.
|
||||
* @return array array of failed keys
|
||||
*/
|
||||
protected function addValues($data, $duration)
|
||||
{
|
||||
$result = $this->useApcu ? apcu_add($data, null, $duration) : apc_add($data, null, $duration);
|
||||
return is_array($result) ? array_keys($result) : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a value with the specified key from cache
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
* @param string $key the key of the value to be deleted
|
||||
* @return bool if no error happens during deletion
|
||||
*/
|
||||
protected function deleteValue($key)
|
||||
{
|
||||
return $this->useApcu ? apcu_delete($key) : apc_delete($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all values from cache.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
* @return bool whether the flush operation was successful.
|
||||
*/
|
||||
protected function flushValues()
|
||||
{
|
||||
return $this->useApcu ? apcu_clear_cache() : apc_clear_cache('user');
|
||||
}
|
||||
}
|
||||
89
vendor/yiisoft/yii2/caching/ArrayCache.php
vendored
Normal file
89
vendor/yiisoft/yii2/caching/ArrayCache.php
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\caching;
|
||||
|
||||
/**
|
||||
* ArrayCache provides caching for the current request only by storing the values in an array.
|
||||
*
|
||||
* See [[Cache]] for common cache operations that ArrayCache supports.
|
||||
*
|
||||
* Unlike the [[Cache]], ArrayCache allows the expire parameter of [[set]], [[add]], [[multiSet]] and [[multiAdd]] to
|
||||
* be a floating point number, so you may specify the time in milliseconds (e.g. 0.1 will be 100 milliseconds).
|
||||
*
|
||||
* For enhanced performance of ArrayCache, you can disable serialization of the stored data by setting [[$serializer]] to `false`.
|
||||
*
|
||||
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview).
|
||||
*
|
||||
* @author Carsten Brandt <mail@cebe.cc>
|
||||
* @since 2.0
|
||||
*/
|
||||
class ArrayCache extends Cache
|
||||
{
|
||||
private $_cache;
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function exists($key)
|
||||
{
|
||||
$key = $this->buildKey($key);
|
||||
return isset($this->_cache[$key]) && ($this->_cache[$key][1] === 0 || $this->_cache[$key][1] > microtime(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getValue($key)
|
||||
{
|
||||
if (isset($this->_cache[$key]) && ($this->_cache[$key][1] === 0 || $this->_cache[$key][1] > microtime(true))) {
|
||||
return $this->_cache[$key][0];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setValue($key, $value, $duration)
|
||||
{
|
||||
$this->_cache[$key] = [$value, $duration === 0 ? 0 : microtime(true) + $duration];
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function addValue($key, $value, $duration)
|
||||
{
|
||||
if (isset($this->_cache[$key]) && ($this->_cache[$key][1] === 0 || $this->_cache[$key][1] > microtime(true))) {
|
||||
return false;
|
||||
}
|
||||
$this->_cache[$key] = [$value, $duration === 0 ? 0 : microtime(true) + $duration];
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function deleteValue($key)
|
||||
{
|
||||
unset($this->_cache[$key]);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function flushValues()
|
||||
{
|
||||
$this->_cache = [];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
582
vendor/yiisoft/yii2/caching/Cache.php
vendored
Normal file
582
vendor/yiisoft/yii2/caching/Cache.php
vendored
Normal file
@@ -0,0 +1,582 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\caching;
|
||||
|
||||
use Yii;
|
||||
use yii\base\Component;
|
||||
use yii\helpers\StringHelper;
|
||||
|
||||
/**
|
||||
* Cache is the base class for cache classes supporting different cache storage implementations.
|
||||
*
|
||||
* A data item can be stored in the cache by calling [[set()]] and be retrieved back
|
||||
* later (in the same or different request) by [[get()]]. In both operations,
|
||||
* a key identifying the data item is required. An expiration time and/or a [[Dependency|dependency]]
|
||||
* can also be specified when calling [[set()]]. If the data item expires or the dependency
|
||||
* changes at the time of calling [[get()]], the cache will return no data.
|
||||
*
|
||||
* A typical usage pattern of cache is like the following:
|
||||
*
|
||||
* ```php
|
||||
* $key = 'demo';
|
||||
* $data = $cache->get($key);
|
||||
* if ($data === false) {
|
||||
* // ...generate $data here...
|
||||
* $cache->set($key, $data, $duration, $dependency);
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Because Cache implements the [[\ArrayAccess]] interface, it can be used like an array. For example,
|
||||
*
|
||||
* ```php
|
||||
* $cache['foo'] = 'some data';
|
||||
* echo $cache['foo'];
|
||||
* ```
|
||||
*
|
||||
* Derived classes should implement the following methods which do the actual cache storage operations:
|
||||
*
|
||||
* - [[getValue()]]: retrieve the value with a key (if any) from cache
|
||||
* - [[setValue()]]: store the value with a key into cache
|
||||
* - [[addValue()]]: store the value only if the cache does not have this key before
|
||||
* - [[deleteValue()]]: delete the value with the specified key from cache
|
||||
* - [[flushValues()]]: delete all values from cache
|
||||
*
|
||||
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
abstract class Cache extends Component implements CacheInterface
|
||||
{
|
||||
/**
|
||||
* @var string a string prefixed to every cache key so that it is unique globally in the whole cache storage.
|
||||
* It is recommended that you set a unique cache key prefix for each application if the same cache
|
||||
* storage is being used by different applications.
|
||||
*
|
||||
* To ensure interoperability, only alphanumeric characters should be used.
|
||||
*/
|
||||
public $keyPrefix;
|
||||
/**
|
||||
* @var null|array|false the functions used to serialize and unserialize cached data. Defaults to null, meaning
|
||||
* using the default PHP `serialize()` and `unserialize()` functions. If you want to use some more efficient
|
||||
* serializer (e.g. [igbinary](http://pecl.php.net/package/igbinary)), you may configure this property with
|
||||
* a two-element array. The first element specifies the serialization function, and the second the deserialization
|
||||
* function. If this property is set false, data will be directly sent to and retrieved from the underlying
|
||||
* cache component without any serialization or deserialization. You should not turn off serialization if
|
||||
* you are using [[Dependency|cache dependency]], because it relies on data serialization. Also, some
|
||||
* implementations of the cache can not correctly save and retrieve data different from a string type.
|
||||
*/
|
||||
public $serializer;
|
||||
/**
|
||||
* @var int default duration in seconds before a cache entry will expire. Default value is 0, meaning infinity.
|
||||
* This value is used by [[set()]] if the duration is not explicitly given.
|
||||
* @since 2.0.11
|
||||
*/
|
||||
public $defaultDuration = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Builds a normalized cache key from a given key.
|
||||
*
|
||||
* If the given key is a string containing alphanumeric characters only and no more than 32 characters,
|
||||
* then the key will be returned back prefixed with [[keyPrefix]]. Otherwise, a normalized key
|
||||
* is generated by serializing the given key, applying MD5 hashing, and prefixing with [[keyPrefix]].
|
||||
*
|
||||
* @param mixed $key the key to be normalized
|
||||
* @return string the generated cache key
|
||||
*/
|
||||
public function buildKey($key)
|
||||
{
|
||||
if (is_string($key)) {
|
||||
$key = ctype_alnum($key) && StringHelper::byteLength($key) <= 32 ? $key : md5($key);
|
||||
} else {
|
||||
$key = md5(json_encode($key));
|
||||
}
|
||||
|
||||
return $this->keyPrefix . $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a value from cache with a specified key.
|
||||
* @param mixed $key a key identifying the cached value. This can be a simple string or
|
||||
* a complex data structure consisting of factors representing the key.
|
||||
* @return mixed the value stored in cache, false if the value is not in the cache, expired,
|
||||
* or the dependency associated with the cached data has changed.
|
||||
*/
|
||||
public function get($key)
|
||||
{
|
||||
$key = $this->buildKey($key);
|
||||
$value = $this->getValue($key);
|
||||
if ($value === false || $this->serializer === false) {
|
||||
return $value;
|
||||
} elseif ($this->serializer === null) {
|
||||
$value = unserialize($value);
|
||||
} else {
|
||||
$value = call_user_func($this->serializer[1], $value);
|
||||
}
|
||||
if (is_array($value) && !($value[1] instanceof Dependency && $value[1]->isChanged($this))) {
|
||||
return $value[0];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a specified key exists in the cache.
|
||||
* This can be faster than getting the value from the cache if the data is big.
|
||||
* In case a cache does not support this feature natively, this method will try to simulate it
|
||||
* but has no performance improvement over getting it.
|
||||
* Note that this method does not check whether the dependency associated
|
||||
* with the cached data, if there is any, has changed. So a call to [[get]]
|
||||
* may return false while exists returns true.
|
||||
* @param mixed $key a key identifying the cached value. This can be a simple string or
|
||||
* a complex data structure consisting of factors representing the key.
|
||||
* @return bool true if a value exists in cache, false if the value is not in the cache or expired.
|
||||
*/
|
||||
public function exists($key)
|
||||
{
|
||||
$key = $this->buildKey($key);
|
||||
$value = $this->getValue($key);
|
||||
|
||||
return $value !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves multiple values from cache with the specified keys.
|
||||
* Some caches (such as memcache, apc) allow retrieving multiple cached values at the same time,
|
||||
* which may improve the performance. In case a cache does not support this feature natively,
|
||||
* this method will try to simulate it.
|
||||
*
|
||||
* @param string[] $keys list of string keys identifying the cached values
|
||||
* @return array list of cached values corresponding to the specified keys. The array
|
||||
* is returned in terms of (key, value) pairs.
|
||||
* If a value is not cached or expired, the corresponding array value will be false.
|
||||
* @deprecated This method is an alias for [[multiGet()]] and will be removed in 2.1.0.
|
||||
*/
|
||||
public function mget($keys)
|
||||
{
|
||||
return $this->multiGet($keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves multiple values from cache with the specified keys.
|
||||
* Some caches (such as memcache, apc) allow retrieving multiple cached values at the same time,
|
||||
* which may improve the performance. In case a cache does not support this feature natively,
|
||||
* this method will try to simulate it.
|
||||
* @param string[] $keys list of string keys identifying the cached values
|
||||
* @return array list of cached values corresponding to the specified keys. The array
|
||||
* is returned in terms of (key, value) pairs.
|
||||
* If a value is not cached or expired, the corresponding array value will be false.
|
||||
* @since 2.0.7
|
||||
*/
|
||||
public function multiGet($keys)
|
||||
{
|
||||
$keyMap = [];
|
||||
foreach ($keys as $key) {
|
||||
$keyMap[$key] = $this->buildKey($key);
|
||||
}
|
||||
$values = $this->getValues(array_values($keyMap));
|
||||
$results = [];
|
||||
foreach ($keyMap as $key => $newKey) {
|
||||
$results[$key] = false;
|
||||
if (isset($values[$newKey])) {
|
||||
if ($this->serializer === false) {
|
||||
$results[$key] = $values[$newKey];
|
||||
} else {
|
||||
$value = $this->serializer === null ? unserialize($values[$newKey])
|
||||
: call_user_func($this->serializer[1], $values[$newKey]);
|
||||
|
||||
if (is_array($value) && !($value[1] instanceof Dependency && $value[1]->isChanged($this))) {
|
||||
$results[$key] = $value[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a value identified by a key into cache.
|
||||
* If the cache already contains such a key, the existing value and
|
||||
* expiration time will be replaced with the new ones, respectively.
|
||||
*
|
||||
* @param mixed $key a key identifying the value to be cached. This can be a simple string or
|
||||
* a complex data structure consisting of factors representing the key.
|
||||
* @param mixed $value the value to be cached
|
||||
* @param int $duration default duration in seconds before the cache will expire. If not set,
|
||||
* default [[defaultDuration]] value is used.
|
||||
* @param Dependency $dependency dependency of the cached item. If the dependency changes,
|
||||
* the corresponding value in the cache will be invalidated when it is fetched via [[get()]].
|
||||
* This parameter is ignored if [[serializer]] is false.
|
||||
* @return bool whether the value is successfully stored into cache
|
||||
*/
|
||||
public function set($key, $value, $duration = null, $dependency = null)
|
||||
{
|
||||
if ($duration === null) {
|
||||
$duration = $this->defaultDuration;
|
||||
}
|
||||
|
||||
if ($dependency !== null && $this->serializer !== false) {
|
||||
$dependency->evaluateDependency($this);
|
||||
}
|
||||
if ($this->serializer === null) {
|
||||
$value = serialize([$value, $dependency]);
|
||||
} elseif ($this->serializer !== false) {
|
||||
$value = call_user_func($this->serializer[0], [$value, $dependency]);
|
||||
}
|
||||
$key = $this->buildKey($key);
|
||||
|
||||
return $this->setValue($key, $value, $duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores multiple items in cache. Each item contains a value identified by a key.
|
||||
* If the cache already contains such a key, the existing value and
|
||||
* expiration time will be replaced with the new ones, respectively.
|
||||
*
|
||||
* @param array $items the items to be cached, as key-value pairs.
|
||||
* @param int $duration default number of seconds in which the cached values will expire. 0 means never expire.
|
||||
* @param Dependency $dependency dependency of the cached items. If the dependency changes,
|
||||
* the corresponding values in the cache will be invalidated when it is fetched via [[get()]].
|
||||
* This parameter is ignored if [[serializer]] is false.
|
||||
* @return array array of failed keys
|
||||
* @deprecated This method is an alias for [[multiSet()]] and will be removed in 2.1.0.
|
||||
*/
|
||||
public function mset($items, $duration = 0, $dependency = null)
|
||||
{
|
||||
return $this->multiSet($items, $duration, $dependency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores multiple items in cache. Each item contains a value identified by a key.
|
||||
* If the cache already contains such a key, the existing value and
|
||||
* expiration time will be replaced with the new ones, respectively.
|
||||
*
|
||||
* @param array $items the items to be cached, as key-value pairs.
|
||||
* @param int $duration default number of seconds in which the cached values will expire. 0 means never expire.
|
||||
* @param Dependency $dependency dependency of the cached items. If the dependency changes,
|
||||
* the corresponding values in the cache will be invalidated when it is fetched via [[get()]].
|
||||
* This parameter is ignored if [[serializer]] is false.
|
||||
* @return array array of failed keys
|
||||
* @since 2.0.7
|
||||
*/
|
||||
public function multiSet($items, $duration = 0, $dependency = null)
|
||||
{
|
||||
if ($dependency !== null && $this->serializer !== false) {
|
||||
$dependency->evaluateDependency($this);
|
||||
}
|
||||
|
||||
$data = [];
|
||||
foreach ($items as $key => $value) {
|
||||
if ($this->serializer === null) {
|
||||
$value = serialize([$value, $dependency]);
|
||||
} elseif ($this->serializer !== false) {
|
||||
$value = call_user_func($this->serializer[0], [$value, $dependency]);
|
||||
}
|
||||
|
||||
$key = $this->buildKey($key);
|
||||
$data[$key] = $value;
|
||||
}
|
||||
|
||||
return $this->setValues($data, $duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores multiple items in cache. Each item contains a value identified by a key.
|
||||
* If the cache already contains such a key, the existing value and expiration time will be preserved.
|
||||
*
|
||||
* @param array $items the items to be cached, as key-value pairs.
|
||||
* @param int $duration default number of seconds in which the cached values will expire. 0 means never expire.
|
||||
* @param Dependency $dependency dependency of the cached items. If the dependency changes,
|
||||
* the corresponding values in the cache will be invalidated when it is fetched via [[get()]].
|
||||
* This parameter is ignored if [[serializer]] is false.
|
||||
* @return array array of failed keys
|
||||
* @deprecated This method is an alias for [[multiAdd()]] and will be removed in 2.1.0.
|
||||
*/
|
||||
public function madd($items, $duration = 0, $dependency = null)
|
||||
{
|
||||
return $this->multiAdd($items, $duration, $dependency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores multiple items in cache. Each item contains a value identified by a key.
|
||||
* If the cache already contains such a key, the existing value and expiration time will be preserved.
|
||||
*
|
||||
* @param array $items the items to be cached, as key-value pairs.
|
||||
* @param int $duration default number of seconds in which the cached values will expire. 0 means never expire.
|
||||
* @param Dependency $dependency dependency of the cached items. If the dependency changes,
|
||||
* the corresponding values in the cache will be invalidated when it is fetched via [[get()]].
|
||||
* This parameter is ignored if [[serializer]] is false.
|
||||
* @return array array of failed keys
|
||||
* @since 2.0.7
|
||||
*/
|
||||
public function multiAdd($items, $duration = 0, $dependency = null)
|
||||
{
|
||||
if ($dependency !== null && $this->serializer !== false) {
|
||||
$dependency->evaluateDependency($this);
|
||||
}
|
||||
|
||||
$data = [];
|
||||
foreach ($items as $key => $value) {
|
||||
if ($this->serializer === null) {
|
||||
$value = serialize([$value, $dependency]);
|
||||
} elseif ($this->serializer !== false) {
|
||||
$value = call_user_func($this->serializer[0], [$value, $dependency]);
|
||||
}
|
||||
|
||||
$key = $this->buildKey($key);
|
||||
$data[$key] = $value;
|
||||
}
|
||||
|
||||
return $this->addValues($data, $duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a value identified by a key into cache if the cache does not contain this key.
|
||||
* Nothing will be done if the cache already contains the key.
|
||||
* @param mixed $key a key identifying the value to be cached. This can be a simple string or
|
||||
* a complex data structure consisting of factors representing the key.
|
||||
* @param mixed $value the value to be cached
|
||||
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
|
||||
* @param Dependency $dependency dependency of the cached item. If the dependency changes,
|
||||
* the corresponding value in the cache will be invalidated when it is fetched via [[get()]].
|
||||
* This parameter is ignored if [[serializer]] is false.
|
||||
* @return bool whether the value is successfully stored into cache
|
||||
*/
|
||||
public function add($key, $value, $duration = 0, $dependency = null)
|
||||
{
|
||||
if ($dependency !== null && $this->serializer !== false) {
|
||||
$dependency->evaluateDependency($this);
|
||||
}
|
||||
if ($this->serializer === null) {
|
||||
$value = serialize([$value, $dependency]);
|
||||
} elseif ($this->serializer !== false) {
|
||||
$value = call_user_func($this->serializer[0], [$value, $dependency]);
|
||||
}
|
||||
$key = $this->buildKey($key);
|
||||
|
||||
return $this->addValue($key, $value, $duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a value with the specified key from cache.
|
||||
* @param mixed $key a key identifying the value to be deleted from cache. This can be a simple string or
|
||||
* a complex data structure consisting of factors representing the key.
|
||||
* @return bool if no error happens during deletion
|
||||
*/
|
||||
public function delete($key)
|
||||
{
|
||||
$key = $this->buildKey($key);
|
||||
|
||||
return $this->deleteValue($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all values from cache.
|
||||
* Be careful of performing this operation if the cache is shared among multiple applications.
|
||||
* @return bool whether the flush operation was successful.
|
||||
*/
|
||||
public function flush()
|
||||
{
|
||||
return $this->flushValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a value from cache with a specified key.
|
||||
* This method should be implemented by child classes to retrieve the data
|
||||
* from specific cache storage.
|
||||
* @param string $key a unique key identifying the cached value
|
||||
* @return mixed|false the value stored in cache, false if the value is not in the cache or expired. Most often
|
||||
* value is a string. If you have disabled [[serializer]], it could be something else.
|
||||
*/
|
||||
abstract protected function getValue($key);
|
||||
|
||||
/**
|
||||
* Stores a value identified by a key in cache.
|
||||
* This method should be implemented by child classes to store the data
|
||||
* in specific cache storage.
|
||||
* @param string $key the key identifying the value to be cached
|
||||
* @param mixed $value the value to be cached. Most often it's a string. If you have disabled [[serializer]],
|
||||
* it could be something else.
|
||||
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
|
||||
* @return bool true if the value is successfully stored into cache, false otherwise
|
||||
*/
|
||||
abstract protected function setValue($key, $value, $duration);
|
||||
|
||||
/**
|
||||
* Stores a value identified by a key into cache if the cache does not contain this key.
|
||||
* This method should be implemented by child classes to store the data
|
||||
* in specific cache storage.
|
||||
* @param string $key the key identifying the value to be cached
|
||||
* @param mixed $value the value to be cached. Most often it's a string. If you have disabled [[serializer]],
|
||||
* it could be something else.
|
||||
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
|
||||
* @return bool true if the value is successfully stored into cache, false otherwise
|
||||
*/
|
||||
abstract protected function addValue($key, $value, $duration);
|
||||
|
||||
/**
|
||||
* Deletes a value with the specified key from cache
|
||||
* This method should be implemented by child classes to delete the data from actual cache storage.
|
||||
* @param string $key the key of the value to be deleted
|
||||
* @return bool if no error happens during deletion
|
||||
*/
|
||||
abstract protected function deleteValue($key);
|
||||
|
||||
/**
|
||||
* Deletes all values from cache.
|
||||
* Child classes may implement this method to realize the flush operation.
|
||||
* @return bool whether the flush operation was successful.
|
||||
*/
|
||||
abstract protected function flushValues();
|
||||
|
||||
/**
|
||||
* Retrieves multiple values from cache with the specified keys.
|
||||
* The default implementation calls [[getValue()]] multiple times to retrieve
|
||||
* the cached values one by one. If the underlying cache storage supports multiget,
|
||||
* this method should be overridden to exploit that feature.
|
||||
* @param array $keys a list of keys identifying the cached values
|
||||
* @return array a list of cached values indexed by the keys
|
||||
*/
|
||||
protected function getValues($keys)
|
||||
{
|
||||
$results = [];
|
||||
foreach ($keys as $key) {
|
||||
$results[$key] = $this->getValue($key);
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores multiple key-value pairs in cache.
|
||||
* The default implementation calls [[setValue()]] multiple times store values one by one. If the underlying cache
|
||||
* storage supports multi-set, this method should be overridden to exploit that feature.
|
||||
* @param array $data array where key corresponds to cache key while value is the value stored
|
||||
* @param int $duration the number of seconds in which the cached values will expire. 0 means never expire.
|
||||
* @return array array of failed keys
|
||||
*/
|
||||
protected function setValues($data, $duration)
|
||||
{
|
||||
$failedKeys = [];
|
||||
foreach ($data as $key => $value) {
|
||||
if ($this->setValue($key, $value, $duration) === false) {
|
||||
$failedKeys[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
return $failedKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds multiple key-value pairs to cache.
|
||||
* The default implementation calls [[addValue()]] multiple times add values one by one. If the underlying cache
|
||||
* storage supports multi-add, this method should be overridden to exploit that feature.
|
||||
* @param array $data array where key corresponds to cache key while value is the value stored.
|
||||
* @param int $duration the number of seconds in which the cached values will expire. 0 means never expire.
|
||||
* @return array array of failed keys
|
||||
*/
|
||||
protected function addValues($data, $duration)
|
||||
{
|
||||
$failedKeys = [];
|
||||
foreach ($data as $key => $value) {
|
||||
if ($this->addValue($key, $value, $duration) === false) {
|
||||
$failedKeys[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
return $failedKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether there is a cache entry with a specified key.
|
||||
* This method is required by the interface [[\ArrayAccess]].
|
||||
* @param string $key a key identifying the cached value
|
||||
* @return bool
|
||||
*/
|
||||
public function offsetExists($key)
|
||||
{
|
||||
return $this->get($key) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the value from cache with a specified key.
|
||||
* This method is required by the interface [[\ArrayAccess]].
|
||||
* @param string $key a key identifying the cached value
|
||||
* @return mixed the value stored in cache, false if the value is not in the cache or expired.
|
||||
*/
|
||||
public function offsetGet($key)
|
||||
{
|
||||
return $this->get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the value identified by a key into cache.
|
||||
* If the cache already contains such a key, the existing value will be
|
||||
* replaced with the new ones. To add expiration and dependencies, use the [[set()]] method.
|
||||
* This method is required by the interface [[\ArrayAccess]].
|
||||
* @param string $key the key identifying the value to be cached
|
||||
* @param mixed $value the value to be cached
|
||||
*/
|
||||
public function offsetSet($key, $value)
|
||||
{
|
||||
$this->set($key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the value with the specified key from cache
|
||||
* This method is required by the interface [[\ArrayAccess]].
|
||||
* @param string $key the key of the value to be deleted
|
||||
*/
|
||||
public function offsetUnset($key)
|
||||
{
|
||||
$this->delete($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method combines both [[set()]] and [[get()]] methods to retrieve value identified by a $key,
|
||||
* or to store the result of $callable execution if there is no cache available for the $key.
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* ```php
|
||||
* public function getTopProducts($count = 10) {
|
||||
* $cache = $this->cache; // Could be Yii::$app->cache
|
||||
* return $cache->getOrSet(['top-n-products', 'n' => $count], function ($cache) use ($count) {
|
||||
* return Products::find()->mostPopular()->limit(10)->all();
|
||||
* }, 1000);
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param mixed $key a key identifying the value to be cached. This can be a simple string or
|
||||
* a complex data structure consisting of factors representing the key.
|
||||
* @param callable|\Closure $callable the callable or closure that will be used to generate a value to be cached.
|
||||
* In case $callable returns `false`, the value will not be cached.
|
||||
* @param int $duration default duration in seconds before the cache will expire. If not set,
|
||||
* [[defaultDuration]] value will be used.
|
||||
* @param Dependency $dependency dependency of the cached item. If the dependency changes,
|
||||
* the corresponding value in the cache will be invalidated when it is fetched via [[get()]].
|
||||
* This parameter is ignored if [[serializer]] is `false`.
|
||||
* @return mixed result of $callable execution
|
||||
* @since 2.0.11
|
||||
*/
|
||||
public function getOrSet($key, $callable, $duration = null, $dependency = null)
|
||||
{
|
||||
if (($value = $this->get($key)) !== false) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$value = call_user_func($callable, $this);
|
||||
if (!$this->set($key, $value, $duration, $dependency)) {
|
||||
Yii::warning('Failed to set cache value for key ' . json_encode($key), __METHOD__);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
192
vendor/yiisoft/yii2/caching/CacheInterface.php
vendored
Normal file
192
vendor/yiisoft/yii2/caching/CacheInterface.php
vendored
Normal file
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\caching;
|
||||
|
||||
/**
|
||||
* CacheInterface is the base interface for cache.
|
||||
*
|
||||
* A data item can be stored in the cache by calling [[set()]] and be retrieved back
|
||||
* later (in the same or different request) by [[get()]]. In both operations,
|
||||
* a key identifying the data item is required. An expiration time and/or a [[Dependency|dependency]]
|
||||
* can also be specified when calling [[set()]]. If the data item expires or the dependency
|
||||
* changes at the time of calling [[get()]], the cache will return no data.
|
||||
*
|
||||
* A typical usage pattern of cache is like the following:
|
||||
*
|
||||
* ```php
|
||||
* $key = 'demo';
|
||||
* $data = $cache->get($key);
|
||||
* if ($data === false) {
|
||||
* // ...generate $data here...
|
||||
* $cache->set($key, $data, $duration, $dependency);
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Because CacheInterface extends the [[\ArrayAccess]] interface, it can be used like an array. For example,
|
||||
*
|
||||
* ```php
|
||||
* $cache['foo'] = 'some data';
|
||||
* echo $cache['foo'];
|
||||
* ```
|
||||
*
|
||||
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @author Dmitry Naumenko <d.naumenko.a@gmail.com>
|
||||
* @since 2.0.13. Previous framework versions used abstract class [[yii\caching\Cache]] as interface.
|
||||
*/
|
||||
interface CacheInterface extends \ArrayAccess
|
||||
{
|
||||
/**
|
||||
* Builds a normalized cache key from a given key.
|
||||
*
|
||||
* If the given key is a string containing alphanumeric characters only and no more than 32 characters,
|
||||
* then the key will be returned back prefixed with [[keyPrefix]]. Otherwise, a normalized key
|
||||
* is generated by serializing the given key, applying MD5 hashing, and prefixing with [[keyPrefix]].
|
||||
*
|
||||
* @param mixed $key the key to be normalized
|
||||
* @return string the generated cache key
|
||||
*/
|
||||
public function buildKey($key);
|
||||
|
||||
/**
|
||||
* Retrieves a value from cache with a specified key.
|
||||
* @param mixed $key a key identifying the cached value. This can be a simple string or
|
||||
* a complex data structure consisting of factors representing the key.
|
||||
* @return mixed the value stored in cache, false if the value is not in the cache, expired,
|
||||
* or the dependency associated with the cached data has changed.
|
||||
*/
|
||||
public function get($key);
|
||||
|
||||
/**
|
||||
* Checks whether a specified key exists in the cache.
|
||||
* This can be faster than getting the value from the cache if the data is big.
|
||||
* In case a cache does not support this feature natively, this method will try to simulate it
|
||||
* but has no performance improvement over getting it.
|
||||
* Note that this method does not check whether the dependency associated
|
||||
* with the cached data, if there is any, has changed. So a call to [[get]]
|
||||
* may return false while exists returns true.
|
||||
* @param mixed $key a key identifying the cached value. This can be a simple string or
|
||||
* a complex data structure consisting of factors representing the key.
|
||||
* @return bool true if a value exists in cache, false if the value is not in the cache or expired.
|
||||
*/
|
||||
public function exists($key);
|
||||
|
||||
/**
|
||||
* Retrieves multiple values from cache with the specified keys.
|
||||
* Some caches (such as memcache, apc) allow retrieving multiple cached values at the same time,
|
||||
* which may improve the performance. In case a cache does not support this feature natively,
|
||||
* this method will try to simulate it.
|
||||
* @param string[] $keys list of string keys identifying the cached values
|
||||
* @return array list of cached values corresponding to the specified keys. The array
|
||||
* is returned in terms of (key, value) pairs.
|
||||
* If a value is not cached or expired, the corresponding array value will be false.
|
||||
*/
|
||||
public function multiGet($keys);
|
||||
|
||||
/**
|
||||
* Stores a value identified by a key into cache.
|
||||
* If the cache already contains such a key, the existing value and
|
||||
* expiration time will be replaced with the new ones, respectively.
|
||||
*
|
||||
* @param mixed $key a key identifying the value to be cached. This can be a simple string or
|
||||
* a complex data structure consisting of factors representing the key.
|
||||
* @param mixed $value the value to be cached
|
||||
* @param int $duration default duration in seconds before the cache will expire. If not set,
|
||||
* default [[defaultDuration]] value is used.
|
||||
* @param Dependency $dependency dependency of the cached item. If the dependency changes,
|
||||
* the corresponding value in the cache will be invalidated when it is fetched via [[get()]].
|
||||
* This parameter is ignored if [[serializer]] is false.
|
||||
* @return bool whether the value is successfully stored into cache
|
||||
*/
|
||||
public function set($key, $value, $duration = null, $dependency = null);
|
||||
|
||||
/**
|
||||
* Stores multiple items in cache. Each item contains a value identified by a key.
|
||||
* If the cache already contains such a key, the existing value and
|
||||
* expiration time will be replaced with the new ones, respectively.
|
||||
*
|
||||
* @param array $items the items to be cached, as key-value pairs.
|
||||
* @param int $duration default number of seconds in which the cached values will expire. 0 means never expire.
|
||||
* @param Dependency $dependency dependency of the cached items. If the dependency changes,
|
||||
* the corresponding values in the cache will be invalidated when it is fetched via [[get()]].
|
||||
* This parameter is ignored if [[serializer]] is false.
|
||||
* @return array array of failed keys
|
||||
*/
|
||||
public function multiSet($items, $duration = 0, $dependency = null);
|
||||
|
||||
/**
|
||||
* Stores a value identified by a key into cache if the cache does not contain this key.
|
||||
* Nothing will be done if the cache already contains the key.
|
||||
* @param mixed $key a key identifying the value to be cached. This can be a simple string or
|
||||
* a complex data structure consisting of factors representing the key.
|
||||
* @param mixed $value the value to be cached
|
||||
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
|
||||
* @param Dependency $dependency dependency of the cached item. If the dependency changes,
|
||||
* the corresponding value in the cache will be invalidated when it is fetched via [[get()]].
|
||||
* This parameter is ignored if [[serializer]] is false.
|
||||
* @return bool whether the value is successfully stored into cache
|
||||
*/
|
||||
public function add($key, $value, $duration = 0, $dependency = null);
|
||||
|
||||
/**
|
||||
* Stores multiple items in cache. Each item contains a value identified by a key.
|
||||
* If the cache already contains such a key, the existing value and expiration time will be preserved.
|
||||
*
|
||||
* @param array $items the items to be cached, as key-value pairs.
|
||||
* @param int $duration default number of seconds in which the cached values will expire. 0 means never expire.
|
||||
* @param Dependency $dependency dependency of the cached items. If the dependency changes,
|
||||
* the corresponding values in the cache will be invalidated when it is fetched via [[get()]].
|
||||
* This parameter is ignored if [[serializer]] is false.
|
||||
* @return array array of failed keys
|
||||
*/
|
||||
public function multiAdd($items, $duration = 0, $dependency = null);
|
||||
|
||||
/**
|
||||
* Deletes a value with the specified key from cache.
|
||||
* @param mixed $key a key identifying the value to be deleted from cache. This can be a simple string or
|
||||
* a complex data structure consisting of factors representing the key.
|
||||
* @return bool if no error happens during deletion
|
||||
*/
|
||||
public function delete($key);
|
||||
|
||||
/**
|
||||
* Deletes all values from cache.
|
||||
* Be careful of performing this operation if the cache is shared among multiple applications.
|
||||
* @return bool whether the flush operation was successful.
|
||||
*/
|
||||
public function flush();
|
||||
|
||||
/**
|
||||
* Method combines both [[set()]] and [[get()]] methods to retrieve value identified by a $key,
|
||||
* or to store the result of $callable execution if there is no cache available for the $key.
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* ```php
|
||||
* public function getTopProducts($count = 10) {
|
||||
* $cache = $this->cache; // Could be Yii::$app->cache
|
||||
* return $cache->getOrSet(['top-n-products', 'n' => $count], function ($cache) use ($count) {
|
||||
* return Products::find()->mostPopular()->limit($count)->all();
|
||||
* }, 1000);
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param mixed $key a key identifying the value to be cached. This can be a simple string or
|
||||
* a complex data structure consisting of factors representing the key.
|
||||
* @param callable|\Closure $callable the callable or closure that will be used to generate a value to be cached.
|
||||
* In case $callable returns `false`, the value will not be cached.
|
||||
* @param int $duration default duration in seconds before the cache will expire. If not set,
|
||||
* [[defaultDuration]] value will be used.
|
||||
* @param Dependency $dependency dependency of the cached item. If the dependency changes,
|
||||
* the corresponding value in the cache will be invalidated when it is fetched via [[get()]].
|
||||
* This parameter is ignored if [[serializer]] is `false`.
|
||||
* @return mixed result of $callable execution
|
||||
*/
|
||||
public function getOrSet($key, $callable, $duration = null, $dependency = null);
|
||||
}
|
||||
75
vendor/yiisoft/yii2/caching/ChainedDependency.php
vendored
Normal file
75
vendor/yiisoft/yii2/caching/ChainedDependency.php
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\caching;
|
||||
|
||||
/**
|
||||
* ChainedDependency represents a dependency which is composed of a list of other dependencies.
|
||||
*
|
||||
* When [[dependOnAll]] is true, if any of the dependencies has changed, this dependency is
|
||||
* considered changed; When [[dependOnAll]] is false, if one of the dependencies has NOT changed,
|
||||
* this dependency is considered NOT changed.
|
||||
*
|
||||
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class ChainedDependency extends Dependency
|
||||
{
|
||||
/**
|
||||
* @var Dependency[] list of dependencies that this dependency is composed of.
|
||||
* Each array element must be a dependency object.
|
||||
*/
|
||||
public $dependencies = [];
|
||||
/**
|
||||
* @var bool whether this dependency is depending on every dependency in [[dependencies]].
|
||||
* Defaults to true, meaning if any of the dependencies has changed, this dependency is considered changed.
|
||||
* When it is set false, it means if one of the dependencies has NOT changed, this dependency
|
||||
* is considered NOT changed.
|
||||
*/
|
||||
public $dependOnAll = true;
|
||||
|
||||
|
||||
/**
|
||||
* Evaluates the dependency by generating and saving the data related with dependency.
|
||||
* @param CacheInterface $cache the cache component that is currently evaluating this dependency
|
||||
*/
|
||||
public function evaluateDependency($cache)
|
||||
{
|
||||
foreach ($this->dependencies as $dependency) {
|
||||
$dependency->evaluateDependency($cache);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the data needed to determine if dependency has been changed.
|
||||
* This method does nothing in this class.
|
||||
* @param CacheInterface $cache the cache component that is currently evaluating this dependency
|
||||
* @return mixed the data needed to determine if dependency has been changed.
|
||||
*/
|
||||
protected function generateDependencyData($cache)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isChanged($cache)
|
||||
{
|
||||
foreach ($this->dependencies as $dependency) {
|
||||
if ($this->dependOnAll && $dependency->isChanged($cache)) {
|
||||
return true;
|
||||
} elseif (!$this->dependOnAll && !$dependency->isChanged($cache)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return !$this->dependOnAll;
|
||||
}
|
||||
}
|
||||
286
vendor/yiisoft/yii2/caching/DbCache.php
vendored
Normal file
286
vendor/yiisoft/yii2/caching/DbCache.php
vendored
Normal file
@@ -0,0 +1,286 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\caching;
|
||||
|
||||
use Yii;
|
||||
use yii\base\InvalidConfigException;
|
||||
use yii\db\Connection;
|
||||
use yii\db\PdoValue;
|
||||
use yii\db\Query;
|
||||
use yii\di\Instance;
|
||||
|
||||
/**
|
||||
* DbCache implements a cache application component by storing cached data in a database.
|
||||
*
|
||||
* By default, DbCache stores session data in a DB table named 'cache'. This table
|
||||
* must be pre-created. The table name can be changed by setting [[cacheTable]].
|
||||
*
|
||||
* Please refer to [[Cache]] for common cache operations that are supported by DbCache.
|
||||
*
|
||||
* The following example shows how you can configure the application to use DbCache:
|
||||
*
|
||||
* ```php
|
||||
* 'cache' => [
|
||||
* 'class' => 'yii\caching\DbCache',
|
||||
* // 'db' => 'mydb',
|
||||
* // 'cacheTable' => 'my_cache',
|
||||
* ]
|
||||
* ```
|
||||
*
|
||||
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class DbCache extends Cache
|
||||
{
|
||||
/**
|
||||
* @var Connection|array|string the DB connection object or the application component ID of the DB connection.
|
||||
* After the DbCache object is created, if you want to change this property, you should only assign it
|
||||
* with a DB connection object.
|
||||
* Starting from version 2.0.2, this can also be a configuration array for creating the object.
|
||||
*/
|
||||
public $db = 'db';
|
||||
/**
|
||||
* @var string name of the DB table to store cache content.
|
||||
* The table should be pre-created as follows:
|
||||
*
|
||||
* ```php
|
||||
* CREATE TABLE cache (
|
||||
* id char(128) NOT NULL PRIMARY KEY,
|
||||
* expire int(11),
|
||||
* data BLOB
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* where 'BLOB' refers to the BLOB-type of your preferred DBMS. Below are the BLOB type
|
||||
* that can be used for some popular DBMS:
|
||||
*
|
||||
* - MySQL: LONGBLOB
|
||||
* - PostgreSQL: BYTEA
|
||||
* - MSSQL: BLOB
|
||||
*
|
||||
* When using DbCache in a production server, we recommend you create a DB index for the 'expire'
|
||||
* column in the cache table to improve the performance.
|
||||
*/
|
||||
public $cacheTable = '{{%cache}}';
|
||||
/**
|
||||
* @var int the probability (parts per million) that garbage collection (GC) should be performed
|
||||
* when storing a piece of data in the cache. Defaults to 100, meaning 0.01% chance.
|
||||
* This number should be between 0 and 1000000. A value 0 meaning no GC will be performed at all.
|
||||
*/
|
||||
public $gcProbability = 100;
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the DbCache component.
|
||||
* This method will initialize the [[db]] property to make sure it refers to a valid DB connection.
|
||||
* @throws InvalidConfigException if [[db]] is invalid.
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
$this->db = Instance::ensure($this->db, Connection::className());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a specified key exists in the cache.
|
||||
* This can be faster than getting the value from the cache if the data is big.
|
||||
* Note that this method does not check whether the dependency associated
|
||||
* with the cached data, if there is any, has changed. So a call to [[get]]
|
||||
* may return false while exists returns true.
|
||||
* @param mixed $key a key identifying the cached value. This can be a simple string or
|
||||
* a complex data structure consisting of factors representing the key.
|
||||
* @return bool true if a value exists in cache, false if the value is not in the cache or expired.
|
||||
*/
|
||||
public function exists($key)
|
||||
{
|
||||
$key = $this->buildKey($key);
|
||||
|
||||
$query = new Query();
|
||||
$query->select(['COUNT(*)'])
|
||||
->from($this->cacheTable)
|
||||
->where('[[id]] = :id AND ([[expire]] = 0 OR [[expire]] >' . time() . ')', [':id' => $key]);
|
||||
if ($this->db->enableQueryCache) {
|
||||
// temporarily disable and re-enable query caching
|
||||
$this->db->enableQueryCache = false;
|
||||
$result = $query->createCommand($this->db)->queryScalar();
|
||||
$this->db->enableQueryCache = true;
|
||||
} else {
|
||||
$result = $query->createCommand($this->db)->queryScalar();
|
||||
}
|
||||
|
||||
return $result > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a value from cache with a specified key.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
* @param string $key a unique key identifying the cached value
|
||||
* @return string|false the value stored in cache, false if the value is not in the cache or expired.
|
||||
*/
|
||||
protected function getValue($key)
|
||||
{
|
||||
$query = new Query();
|
||||
$query->select(['data'])
|
||||
->from($this->cacheTable)
|
||||
->where('[[id]] = :id AND ([[expire]] = 0 OR [[expire]] >' . time() . ')', [':id' => $key]);
|
||||
if ($this->db->enableQueryCache) {
|
||||
// temporarily disable and re-enable query caching
|
||||
$this->db->enableQueryCache = false;
|
||||
$result = $query->createCommand($this->db)->queryScalar();
|
||||
$this->db->enableQueryCache = true;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $query->createCommand($this->db)->queryScalar();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves multiple values from cache with the specified keys.
|
||||
* @param array $keys a list of keys identifying the cached values
|
||||
* @return array a list of cached values indexed by the keys
|
||||
*/
|
||||
protected function getValues($keys)
|
||||
{
|
||||
if (empty($keys)) {
|
||||
return [];
|
||||
}
|
||||
$query = new Query();
|
||||
$query->select(['id', 'data'])
|
||||
->from($this->cacheTable)
|
||||
->where(['id' => $keys])
|
||||
->andWhere('([[expire]] = 0 OR [[expire]] > ' . time() . ')');
|
||||
|
||||
if ($this->db->enableQueryCache) {
|
||||
$this->db->enableQueryCache = false;
|
||||
$rows = $query->createCommand($this->db)->queryAll();
|
||||
$this->db->enableQueryCache = true;
|
||||
} else {
|
||||
$rows = $query->createCommand($this->db)->queryAll();
|
||||
}
|
||||
|
||||
$results = [];
|
||||
foreach ($keys as $key) {
|
||||
$results[$key] = false;
|
||||
}
|
||||
foreach ($rows as $row) {
|
||||
if (is_resource($row['data']) && get_resource_type($row['data']) === 'stream') {
|
||||
$results[$row['id']] = stream_get_contents($row['data']);
|
||||
} else {
|
||||
$results[$row['id']] = $row['data'];
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a value identified by a key in cache.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
*
|
||||
* @param string $key the key identifying the value to be cached
|
||||
* @param string $value the value to be cached. Other types (if you have disabled [[serializer]]) cannot be saved.
|
||||
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
|
||||
* @return bool true if the value is successfully stored into cache, false otherwise
|
||||
*/
|
||||
protected function setValue($key, $value, $duration)
|
||||
{
|
||||
$result = $this->db->noCache(function (Connection $db) use ($key, $value, $duration) {
|
||||
$command = $db->createCommand()
|
||||
->update($this->cacheTable, [
|
||||
'expire' => $duration > 0 ? $duration + time() : 0,
|
||||
'data' => new PdoValue($value, \PDO::PARAM_LOB),
|
||||
], ['id' => $key]);
|
||||
return $command->execute();
|
||||
});
|
||||
|
||||
if ($result) {
|
||||
$this->gc();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->addValue($key, $value, $duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a value identified by a key into cache if the cache does not contain this key.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
*
|
||||
* @param string $key the key identifying the value to be cached
|
||||
* @param string $value the value to be cached. Other types (if you have disabled [[serializer]]) cannot be saved.
|
||||
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
|
||||
* @return bool true if the value is successfully stored into cache, false otherwise
|
||||
*/
|
||||
protected function addValue($key, $value, $duration)
|
||||
{
|
||||
$this->gc();
|
||||
|
||||
try {
|
||||
$this->db->noCache(function (Connection $db) use ($key, $value, $duration) {
|
||||
$db->createCommand()
|
||||
->insert($this->cacheTable, [
|
||||
'id' => $key,
|
||||
'expire' => $duration > 0 ? $duration + time() : 0,
|
||||
'data' => new PdoValue($value, \PDO::PARAM_LOB),
|
||||
])->execute();
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a value with the specified key from cache
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
* @param string $key the key of the value to be deleted
|
||||
* @return bool if no error happens during deletion
|
||||
*/
|
||||
protected function deleteValue($key)
|
||||
{
|
||||
$this->db->noCache(function (Connection $db) use ($key) {
|
||||
$db->createCommand()
|
||||
->delete($this->cacheTable, ['id' => $key])
|
||||
->execute();
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the expired data values.
|
||||
* @param bool $force whether to enforce the garbage collection regardless of [[gcProbability]].
|
||||
* Defaults to false, meaning the actual deletion happens with the probability as specified by [[gcProbability]].
|
||||
*/
|
||||
public function gc($force = false)
|
||||
{
|
||||
if ($force || mt_rand(0, 1000000) < $this->gcProbability) {
|
||||
$this->db->createCommand()
|
||||
->delete($this->cacheTable, '[[expire]] > 0 AND [[expire]] < ' . time())
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all values from cache.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
* @return bool whether the flush operation was successful.
|
||||
*/
|
||||
protected function flushValues()
|
||||
{
|
||||
$this->db->createCommand()
|
||||
->delete($this->cacheTable)
|
||||
->execute();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
69
vendor/yiisoft/yii2/caching/DbDependency.php
vendored
Normal file
69
vendor/yiisoft/yii2/caching/DbDependency.php
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\caching;
|
||||
|
||||
use Yii;
|
||||
use yii\base\InvalidConfigException;
|
||||
use yii\db\Connection;
|
||||
use yii\di\Instance;
|
||||
|
||||
/**
|
||||
* DbDependency represents a dependency based on the query result of a SQL statement.
|
||||
*
|
||||
* If the query result changes, the dependency is considered as changed.
|
||||
* The query is specified via the [[sql]] property.
|
||||
*
|
||||
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class DbDependency extends Dependency
|
||||
{
|
||||
/**
|
||||
* @var string the application component ID of the DB connection.
|
||||
*/
|
||||
public $db = 'db';
|
||||
/**
|
||||
* @var string the SQL query whose result is used to determine if the dependency has been changed.
|
||||
* Only the first row of the query result will be used.
|
||||
*/
|
||||
public $sql;
|
||||
/**
|
||||
* @var array the parameters (name => value) to be bound to the SQL statement specified by [[sql]].
|
||||
*/
|
||||
public $params = [];
|
||||
|
||||
|
||||
/**
|
||||
* Generates the data needed to determine if dependency has been changed.
|
||||
* This method returns the value of the global state.
|
||||
* @param CacheInterface $cache the cache component that is currently evaluating this dependency
|
||||
* @return mixed the data needed to determine if dependency has been changed.
|
||||
* @throws InvalidConfigException if [[db]] is not a valid application component ID
|
||||
*/
|
||||
protected function generateDependencyData($cache)
|
||||
{
|
||||
/* @var $db Connection */
|
||||
$db = Instance::ensure($this->db, Connection::className());
|
||||
if ($this->sql === null) {
|
||||
throw new InvalidConfigException('DbDependency::sql must be set.');
|
||||
}
|
||||
|
||||
if ($db->enableQueryCache) {
|
||||
// temporarily disable and re-enable query caching
|
||||
$db->enableQueryCache = false;
|
||||
$result = $db->createCommand($this->sql, $this->params)->queryOne();
|
||||
$db->enableQueryCache = true;
|
||||
} else {
|
||||
$result = $db->createCommand($this->sql, $this->params)->queryOne();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
111
vendor/yiisoft/yii2/caching/DbQueryDependency.php
vendored
Normal file
111
vendor/yiisoft/yii2/caching/DbQueryDependency.php
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\caching;
|
||||
|
||||
use yii\base\InvalidConfigException;
|
||||
use yii\db\QueryInterface;
|
||||
use yii\di\Instance;
|
||||
|
||||
/**
|
||||
* DbQueryDependency represents a dependency based on the query result of an [[QueryInterface]] instance.
|
||||
*
|
||||
* If the query result changes, the dependency is considered as changed.
|
||||
* The query is specified via the [[query]] property.
|
||||
*
|
||||
* Object of any class which matches [[QueryInterface]] can be used, so this dependency can be used not only
|
||||
* with regular relational databases but with MongoDB, Redis and so on as well.
|
||||
*
|
||||
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview).
|
||||
*
|
||||
* @see QueryInterface
|
||||
*
|
||||
* @author Paul Klimov <klimov.paul@gmail.com>
|
||||
* @since 2.0.12
|
||||
*/
|
||||
class DbQueryDependency extends Dependency
|
||||
{
|
||||
/**
|
||||
* @var string|array|object the application component ID of the database connection, connection object or
|
||||
* its array configuration.
|
||||
* This field can be left blank, allowing query to determine connection automatically.
|
||||
*/
|
||||
public $db;
|
||||
/**
|
||||
* @var QueryInterface the query which result is used to determine if the dependency has been changed.
|
||||
* Actual query method to be invoked is determined by [[method]].
|
||||
*/
|
||||
public $query;
|
||||
/**
|
||||
* @var string|callable method which should be invoked in over the [[query]] object.
|
||||
*
|
||||
* If specified as a string an own query method with such name will be invoked, passing [[db]] value as its
|
||||
* first argument. For example: `exists`, `all`.
|
||||
*
|
||||
* This field can be specified as a PHP callback of following signature:
|
||||
*
|
||||
* ```php
|
||||
* function (QueryInterface $query, mixed $db) {
|
||||
* //return mixed;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* If not set - [[QueryInterface::one()]] will be used.
|
||||
*/
|
||||
public $method;
|
||||
|
||||
|
||||
/**
|
||||
* Generates the data needed to determine if dependency is changed.
|
||||
*
|
||||
* This method returns the query result.
|
||||
* @param CacheInterface $cache the cache component that is currently evaluating this dependency
|
||||
* @return mixed the data needed to determine if dependency has been changed.
|
||||
* @throws InvalidConfigException on invalid configuration.
|
||||
*/
|
||||
protected function generateDependencyData($cache)
|
||||
{
|
||||
$db = $this->db;
|
||||
if ($db !== null) {
|
||||
$db = Instance::ensure($db);
|
||||
}
|
||||
|
||||
if (!$this->query instanceof QueryInterface) {
|
||||
throw new InvalidConfigException('"' . get_class($this) . '::$query" should be an instance of "yii\db\QueryInterface".');
|
||||
}
|
||||
|
||||
if (!empty($db->enableQueryCache)) {
|
||||
// temporarily disable and re-enable query caching
|
||||
$originEnableQueryCache = $db->enableQueryCache;
|
||||
$db->enableQueryCache = false;
|
||||
$result = $this->executeQuery($this->query, $db);
|
||||
$db->enableQueryCache = $originEnableQueryCache;
|
||||
} else {
|
||||
$result = $this->executeQuery($this->query, $db);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the query according to [[method]] specification.
|
||||
* @param QueryInterface $query query to be executed.
|
||||
* @param mixed $db connection.
|
||||
* @return mixed query result.
|
||||
*/
|
||||
private function executeQuery($query, $db)
|
||||
{
|
||||
if ($this->method === null) {
|
||||
return $query->one($db);
|
||||
}
|
||||
if (is_string($this->method)) {
|
||||
return call_user_func([$query, $this->method], $db);
|
||||
}
|
||||
|
||||
return call_user_func($this->method, $query, $db);
|
||||
}
|
||||
}
|
||||
121
vendor/yiisoft/yii2/caching/Dependency.php
vendored
Normal file
121
vendor/yiisoft/yii2/caching/Dependency.php
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\caching;
|
||||
|
||||
/**
|
||||
* Dependency is the base class for cache dependency classes.
|
||||
*
|
||||
* Child classes should override its [[generateDependencyData()]] for generating
|
||||
* the actual dependency data.
|
||||
*
|
||||
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
abstract class Dependency extends \yii\base\BaseObject
|
||||
{
|
||||
/**
|
||||
* @var mixed the dependency data that is saved in cache and later is compared with the
|
||||
* latest dependency data.
|
||||
*/
|
||||
public $data;
|
||||
/**
|
||||
* @var bool whether this dependency is reusable or not. True value means that dependent
|
||||
* data for this cache dependency will be generated only once per request. This allows you
|
||||
* to use the same cache dependency for multiple separate cache calls while generating the same
|
||||
* page without an overhead of re-evaluating dependency data each time. Defaults to false.
|
||||
*/
|
||||
public $reusable = false;
|
||||
|
||||
/**
|
||||
* @var array static storage of cached data for reusable dependencies.
|
||||
*/
|
||||
private static $_reusableData = [];
|
||||
|
||||
|
||||
/**
|
||||
* Evaluates the dependency by generating and saving the data related with dependency.
|
||||
* This method is invoked by cache before writing data into it.
|
||||
* @param CacheInterface $cache the cache component that is currently evaluating this dependency
|
||||
*/
|
||||
public function evaluateDependency($cache)
|
||||
{
|
||||
if ($this->reusable) {
|
||||
$hash = $this->generateReusableHash();
|
||||
if (!array_key_exists($hash, self::$_reusableData)) {
|
||||
self::$_reusableData[$hash] = $this->generateDependencyData($cache);
|
||||
}
|
||||
$this->data = self::$_reusableData[$hash];
|
||||
} else {
|
||||
$this->data = $this->generateDependencyData($cache);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value indicating whether the dependency has changed.
|
||||
* @deprecated since version 2.0.11. Will be removed in version 2.1. Use [[isChanged()]] instead.
|
||||
* @param CacheInterface $cache the cache component that is currently evaluating this dependency
|
||||
* @return bool whether the dependency has changed.
|
||||
*/
|
||||
public function getHasChanged($cache)
|
||||
{
|
||||
return $this->isChanged($cache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the dependency is changed.
|
||||
* @param CacheInterface $cache the cache component that is currently evaluating this dependency
|
||||
* @return bool whether the dependency has changed.
|
||||
* @since 2.0.11
|
||||
*/
|
||||
public function isChanged($cache)
|
||||
{
|
||||
if ($this->reusable) {
|
||||
$hash = $this->generateReusableHash();
|
||||
if (!array_key_exists($hash, self::$_reusableData)) {
|
||||
self::$_reusableData[$hash] = $this->generateDependencyData($cache);
|
||||
}
|
||||
$data = self::$_reusableData[$hash];
|
||||
} else {
|
||||
$data = $this->generateDependencyData($cache);
|
||||
}
|
||||
|
||||
return $data !== $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets all cached data for reusable dependencies.
|
||||
*/
|
||||
public static function resetReusableData()
|
||||
{
|
||||
self::$_reusableData = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a unique hash that can be used for retrieving reusable dependency data.
|
||||
* @return string a unique hash value for this cache dependency.
|
||||
* @see reusable
|
||||
*/
|
||||
protected function generateReusableHash()
|
||||
{
|
||||
$data = $this->data;
|
||||
$this->data = null; // https://github.com/yiisoft/yii2/issues/3052
|
||||
$key = sha1(serialize($this));
|
||||
$this->data = $data;
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the data needed to determine if dependency is changed.
|
||||
* Derived classes should override this method to generate the actual dependency data.
|
||||
* @param CacheInterface $cache the cache component that is currently evaluating this dependency
|
||||
* @return mixed the data needed to determine if dependency has been changed.
|
||||
*/
|
||||
abstract protected function generateDependencyData($cache);
|
||||
}
|
||||
83
vendor/yiisoft/yii2/caching/DummyCache.php
vendored
Normal file
83
vendor/yiisoft/yii2/caching/DummyCache.php
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\caching;
|
||||
|
||||
/**
|
||||
* DummyCache is a placeholder cache component.
|
||||
*
|
||||
* DummyCache does not cache anything. It is provided so that one can always configure
|
||||
* a 'cache' application component and save the check of existence of `\Yii::$app->cache`.
|
||||
* By replacing DummyCache with some other cache component, one can quickly switch from
|
||||
* non-caching mode to caching mode.
|
||||
*
|
||||
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class DummyCache extends Cache
|
||||
{
|
||||
/**
|
||||
* Retrieves a value from cache with a specified key.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
* @param string $key a unique key identifying the cached value
|
||||
* @return mixed|false the value stored in cache, false if the value is not in the cache or expired.
|
||||
*/
|
||||
protected function getValue($key)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a value identified by a key in cache.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
*
|
||||
* @param string $key the key identifying the value to be cached
|
||||
* @param mixed $value the value to be cached
|
||||
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
|
||||
* @return bool true if the value is successfully stored into cache, false otherwise
|
||||
*/
|
||||
protected function setValue($key, $value, $duration)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a value identified by a key into cache if the cache does not contain this key.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
* @param string $key the key identifying the value to be cached
|
||||
* @param mixed $value the value to be cached
|
||||
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
|
||||
* @return bool true if the value is successfully stored into cache, false otherwise
|
||||
*/
|
||||
protected function addValue($key, $value, $duration)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a value with the specified key from cache
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
* @param string $key the key of the value to be deleted
|
||||
* @return bool if no error happens during deletion
|
||||
*/
|
||||
protected function deleteValue($key)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all values from cache.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
* @return bool whether the flush operation was successful.
|
||||
*/
|
||||
protected function flushValues()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
50
vendor/yiisoft/yii2/caching/ExpressionDependency.php
vendored
Normal file
50
vendor/yiisoft/yii2/caching/ExpressionDependency.php
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\caching;
|
||||
|
||||
/**
|
||||
* ExpressionDependency represents a dependency based on the result of a PHP expression.
|
||||
*
|
||||
* ExpressionDependency will use `eval()` to evaluate the PHP expression.
|
||||
* The dependency is reported as unchanged if and only if the result of the expression is
|
||||
* the same as the one evaluated when storing the data to cache.
|
||||
*
|
||||
* A PHP expression can be any PHP code that has a value. To learn more about what an expression is,
|
||||
* please refer to the [php manual](http://www.php.net/manual/en/language.expressions.php).
|
||||
*
|
||||
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class ExpressionDependency extends Dependency
|
||||
{
|
||||
/**
|
||||
* @var string the string representation of a PHP expression whose result is used to determine the dependency.
|
||||
* A PHP expression can be any PHP code that evaluates to a value. To learn more about what an expression is,
|
||||
* please refer to the [php manual](http://www.php.net/manual/en/language.expressions.php).
|
||||
*/
|
||||
public $expression = 'true';
|
||||
/**
|
||||
* @var mixed custom parameters associated with this dependency. You may get the value
|
||||
* of this property in [[expression]] using `$this->params`.
|
||||
*/
|
||||
public $params;
|
||||
|
||||
|
||||
/**
|
||||
* Generates the data needed to determine if dependency has been changed.
|
||||
* This method returns the result of the PHP expression.
|
||||
* @param CacheInterface $cache the cache component that is currently evaluating this dependency
|
||||
* @return mixed the data needed to determine if dependency has been changed.
|
||||
*/
|
||||
protected function generateDependencyData($cache)
|
||||
{
|
||||
return eval("return {$this->expression};");
|
||||
}
|
||||
}
|
||||
273
vendor/yiisoft/yii2/caching/FileCache.php
vendored
Normal file
273
vendor/yiisoft/yii2/caching/FileCache.php
vendored
Normal file
@@ -0,0 +1,273 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\caching;
|
||||
|
||||
use Yii;
|
||||
use yii\helpers\FileHelper;
|
||||
|
||||
/**
|
||||
* FileCache implements a cache component using files.
|
||||
*
|
||||
* For each data value being cached, FileCache will store it in a separate file.
|
||||
* The cache files are placed under [[cachePath]]. FileCache will perform garbage collection
|
||||
* automatically to remove expired cache files.
|
||||
*
|
||||
* Please refer to [[Cache]] for common cache operations that are supported by FileCache.
|
||||
*
|
||||
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class FileCache extends Cache
|
||||
{
|
||||
/**
|
||||
* @var string a string prefixed to every cache key. This is needed when you store
|
||||
* cache data under the same [[cachePath]] for different applications to avoid
|
||||
* conflict.
|
||||
*
|
||||
* To ensure interoperability, only alphanumeric characters should be used.
|
||||
*/
|
||||
public $keyPrefix = '';
|
||||
/**
|
||||
* @var string the directory to store cache files. You may use [path alias](guide:concept-aliases) here.
|
||||
* If not set, it will use the "cache" subdirectory under the application runtime path.
|
||||
*/
|
||||
public $cachePath = '@runtime/cache';
|
||||
/**
|
||||
* @var string cache file suffix. Defaults to '.bin'.
|
||||
*/
|
||||
public $cacheFileSuffix = '.bin';
|
||||
/**
|
||||
* @var int the level of sub-directories to store cache files. Defaults to 1.
|
||||
* If the system has huge number of cache files (e.g. one million), you may use a bigger value
|
||||
* (usually no bigger than 3). Using sub-directories is mainly to ensure the file system
|
||||
* is not over burdened with a single directory having too many files.
|
||||
*/
|
||||
public $directoryLevel = 1;
|
||||
/**
|
||||
* @var int the probability (parts per million) that garbage collection (GC) should be performed
|
||||
* when storing a piece of data in the cache. Defaults to 10, meaning 0.001% chance.
|
||||
* This number should be between 0 and 1000000. A value 0 means no GC will be performed at all.
|
||||
*/
|
||||
public $gcProbability = 10;
|
||||
/**
|
||||
* @var int the permission to be set for newly created cache files.
|
||||
* This value will be used by PHP chmod() function. No umask will be applied.
|
||||
* If not set, the permission will be determined by the current environment.
|
||||
*/
|
||||
public $fileMode;
|
||||
/**
|
||||
* @var int the permission to be set for newly created directories.
|
||||
* This value will be used by PHP chmod() function. No umask will be applied.
|
||||
* Defaults to 0775, meaning the directory is read-writable by owner and group,
|
||||
* but read-only for other users.
|
||||
*/
|
||||
public $dirMode = 0775;
|
||||
|
||||
|
||||
/**
|
||||
* Initializes this component by ensuring the existence of the cache path.
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
$this->cachePath = Yii::getAlias($this->cachePath);
|
||||
if (!is_dir($this->cachePath)) {
|
||||
FileHelper::createDirectory($this->cachePath, $this->dirMode, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a specified key exists in the cache.
|
||||
* This can be faster than getting the value from the cache if the data is big.
|
||||
* Note that this method does not check whether the dependency associated
|
||||
* with the cached data, if there is any, has changed. So a call to [[get]]
|
||||
* may return false while exists returns true.
|
||||
* @param mixed $key a key identifying the cached value. This can be a simple string or
|
||||
* a complex data structure consisting of factors representing the key.
|
||||
* @return bool true if a value exists in cache, false if the value is not in the cache or expired.
|
||||
*/
|
||||
public function exists($key)
|
||||
{
|
||||
$cacheFile = $this->getCacheFile($this->buildKey($key));
|
||||
|
||||
return @filemtime($cacheFile) > time();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a value from cache with a specified key.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
* @param string $key a unique key identifying the cached value
|
||||
* @return string|false the value stored in cache, false if the value is not in the cache or expired.
|
||||
*/
|
||||
protected function getValue($key)
|
||||
{
|
||||
$cacheFile = $this->getCacheFile($key);
|
||||
|
||||
if (@filemtime($cacheFile) > time()) {
|
||||
$fp = @fopen($cacheFile, 'r');
|
||||
if ($fp !== false) {
|
||||
@flock($fp, LOCK_SH);
|
||||
$cacheValue = @stream_get_contents($fp);
|
||||
@flock($fp, LOCK_UN);
|
||||
@fclose($fp);
|
||||
return $cacheValue;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a value identified by a key in cache.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
*
|
||||
* @param string $key the key identifying the value to be cached
|
||||
* @param string $value the value to be cached. Other types (If you have disabled [[serializer]]) unable to get is
|
||||
* correct in [[getValue()]].
|
||||
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
|
||||
* @return bool true if the value is successfully stored into cache, false otherwise
|
||||
*/
|
||||
protected function setValue($key, $value, $duration)
|
||||
{
|
||||
$this->gc();
|
||||
$cacheFile = $this->getCacheFile($key);
|
||||
if ($this->directoryLevel > 0) {
|
||||
@FileHelper::createDirectory(dirname($cacheFile), $this->dirMode, true);
|
||||
}
|
||||
if (@file_put_contents($cacheFile, $value, LOCK_EX) !== false) {
|
||||
if ($this->fileMode !== null) {
|
||||
@chmod($cacheFile, $this->fileMode);
|
||||
}
|
||||
if ($duration <= 0) {
|
||||
$duration = 31536000; // 1 year
|
||||
}
|
||||
|
||||
return @touch($cacheFile, $duration + time());
|
||||
}
|
||||
|
||||
$error = error_get_last();
|
||||
Yii::warning("Unable to write cache file '{$cacheFile}': {$error['message']}", __METHOD__);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a value identified by a key into cache if the cache does not contain this key.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
*
|
||||
* @param string $key the key identifying the value to be cached
|
||||
* @param string $value the value to be cached. Other types (if you have disabled [[serializer]]) unable to get is
|
||||
* correct in [[getValue()]].
|
||||
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
|
||||
* @return bool true if the value is successfully stored into cache, false otherwise
|
||||
*/
|
||||
protected function addValue($key, $value, $duration)
|
||||
{
|
||||
$cacheFile = $this->getCacheFile($key);
|
||||
if (@filemtime($cacheFile) > time()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->setValue($key, $value, $duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a value with the specified key from cache
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
* @param string $key the key of the value to be deleted
|
||||
* @return bool if no error happens during deletion
|
||||
*/
|
||||
protected function deleteValue($key)
|
||||
{
|
||||
$cacheFile = $this->getCacheFile($key);
|
||||
|
||||
return @unlink($cacheFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cache file path given the cache key.
|
||||
* @param string $key cache key
|
||||
* @return string the cache file path
|
||||
*/
|
||||
protected function getCacheFile($key)
|
||||
{
|
||||
if ($this->directoryLevel > 0) {
|
||||
$base = $this->cachePath;
|
||||
for ($i = 0; $i < $this->directoryLevel; ++$i) {
|
||||
if (($prefix = substr($key, $i + $i, 2)) !== false) {
|
||||
$base .= DIRECTORY_SEPARATOR . $prefix;
|
||||
}
|
||||
}
|
||||
|
||||
return $base . DIRECTORY_SEPARATOR . $key . $this->cacheFileSuffix;
|
||||
}
|
||||
|
||||
return $this->cachePath . DIRECTORY_SEPARATOR . $key . $this->cacheFileSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all values from cache.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
* @return bool whether the flush operation was successful.
|
||||
*/
|
||||
protected function flushValues()
|
||||
{
|
||||
$this->gc(true, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes expired cache files.
|
||||
* @param bool $force whether to enforce the garbage collection regardless of [[gcProbability]].
|
||||
* Defaults to false, meaning the actual deletion happens with the probability as specified by [[gcProbability]].
|
||||
* @param bool $expiredOnly whether to removed expired cache files only.
|
||||
* If false, all cache files under [[cachePath]] will be removed.
|
||||
*/
|
||||
public function gc($force = false, $expiredOnly = true)
|
||||
{
|
||||
if ($force || mt_rand(0, 1000000) < $this->gcProbability) {
|
||||
$this->gcRecursive($this->cachePath, $expiredOnly);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively removing expired cache files under a directory.
|
||||
* This method is mainly used by [[gc()]].
|
||||
* @param string $path the directory under which expired cache files are removed.
|
||||
* @param bool $expiredOnly whether to only remove expired cache files. If false, all files
|
||||
* under `$path` will be removed.
|
||||
*/
|
||||
protected function gcRecursive($path, $expiredOnly)
|
||||
{
|
||||
if (($handle = opendir($path)) !== false) {
|
||||
while (($file = readdir($handle)) !== false) {
|
||||
if ($file[0] === '.') {
|
||||
continue;
|
||||
}
|
||||
$fullPath = $path . DIRECTORY_SEPARATOR . $file;
|
||||
if (is_dir($fullPath)) {
|
||||
$this->gcRecursive($fullPath, $expiredOnly);
|
||||
if (!$expiredOnly) {
|
||||
if (!@rmdir($fullPath)) {
|
||||
$error = error_get_last();
|
||||
Yii::warning("Unable to remove directory '{$fullPath}': {$error['message']}", __METHOD__);
|
||||
}
|
||||
}
|
||||
} elseif (!$expiredOnly || $expiredOnly && @filemtime($fullPath) < time()) {
|
||||
if (!@unlink($fullPath)) {
|
||||
$error = error_get_last();
|
||||
Yii::warning("Unable to remove file '{$fullPath}': {$error['message']}", __METHOD__);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
50
vendor/yiisoft/yii2/caching/FileDependency.php
vendored
Normal file
50
vendor/yiisoft/yii2/caching/FileDependency.php
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\caching;
|
||||
|
||||
use Yii;
|
||||
use yii\base\InvalidConfigException;
|
||||
|
||||
/**
|
||||
* FileDependency represents a dependency based on a file's last modification time.
|
||||
*
|
||||
* If the last modification time of the file specified via [[fileName]] is changed,
|
||||
* the dependency is considered as changed.
|
||||
*
|
||||
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class FileDependency extends Dependency
|
||||
{
|
||||
/**
|
||||
* @var string the file path or [path alias](guide:concept-aliases) whose last modification time is used to
|
||||
* check if the dependency has been changed.
|
||||
*/
|
||||
public $fileName;
|
||||
|
||||
|
||||
/**
|
||||
* Generates the data needed to determine if dependency has been changed.
|
||||
* This method returns the file's last modification time.
|
||||
* @param CacheInterface $cache the cache component that is currently evaluating this dependency
|
||||
* @return mixed the data needed to determine if dependency has been changed.
|
||||
* @throws InvalidConfigException if [[fileName]] is not set
|
||||
*/
|
||||
protected function generateDependencyData($cache)
|
||||
{
|
||||
if ($this->fileName === null) {
|
||||
throw new InvalidConfigException('FileDependency::fileName must be set');
|
||||
}
|
||||
|
||||
$fileName = Yii::getAlias($this->fileName);
|
||||
clearstatcache(false, $fileName);
|
||||
return @filemtime($fileName);
|
||||
}
|
||||
}
|
||||
365
vendor/yiisoft/yii2/caching/MemCache.php
vendored
Normal file
365
vendor/yiisoft/yii2/caching/MemCache.php
vendored
Normal file
@@ -0,0 +1,365 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\caching;
|
||||
|
||||
use Yii;
|
||||
use yii\base\InvalidConfigException;
|
||||
|
||||
/**
|
||||
* MemCache implements a cache application component based on [memcache](http://pecl.php.net/package/memcache)
|
||||
* and [memcached](http://pecl.php.net/package/memcached).
|
||||
*
|
||||
* MemCache supports both [memcache](http://pecl.php.net/package/memcache) and
|
||||
* [memcached](http://pecl.php.net/package/memcached). By setting [[useMemcached]] to be true or false,
|
||||
* one can let MemCache to use either memcached or memcache, respectively.
|
||||
*
|
||||
* MemCache can be configured with a list of memcache servers by settings its [[servers]] property.
|
||||
* By default, MemCache assumes there is a memcache server running on localhost at port 11211.
|
||||
*
|
||||
* See [[Cache]] for common cache operations that MemCache supports.
|
||||
*
|
||||
* Note, there is no security measure to protected data in memcache.
|
||||
* All data in memcache can be accessed by any process running in the system.
|
||||
*
|
||||
* To use MemCache as the cache application component, configure the application as follows,
|
||||
*
|
||||
* ```php
|
||||
* [
|
||||
* 'components' => [
|
||||
* 'cache' => [
|
||||
* 'class' => 'yii\caching\MemCache',
|
||||
* 'servers' => [
|
||||
* [
|
||||
* 'host' => 'server1',
|
||||
* 'port' => 11211,
|
||||
* 'weight' => 60,
|
||||
* ],
|
||||
* [
|
||||
* 'host' => 'server2',
|
||||
* 'port' => 11211,
|
||||
* 'weight' => 40,
|
||||
* ],
|
||||
* ],
|
||||
* ],
|
||||
* ],
|
||||
* ]
|
||||
* ```
|
||||
*
|
||||
* In the above, two memcache servers are used: server1 and server2. You can configure more properties of
|
||||
* each server, such as `persistent`, `weight`, `timeout`. Please see [[MemCacheServer]] for available options.
|
||||
*
|
||||
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview).
|
||||
*
|
||||
* @property \Memcache|\Memcached $memcache The memcache (or memcached) object used by this cache component.
|
||||
* This property is read-only.
|
||||
* @property MemCacheServer[] $servers List of memcache server configurations. Note that the type of this
|
||||
* property differs in getter and setter. See [[getServers()]] and [[setServers()]] for details.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class MemCache extends Cache
|
||||
{
|
||||
/**
|
||||
* @var bool whether to use memcached or memcache as the underlying caching extension.
|
||||
* If true, [memcached](http://pecl.php.net/package/memcached) will be used.
|
||||
* If false, [memcache](http://pecl.php.net/package/memcache) will be used.
|
||||
* Defaults to false.
|
||||
*/
|
||||
public $useMemcached = false;
|
||||
/**
|
||||
* @var string an ID that identifies a Memcached instance. This property is used only when [[useMemcached]] is true.
|
||||
* By default the Memcached instances are destroyed at the end of the request. To create an instance that
|
||||
* persists between requests, you may specify a unique ID for the instance. All instances created with the
|
||||
* same ID will share the same connection.
|
||||
* @see http://ca2.php.net/manual/en/memcached.construct.php
|
||||
*/
|
||||
public $persistentId;
|
||||
/**
|
||||
* @var array options for Memcached. This property is used only when [[useMemcached]] is true.
|
||||
* @see http://ca2.php.net/manual/en/memcached.setoptions.php
|
||||
*/
|
||||
public $options;
|
||||
/**
|
||||
* @var string memcached sasl username. This property is used only when [[useMemcached]] is true.
|
||||
* @see http://php.net/manual/en/memcached.setsaslauthdata.php
|
||||
*/
|
||||
public $username;
|
||||
/**
|
||||
* @var string memcached sasl password. This property is used only when [[useMemcached]] is true.
|
||||
* @see http://php.net/manual/en/memcached.setsaslauthdata.php
|
||||
*/
|
||||
public $password;
|
||||
|
||||
/**
|
||||
* @var \Memcache|\Memcached the Memcache instance
|
||||
*/
|
||||
private $_cache;
|
||||
/**
|
||||
* @var array list of memcache server configurations
|
||||
*/
|
||||
private $_servers = [];
|
||||
|
||||
|
||||
/**
|
||||
* Initializes this application component.
|
||||
* It creates the memcache instance and adds memcache servers.
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
$this->addServers($this->getMemcache(), $this->getServers());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add servers to the server pool of the cache specified.
|
||||
*
|
||||
* @param \Memcache|\Memcached $cache
|
||||
* @param MemCacheServer[] $servers
|
||||
* @throws InvalidConfigException
|
||||
*/
|
||||
protected function addServers($cache, $servers)
|
||||
{
|
||||
if (empty($servers)) {
|
||||
$servers = [new MemCacheServer([
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 11211,
|
||||
])];
|
||||
} else {
|
||||
foreach ($servers as $server) {
|
||||
if ($server->host === null) {
|
||||
throw new InvalidConfigException("The 'host' property must be specified for every memcache server.");
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($this->useMemcached) {
|
||||
$this->addMemcachedServers($cache, $servers);
|
||||
} else {
|
||||
$this->addMemcacheServers($cache, $servers);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add servers to the server pool of the cache specified
|
||||
* Used for memcached PECL extension.
|
||||
*
|
||||
* @param \Memcached $cache
|
||||
* @param MemCacheServer[] $servers
|
||||
*/
|
||||
protected function addMemcachedServers($cache, $servers)
|
||||
{
|
||||
$existingServers = [];
|
||||
if ($this->persistentId !== null) {
|
||||
foreach ($cache->getServerList() as $s) {
|
||||
$existingServers[$s['host'] . ':' . $s['port']] = true;
|
||||
}
|
||||
}
|
||||
foreach ($servers as $server) {
|
||||
if (empty($existingServers) || !isset($existingServers[$server->host . ':' . $server->port])) {
|
||||
$cache->addServer($server->host, $server->port, $server->weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add servers to the server pool of the cache specified
|
||||
* Used for memcache PECL extension.
|
||||
*
|
||||
* @param \Memcache $cache
|
||||
* @param MemCacheServer[] $servers
|
||||
*/
|
||||
protected function addMemcacheServers($cache, $servers)
|
||||
{
|
||||
$class = new \ReflectionClass($cache);
|
||||
$paramCount = $class->getMethod('addServer')->getNumberOfParameters();
|
||||
foreach ($servers as $server) {
|
||||
// $timeout is used for memcache versions that do not have $timeoutms parameter
|
||||
$timeout = (int) ($server->timeout / 1000) + (($server->timeout % 1000 > 0) ? 1 : 0);
|
||||
if ($paramCount === 9) {
|
||||
$cache->addserver(
|
||||
$server->host,
|
||||
$server->port,
|
||||
$server->persistent,
|
||||
$server->weight,
|
||||
$timeout,
|
||||
$server->retryInterval,
|
||||
$server->status,
|
||||
$server->failureCallback,
|
||||
$server->timeout
|
||||
);
|
||||
} else {
|
||||
$cache->addserver(
|
||||
$server->host,
|
||||
$server->port,
|
||||
$server->persistent,
|
||||
$server->weight,
|
||||
$timeout,
|
||||
$server->retryInterval,
|
||||
$server->status,
|
||||
$server->failureCallback
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying memcache (or memcached) object.
|
||||
* @return \Memcache|\Memcached the memcache (or memcached) object used by this cache component.
|
||||
* @throws InvalidConfigException if memcache or memcached extension is not loaded
|
||||
*/
|
||||
public function getMemcache()
|
||||
{
|
||||
if ($this->_cache === null) {
|
||||
$extension = $this->useMemcached ? 'memcached' : 'memcache';
|
||||
if (!extension_loaded($extension)) {
|
||||
throw new InvalidConfigException("MemCache requires PHP $extension extension to be loaded.");
|
||||
}
|
||||
|
||||
if ($this->useMemcached) {
|
||||
$this->_cache = $this->persistentId !== null ? new \Memcached($this->persistentId) : new \Memcached();
|
||||
if ($this->username !== null || $this->password !== null) {
|
||||
$this->_cache->setOption(\Memcached::OPT_BINARY_PROTOCOL, true);
|
||||
$this->_cache->setSaslAuthData($this->username, $this->password);
|
||||
}
|
||||
if (!empty($this->options)) {
|
||||
$this->_cache->setOptions($this->options);
|
||||
}
|
||||
} else {
|
||||
$this->_cache = new \Memcache();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the memcache or memcached server configurations.
|
||||
* @return MemCacheServer[] list of memcache server configurations.
|
||||
*/
|
||||
public function getServers()
|
||||
{
|
||||
return $this->_servers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $config list of memcache or memcached server configurations. Each element must be an array
|
||||
* with the following keys: host, port, persistent, weight, timeout, retryInterval, status.
|
||||
* @see http://php.net/manual/en/memcache.addserver.php
|
||||
* @see http://php.net/manual/en/memcached.addserver.php
|
||||
*/
|
||||
public function setServers($config)
|
||||
{
|
||||
foreach ($config as $c) {
|
||||
$this->_servers[] = new MemCacheServer($c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a value from cache with a specified key.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
* @param string $key a unique key identifying the cached value
|
||||
* @return mixed|false the value stored in cache, false if the value is not in the cache or expired.
|
||||
*/
|
||||
protected function getValue($key)
|
||||
{
|
||||
return $this->_cache->get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves multiple values from cache with the specified keys.
|
||||
* @param array $keys a list of keys identifying the cached values
|
||||
* @return array a list of cached values indexed by the keys
|
||||
*/
|
||||
protected function getValues($keys)
|
||||
{
|
||||
return $this->useMemcached ? $this->_cache->getMulti($keys) : $this->_cache->get($keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a value identified by a key in cache.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
*
|
||||
* @param string $key the key identifying the value to be cached
|
||||
* @param mixed $value the value to be cached.
|
||||
* @see [Memcache::set()](http://php.net/manual/en/memcache.set.php)
|
||||
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
|
||||
* @return bool true if the value is successfully stored into cache, false otherwise
|
||||
*/
|
||||
protected function setValue($key, $value, $duration)
|
||||
{
|
||||
// Use UNIX timestamp since it doesn't have any limitation
|
||||
// @see http://php.net/manual/en/memcache.set.php
|
||||
// @see http://php.net/manual/en/memcached.expiration.php
|
||||
$expire = $duration > 0 ? $duration + time() : 0;
|
||||
|
||||
return $this->useMemcached ? $this->_cache->set($key, $value, $expire) : $this->_cache->set($key, $value, 0, $expire);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores multiple key-value pairs in cache.
|
||||
* @param array $data array where key corresponds to cache key while value is the value stored
|
||||
* @param int $duration the number of seconds in which the cached values will expire. 0 means never expire.
|
||||
* @return array array of failed keys.
|
||||
*/
|
||||
protected function setValues($data, $duration)
|
||||
{
|
||||
if ($this->useMemcached) {
|
||||
// Use UNIX timestamp since it doesn't have any limitation
|
||||
// @see http://php.net/manual/en/memcache.set.php
|
||||
// @see http://php.net/manual/en/memcached.expiration.php
|
||||
$expire = $duration > 0 ? $duration + time() : 0;
|
||||
|
||||
// Memcached::setMulti() returns boolean
|
||||
// @see http://php.net/manual/en/memcached.setmulti.php
|
||||
return $this->_cache->setMulti($data, $expire) ? [] : array_keys($data);
|
||||
}
|
||||
|
||||
return parent::setValues($data, $duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a value identified by a key into cache if the cache does not contain this key.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
*
|
||||
* @param string $key the key identifying the value to be cached
|
||||
* @param mixed $value the value to be cached
|
||||
* @see [Memcache::set()](http://php.net/manual/en/memcache.set.php)
|
||||
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
|
||||
* @return bool true if the value is successfully stored into cache, false otherwise
|
||||
*/
|
||||
protected function addValue($key, $value, $duration)
|
||||
{
|
||||
// Use UNIX timestamp since it doesn't have any limitation
|
||||
// @see http://php.net/manual/en/memcache.set.php
|
||||
// @see http://php.net/manual/en/memcached.expiration.php
|
||||
$expire = $duration > 0 ? $duration + time() : 0;
|
||||
|
||||
return $this->useMemcached ? $this->_cache->add($key, $value, $expire) : $this->_cache->add($key, $value, 0, $expire);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a value with the specified key from cache
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
* @param string $key the key of the value to be deleted
|
||||
* @return bool if no error happens during deletion
|
||||
*/
|
||||
protected function deleteValue($key)
|
||||
{
|
||||
return $this->_cache->delete($key, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all values from cache.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
* @return bool whether the flush operation was successful.
|
||||
*/
|
||||
protected function flushValues()
|
||||
{
|
||||
return $this->_cache->flush();
|
||||
}
|
||||
}
|
||||
60
vendor/yiisoft/yii2/caching/MemCacheServer.php
vendored
Normal file
60
vendor/yiisoft/yii2/caching/MemCacheServer.php
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\caching;
|
||||
|
||||
/**
|
||||
* MemCacheServer represents the configuration data for a single memcache or memcached server.
|
||||
*
|
||||
* See [PHP manual](http://php.net/manual/en/memcache.addserver.php) for detailed explanation
|
||||
* of each configuration property.
|
||||
*
|
||||
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class MemCacheServer extends \yii\base\BaseObject
|
||||
{
|
||||
/**
|
||||
* @var string memcache server hostname or IP address
|
||||
*/
|
||||
public $host;
|
||||
/**
|
||||
* @var int memcache server port
|
||||
*/
|
||||
public $port = 11211;
|
||||
/**
|
||||
* @var int probability of using this server among all servers.
|
||||
*/
|
||||
public $weight = 1;
|
||||
/**
|
||||
* @var bool whether to use a persistent connection. This is used by memcache only.
|
||||
*/
|
||||
public $persistent = true;
|
||||
/**
|
||||
* @var int timeout in milliseconds which will be used for connecting to the server.
|
||||
* This is used by memcache only. For old versions of memcache that only support specifying
|
||||
* timeout in seconds this will be rounded up to full seconds.
|
||||
*/
|
||||
public $timeout = 1000;
|
||||
/**
|
||||
* @var int how often a failed server will be retried (in seconds). This is used by memcache only.
|
||||
*/
|
||||
public $retryInterval = 15;
|
||||
/**
|
||||
* @var bool if the server should be flagged as online upon a failure. This is used by memcache only.
|
||||
*/
|
||||
public $status = true;
|
||||
/**
|
||||
* @var \Closure this callback function will run upon encountering an error.
|
||||
* The callback is run before fail over is attempted. The function takes two parameters,
|
||||
* the [[host]] and the [[port]] of the failed server.
|
||||
* This is used by memcache only.
|
||||
*/
|
||||
public $failureCallback;
|
||||
}
|
||||
119
vendor/yiisoft/yii2/caching/TagDependency.php
vendored
Normal file
119
vendor/yiisoft/yii2/caching/TagDependency.php
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\caching;
|
||||
|
||||
/**
|
||||
* TagDependency associates a cached data item with one or multiple [[tags]].
|
||||
*
|
||||
* By calling [[invalidate()]], you can invalidate all cached data items that are associated with the specified tag name(s).
|
||||
*
|
||||
* ```php
|
||||
* // setting multiple cache keys to store data forever and tagging them with "user-123"
|
||||
* Yii::$app->cache->set('user_42_profile', '', 0, new TagDependency(['tags' => 'user-123']));
|
||||
* Yii::$app->cache->set('user_42_stats', '', 0, new TagDependency(['tags' => 'user-123']));
|
||||
*
|
||||
* // invalidating all keys tagged with "user-123"
|
||||
* TagDependency::invalidate(Yii::$app->cache, 'user-123');
|
||||
* ```
|
||||
*
|
||||
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class TagDependency extends Dependency
|
||||
{
|
||||
/**
|
||||
* @var string|array a list of tag names for this dependency. For a single tag, you may specify it as a string.
|
||||
*/
|
||||
public $tags = [];
|
||||
|
||||
|
||||
/**
|
||||
* Generates the data needed to determine if dependency has been changed.
|
||||
* This method does nothing in this class.
|
||||
* @param CacheInterface $cache the cache component that is currently evaluating this dependency
|
||||
* @return mixed the data needed to determine if dependency has been changed.
|
||||
*/
|
||||
protected function generateDependencyData($cache)
|
||||
{
|
||||
$timestamps = $this->getTimestamps($cache, (array) $this->tags);
|
||||
|
||||
$newKeys = [];
|
||||
foreach ($timestamps as $key => $timestamp) {
|
||||
if ($timestamp === false) {
|
||||
$newKeys[] = $key;
|
||||
}
|
||||
}
|
||||
if (!empty($newKeys)) {
|
||||
$timestamps = array_merge($timestamps, static::touchKeys($cache, $newKeys));
|
||||
}
|
||||
|
||||
return $timestamps;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isChanged($cache)
|
||||
{
|
||||
$timestamps = $this->getTimestamps($cache, (array) $this->tags);
|
||||
return $timestamps !== $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates all of the cached data items that are associated with any of the specified [[tags]].
|
||||
* @param CacheInterface $cache the cache component that caches the data items
|
||||
* @param string|array $tags
|
||||
*/
|
||||
public static function invalidate($cache, $tags)
|
||||
{
|
||||
$keys = [];
|
||||
foreach ((array) $tags as $tag) {
|
||||
$keys[] = $cache->buildKey([__CLASS__, $tag]);
|
||||
}
|
||||
static::touchKeys($cache, $keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the timestamp for the specified cache keys.
|
||||
* @param CacheInterface $cache
|
||||
* @param string[] $keys
|
||||
* @return array the timestamp indexed by cache keys
|
||||
*/
|
||||
protected static function touchKeys($cache, $keys)
|
||||
{
|
||||
$items = [];
|
||||
$time = microtime();
|
||||
foreach ($keys as $key) {
|
||||
$items[$key] = $time;
|
||||
}
|
||||
$cache->multiSet($items);
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the timestamps for the specified tags.
|
||||
* @param CacheInterface $cache
|
||||
* @param string[] $tags
|
||||
* @return array the timestamps indexed by the specified tags.
|
||||
*/
|
||||
protected function getTimestamps($cache, $tags)
|
||||
{
|
||||
if (empty($tags)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$keys = [];
|
||||
foreach ($tags as $tag) {
|
||||
$keys[] = $cache->buildKey([__CLASS__, $tag]);
|
||||
}
|
||||
|
||||
return $cache->multiGet($keys);
|
||||
}
|
||||
}
|
||||
137
vendor/yiisoft/yii2/caching/WinCache.php
vendored
Normal file
137
vendor/yiisoft/yii2/caching/WinCache.php
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\caching;
|
||||
|
||||
/**
|
||||
* WinCache provides Windows Cache caching in terms of an application component.
|
||||
*
|
||||
* To use this application component, the [WinCache PHP extension](http://www.iis.net/expand/wincacheforphp)
|
||||
* must be loaded. Also note that "wincache.ucenabled" should be set to "On" in your php.ini file.
|
||||
*
|
||||
* See [[Cache]] manual for common cache operations that are supported by WinCache.
|
||||
*
|
||||
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class WinCache extends Cache
|
||||
{
|
||||
/**
|
||||
* Checks whether a specified key exists in the cache.
|
||||
* This can be faster than getting the value from the cache if the data is big.
|
||||
* Note that this method does not check whether the dependency associated
|
||||
* with the cached data, if there is any, has changed. So a call to [[get]]
|
||||
* may return false while exists returns true.
|
||||
* @param mixed $key a key identifying the cached value. This can be a simple string or
|
||||
* a complex data structure consisting of factors representing the key.
|
||||
* @return bool true if a value exists in cache, false if the value is not in the cache or expired.
|
||||
*/
|
||||
public function exists($key)
|
||||
{
|
||||
$key = $this->buildKey($key);
|
||||
|
||||
return wincache_ucache_exists($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a value from cache with a specified key.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
* @param string $key a unique key identifying the cached value
|
||||
* @return string|bool the value stored in cache, false if the value is not in the cache or expired.
|
||||
*/
|
||||
protected function getValue($key)
|
||||
{
|
||||
return wincache_ucache_get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves multiple values from cache with the specified keys.
|
||||
* @param array $keys a list of keys identifying the cached values
|
||||
* @return array a list of cached values indexed by the keys
|
||||
*/
|
||||
protected function getValues($keys)
|
||||
{
|
||||
return wincache_ucache_get($keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a value identified by a key in cache.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
*
|
||||
* @param string $key the key identifying the value to be cached
|
||||
* @param mixed $value the value to be cached. Most often it's a string. If you have disabled [[serializer]],
|
||||
* it could be something else.
|
||||
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
|
||||
* @return bool true if the value is successfully stored into cache, false otherwise
|
||||
*/
|
||||
protected function setValue($key, $value, $duration)
|
||||
{
|
||||
return wincache_ucache_set($key, $value, $duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores multiple key-value pairs in cache.
|
||||
* @param array $data array where key corresponds to cache key while value is the value stored
|
||||
* @param int $duration the number of seconds in which the cached values will expire. 0 means never expire.
|
||||
* @return array array of failed keys
|
||||
*/
|
||||
protected function setValues($data, $duration)
|
||||
{
|
||||
return wincache_ucache_set($data, null, $duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a value identified by a key into cache if the cache does not contain this key.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
*
|
||||
* @param string $key the key identifying the value to be cached
|
||||
* @param mixed $value the value to be cached. Most often it's a string. If you have disabled [[serializer]],
|
||||
* it could be something else.
|
||||
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
|
||||
* @return bool true if the value is successfully stored into cache, false otherwise
|
||||
*/
|
||||
protected function addValue($key, $value, $duration)
|
||||
{
|
||||
return wincache_ucache_add($key, $value, $duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds multiple key-value pairs to cache.
|
||||
* The default implementation calls [[addValue()]] multiple times add values one by one. If the underlying cache
|
||||
* storage supports multiadd, this method should be overridden to exploit that feature.
|
||||
* @param array $data array where key corresponds to cache key while value is the value stored
|
||||
* @param int $duration the number of seconds in which the cached values will expire. 0 means never expire.
|
||||
* @return array array of failed keys
|
||||
*/
|
||||
protected function addValues($data, $duration)
|
||||
{
|
||||
return wincache_ucache_add($data, null, $duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a value with the specified key from cache
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
* @param string $key the key of the value to be deleted
|
||||
* @return bool if no error happens during deletion
|
||||
*/
|
||||
protected function deleteValue($key)
|
||||
{
|
||||
return wincache_ucache_delete($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all values from cache.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
* @return bool whether the flush operation was successful.
|
||||
*/
|
||||
protected function flushValues()
|
||||
{
|
||||
return wincache_ucache_clear();
|
||||
}
|
||||
}
|
||||
111
vendor/yiisoft/yii2/caching/XCache.php
vendored
Normal file
111
vendor/yiisoft/yii2/caching/XCache.php
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\caching;
|
||||
|
||||
/**
|
||||
* XCache provides XCache caching in terms of an application component.
|
||||
*
|
||||
* To use this application component, the [XCache PHP extension](http://xcache.lighttpd.net/) must be loaded.
|
||||
* Also note that the [[flush()]] functionality will work correctly only if "xcache.admin.enable_auth"
|
||||
* is set to "Off" in php.ini.
|
||||
*
|
||||
* See [[Cache]] for common cache operations that XCache supports.
|
||||
*
|
||||
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
* @deprecated since 2.0.14. This class will be removed in 2.1.0.
|
||||
*/
|
||||
class XCache extends Cache
|
||||
{
|
||||
/**
|
||||
* Checks whether a specified key exists in the cache.
|
||||
* This can be faster than getting the value from the cache if the data is big.
|
||||
* Note that this method does not check whether the dependency associated
|
||||
* with the cached data, if there is any, has changed. So a call to [[get]]
|
||||
* may return false while exists returns true.
|
||||
* @param mixed $key a key identifying the cached value. This can be a simple string or
|
||||
* a complex data structure consisting of factors representing the key.
|
||||
* @return bool true if a value exists in cache, false if the value is not in the cache or expired.
|
||||
*/
|
||||
public function exists($key)
|
||||
{
|
||||
$key = $this->buildKey($key);
|
||||
|
||||
return xcache_isset($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a value from cache with a specified key.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
* @param string $key a unique key identifying the cached value
|
||||
* @return mixed|false the value stored in cache, false if the value is not in the cache or expired.
|
||||
*/
|
||||
protected function getValue($key)
|
||||
{
|
||||
return xcache_isset($key) ? xcache_get($key) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a value identified by a key in cache.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
*
|
||||
* @param string $key the key identifying the value to be cached
|
||||
* @param mixed $value the value to be cached. Most often it's a string. If you have disabled [[serializer]],
|
||||
* it could be something else.
|
||||
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
|
||||
* @return bool true if the value is successfully stored into cache, false otherwise
|
||||
*/
|
||||
protected function setValue($key, $value, $duration)
|
||||
{
|
||||
return xcache_set($key, $value, $duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a value identified by a key into cache if the cache does not contain this key.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
*
|
||||
* @param string $key the key identifying the value to be cached
|
||||
* @param mixed $value the value to be cached. Most often it's a string. If you have disabled [[serializer]],
|
||||
* it could be something else.
|
||||
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
|
||||
* @return bool true if the value is successfully stored into cache, false otherwise
|
||||
*/
|
||||
protected function addValue($key, $value, $duration)
|
||||
{
|
||||
return !xcache_isset($key) ? $this->setValue($key, $value, $duration) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a value with the specified key from cache
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
* @param string $key the key of the value to be deleted
|
||||
* @return bool if no error happens during deletion
|
||||
*/
|
||||
protected function deleteValue($key)
|
||||
{
|
||||
return xcache_unset($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all values from cache.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
* @return bool whether the flush operation was successful.
|
||||
*/
|
||||
protected function flushValues()
|
||||
{
|
||||
for ($i = 0, $max = xcache_count(XC_TYPE_VAR); $i < $max; $i++) {
|
||||
if (xcache_clear_cache(XC_TYPE_VAR, $i) === false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
89
vendor/yiisoft/yii2/caching/ZendDataCache.php
vendored
Normal file
89
vendor/yiisoft/yii2/caching/ZendDataCache.php
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\caching;
|
||||
|
||||
/**
|
||||
* ZendDataCache provides Zend data caching in terms of an application component.
|
||||
*
|
||||
* To use this application component, the [Zend Data Cache PHP extension](http://www.zend.com/en/products/server/)
|
||||
* must be loaded.
|
||||
*
|
||||
* See [[Cache]] for common cache operations that ZendDataCache supports.
|
||||
*
|
||||
* For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview).
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
* @deprecated since 2.0.14. This class will be removed in 2.1.0.
|
||||
*/
|
||||
class ZendDataCache extends Cache
|
||||
{
|
||||
/**
|
||||
* Retrieves a value from cache with a specified key.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
* @param string $key a unique key identifying the cached value
|
||||
* @return mixed|false the value stored in cache, false if the value is not in the cache or expired.
|
||||
*/
|
||||
protected function getValue($key)
|
||||
{
|
||||
$result = zend_shm_cache_fetch($key);
|
||||
|
||||
return $result === null ? false : $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a value identified by a key in cache.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
*
|
||||
* @param string $key the key identifying the value to be cached
|
||||
* @param mixed $value the value to be cached. Most often it's a string. If you have disabled [[serializer]],
|
||||
* it could be something else.
|
||||
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
|
||||
* @return bool true if the value is successfully stored into cache, false otherwise
|
||||
*/
|
||||
protected function setValue($key, $value, $duration)
|
||||
{
|
||||
return zend_shm_cache_store($key, $value, $duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a value identified by a key into cache if the cache does not contain this key.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
*
|
||||
* @param string $key the key identifying the value to be cached
|
||||
* @param mixed $value the value to be cached. Most often it's a string. If you have disabled [[serializer]],
|
||||
* it could be something else.
|
||||
* @param int $duration the number of seconds in which the cached value will expire. 0 means never expire.
|
||||
* @return bool true if the value is successfully stored into cache, false otherwise
|
||||
*/
|
||||
protected function addValue($key, $value, $duration)
|
||||
{
|
||||
return zend_shm_cache_fetch($key) === null ? $this->setValue($key, $value, $duration) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a value with the specified key from cache
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
* @param string $key the key of the value to be deleted
|
||||
* @return bool if no error happens during deletion
|
||||
*/
|
||||
protected function deleteValue($key)
|
||||
{
|
||||
return zend_shm_cache_delete($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all values from cache.
|
||||
* This is the implementation of the method declared in the parent class.
|
||||
* @return bool whether the flush operation was successful.
|
||||
*/
|
||||
protected function flushValues()
|
||||
{
|
||||
return zend_shm_cache_clear();
|
||||
}
|
||||
}
|
||||
66
vendor/yiisoft/yii2/caching/migrations/m150909_153426_cache_init.php
vendored
Normal file
66
vendor/yiisoft/yii2/caching/migrations/m150909_153426_cache_init.php
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
use yii\base\InvalidConfigException;
|
||||
use yii\caching\DbCache;
|
||||
use yii\db\Migration;
|
||||
|
||||
/**
|
||||
* Initializes Cache tables.
|
||||
*
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @since 2.0.7
|
||||
*/
|
||||
class m150909_153426_cache_init extends Migration
|
||||
{
|
||||
/**
|
||||
* @throws yii\base\InvalidConfigException
|
||||
* @return DbCache
|
||||
*/
|
||||
protected function getCache()
|
||||
{
|
||||
$cache = Yii::$app->getCache();
|
||||
if (!$cache instanceof DbCache) {
|
||||
throw new InvalidConfigException('You should configure "cache" component to use database before executing this migration.');
|
||||
}
|
||||
|
||||
return $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
$cache = $this->getCache();
|
||||
$this->db = $cache->db;
|
||||
|
||||
$tableOptions = null;
|
||||
if ($this->db->driverName === 'mysql') {
|
||||
// http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci
|
||||
$tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
|
||||
}
|
||||
|
||||
$this->createTable($cache->cacheTable, [
|
||||
'id' => $this->string(128)->notNull(),
|
||||
'expire' => $this->integer(),
|
||||
'data' => $this->binary(),
|
||||
'PRIMARY KEY ([[id]])',
|
||||
], $tableOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
$cache = $this->getCache();
|
||||
$this->db = $cache->db;
|
||||
|
||||
$this->dropTable($cache->cacheTable);
|
||||
}
|
||||
}
|
||||
22
vendor/yiisoft/yii2/caching/migrations/schema-mssql.sql
vendored
Normal file
22
vendor/yiisoft/yii2/caching/migrations/schema-mssql.sql
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Database schema required by \yii\caching\DbCache.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
* @since 2.0.7
|
||||
*/
|
||||
if object_id('[cache]', 'U') is not null
|
||||
drop table [cache];
|
||||
|
||||
drop table if exists [cache];
|
||||
|
||||
create table [cache]
|
||||
(
|
||||
[id] varchar(128) not null,
|
||||
[expire] integer,
|
||||
[data] BLOB,
|
||||
primary key ([id])
|
||||
);
|
||||
20
vendor/yiisoft/yii2/caching/migrations/schema-mysql.sql
vendored
Normal file
20
vendor/yiisoft/yii2/caching/migrations/schema-mysql.sql
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Database schema required by \yii\caching\DbCache.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
* @since 2.0.7
|
||||
*/
|
||||
|
||||
drop table if exists `cache`;
|
||||
|
||||
create table `cache`
|
||||
(
|
||||
`id` varchar(128) not null,
|
||||
`expire` integer,
|
||||
`data` LONGBLOB,
|
||||
primary key (`id`)
|
||||
) engine InnoDB;
|
||||
20
vendor/yiisoft/yii2/caching/migrations/schema-oci.sql
vendored
Normal file
20
vendor/yiisoft/yii2/caching/migrations/schema-oci.sql
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Database schema required by \yii\caching\DbCache.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
* @since 2.0.7
|
||||
*/
|
||||
|
||||
drop table if exists "cache";
|
||||
|
||||
create table "cache"
|
||||
(
|
||||
"id" varchar(128) not null,
|
||||
"expire" integer,
|
||||
"data" BYTEA,
|
||||
primary key ("id")
|
||||
);
|
||||
20
vendor/yiisoft/yii2/caching/migrations/schema-pgsql.sql
vendored
Normal file
20
vendor/yiisoft/yii2/caching/migrations/schema-pgsql.sql
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Database schema required by \yii\caching\DbCache.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
* @since 2.0.7
|
||||
*/
|
||||
|
||||
drop table if exists "cache";
|
||||
|
||||
create table "cache"
|
||||
(
|
||||
"id" varchar(128) not null,
|
||||
"expire" integer,
|
||||
"data" bytea,
|
||||
primary key ("id")
|
||||
);
|
||||
20
vendor/yiisoft/yii2/caching/migrations/schema-sqlite.sql
vendored
Normal file
20
vendor/yiisoft/yii2/caching/migrations/schema-sqlite.sql
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Database schema required by \yii\caching\DbCache.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
* @since 2.0.7
|
||||
*/
|
||||
|
||||
drop table if exists "cache";
|
||||
|
||||
create table "cache"
|
||||
(
|
||||
"id" varchar(128) not null,
|
||||
"expire" integer,
|
||||
"data" BLOB,
|
||||
primary key ("id")
|
||||
);
|
||||
177
vendor/yiisoft/yii2/captcha/Captcha.php
vendored
Normal file
177
vendor/yiisoft/yii2/captcha/Captcha.php
vendored
Normal file
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\captcha;
|
||||
|
||||
use Yii;
|
||||
use yii\base\InvalidConfigException;
|
||||
use yii\helpers\Html;
|
||||
use yii\helpers\Json;
|
||||
use yii\helpers\Url;
|
||||
use yii\widgets\InputWidget;
|
||||
|
||||
/**
|
||||
* Captcha renders a CAPTCHA image and an input field that takes user-entered verification code.
|
||||
*
|
||||
* Captcha is used together with [[CaptchaAction]] to provide [CAPTCHA](http://en.wikipedia.org/wiki/Captcha) - a way
|
||||
* of preventing website spamming.
|
||||
*
|
||||
* The image element rendered by Captcha will display a CAPTCHA image generated by
|
||||
* an action whose route is specified by [[captchaAction]]. This action must be an instance of [[CaptchaAction]].
|
||||
*
|
||||
* When the user clicks on the CAPTCHA image, it will cause the CAPTCHA image
|
||||
* to be refreshed with a new CAPTCHA.
|
||||
*
|
||||
* You may use [[\yii\captcha\CaptchaValidator]] to validate the user input matches
|
||||
* the current CAPTCHA verification code.
|
||||
*
|
||||
* The following example shows how to use this widget with a model attribute:
|
||||
*
|
||||
* ```php
|
||||
* echo Captcha::widget([
|
||||
* 'model' => $model,
|
||||
* 'attribute' => 'captcha',
|
||||
* ]);
|
||||
* ```
|
||||
*
|
||||
* The following example will use the name property instead:
|
||||
*
|
||||
* ```php
|
||||
* echo Captcha::widget([
|
||||
* 'name' => 'captcha',
|
||||
* ]);
|
||||
* ```
|
||||
*
|
||||
* You can also use this widget in an [[\yii\widgets\ActiveForm|ActiveForm]] using the [[\yii\widgets\ActiveField::widget()|widget()]]
|
||||
* method, for example like this:
|
||||
*
|
||||
* ```php
|
||||
* <?= $form->field($model, 'captcha')->widget(\yii\captcha\Captcha::classname(), [
|
||||
* // configure additional widget properties here
|
||||
* ]) ?>
|
||||
* ```
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class Captcha extends InputWidget
|
||||
{
|
||||
/**
|
||||
* @var string|array the route of the action that generates the CAPTCHA images.
|
||||
* The action represented by this route must be an action of [[CaptchaAction]].
|
||||
* Please refer to [[\yii\helpers\Url::toRoute()]] for acceptable formats.
|
||||
*/
|
||||
public $captchaAction = 'site/captcha';
|
||||
/**
|
||||
* @var array HTML attributes to be applied to the CAPTCHA image tag.
|
||||
* @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
|
||||
*/
|
||||
public $imageOptions = [];
|
||||
/**
|
||||
* @var string the template for arranging the CAPTCHA image tag and the text input tag.
|
||||
* In this template, the token `{image}` will be replaced with the actual image tag,
|
||||
* while `{input}` will be replaced with the text input tag.
|
||||
*/
|
||||
public $template = '{image} {input}';
|
||||
/**
|
||||
* @var array the HTML attributes for the input tag.
|
||||
* @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
|
||||
*/
|
||||
public $options = ['class' => 'form-control'];
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the widget.
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
|
||||
static::checkRequirements();
|
||||
|
||||
if (!isset($this->imageOptions['id'])) {
|
||||
$this->imageOptions['id'] = $this->options['id'] . '-image';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the widget.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$this->registerClientScript();
|
||||
$input = $this->renderInputHtml('text');
|
||||
$route = $this->captchaAction;
|
||||
if (is_array($route)) {
|
||||
$route['v'] = uniqid('', true);
|
||||
} else {
|
||||
$route = [$route, 'v' => uniqid('', true)];
|
||||
}
|
||||
$image = Html::img($route, $this->imageOptions);
|
||||
echo strtr($this->template, [
|
||||
'{input}' => $input,
|
||||
'{image}' => $image,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the needed JavaScript.
|
||||
*/
|
||||
public function registerClientScript()
|
||||
{
|
||||
$options = $this->getClientOptions();
|
||||
$options = empty($options) ? '' : Json::htmlEncode($options);
|
||||
$id = $this->imageOptions['id'];
|
||||
$view = $this->getView();
|
||||
CaptchaAsset::register($view);
|
||||
$view->registerJs("jQuery('#$id').yiiCaptcha($options);");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the options for the captcha JS widget.
|
||||
* @return array the options
|
||||
*/
|
||||
protected function getClientOptions()
|
||||
{
|
||||
$route = $this->captchaAction;
|
||||
if (is_array($route)) {
|
||||
$route[CaptchaAction::REFRESH_GET_VAR] = 1;
|
||||
} else {
|
||||
$route = [$route, CaptchaAction::REFRESH_GET_VAR => 1];
|
||||
}
|
||||
|
||||
$options = [
|
||||
'refreshUrl' => Url::toRoute($route),
|
||||
'hashKey' => 'yiiCaptcha/' . trim($route[0], '/'),
|
||||
];
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there is graphic extension available to generate CAPTCHA images.
|
||||
* This method will check the existence of ImageMagick and GD extensions.
|
||||
* @return string the name of the graphic extension, either "imagick" or "gd".
|
||||
* @throws InvalidConfigException if neither ImageMagick nor GD is installed.
|
||||
*/
|
||||
public static function checkRequirements()
|
||||
{
|
||||
if (extension_loaded('imagick')) {
|
||||
$imagickFormats = (new \Imagick())->queryFormats('PNG');
|
||||
if (in_array('PNG', $imagickFormats, true)) {
|
||||
return 'imagick';
|
||||
}
|
||||
}
|
||||
if (extension_loaded('gd')) {
|
||||
$gdInfo = gd_info();
|
||||
if (!empty($gdInfo['FreeType Support'])) {
|
||||
return 'gd';
|
||||
}
|
||||
}
|
||||
throw new InvalidConfigException('Either GD PHP extension with FreeType support or ImageMagick PHP extension with PNG support is required.');
|
||||
}
|
||||
}
|
||||
367
vendor/yiisoft/yii2/captcha/CaptchaAction.php
vendored
Normal file
367
vendor/yiisoft/yii2/captcha/CaptchaAction.php
vendored
Normal file
@@ -0,0 +1,367 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\captcha;
|
||||
|
||||
use Yii;
|
||||
use yii\base\Action;
|
||||
use yii\base\InvalidConfigException;
|
||||
use yii\helpers\Url;
|
||||
use yii\web\Response;
|
||||
|
||||
/**
|
||||
* CaptchaAction renders a CAPTCHA image.
|
||||
*
|
||||
* CaptchaAction is used together with [[Captcha]] and [[\yii\captcha\CaptchaValidator]]
|
||||
* to provide the [CAPTCHA](http://en.wikipedia.org/wiki/Captcha) feature.
|
||||
*
|
||||
* By configuring the properties of CaptchaAction, you may customize the appearance of
|
||||
* the generated CAPTCHA images, such as the font color, the background color, etc.
|
||||
*
|
||||
* Note that CaptchaAction requires either GD2 extension or ImageMagick PHP extension.
|
||||
*
|
||||
* Using CAPTCHA involves the following steps:
|
||||
*
|
||||
* 1. Override [[\yii\web\Controller::actions()]] and register an action of class CaptchaAction with ID 'captcha'
|
||||
* 2. In the form model, declare an attribute to store user-entered verification code, and declare the attribute
|
||||
* to be validated by the 'captcha' validator.
|
||||
* 3. In the controller view, insert a [[Captcha]] widget in the form.
|
||||
*
|
||||
* @property string $verifyCode The verification code. This property is read-only.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class CaptchaAction extends Action
|
||||
{
|
||||
/**
|
||||
* The name of the GET parameter indicating whether the CAPTCHA image should be regenerated.
|
||||
*/
|
||||
const REFRESH_GET_VAR = 'refresh';
|
||||
|
||||
/**
|
||||
* @var int how many times should the same CAPTCHA be displayed. Defaults to 3.
|
||||
* A value less than or equal to 0 means the test is unlimited (available since version 1.1.2).
|
||||
*/
|
||||
public $testLimit = 3;
|
||||
/**
|
||||
* @var int the width of the generated CAPTCHA image. Defaults to 120.
|
||||
*/
|
||||
public $width = 120;
|
||||
/**
|
||||
* @var int the height of the generated CAPTCHA image. Defaults to 50.
|
||||
*/
|
||||
public $height = 50;
|
||||
/**
|
||||
* @var int padding around the text. Defaults to 2.
|
||||
*/
|
||||
public $padding = 2;
|
||||
/**
|
||||
* @var int the background color. For example, 0x55FF00.
|
||||
* Defaults to 0xFFFFFF, meaning white color.
|
||||
*/
|
||||
public $backColor = 0xFFFFFF;
|
||||
/**
|
||||
* @var int the font color. For example, 0x55FF00. Defaults to 0x2040A0 (blue color).
|
||||
*/
|
||||
public $foreColor = 0x2040A0;
|
||||
/**
|
||||
* @var bool whether to use transparent background. Defaults to false.
|
||||
*/
|
||||
public $transparent = false;
|
||||
/**
|
||||
* @var int the minimum length for randomly generated word. Defaults to 6.
|
||||
*/
|
||||
public $minLength = 6;
|
||||
/**
|
||||
* @var int the maximum length for randomly generated word. Defaults to 7.
|
||||
*/
|
||||
public $maxLength = 7;
|
||||
/**
|
||||
* @var int the offset between characters. Defaults to -2. You can adjust this property
|
||||
* in order to decrease or increase the readability of the captcha.
|
||||
*/
|
||||
public $offset = -2;
|
||||
/**
|
||||
* @var string the TrueType font file. This can be either a file path or [path alias](guide:concept-aliases).
|
||||
*/
|
||||
public $fontFile = '@yii/captcha/SpicyRice.ttf';
|
||||
/**
|
||||
* @var string the fixed verification code. When this property is set,
|
||||
* [[getVerifyCode()]] will always return the value of this property.
|
||||
* This is mainly used in automated tests where we want to be able to reproduce
|
||||
* the same verification code each time we run the tests.
|
||||
* If not set, it means the verification code will be randomly generated.
|
||||
*/
|
||||
public $fixedVerifyCode;
|
||||
/**
|
||||
* @var string the rendering library to use. Currently supported only 'gd' and 'imagick'.
|
||||
* If not set, library will be determined automatically.
|
||||
* @since 2.0.7
|
||||
*/
|
||||
public $imageLibrary;
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the action.
|
||||
* @throws InvalidConfigException if the font file does not exist.
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->fontFile = Yii::getAlias($this->fontFile);
|
||||
if (!is_file($this->fontFile)) {
|
||||
throw new InvalidConfigException("The font file does not exist: {$this->fontFile}");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the action.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
if (Yii::$app->request->getQueryParam(self::REFRESH_GET_VAR) !== null) {
|
||||
// AJAX request for regenerating code
|
||||
$code = $this->getVerifyCode(true);
|
||||
Yii::$app->response->format = Response::FORMAT_JSON;
|
||||
return [
|
||||
'hash1' => $this->generateValidationHash($code),
|
||||
'hash2' => $this->generateValidationHash(strtolower($code)),
|
||||
// we add a random 'v' parameter so that FireFox can refresh the image
|
||||
// when src attribute of image tag is changed
|
||||
'url' => Url::to([$this->id, 'v' => uniqid('', true)]),
|
||||
];
|
||||
}
|
||||
|
||||
$this->setHttpHeaders();
|
||||
Yii::$app->response->format = Response::FORMAT_RAW;
|
||||
|
||||
return $this->renderImage($this->getVerifyCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a hash code that can be used for client-side validation.
|
||||
* @param string $code the CAPTCHA code
|
||||
* @return string a hash code generated from the CAPTCHA code
|
||||
*/
|
||||
public function generateValidationHash($code)
|
||||
{
|
||||
for ($h = 0, $i = strlen($code) - 1; $i >= 0; --$i) {
|
||||
$h += ord($code[$i]);
|
||||
}
|
||||
|
||||
return $h;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the verification code.
|
||||
* @param bool $regenerate whether the verification code should be regenerated.
|
||||
* @return string the verification code.
|
||||
*/
|
||||
public function getVerifyCode($regenerate = false)
|
||||
{
|
||||
if ($this->fixedVerifyCode !== null) {
|
||||
return $this->fixedVerifyCode;
|
||||
}
|
||||
|
||||
$session = Yii::$app->getSession();
|
||||
$session->open();
|
||||
$name = $this->getSessionKey();
|
||||
if ($session[$name] === null || $regenerate) {
|
||||
$session[$name] = $this->generateVerifyCode();
|
||||
$session[$name . 'count'] = 1;
|
||||
}
|
||||
|
||||
return $session[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the input to see if it matches the generated code.
|
||||
* @param string $input user input
|
||||
* @param bool $caseSensitive whether the comparison should be case-sensitive
|
||||
* @return bool whether the input is valid
|
||||
*/
|
||||
public function validate($input, $caseSensitive)
|
||||
{
|
||||
$code = $this->getVerifyCode();
|
||||
$valid = $caseSensitive ? ($input === $code) : strcasecmp($input, $code) === 0;
|
||||
$session = Yii::$app->getSession();
|
||||
$session->open();
|
||||
$name = $this->getSessionKey() . 'count';
|
||||
$session[$name] += 1;
|
||||
if ($valid || $session[$name] > $this->testLimit && $this->testLimit > 0) {
|
||||
$this->getVerifyCode(true);
|
||||
}
|
||||
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new verification code.
|
||||
* @return string the generated verification code
|
||||
*/
|
||||
protected function generateVerifyCode()
|
||||
{
|
||||
if ($this->minLength > $this->maxLength) {
|
||||
$this->maxLength = $this->minLength;
|
||||
}
|
||||
if ($this->minLength < 3) {
|
||||
$this->minLength = 3;
|
||||
}
|
||||
if ($this->maxLength > 20) {
|
||||
$this->maxLength = 20;
|
||||
}
|
||||
$length = mt_rand($this->minLength, $this->maxLength);
|
||||
|
||||
$letters = 'bcdfghjklmnpqrstvwxyz';
|
||||
$vowels = 'aeiou';
|
||||
$code = '';
|
||||
for ($i = 0; $i < $length; ++$i) {
|
||||
if ($i % 2 && mt_rand(0, 10) > 2 || !($i % 2) && mt_rand(0, 10) > 9) {
|
||||
$code .= $vowels[mt_rand(0, 4)];
|
||||
} else {
|
||||
$code .= $letters[mt_rand(0, 20)];
|
||||
}
|
||||
}
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the session variable name used to store verification code.
|
||||
* @return string the session variable name
|
||||
*/
|
||||
protected function getSessionKey()
|
||||
{
|
||||
return '__captcha/' . $this->getUniqueId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the CAPTCHA image.
|
||||
* @param string $code the verification code
|
||||
* @return string image contents
|
||||
* @throws InvalidConfigException if imageLibrary is not supported
|
||||
*/
|
||||
protected function renderImage($code)
|
||||
{
|
||||
if (isset($this->imageLibrary)) {
|
||||
$imageLibrary = $this->imageLibrary;
|
||||
} else {
|
||||
$imageLibrary = Captcha::checkRequirements();
|
||||
}
|
||||
if ($imageLibrary === 'gd') {
|
||||
return $this->renderImageByGD($code);
|
||||
} elseif ($imageLibrary === 'imagick') {
|
||||
return $this->renderImageByImagick($code);
|
||||
}
|
||||
|
||||
throw new InvalidConfigException("Defined library '{$imageLibrary}' is not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the CAPTCHA image based on the code using GD library.
|
||||
* @param string $code the verification code
|
||||
* @return string image contents in PNG format.
|
||||
*/
|
||||
protected function renderImageByGD($code)
|
||||
{
|
||||
$image = imagecreatetruecolor($this->width, $this->height);
|
||||
|
||||
$backColor = imagecolorallocate(
|
||||
$image,
|
||||
(int) ($this->backColor % 0x1000000 / 0x10000),
|
||||
(int) ($this->backColor % 0x10000 / 0x100),
|
||||
$this->backColor % 0x100
|
||||
);
|
||||
imagefilledrectangle($image, 0, 0, $this->width - 1, $this->height - 1, $backColor);
|
||||
imagecolordeallocate($image, $backColor);
|
||||
|
||||
if ($this->transparent) {
|
||||
imagecolortransparent($image, $backColor);
|
||||
}
|
||||
|
||||
$foreColor = imagecolorallocate(
|
||||
$image,
|
||||
(int) ($this->foreColor % 0x1000000 / 0x10000),
|
||||
(int) ($this->foreColor % 0x10000 / 0x100),
|
||||
$this->foreColor % 0x100
|
||||
);
|
||||
|
||||
$length = strlen($code);
|
||||
$box = imagettfbbox(30, 0, $this->fontFile, $code);
|
||||
$w = $box[4] - $box[0] + $this->offset * ($length - 1);
|
||||
$h = $box[1] - $box[5];
|
||||
$scale = min(($this->width - $this->padding * 2) / $w, ($this->height - $this->padding * 2) / $h);
|
||||
$x = 10;
|
||||
$y = round($this->height * 27 / 40);
|
||||
for ($i = 0; $i < $length; ++$i) {
|
||||
$fontSize = (int) (mt_rand(26, 32) * $scale * 0.8);
|
||||
$angle = mt_rand(-10, 10);
|
||||
$letter = $code[$i];
|
||||
$box = imagettftext($image, $fontSize, $angle, $x, $y, $foreColor, $this->fontFile, $letter);
|
||||
$x = $box[2] + $this->offset;
|
||||
}
|
||||
|
||||
imagecolordeallocate($image, $foreColor);
|
||||
|
||||
ob_start();
|
||||
imagepng($image);
|
||||
imagedestroy($image);
|
||||
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the CAPTCHA image based on the code using ImageMagick library.
|
||||
* @param string $code the verification code
|
||||
* @return string image contents in PNG format.
|
||||
*/
|
||||
protected function renderImageByImagick($code)
|
||||
{
|
||||
$backColor = $this->transparent ? new \ImagickPixel('transparent') : new \ImagickPixel('#' . str_pad(dechex($this->backColor), 6, 0, STR_PAD_LEFT));
|
||||
$foreColor = new \ImagickPixel('#' . str_pad(dechex($this->foreColor), 6, 0, STR_PAD_LEFT));
|
||||
|
||||
$image = new \Imagick();
|
||||
$image->newImage($this->width, $this->height, $backColor);
|
||||
|
||||
$draw = new \ImagickDraw();
|
||||
$draw->setFont($this->fontFile);
|
||||
$draw->setFontSize(30);
|
||||
$fontMetrics = $image->queryFontMetrics($draw, $code);
|
||||
|
||||
$length = strlen($code);
|
||||
$w = (int) $fontMetrics['textWidth'] - 8 + $this->offset * ($length - 1);
|
||||
$h = (int) $fontMetrics['textHeight'] - 8;
|
||||
$scale = min(($this->width - $this->padding * 2) / $w, ($this->height - $this->padding * 2) / $h);
|
||||
$x = 10;
|
||||
$y = round($this->height * 27 / 40);
|
||||
for ($i = 0; $i < $length; ++$i) {
|
||||
$draw = new \ImagickDraw();
|
||||
$draw->setFont($this->fontFile);
|
||||
$draw->setFontSize((int) (mt_rand(26, 32) * $scale * 0.8));
|
||||
$draw->setFillColor($foreColor);
|
||||
$image->annotateImage($draw, $x, $y, mt_rand(-10, 10), $code[$i]);
|
||||
$fontMetrics = $image->queryFontMetrics($draw, $code[$i]);
|
||||
$x += (int) $fontMetrics['textWidth'] + $this->offset;
|
||||
}
|
||||
|
||||
$image->setImageFormat('png');
|
||||
return $image->getImageBlob();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the HTTP headers needed by image response.
|
||||
*/
|
||||
protected function setHttpHeaders()
|
||||
{
|
||||
Yii::$app->getResponse()->getHeaders()
|
||||
->set('Pragma', 'public')
|
||||
->set('Expires', '0')
|
||||
->set('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
|
||||
->set('Content-Transfer-Encoding', 'binary')
|
||||
->set('Content-type', 'image/png');
|
||||
}
|
||||
}
|
||||
27
vendor/yiisoft/yii2/captcha/CaptchaAsset.php
vendored
Normal file
27
vendor/yiisoft/yii2/captcha/CaptchaAsset.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\captcha;
|
||||
|
||||
use yii\web\AssetBundle;
|
||||
|
||||
/**
|
||||
* This asset bundle provides the javascript files needed for the [[Captcha]] widget.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class CaptchaAsset extends AssetBundle
|
||||
{
|
||||
public $sourcePath = '@yii/assets';
|
||||
public $js = [
|
||||
'yii.captcha.js',
|
||||
];
|
||||
public $depends = [
|
||||
'yii\web\YiiAsset',
|
||||
];
|
||||
}
|
||||
117
vendor/yiisoft/yii2/captcha/CaptchaValidator.php
vendored
Normal file
117
vendor/yiisoft/yii2/captcha/CaptchaValidator.php
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\captcha;
|
||||
|
||||
use Yii;
|
||||
use yii\base\InvalidConfigException;
|
||||
use yii\validators\ValidationAsset;
|
||||
use yii\validators\Validator;
|
||||
|
||||
/**
|
||||
* CaptchaValidator validates that the attribute value is the same as the verification code displayed in the CAPTCHA.
|
||||
*
|
||||
* CaptchaValidator should be used together with [[CaptchaAction]].
|
||||
*
|
||||
* Note that once CAPTCHA validation succeeds, a new CAPTCHA will be generated automatically. As a result,
|
||||
* CAPTCHA validation should not be used in AJAX validation mode because it may fail the validation
|
||||
* even if a user enters the same code as shown in the CAPTCHA image which is actually different from the latest CAPTCHA code.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class CaptchaValidator extends Validator
|
||||
{
|
||||
/**
|
||||
* @var bool whether to skip this validator if the input is empty.
|
||||
*/
|
||||
public $skipOnEmpty = false;
|
||||
/**
|
||||
* @var bool whether the comparison is case sensitive. Defaults to false.
|
||||
*/
|
||||
public $caseSensitive = false;
|
||||
/**
|
||||
* @var string the route of the controller action that renders the CAPTCHA image.
|
||||
*/
|
||||
public $captchaAction = 'site/captcha';
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
if ($this->message === null) {
|
||||
$this->message = Yii::t('yii', 'The verification code is incorrect.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function validateValue($value)
|
||||
{
|
||||
$captcha = $this->createCaptchaAction();
|
||||
$valid = !is_array($value) && $captcha->validate($value, $this->caseSensitive);
|
||||
|
||||
return $valid ? null : [$this->message, []];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the CAPTCHA action object from the route specified by [[captchaAction]].
|
||||
* @return \yii\captcha\CaptchaAction the action object
|
||||
* @throws InvalidConfigException
|
||||
*/
|
||||
public function createCaptchaAction()
|
||||
{
|
||||
$ca = Yii::$app->createController($this->captchaAction);
|
||||
if ($ca !== false) {
|
||||
/* @var $controller \yii\base\Controller */
|
||||
list($controller, $actionID) = $ca;
|
||||
$action = $controller->createAction($actionID);
|
||||
if ($action !== null) {
|
||||
return $action;
|
||||
}
|
||||
}
|
||||
throw new InvalidConfigException('Invalid CAPTCHA action ID: ' . $this->captchaAction);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clientValidateAttribute($model, $attribute, $view)
|
||||
{
|
||||
ValidationAsset::register($view);
|
||||
$options = $this->getClientOptions($model, $attribute);
|
||||
|
||||
return 'yii.validation.captcha(value, messages, ' . json_encode($options, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . ');';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getClientOptions($model, $attribute)
|
||||
{
|
||||
$captcha = $this->createCaptchaAction();
|
||||
$code = $captcha->getVerifyCode(false);
|
||||
$hash = $captcha->generateValidationHash($this->caseSensitive ? $code : strtolower($code));
|
||||
$options = [
|
||||
'hash' => $hash,
|
||||
'hashKey' => 'yiiCaptcha/' . $captcha->getUniqueId(),
|
||||
'caseSensitive' => $this->caseSensitive,
|
||||
'message' => Yii::$app->getI18n()->format($this->message, [
|
||||
'attribute' => $model->getAttributeLabel($attribute),
|
||||
], Yii::$app->language),
|
||||
];
|
||||
if ($this->skipOnEmpty) {
|
||||
$options['skipOnEmpty'] = 1;
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
11
vendor/yiisoft/yii2/captcha/SpicyRice.md
vendored
Normal file
11
vendor/yiisoft/yii2/captcha/SpicyRice.md
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
## Spicy Rice font
|
||||
|
||||
* **Author:** Brian J. Bonislawsky, Astigmatic (AOETI, Astigmatic One Eye Typographic Institute)
|
||||
* **License:** SIL Open Font License (OFL), version 1.1, [notes and FAQ](http://scripts.sil.org/OFL)
|
||||
|
||||
## Links
|
||||
|
||||
* [Astigmatic](http://www.astigmatic.com/)
|
||||
* [Google WebFonts](http://www.google.com/webfonts/specimen/Spicy+Rice)
|
||||
* [fontsquirrel.com](http://www.fontsquirrel.com/fonts/spicy-rice)
|
||||
* [fontspace.com](http://www.fontspace.com/astigmatic-one-eye-typographic-institute/spicy-rice)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user