70 changed files with 2170 additions and 1897 deletions
			
			
		| @ -0,0 +1,22 @@ | ||||
| <?php | ||||
| /** | ||||
|  * @link http://www.yiiframework.com/ | ||||
|  * @copyright Copyright (c) 2008 Yii Software LLC | ||||
|  * @license http://www.yiiframework.com/license/ | ||||
|  */ | ||||
| 
 | ||||
| namespace yii\base; | ||||
| 
 | ||||
| /** | ||||
|  * Jsonable should be implemented by classes that need to be represented in JSON format. | ||||
|  * | ||||
|  * @author Qiang Xue <qiang.xue@gmail.com> | ||||
|  * @since 2.0 | ||||
|  */ | ||||
| interface Jsonable | ||||
| { | ||||
| 	/** | ||||
| 	 * @return string the JSON representation of this object | ||||
| 	 */ | ||||
| 	public function toJson(); | ||||
| } | ||||
									
										
											File diff suppressed because it is too large
											Load Diff
										
									
								
							
						| @ -1,103 +0,0 @@ | ||||
| <?php | ||||
| 
 | ||||
| /** | ||||
|  * @link http://www.yiiframework.com/ | ||||
|  * @copyright Copyright (c) 2008 Yii Software LLC | ||||
|  * @license http://www.yiiframework.com/license/ | ||||
|  */ | ||||
| 
 | ||||
| namespace yii\db\pgsql; | ||||
| 
 | ||||
| /** | ||||
|  * This is an extension of the default PDO class for PostgreSQL drivers. | ||||
|  * It provides additional low level functionality for setting database  | ||||
|  * configuration parameters. | ||||
|  * | ||||
|  * @author Gevik babakhani <gevikb@gmail.com> | ||||
|  * @since 2.0 | ||||
|  */ | ||||
| class PDO extends \PDO | ||||
| { | ||||
| 
 | ||||
| 	const OPT_SEARCH_PATH = 'search_path'; | ||||
| 	const OPT_DEFAULT_SCHEMA = 'default_schema'; | ||||
| 	const DEFAULT_SCHEMA = 'public'; | ||||
| 
 | ||||
| 	private $_currentDatabase; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Returns value of the last inserted ID. | ||||
| 	 * @param string|null $sequence the sequence name. Defaults to null. | ||||
| 	 * @return integer last inserted ID value. | ||||
| 	 */ | ||||
| 	public function lastInsertId($sequence = null) { | ||||
| 		if ($sequence !== null) { | ||||
| 			$sequence = $this->quote($sequence); | ||||
| 			return $this->query("SELECT currval({$sequence})")->fetchColumn(); | ||||
| 		} else { | ||||
| 			return null; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Here we override the default PDO constructor in order to  | ||||
| 	 * find and set the default schema search path. | ||||
| 	 */ | ||||
| 	public function __construct($dsn, $username, $passwd, $options) { | ||||
| 		$searchPath = null; | ||||
| 		if (is_array($options)) { | ||||
| 			if (isset($options[self::OPT_SEARCH_PATH])) { | ||||
| 				$matches = null; | ||||
| 				if (preg_match("/(\s?)+(\w)+((\s+)?,(\s+)?\w+)*/", $options[self::OPT_SEARCH_PATH], $matches) === 1) { | ||||
| 					$searchPath = $matches[0]; | ||||
| 				} | ||||
| 			} | ||||
| 			if (isset($options[self::OPT_DEFAULT_SCHEMA])) { | ||||
| 				$schema = trim($options[self::OPT_DEFAULT_SCHEMA]); | ||||
| 				if (!empty($schema)) { | ||||
| 					Schema::$DEFAULT_SCHEMA = $schema; | ||||
| 				} | ||||
| 			} | ||||
| 			if (is_null(Schema::$DEFAULT_SCHEMA) || empty(Schema::$DEFAULT_SCHEMA)) { | ||||
| 				Schema::$DEFAULT_SCHEMA = self::DEFAULT_SCHEMA; | ||||
| 			} | ||||
| 		} | ||||
| 		parent::__construct($dsn, $username, $passwd, $options); | ||||
| 		if (!is_null($searchPath)) { | ||||
| 			$this->setSchemaSearchPath($searchPath); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Returns the name of the current (connected) database  | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function getCurrentDatabase() { | ||||
| 		if (is_null($this->_currentDatabase)) { | ||||
| 			return $this->query('select current_database()')->fetchColumn(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Sets the schema search path of the current users session. | ||||
| 	 * The syntax of the path is a comma separated string with  | ||||
| 	 * your custom search path at the beginning and the "public" | ||||
| 	 * schema at the end.  | ||||
| 	 *  | ||||
| 	 * This method automatically adds the "public" schema at the  | ||||
| 	 * end of the search path if it is not provied. | ||||
| 	 * @param string custom schema search path. defaults to public | ||||
| 	 */ | ||||
| 	public function setSchemaSearchPath($searchPath = 'public') { | ||||
| 		$schemas = explode(',', str_replace(' ', '', $searchPath)); | ||||
| 		if (end($schemas) !== 'public') { | ||||
| 			$schemas[] = 'public'; | ||||
| 		} | ||||
| 		foreach ($schemas as $k => $item) { | ||||
| 			$schemas[$k] = '"' . str_replace(array('"', "'", ';'), '', $item) . '"'; | ||||
| 		} | ||||
| 		$path = implode(', ', $schemas); | ||||
| 		$this->exec('SET search_path TO ' . $path); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,158 @@ | ||||
| <?php | ||||
| /** | ||||
|  * @link http://www.yiiframework.com/ | ||||
|  * @copyright Copyright (c) 2008 Yii Software LLC | ||||
|  * @license http://www.yiiframework.com/license/ | ||||
|  */ | ||||
| 
 | ||||
| namespace yii\i18n; | ||||
| 
 | ||||
| use Yii; | ||||
| use yii\base\InvalidConfigException; | ||||
| use yii\helpers\ArrayHelper; | ||||
| use yii\caching\Cache; | ||||
| use yii\db\Connection; | ||||
| use yii\db\Query; | ||||
| 
 | ||||
| /** | ||||
|  * DbMessageSource extends [[MessageSource]] and represents a message source that stores translated | ||||
|  * messages in database. | ||||
|  * | ||||
|  * The database must contain the following two tables: | ||||
|  * | ||||
|  * ~~~ | ||||
|  * CREATE TABLE tbl_source_message ( | ||||
|  *     id INTEGER PRIMARY KEY, | ||||
|  *     category VARCHAR(32), | ||||
|  *     message TEXT | ||||
|  * ); | ||||
|  * | ||||
|  * CREATE TABLE tbl_message ( | ||||
|  *     id INTEGER, | ||||
|  *     language VARCHAR(16), | ||||
|  *     translation TEXT, | ||||
|  *     PRIMARY KEY (id, language), | ||||
|  *     CONSTRAINT fk_message_source_message FOREIGN KEY (id) | ||||
|  *         REFERENCES tbl_source_message (id) ON DELETE CASCADE ON UPDATE RESTRICT | ||||
|  * ); | ||||
|  * ~~~ | ||||
|  * | ||||
|  * The `tbl_source_message` table stores the messages to be translated, and the `tbl_message` table stores | ||||
|  * the translated messages. The name of these two tables can be customized by setting [[sourceMessageTable]] | ||||
|  * and [[messageTable]], respectively. | ||||
|  * | ||||
|  * @author resurtm <resurtm@gmail.com> | ||||
|  * @since 2.0 | ||||
|  */ | ||||
| class DbMessageSource extends MessageSource | ||||
| { | ||||
| 	/** | ||||
| 	 * Prefix which would be used when generating cache key. | ||||
| 	 */ | ||||
| 	const CACHE_KEY_PREFIX = 'DbMessageSource'; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @var Connection|string the DB connection object or the application component ID of the DB connection. | ||||
| 	 * After the DbMessageSource object is created, if you want to change this property, you should only assign | ||||
| 	 * it with a DB connection object. | ||||
| 	 */ | ||||
| 	public $db = 'db'; | ||||
| 	/** | ||||
| 	 * @var Cache|string the cache object or the application component ID of the cache object. | ||||
| 	 * The messages data will be cached using this cache object. Note, this property has meaning only | ||||
| 	 * in case [[cachingDuration]] set to non-zero value. | ||||
| 	 * After the DbMessageSource object is created, if you want to change this property, you should only assign | ||||
| 	 * it with a cache object. | ||||
| 	 */ | ||||
| 	public $cache = 'cache'; | ||||
| 	/** | ||||
| 	 * @var string the name of the source message table. | ||||
| 	 */ | ||||
| 	public $sourceMessageTable = 'tbl_source_message'; | ||||
| 	/** | ||||
| 	 * @var string the name of the translated message table. | ||||
| 	 */ | ||||
| 	public $messageTable = 'tbl_message'; | ||||
| 	/** | ||||
| 	 * @var integer the time in seconds that the messages can remain valid in cache. | ||||
| 	 * Use 0 to indicate that the cached data will never expire. | ||||
| 	 * @see enableCaching | ||||
| 	 */ | ||||
| 	public $cachingDuration = 0; | ||||
| 	/** | ||||
| 	 * @var boolean whether to enable caching translated messages | ||||
| 	 */ | ||||
| 	public $enableCaching = false; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Initializes the DbMessageSource component. | ||||
| 	 * This method will initialize the [[db]] property to make sure it refers to a valid DB connection. | ||||
| 	 * Configured [[cache]] component would also be initialized. | ||||
| 	 * @throws InvalidConfigException if [[db]] is invalid or [[cache]] is invalid. | ||||
| 	 */ | ||||
| 	public function init() | ||||
| 	{ | ||||
| 		parent::init(); | ||||
| 		if (is_string($this->db)) { | ||||
| 			$this->db = Yii::$app->getComponent($this->db); | ||||
| 		} | ||||
| 		if (!$this->db instanceof Connection) { | ||||
| 			throw new InvalidConfigException("DbMessageSource::db must be either a DB connection instance or the application component ID of a DB connection."); | ||||
| 		} | ||||
| 		if ($this->enableCaching) { | ||||
| 			if (is_string($this->cache)) { | ||||
| 				$this->cache = Yii::$app->getComponent($this->cache); | ||||
| 			} | ||||
| 			if (!$this->cache instanceof Cache) { | ||||
| 				throw new InvalidConfigException("DbMessageSource::cache must be either a cache object or the application component ID of the cache object."); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Loads the message translation for the specified language and category. | ||||
| 	 * Child classes should override this method to return the message translations of | ||||
| 	 * the specified language and category. | ||||
| 	 * @param string $category the message category | ||||
| 	 * @param string $language the target language | ||||
| 	 * @return array the loaded messages. The keys are original messages, and the values | ||||
| 	 * are translated messages. | ||||
| 	 */ | ||||
| 	protected function loadMessages($category, $language) | ||||
| 	{ | ||||
| 		if ($this->enableCaching) { | ||||
| 			$key = array( | ||||
| 				__CLASS__, | ||||
| 				$category, | ||||
| 				$language, | ||||
| 			); | ||||
| 			$messages = $this->cache->get($key); | ||||
| 			if ($messages === false) { | ||||
| 				$messages = $this->loadMessagesFromDb($category, $language); | ||||
| 				$this->cache->set($key, $messages, $this->cachingDuration); | ||||
| 			} | ||||
| 			return $messages; | ||||
| 		} else { | ||||
| 			return $this->loadMessagesFromDb($category, $language); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Loads the messages from database. | ||||
| 	 * You may override this method to customize the message storage in the database. | ||||
| 	 * @param string $category the message category. | ||||
| 	 * @param string $language the target language. | ||||
| 	 * @return array the messages loaded from database. | ||||
| 	 */ | ||||
| 	protected function loadMessagesFromDb($category, $language) | ||||
| 	{ | ||||
| 		$query = new Query(); | ||||
| 		$messages = $query->select(array('t1.message message', 't2.translation translation')) | ||||
| 			->from(array($this->sourceMessageTable . ' t1', $this->messageTable . ' t2')) | ||||
| 			->where('t1.id = t2.id AND t1.category = :category AND t2.language = :language') | ||||
| 			->params(array(':category' => $category, ':language' => $language)) | ||||
| 			->createCommand($this->db) | ||||
| 			->queryAll(); | ||||
| 		return ArrayHelper::map($messages, 'message', 'translation'); | ||||
| 	} | ||||
| } | ||||
| @ -1,104 +1,104 @@ | ||||
| <?php | ||||
| /** | ||||
|  * @link http://www.yiiframework.com/ | ||||
|  * @copyright Copyright (c) 2008 Yii Software LLC | ||||
|  * @license http://www.yiiframework.com/license/ | ||||
|  */ | ||||
| 
 | ||||
| namespace yii\web; | ||||
| 
 | ||||
| use Yii; | ||||
| use yii\base\ActionFilter; | ||||
| use yii\base\Action; | ||||
| use yii\base\View; | ||||
| use yii\caching\Dependency; | ||||
| 
 | ||||
| /** | ||||
|  * @author Qiang Xue <qiang.xue@gmail.com> | ||||
|  * @since 2.0 | ||||
|  */ | ||||
| class PageCache extends ActionFilter | ||||
| { | ||||
| 	/** | ||||
| 	 * @var boolean whether the content being cached should be differentiated according to the route. | ||||
| 	 * A route consists of the requested controller ID and action ID. Defaults to true. | ||||
| 	 */ | ||||
| 	public $varyByRoute = true; | ||||
| 	/** | ||||
| 	 * @var string the application component ID of the [[\yii\caching\Cache|cache]] object. | ||||
| 	 */ | ||||
| 	public $cache = 'cache'; | ||||
| 	/** | ||||
| 	 * @var integer number of seconds that the data can remain valid in cache. | ||||
| 	 * Use 0 to indicate that the cached data will never expire. | ||||
| 	 */ | ||||
| 	public $duration = 60; | ||||
| 	/** | ||||
| 	 * @var array|Dependency the dependency that the cached content depends on. | ||||
| 	 * This can be either a [[Dependency]] object or a configuration array for creating the dependency object. | ||||
| 	 * For example, | ||||
| 	 * | ||||
| 	 * ~~~ | ||||
| 	 * array( | ||||
| 	 *     'class' => 'yii\caching\DbDependency', | ||||
| 	 *     'sql' => 'SELECT MAX(lastModified) FROM Post', | ||||
| 	 * ) | ||||
| 	 * ~~~ | ||||
| 	 * | ||||
| 	 * would make the output cache depends on the last modified time of all posts. | ||||
| 	 * If any post has its modification time changed, the cached content would be invalidated. | ||||
| 	 */ | ||||
| 	public $dependency; | ||||
| 	/** | ||||
| 	 * @var array list of factors that would cause the variation of the content being cached. | ||||
| 	 * Each factor is a string representing a variation (e.g. the language, a GET parameter). | ||||
| 	 * The following variation setting will cause the content to be cached in different versions | ||||
| 	 * according to the current application language: | ||||
| 	 * | ||||
| 	 * ~~~ | ||||
| 	 * array( | ||||
| 	 *     Yii::$app->language, | ||||
| 	 * ) | ||||
| 	 */ | ||||
| 	public $variations; | ||||
| 	/** | ||||
| 	 * @var boolean whether to enable the fragment cache. You may use this property to turn on and off | ||||
| 	 * the fragment cache according to specific setting (e.g. enable fragment cache only for GET requests). | ||||
| 	 */ | ||||
| 	public $enabled = true; | ||||
| 
 | ||||
| 
 | ||||
| 	public function init() | ||||
| 	{ | ||||
| 		parent::init(); | ||||
| 		if ($this->view === null) { | ||||
| 			$this->view = Yii::$app->getView(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * 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 boolean whether the action should continue to be executed. | ||||
| 	 */ | ||||
| 	public function beforeAction($action) | ||||
| 	{ | ||||
| 		$properties = array(); | ||||
| 		foreach (array('cache', 'duration', 'dependency', 'variations', 'enabled') as $name) { | ||||
| 			$properties[$name] = $this->$name; | ||||
| 		} | ||||
| 		$id = $this->varyByRoute ? $action->getUniqueId() : __CLASS__; | ||||
| 		return $this->view->beginCache($id, $properties); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * 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. | ||||
| 	 */ | ||||
| 	public function afterAction($action) | ||||
| 	{ | ||||
| 		$this->view->endCache(); | ||||
| 	} | ||||
| <?php | ||||
| /** | ||||
|  * @link http://www.yiiframework.com/ | ||||
|  * @copyright Copyright (c) 2008 Yii Software LLC | ||||
|  * @license http://www.yiiframework.com/license/ | ||||
|  */ | ||||
| 
 | ||||
| namespace yii\web; | ||||
| 
 | ||||
| use Yii; | ||||
| use yii\base\ActionFilter; | ||||
| use yii\base\Action; | ||||
| use yii\base\View; | ||||
| use yii\caching\Dependency; | ||||
| 
 | ||||
| /** | ||||
|  * @author Qiang Xue <qiang.xue@gmail.com> | ||||
|  * @since 2.0 | ||||
|  */ | ||||
| class PageCache extends ActionFilter | ||||
| { | ||||
| 	/** | ||||
| 	 * @var boolean whether the content being cached should be differentiated according to the route. | ||||
| 	 * A route consists of the requested controller ID and action ID. Defaults to true. | ||||
| 	 */ | ||||
| 	public $varyByRoute = true; | ||||
| 	/** | ||||
| 	 * @var string the application component ID of the [[\yii\caching\Cache|cache]] object. | ||||
| 	 */ | ||||
| 	public $cache = 'cache'; | ||||
| 	/** | ||||
| 	 * @var integer number of seconds that the data can remain valid in cache. | ||||
| 	 * Use 0 to indicate that the cached data will never expire. | ||||
| 	 */ | ||||
| 	public $duration = 60; | ||||
| 	/** | ||||
| 	 * @var array|Dependency the dependency that the cached content depends on. | ||||
| 	 * This can be either a [[Dependency]] object or a configuration array for creating the dependency object. | ||||
| 	 * For example, | ||||
| 	 * | ||||
| 	 * ~~~ | ||||
| 	 * array( | ||||
| 	 *     'class' => 'yii\caching\DbDependency', | ||||
| 	 *     'sql' => 'SELECT MAX(lastModified) FROM Post', | ||||
| 	 * ) | ||||
| 	 * ~~~ | ||||
| 	 * | ||||
| 	 * would make the output cache depends on the last modified time of all posts. | ||||
| 	 * If any post has its modification time changed, the cached content would be invalidated. | ||||
| 	 */ | ||||
| 	public $dependency; | ||||
| 	/** | ||||
| 	 * @var array list of factors that would cause the variation of the content being cached. | ||||
| 	 * Each factor is a string representing a variation (e.g. the language, a GET parameter). | ||||
| 	 * The following variation setting will cause the content to be cached in different versions | ||||
| 	 * according to the current application language: | ||||
| 	 * | ||||
| 	 * ~~~ | ||||
| 	 * array( | ||||
| 	 *     Yii::$app->language, | ||||
| 	 * ) | ||||
| 	 */ | ||||
| 	public $variations; | ||||
| 	/** | ||||
| 	 * @var boolean whether to enable the fragment cache. You may use this property to turn on and off | ||||
| 	 * the fragment cache according to specific setting (e.g. enable fragment cache only for GET requests). | ||||
| 	 */ | ||||
| 	public $enabled = true; | ||||
| 
 | ||||
| 
 | ||||
| 	public function init() | ||||
| 	{ | ||||
| 		parent::init(); | ||||
| 		if ($this->view === null) { | ||||
| 			$this->view = Yii::$app->getView(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * 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 boolean whether the action should continue to be executed. | ||||
| 	 */ | ||||
| 	public function beforeAction($action) | ||||
| 	{ | ||||
| 		$properties = array(); | ||||
| 		foreach (array('cache', 'duration', 'dependency', 'variations', 'enabled') as $name) { | ||||
| 			$properties[$name] = $this->$name; | ||||
| 		} | ||||
| 		$id = $this->varyByRoute ? $action->getUniqueId() : __CLASS__; | ||||
| 		return $this->view->beginCache($id, $properties); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * 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. | ||||
| 	 */ | ||||
| 	public function afterAction($action) | ||||
| 	{ | ||||
| 		$this->view->endCache(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -1,174 +1,174 @@ | ||||
| <?php | ||||
| /** | ||||
|  * @link http://www.yiiframework.com/ | ||||
|  * @copyright Copyright (c) 2008 Yii Software LLC | ||||
|  * @license http://www.yiiframework.com/license/ | ||||
|  */ | ||||
| 
 | ||||
| namespace yii\widgets; | ||||
| 
 | ||||
| use Yii; | ||||
| use yii\base\Widget; | ||||
| use yii\caching\Cache; | ||||
| use yii\caching\Dependency; | ||||
| 
 | ||||
| /** | ||||
|  * @author Qiang Xue <qiang.xue@gmail.com> | ||||
|  * @since 2.0 | ||||
|  */ | ||||
| class FragmentCache extends Widget | ||||
| { | ||||
| 	/** | ||||
| 	 * @var Cache|string the cache object or the application component ID of the cache object. | ||||
| 	 * After the FragmentCache object is created, if you want to change this property, | ||||
| 	 * you should only assign it with a cache object. | ||||
| 	 */ | ||||
| 	public $cache = 'cache'; | ||||
| 	/** | ||||
| 	 * @var integer number of seconds that the data can remain valid in cache. | ||||
| 	 * Use 0 to indicate that the cached data will never expire. | ||||
| 	 */ | ||||
| 	public $duration = 60; | ||||
| 	/** | ||||
| 	 * @var array|Dependency the dependency that the cached content depends on. | ||||
| 	 * This can be either a [[Dependency]] object or a configuration array for creating the dependency object. | ||||
| 	 * For example, | ||||
| 	 * | ||||
| 	 * ~~~ | ||||
| 	 * array( | ||||
| 	 *     'class' => 'yii\caching\DbDependency', | ||||
| 	 *     'sql' => 'SELECT MAX(lastModified) FROM Post', | ||||
| 	 * ) | ||||
| 	 * ~~~ | ||||
| 	 * | ||||
| 	 * would make the output cache depends on the last modified time of all posts. | ||||
| 	 * If any post has its modification time changed, the cached content would be invalidated. | ||||
| 	 */ | ||||
| 	public $dependency; | ||||
| 	/** | ||||
| 	 * @var array list of factors that would cause the variation of the content being cached. | ||||
| 	 * Each factor is a string representing a variation (e.g. the language, a GET parameter). | ||||
| 	 * The following variation setting will cause the content to be cached in different versions | ||||
| 	 * according to the current application language: | ||||
| 	 * | ||||
| 	 * ~~~ | ||||
| 	 * array( | ||||
| 	 *     Yii::$app->language, | ||||
| 	 * ) | ||||
| 	 */ | ||||
| 	public $variations; | ||||
| 	/** | ||||
| 	 * @var boolean whether to enable the fragment cache. You may use this property to turn on and off | ||||
| 	 * the fragment cache according to specific setting (e.g. enable fragment cache only for GET requests). | ||||
| 	 */ | ||||
| 	public $enabled = true; | ||||
| 	/** | ||||
| 	 * @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. | ||||
| 	 */ | ||||
| 	public $dynamicPlaceholders; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Initializes the FragmentCache object. | ||||
| 	 */ | ||||
| 	public function init() | ||||
| 	{ | ||||
| 		parent::init(); | ||||
| 
 | ||||
| 		if (!$this->enabled) { | ||||
| 			$this->cache = null; | ||||
| 		} elseif (is_string($this->cache)) { | ||||
| 			$this->cache = Yii::$app->getComponent($this->cache); | ||||
| 		} | ||||
| 
 | ||||
| 		if ($this->getCachedContent() === false) { | ||||
| 			$this->view->cacheStack[] = $this; | ||||
| 			ob_start(); | ||||
| 			ob_implicit_flush(false); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Marks the end of content to be cached. | ||||
| 	 * Content displayed before this method call and after {@link init()} | ||||
| 	 * will be captured and saved in cache. | ||||
| 	 * This method does nothing if valid content is already found in cache. | ||||
| 	 */ | ||||
| 	public function run() | ||||
| 	{ | ||||
| 		if (($content = $this->getCachedContent()) !== false) { | ||||
| 			echo $content; | ||||
| 		} elseif ($this->cache instanceof Cache) { | ||||
| 			$content = ob_get_clean(); | ||||
| 			array_pop($this->view->cacheStack); | ||||
| 			if (is_array($this->dependency)) { | ||||
| 				$this->dependency = Yii::createObject($this->dependency); | ||||
| 			} | ||||
| 			$data = array($content, $this->dynamicPlaceholders); | ||||
| 			$this->cache->set($this->calculateKey(), $data, $this->duration, $this->dependency); | ||||
| 
 | ||||
| 			if (empty($this->view->cacheStack) && !empty($this->dynamicPlaceholders)) { | ||||
| 				$content = $this->updateDynamicContent($content, $this->dynamicPlaceholders); | ||||
| 			} | ||||
| 			echo $content; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @var string|boolean the cached content. False if the content is not cached. | ||||
| 	 */ | ||||
| 	private $_content; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Returns the cached content if available. | ||||
| 	 * @return string|boolean the cached content. False is returned if valid content is not found in the cache. | ||||
| 	 */ | ||||
| 	public function getCachedContent() | ||||
| 	{ | ||||
| 		if ($this->_content === null) { | ||||
| 			$this->_content = false; | ||||
| 			if ($this->cache instanceof Cache) { | ||||
| 				$key = $this->calculateKey(); | ||||
| 				$data = $this->cache->get($key); | ||||
| 				if (is_array($data) && count($data) === 2) { | ||||
| 					list ($content, $placeholders) = $data; | ||||
| 					if (is_array($placeholders) && count($placeholders) > 0) { | ||||
| 						if (empty($this->view->cacheStack)) { | ||||
| 							// outermost cache: replace placeholder with dynamic content | ||||
| 							$content = $this->updateDynamicContent($content, $placeholders); | ||||
| 						} | ||||
| 						foreach ($placeholders as $name => $statements) { | ||||
| 							$this->view->addDynamicPlaceholder($name, $statements); | ||||
| 						} | ||||
| 					} | ||||
| 					$this->_content = $content; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		return $this->_content; | ||||
| 	} | ||||
| 
 | ||||
| 	protected function updateDynamicContent($content, $placeholders) | ||||
| 	{ | ||||
| 		foreach ($placeholders as $name => $statements) { | ||||
| 			$placeholders[$name] = $this->view->evaluateDynamicContent($statements); | ||||
| 		} | ||||
| 		return strtr($content, $placeholders); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Generates a unique key used for storing the content in cache. | ||||
| 	 * The key generated depends on both [[id]] and [[variations]]. | ||||
| 	 * @return mixed a valid cache key | ||||
| 	 */ | ||||
| 	protected function calculateKey() | ||||
| 	{ | ||||
| 		$factors = array(__CLASS__, $this->getId()); | ||||
| 		if (is_array($this->variations)) { | ||||
| 			foreach ($this->variations as $factor) { | ||||
| 				$factors[] = $factor; | ||||
| 			} | ||||
| 		} | ||||
| 		return $factors; | ||||
| 	} | ||||
| } | ||||
| <?php | ||||
| /** | ||||
|  * @link http://www.yiiframework.com/ | ||||
|  * @copyright Copyright (c) 2008 Yii Software LLC | ||||
|  * @license http://www.yiiframework.com/license/ | ||||
|  */ | ||||
| 
 | ||||
| namespace yii\widgets; | ||||
| 
 | ||||
| use Yii; | ||||
| use yii\base\Widget; | ||||
| use yii\caching\Cache; | ||||
| use yii\caching\Dependency; | ||||
| 
 | ||||
| /** | ||||
|  * @author Qiang Xue <qiang.xue@gmail.com> | ||||
|  * @since 2.0 | ||||
|  */ | ||||
| class FragmentCache extends Widget | ||||
| { | ||||
| 	/** | ||||
| 	 * @var Cache|string the cache object or the application component ID of the cache object. | ||||
| 	 * After the FragmentCache object is created, if you want to change this property, | ||||
| 	 * you should only assign it with a cache object. | ||||
| 	 */ | ||||
| 	public $cache = 'cache'; | ||||
| 	/** | ||||
| 	 * @var integer number of seconds that the data can remain valid in cache. | ||||
| 	 * Use 0 to indicate that the cached data will never expire. | ||||
| 	 */ | ||||
| 	public $duration = 60; | ||||
| 	/** | ||||
| 	 * @var array|Dependency the dependency that the cached content depends on. | ||||
| 	 * This can be either a [[Dependency]] object or a configuration array for creating the dependency object. | ||||
| 	 * For example, | ||||
| 	 * | ||||
| 	 * ~~~ | ||||
| 	 * array( | ||||
| 	 *     'class' => 'yii\caching\DbDependency', | ||||
| 	 *     'sql' => 'SELECT MAX(lastModified) FROM Post', | ||||
| 	 * ) | ||||
| 	 * ~~~ | ||||
| 	 * | ||||
| 	 * would make the output cache depends on the last modified time of all posts. | ||||
| 	 * If any post has its modification time changed, the cached content would be invalidated. | ||||
| 	 */ | ||||
| 	public $dependency; | ||||
| 	/** | ||||
| 	 * @var array list of factors that would cause the variation of the content being cached. | ||||
| 	 * Each factor is a string representing a variation (e.g. the language, a GET parameter). | ||||
| 	 * The following variation setting will cause the content to be cached in different versions | ||||
| 	 * according to the current application language: | ||||
| 	 * | ||||
| 	 * ~~~ | ||||
| 	 * array( | ||||
| 	 *     Yii::$app->language, | ||||
| 	 * ) | ||||
| 	 */ | ||||
| 	public $variations; | ||||
| 	/** | ||||
| 	 * @var boolean whether to enable the fragment cache. You may use this property to turn on and off | ||||
| 	 * the fragment cache according to specific setting (e.g. enable fragment cache only for GET requests). | ||||
| 	 */ | ||||
| 	public $enabled = true; | ||||
| 	/** | ||||
| 	 * @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. | ||||
| 	 */ | ||||
| 	public $dynamicPlaceholders; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Initializes the FragmentCache object. | ||||
| 	 */ | ||||
| 	public function init() | ||||
| 	{ | ||||
| 		parent::init(); | ||||
| 
 | ||||
| 		if (!$this->enabled) { | ||||
| 			$this->cache = null; | ||||
| 		} elseif (is_string($this->cache)) { | ||||
| 			$this->cache = Yii::$app->getComponent($this->cache); | ||||
| 		} | ||||
| 
 | ||||
| 		if ($this->getCachedContent() === false) { | ||||
| 			$this->view->cacheStack[] = $this; | ||||
| 			ob_start(); | ||||
| 			ob_implicit_flush(false); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Marks the end of content to be cached. | ||||
| 	 * Content displayed before this method call and after {@link init()} | ||||
| 	 * will be captured and saved in cache. | ||||
| 	 * This method does nothing if valid content is already found in cache. | ||||
| 	 */ | ||||
| 	public function run() | ||||
| 	{ | ||||
| 		if (($content = $this->getCachedContent()) !== false) { | ||||
| 			echo $content; | ||||
| 		} elseif ($this->cache instanceof Cache) { | ||||
| 			$content = ob_get_clean(); | ||||
| 			array_pop($this->view->cacheStack); | ||||
| 			if (is_array($this->dependency)) { | ||||
| 				$this->dependency = Yii::createObject($this->dependency); | ||||
| 			} | ||||
| 			$data = array($content, $this->dynamicPlaceholders); | ||||
| 			$this->cache->set($this->calculateKey(), $data, $this->duration, $this->dependency); | ||||
| 
 | ||||
| 			if (empty($this->view->cacheStack) && !empty($this->dynamicPlaceholders)) { | ||||
| 				$content = $this->updateDynamicContent($content, $this->dynamicPlaceholders); | ||||
| 			} | ||||
| 			echo $content; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @var string|boolean the cached content. False if the content is not cached. | ||||
| 	 */ | ||||
| 	private $_content; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Returns the cached content if available. | ||||
| 	 * @return string|boolean the cached content. False is returned if valid content is not found in the cache. | ||||
| 	 */ | ||||
| 	public function getCachedContent() | ||||
| 	{ | ||||
| 		if ($this->_content === null) { | ||||
| 			$this->_content = false; | ||||
| 			if ($this->cache instanceof Cache) { | ||||
| 				$key = $this->calculateKey(); | ||||
| 				$data = $this->cache->get($key); | ||||
| 				if (is_array($data) && count($data) === 2) { | ||||
| 					list ($content, $placeholders) = $data; | ||||
| 					if (is_array($placeholders) && count($placeholders) > 0) { | ||||
| 						if (empty($this->view->cacheStack)) { | ||||
| 							// outermost cache: replace placeholder with dynamic content | ||||
| 							$content = $this->updateDynamicContent($content, $placeholders); | ||||
| 						} | ||||
| 						foreach ($placeholders as $name => $statements) { | ||||
| 							$this->view->addDynamicPlaceholder($name, $statements); | ||||
| 						} | ||||
| 					} | ||||
| 					$this->_content = $content; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		return $this->_content; | ||||
| 	} | ||||
| 
 | ||||
| 	protected function updateDynamicContent($content, $placeholders) | ||||
| 	{ | ||||
| 		foreach ($placeholders as $name => $statements) { | ||||
| 			$placeholders[$name] = $this->view->evaluateDynamicContent($statements); | ||||
| 		} | ||||
| 		return strtr($content, $placeholders); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Generates a unique key used for storing the content in cache. | ||||
| 	 * The key generated depends on both [[id]] and [[variations]]. | ||||
| 	 * @return mixed a valid cache key | ||||
| 	 */ | ||||
| 	protected function calculateKey() | ||||
| 	{ | ||||
| 		$factors = array(__CLASS__, $this->getId()); | ||||
| 		if (is_array($this->variations)) { | ||||
| 			foreach ($this->variations as $factor) { | ||||
| 				$factors[] = $factor; | ||||
| 			} | ||||
| 		} | ||||
| 		return $factors; | ||||
| 	} | ||||
| } | ||||
|  | ||||
					Loading…
					
					
				
		Reference in new issue