Browse Source
* upstream/master: (91 commits) fixed init.bat paths renamed backstage → backend Fixed test break. Response WIP coding style fix. [1] Redone missing code. [2] Added empty line at the end of file [3] Removed exception. Updated code style. braces on the same line for control statements. Removed unused columsn from find constraint sql. Fixed typo. Added extra schema check for when a foreign table is not in the same schema. Updated indentation to conform to other classes. Multilevel Items Fixes issue #514. Removed the config setting that should not have been commited. Removed false exception catching. Removed custom pgsql PDO and added defaultSchema as public property. CS fixes. Minor refactoring of DbMessageSource. Response WIP Minor refactoring of t(). Added Jsonable support. Fixes #13. Implement DB message source. Yii::t() minor fix. ...tags/2.0.0-beta
Antonio Ramirez
12 years ago
150 changed files with 4527 additions and 3045 deletions
@ -1,6 +1,6 @@ |
|||||||
<?php |
<?php |
||||||
|
|
||||||
namespace backstage\controllers; |
namespace backend\controllers; |
||||||
|
|
||||||
use Yii; |
use Yii; |
||||||
use yii\web\Controller; |
use yii\web\Controller; |
@ -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(); |
||||||
|
} |
@ -0,0 +1,17 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\console; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Qiang Xue <qiang.xue@gmail.com> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
class Response extends \yii\base\Response |
||||||
|
{ |
||||||
|
|
||||||
|
} |
@ -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\db\pgsql; |
||||||
|
|
||||||
|
/** |
||||||
|
* QueryBuilder is the query builder for PostgreSQL databases. |
||||||
|
* |
||||||
|
* @author Gevik Babakhani <gevikb@gmail.com> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
class QueryBuilder extends \yii\db\QueryBuilder |
||||||
|
{ |
||||||
|
|
||||||
|
/** |
||||||
|
* @var array mapping from abstract column types (keys) to physical column types (values). |
||||||
|
*/ |
||||||
|
public $typeMap = array( |
||||||
|
Schema::TYPE_PK => 'serial not null primary key', |
||||||
|
Schema::TYPE_STRING => 'varchar', |
||||||
|
Schema::TYPE_TEXT => 'text', |
||||||
|
Schema::TYPE_SMALLINT => 'smallint', |
||||||
|
Schema::TYPE_INTEGER => 'integer', |
||||||
|
Schema::TYPE_BIGINT => 'bigint', |
||||||
|
Schema::TYPE_FLOAT => 'double precision', |
||||||
|
Schema::TYPE_DECIMAL => 'numeric', |
||||||
|
Schema::TYPE_DATETIME => 'timestamp', |
||||||
|
Schema::TYPE_TIMESTAMP => 'timestamp', |
||||||
|
Schema::TYPE_TIME => 'time', |
||||||
|
Schema::TYPE_DATE => 'date', |
||||||
|
Schema::TYPE_BINARY => 'bytea', |
||||||
|
Schema::TYPE_BOOLEAN => 'boolean', |
||||||
|
Schema::TYPE_MONEY => 'numeric(19,4)', |
||||||
|
); |
||||||
|
|
||||||
|
} |
@ -0,0 +1,288 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\db\pgsql; |
||||||
|
|
||||||
|
use yii\db\TableSchema; |
||||||
|
use yii\db\ColumnSchema; |
||||||
|
|
||||||
|
/** |
||||||
|
* Schema is the class for retrieving metadata from a PostgreSQL database |
||||||
|
* (version 9.x and above). |
||||||
|
* |
||||||
|
* @author Gevik Babakhani <gevikb@gmail.com> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
class Schema extends \yii\db\Schema |
||||||
|
{ |
||||||
|
|
||||||
|
/** |
||||||
|
* The default schema used for the current session. |
||||||
|
* @var string |
||||||
|
*/ |
||||||
|
public $defaultSchema = 'public'; |
||||||
|
|
||||||
|
/** |
||||||
|
* @var array mapping from physical column types (keys) to abstract |
||||||
|
* column types (values) |
||||||
|
*/ |
||||||
|
public $typeMap = array( |
||||||
|
'abstime' => self::TYPE_TIMESTAMP, |
||||||
|
'bit' => self::TYPE_STRING, |
||||||
|
'boolean' => self::TYPE_BOOLEAN, |
||||||
|
'box' => self::TYPE_STRING, |
||||||
|
'character' => self::TYPE_STRING, |
||||||
|
'bytea' => self::TYPE_BINARY, |
||||||
|
'char' => self::TYPE_STRING, |
||||||
|
'cidr' => self::TYPE_STRING, |
||||||
|
'circle' => self::TYPE_STRING, |
||||||
|
'date' => self::TYPE_DATE, |
||||||
|
'real' => self::TYPE_FLOAT, |
||||||
|
'double precision' => self::TYPE_DECIMAL, |
||||||
|
'inet' => self::TYPE_STRING, |
||||||
|
'smallint' => self::TYPE_SMALLINT, |
||||||
|
'integer' => self::TYPE_INTEGER, |
||||||
|
'bigint' => self::TYPE_BIGINT, |
||||||
|
'interval' => self::TYPE_STRING, |
||||||
|
'json' => self::TYPE_STRING, |
||||||
|
'line' => self::TYPE_STRING, |
||||||
|
'macaddr' => self::TYPE_STRING, |
||||||
|
'money' => self::TYPE_MONEY, |
||||||
|
'name' => self::TYPE_STRING, |
||||||
|
'numeric' => self::TYPE_STRING, |
||||||
|
'numrange' => self::TYPE_DECIMAL, |
||||||
|
'oid' => self::TYPE_BIGINT, // should not be used. it's pg internal! |
||||||
|
'path' => self::TYPE_STRING, |
||||||
|
'point' => self::TYPE_STRING, |
||||||
|
'polygon' => self::TYPE_STRING, |
||||||
|
'text' => self::TYPE_TEXT, |
||||||
|
'time without time zone' => self::TYPE_TIME, |
||||||
|
'timestamp without time zone' => self::TYPE_TIMESTAMP, |
||||||
|
'timestamp with time zone' => self::TYPE_TIMESTAMP, |
||||||
|
'time with time zone' => self::TYPE_TIMESTAMP, |
||||||
|
'unknown' => self::TYPE_STRING, |
||||||
|
'uuid' => self::TYPE_STRING, |
||||||
|
'bit varying' => self::TYPE_STRING, |
||||||
|
'character varying' => self::TYPE_STRING, |
||||||
|
'xml' => self::TYPE_STRING |
||||||
|
); |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a query builder for the PostgreSQL database. |
||||||
|
* @return QueryBuilder query builder instance |
||||||
|
*/ |
||||||
|
public function createQueryBuilder() |
||||||
|
{ |
||||||
|
return new QueryBuilder($this->db); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Resolves the table name and schema name (if any). |
||||||
|
* @param TableSchema $table the table metadata object |
||||||
|
* @param string $name the table name |
||||||
|
*/ |
||||||
|
protected function resolveTableNames($table, $name) |
||||||
|
{ |
||||||
|
$parts = explode('.', str_replace('"', '', $name)); |
||||||
|
if (isset($parts[1])) { |
||||||
|
$table->schemaName = $parts[0]; |
||||||
|
$table->name = $parts[1]; |
||||||
|
} else { |
||||||
|
$table->name = $parts[0]; |
||||||
|
} |
||||||
|
if ($table->schemaName === null) { |
||||||
|
$table->schemaName = $this->defaultSchema; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Quotes a table name for use in a query. |
||||||
|
* A simple table name has no schema prefix. |
||||||
|
* @param string $name table name |
||||||
|
* @return string the properly quoted table name |
||||||
|
*/ |
||||||
|
public function quoteSimpleTableName($name) |
||||||
|
{ |
||||||
|
return strpos($name, '"') !== false ? $name : '"' . $name . '"'; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Loads the metadata for the specified table. |
||||||
|
* @param string $name table name |
||||||
|
* @return TableSchema|null driver dependent table metadata. Null if the table does not exist. |
||||||
|
*/ |
||||||
|
public function loadTableSchema($name) |
||||||
|
{ |
||||||
|
$table = new TableSchema(); |
||||||
|
$this->resolveTableNames($table, $name); |
||||||
|
if ($this->findColumns($table)) { |
||||||
|
$this->findConstraints($table); |
||||||
|
return $table; |
||||||
|
} else { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Collects the foreign key column details for the given table. |
||||||
|
* @param TableSchema $table the table metadata |
||||||
|
*/ |
||||||
|
protected function findConstraints($table) |
||||||
|
{ |
||||||
|
|
||||||
|
$tableName = $this->quoteValue($table->name); |
||||||
|
$tableSchema = $this->quoteValue($table->schemaName); |
||||||
|
|
||||||
|
//We need to extract the constraints de hard way since: |
||||||
|
//http://www.postgresql.org/message-id/26677.1086673982@sss.pgh.pa.us |
||||||
|
|
||||||
|
$sql = <<<SQL |
||||||
|
select |
||||||
|
(select string_agg(attname,',') attname from pg_attribute where attrelid=ct.conrelid and attnum = any(ct.conkey)) as columns, |
||||||
|
fc.relname as foreign_table_name, |
||||||
|
fns.nspname as foreign_table_schema, |
||||||
|
(select string_agg(attname,',') attname from pg_attribute where attrelid=ct.confrelid and attnum = any(ct.confkey)) as foreign_columns |
||||||
|
from |
||||||
|
pg_constraint ct |
||||||
|
inner join pg_class c on c.oid=ct.conrelid |
||||||
|
inner join pg_namespace ns on c.relnamespace=ns.oid |
||||||
|
left join pg_class fc on fc.oid=ct.confrelid |
||||||
|
left join pg_namespace fns on fc.relnamespace=fns.oid |
||||||
|
|
||||||
|
where |
||||||
|
ct.contype='f' |
||||||
|
and c.relname={$tableName} |
||||||
|
and ns.nspname={$tableSchema} |
||||||
|
SQL; |
||||||
|
|
||||||
|
$constraints = $this->db->createCommand($sql)->queryAll(); |
||||||
|
foreach ($constraints as $constraint) { |
||||||
|
$columns = explode(',', $constraint['columns']); |
||||||
|
$fcolumns = explode(',', $constraint['foreign_columns']); |
||||||
|
if ($constraint['foreign_table_schema'] !== $this->defaultSchema) { |
||||||
|
$foreignTable = $constraint['foreign_table_schema'] . '.' . $constraint['foreign_table_name']; |
||||||
|
} else { |
||||||
|
$foreignTable = $constraint['foreign_table_name']; |
||||||
|
} |
||||||
|
$citem = array($foreignTable); |
||||||
|
foreach ($columns as $idx => $column) { |
||||||
|
$citem[] = array($fcolumns[$idx] => $column); |
||||||
|
} |
||||||
|
$table->foreignKeys[] = $citem; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Collects the metadata of table columns. |
||||||
|
* @param TableSchema $table the table metadata |
||||||
|
* @return boolean whether the table exists in the database |
||||||
|
*/ |
||||||
|
protected function findColumns($table) |
||||||
|
{ |
||||||
|
$tableName = $this->db->quoteValue($table->name); |
||||||
|
$schemaName = $this->db->quoteValue($table->schemaName); |
||||||
|
$sql = <<<SQL |
||||||
|
SELECT |
||||||
|
current_database() as table_catalog, |
||||||
|
d.nspname AS table_schema, |
||||||
|
c.relname AS table_name, |
||||||
|
a.attname AS column_name, |
||||||
|
t.typname AS data_type, |
||||||
|
a.attlen AS character_maximum_length, |
||||||
|
pg_catalog.col_description(c.oid, a.attnum) AS column_comment, |
||||||
|
a.atttypmod AS modifier, |
||||||
|
a.attnotnull = false AS is_nullable, |
||||||
|
CAST(pg_get_expr(ad.adbin, ad.adrelid) AS varchar) AS column_default, |
||||||
|
coalesce(pg_get_expr(ad.adbin, ad.adrelid) ~ 'nextval',false) AS is_autoinc, |
||||||
|
array_to_string((select array_agg(enumlabel) from pg_enum where enumtypid=a.atttypid)::varchar[],',') as enum_values, |
||||||
|
CASE atttypid |
||||||
|
WHEN 21 /*int2*/ THEN 16 |
||||||
|
WHEN 23 /*int4*/ THEN 32 |
||||||
|
WHEN 20 /*int8*/ THEN 64 |
||||||
|
WHEN 1700 /*numeric*/ THEN |
||||||
|
CASE WHEN atttypmod = -1 |
||||||
|
THEN null |
||||||
|
ELSE ((atttypmod - 4) >> 16) & 65535 |
||||||
|
END |
||||||
|
WHEN 700 /*float4*/ THEN 24 /*FLT_MANT_DIG*/ |
||||||
|
WHEN 701 /*float8*/ THEN 53 /*DBL_MANT_DIG*/ |
||||||
|
ELSE null |
||||||
|
END AS numeric_precision, |
||||||
|
CASE |
||||||
|
WHEN atttypid IN (21, 23, 20) THEN 0 |
||||||
|
WHEN atttypid IN (1700) THEN |
||||||
|
CASE |
||||||
|
WHEN atttypmod = -1 THEN null |
||||||
|
ELSE (atttypmod - 4) & 65535 |
||||||
|
END |
||||||
|
ELSE null |
||||||
|
END AS numeric_scale, |
||||||
|
CAST( |
||||||
|
information_schema._pg_char_max_length(information_schema._pg_truetypid(a, t), information_schema._pg_truetypmod(a, t)) |
||||||
|
AS numeric |
||||||
|
) AS size, |
||||||
|
a.attnum = any (ct.conkey) as is_pkey |
||||||
|
FROM |
||||||
|
pg_class c |
||||||
|
LEFT JOIN pg_attribute a ON a.attrelid = c.oid |
||||||
|
LEFT JOIN pg_attrdef ad ON a.attrelid = ad.adrelid AND a.attnum = ad.adnum |
||||||
|
LEFT JOIN pg_type t ON a.atttypid = t.oid |
||||||
|
LEFT JOIN pg_namespace d ON d.oid = c.relnamespace |
||||||
|
LEFT join pg_constraint ct on ct.conrelid=c.oid and ct.contype='p' |
||||||
|
WHERE |
||||||
|
a.attnum > 0 |
||||||
|
and c.relname = {$tableName} |
||||||
|
and d.nspname = {$schemaName} |
||||||
|
ORDER BY |
||||||
|
a.attnum; |
||||||
|
SQL; |
||||||
|
|
||||||
|
$columns = $this->db->createCommand($sql)->queryAll(); |
||||||
|
foreach ($columns as $column) { |
||||||
|
$column = $this->loadColumnSchema($column); |
||||||
|
$table->columns[$column->name] = $column; |
||||||
|
if ($column->isPrimaryKey === true) { |
||||||
|
$table->primaryKey[] = $column->name; |
||||||
|
if ($table->sequenceName === null && preg_match("/nextval\('\w+'(::regclass)?\)/", $column->defaultValue) === 1) { |
||||||
|
$table->sequenceName = preg_replace(array('/nextval/', '/::/', '/regclass/', '/\'\)/', '/\(\'/'), '', $column->defaultValue); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Loads the column information into a [[ColumnSchema]] object. |
||||||
|
* @param array $info column information |
||||||
|
* @return ColumnSchema the column schema object |
||||||
|
*/ |
||||||
|
protected function loadColumnSchema($info) |
||||||
|
{ |
||||||
|
$column = new ColumnSchema(); |
||||||
|
$column->allowNull = $info['is_nullable']; |
||||||
|
$column->autoIncrement = $info['is_autoinc']; |
||||||
|
$column->comment = $info['column_comment']; |
||||||
|
$column->dbType = $info['data_type']; |
||||||
|
$column->defaultValue = $info['column_default']; |
||||||
|
$column->enumValues = explode(',', str_replace(array("''"), array("'"), $info['enum_values'])); |
||||||
|
$column->unsigned = false; // has no meanining in PG |
||||||
|
$column->isPrimaryKey = $info['is_pkey']; |
||||||
|
$column->name = $info['column_name']; |
||||||
|
$column->precision = $info['numeric_precision']; |
||||||
|
$column->scale = $info['numeric_scale']; |
||||||
|
$column->size = $info['size']; |
||||||
|
|
||||||
|
if (isset($this->typeMap[$column->dbType])) { |
||||||
|
$column->type = $this->typeMap[$column->dbType]; |
||||||
|
} else { |
||||||
|
$column->type = self::TYPE_STRING; |
||||||
|
} |
||||||
|
$column->phpType = $this->getColumnPhpType($column); |
||||||
|
return $column; |
||||||
|
} |
||||||
|
} |
@ -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'); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,201 @@ |
|||||||
|
<?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\Object; |
||||||
|
use ArrayIterator; |
||||||
|
|
||||||
|
/** |
||||||
|
* HeaderCollection is used by [[Response]] to maintain the currently registered HTTP headers. |
||||||
|
* |
||||||
|
* @author Qiang Xue <qiang.xue@gmail.com> |
||||||
|
* @since 2.0 |
||||||
|
*/ |
||||||
|
class HeaderCollection extends Object implements \IteratorAggregate, \ArrayAccess, \Countable |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @var array the headers in this collection (indexed by the header names) |
||||||
|
*/ |
||||||
|
private $_headers = array(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns an iterator for traversing the headers in the collection. |
||||||
|
* 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 headers in the collection. |
||||||
|
*/ |
||||||
|
public function getIterator() |
||||||
|
{ |
||||||
|
return new ArrayIterator($this->_headers); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the number of headers in the collection. |
||||||
|
* This method is required by the SPL `Countable` interface. |
||||||
|
* It will be implicitly called when you use `count($collection)`. |
||||||
|
* @return integer the number of headers in the collection. |
||||||
|
*/ |
||||||
|
public function count() |
||||||
|
{ |
||||||
|
return $this->getCount(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the number of headers in the collection. |
||||||
|
* @return integer the number of headers in the collection. |
||||||
|
*/ |
||||||
|
public function getCount() |
||||||
|
{ |
||||||
|
return count($this->_headers); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the named header(s). |
||||||
|
* @param string $name the name of the header to return |
||||||
|
* @param mixed $default the value to return in case the named header does not exist |
||||||
|
* @param boolean $first whether to only return the first header of the specified name. |
||||||
|
* If false, all headers of the specified name will be returned. |
||||||
|
* @return string|array the named header(s). If `$first` is true, a string will be returned; |
||||||
|
* If `$first` is false, an array will be returned. |
||||||
|
*/ |
||||||
|
public function get($name, $default = null, $first = true) |
||||||
|
{ |
||||||
|
$name = strtolower($name); |
||||||
|
if (isset($this->_headers[$name])) { |
||||||
|
return $first ? reset($this->_headers[$name]) : $this->_headers[$name]; |
||||||
|
} else { |
||||||
|
return $default; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Adds a new header. |
||||||
|
* If there is already a header with the same name, it will be replaced. |
||||||
|
* @param string $name the name of the header |
||||||
|
* @param string $value the value of the header |
||||||
|
* @return HeaderCollection the collection object itself |
||||||
|
*/ |
||||||
|
public function set($name, $value = '') |
||||||
|
{ |
||||||
|
$name = strtolower($name); |
||||||
|
$this->_headers[$name] = (array)$value; |
||||||
|
return $this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Adds a new header. |
||||||
|
* If there is already a header with the same name, the new one will |
||||||
|
* be appended to it instead of replacing it. |
||||||
|
* @param string $name the name of the header |
||||||
|
* @param string $value the value of the header |
||||||
|
* @return HeaderCollection the collection object itself |
||||||
|
*/ |
||||||
|
public function add($name, $value) |
||||||
|
{ |
||||||
|
$name = strtolower($name); |
||||||
|
$this->_headers[$name][] = $value; |
||||||
|
return $this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a value indicating whether the named header exists. |
||||||
|
* @param string $name the name of the header |
||||||
|
* @return boolean whether the named header exists |
||||||
|
*/ |
||||||
|
public function has($name) |
||||||
|
{ |
||||||
|
$name = strtolower($name); |
||||||
|
return isset($this->_headers[$name]); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Removes a header. |
||||||
|
* @param string $name the name of the header to be removed. |
||||||
|
* @return string the value of the removed header. Null is returned if the header does not exist. |
||||||
|
*/ |
||||||
|
public function remove($name) |
||||||
|
{ |
||||||
|
$name = strtolower($name); |
||||||
|
if (isset($this->_headers[$name])) { |
||||||
|
$value = $this->_headers[$name]; |
||||||
|
unset($this->_headers[$name]); |
||||||
|
return $value; |
||||||
|
} else { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Removes all headers. |
||||||
|
*/ |
||||||
|
public function removeAll() |
||||||
|
{ |
||||||
|
$this->_headers = array(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the collection as a PHP array. |
||||||
|
* @return array the array representation of the collection. |
||||||
|
* The array keys are header names, and the array values are the corresponding header values. |
||||||
|
*/ |
||||||
|
public function toArray() |
||||||
|
{ |
||||||
|
return $this->_headers; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns whether there is a header with the specified name. |
||||||
|
* This method is required by the SPL interface `ArrayAccess`. |
||||||
|
* It is implicitly called when you use something like `isset($collection[$name])`. |
||||||
|
* @param string $name the header name |
||||||
|
* @return boolean whether the named header exists |
||||||
|
*/ |
||||||
|
public function offsetExists($name) |
||||||
|
{ |
||||||
|
return $this->has($name); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the header with the specified name. |
||||||
|
* This method is required by the SPL interface `ArrayAccess`. |
||||||
|
* It is implicitly called when you use something like `$header = $collection[$name];`. |
||||||
|
* This is equivalent to [[get()]]. |
||||||
|
* @param string $name the header name |
||||||
|
* @return string the header value with the specified name, null if the named header does not exist. |
||||||
|
*/ |
||||||
|
public function offsetGet($name) |
||||||
|
{ |
||||||
|
return $this->get($name); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Adds the header to the collection. |
||||||
|
* This method is required by the SPL interface `ArrayAccess`. |
||||||
|
* It is implicitly called when you use something like `$collection[$name] = $header;`. |
||||||
|
* This is equivalent to [[add()]]. |
||||||
|
* @param string $name the header name |
||||||
|
* @param string $value the header value to be added |
||||||
|
*/ |
||||||
|
public function offsetSet($name, $value) |
||||||
|
{ |
||||||
|
$this->set($name, $value); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Removes the named header. |
||||||
|
* This method is required by the SPL interface `ArrayAccess`. |
||||||
|
* It is implicitly called when you use something like `unset($collection[$name])`. |
||||||
|
* This is equivalent to [[remove()]]. |
||||||
|
* @param string $name the header name |
||||||
|
*/ |
||||||
|
public function offsetUnset($name) |
||||||
|
{ |
||||||
|
$this->remove($name); |
||||||
|
} |
||||||
|
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue