Commit d9a3f399 by Alexander Makarov

Merge branch 'master'

Conflicts: framework/CHANGELOG.md
parents 1122da95 ee2b968b
...@@ -19,6 +19,8 @@ Thumbs.db ...@@ -19,6 +19,8 @@ Thumbs.db
composer.phar composer.phar
# composer.lock should not be committed as we always want the latest versions # composer.lock should not be committed as we always want the latest versions
/composer.lock /composer.lock
# composer.lock in applications is ignored in dev repo, will be committed in checked out app repos
/apps/*/composer.lock
# Mac DS_Store Files # Mac DS_Store Files
.DS_Store .DS_Store
......
...@@ -5,14 +5,16 @@ php: ...@@ -5,14 +5,16 @@ php:
- 5.5 - 5.5
- 5.6 - 5.6
- hhvm - hhvm
- hhvm-nightly
# run build against PHP 5.6 and hhvm but allow them to fail # run build against PHP 5.6 and hhvm but allow them to fail
# http://docs.travis-ci.com/user/build-configuration/#Rows-That-are-Allowed-To-Fail # http://docs.travis-ci.com/user/build-configuration/#Rows-That-are-Allowed-To-Fail
matrix: matrix:
fast_finish: true fast_finish: true
allow_failures: allow_failures:
- php: hhvm
- php: 5.6 - php: 5.6
- php: hhvm
- php: hhvm-nightly
services: services:
- redis-server - redis-server
......
...@@ -227,8 +227,8 @@ return [ ...@@ -227,8 +227,8 @@ return [
'app\config\AllAsset' => [ 'app\config\AllAsset' => [
'basePath' => 'path/to/web', 'basePath' => 'path/to/web',
'baseUrl' => '', 'baseUrl' => '',
'js' => 'js/all-{ts}.js', 'js' => 'js/all-{hash}.js',
'css' => 'css/all-{ts}.css', 'css' => 'css/all-{hash}.css',
], ],
], ],
// Asset manager configuration: // Asset manager configuration:
...@@ -246,8 +246,8 @@ everything to `path/to/web` that can be accessed like `http://example.com/` i.e. ...@@ -246,8 +246,8 @@ everything to `path/to/web` that can be accessed like `http://example.com/` i.e.
> Note: in the console environment some path aliases like '@webroot' and '@web' may not exist, > Note: in the console environment some path aliases like '@webroot' and '@web' may not exist,
so corresponding paths inside the configuration should be specified directly. so corresponding paths inside the configuration should be specified directly.
JavaScript files are combined, compressed and written to `js/all-{ts}.js` where {ts} is replaced with current UNIX JavaScript files are combined, compressed and written to `js/all-{hash}.js` where {hash} is replaced with the hash of
timestamp. the resulting file.
`jsCompressor` and `cssCompressor` are console commands or PHP callbacks, which should perform JavaScript and CSS files `jsCompressor` and `cssCompressor` are console commands or PHP callbacks, which should perform JavaScript and CSS files
compression correspondingly. You should adjust these values according to your environment. compression correspondingly. You should adjust these values according to your environment.
......
...@@ -28,10 +28,12 @@ Yii Framework 2 Change Log ...@@ -28,10 +28,12 @@ Yii Framework 2 Change Log
- Bug #3431: Allow using extended ErrorHandler class from the app namespace (cebe) - Bug #3431: Allow using extended ErrorHandler class from the app namespace (cebe)
- Bug #3436: Fixed the issue that `ServiceLocator` still returns the old component after calling `set()` with a new definition (qiangxue) - Bug #3436: Fixed the issue that `ServiceLocator` still returns the old component after calling `set()` with a new definition (qiangxue)
- Bug #3458: Fixed the bug that the image rendered by `CaptchaAction` was using a wrong content type (MDMunir, qiangxue) - Bug #3458: Fixed the bug that the image rendered by `CaptchaAction` was using a wrong content type (MDMunir, qiangxue)
- Bug #3473: Allow postgreSQL to specify timestamp precision via abstract types in QueryBuilder (cebe)
- Bug #3522: Fixed BaseFileHelper::normalizePath to allow a (.) for the current path. (skotos) - Bug #3522: Fixed BaseFileHelper::normalizePath to allow a (.) for the current path. (skotos)
- Bug #3548: Fixed the bug that X-Rate-Limit-Remaining header is always zero when using RateLimiter (qiangxue) - Bug #3548: Fixed the bug that X-Rate-Limit-Remaining header is always zero when using RateLimiter (qiangxue)
- Bug #3564: Fixed the bug that primary key columns should not take default values from schema (qiangxue) - Bug #3564: Fixed the bug that primary key columns should not take default values from schema (qiangxue)
- Bug #3567: Fixed the bug that smallint was treated as string for PostgreSQL (qiangxue) - Bug #3567: Fixed the bug that smallint was treated as string for PostgreSQL (qiangxue)
- Bug #3578: Fixed postgreSQL column type detection, added missing types (MDMunir, cebe)
- Bug: Fixed inconsistent return of `\yii\console\Application::runAction()` (samdark) - Bug: Fixed inconsistent return of `\yii\console\Application::runAction()` (samdark)
- Enh #2264: `CookieCollection::has()` will return false for expired or removed cookies (qiangxue) - Enh #2264: `CookieCollection::has()` will return false for expired or removed cookies (qiangxue)
- Enh #2435: `yii\db\IntegrityException` is now thrown on database integrity errors instead of general `yii\db\Exception` (samdark) - Enh #2435: `yii\db\IntegrityException` is now thrown on database integrity errors instead of general `yii\db\Exception` (samdark)
...@@ -55,6 +57,7 @@ Yii Framework 2 Change Log ...@@ -55,6 +57,7 @@ Yii Framework 2 Change Log
- Enh #3518: `yii\helpers\Html::encode()` now replaces invalid code sequences with "?" (DaSourcerer) - Enh #3518: `yii\helpers\Html::encode()` now replaces invalid code sequences with "?" (DaSourcerer)
- Enh #3521: Added `yii\filters\HttpCache::sessionCacheLimiter` (qiangxue) - Enh #3521: Added `yii\filters\HttpCache::sessionCacheLimiter` (qiangxue)
- Enh #3542: Removed requirement to specify `extensions` in application config (samdark) - Enh #3542: Removed requirement to specify `extensions` in application config (samdark)
- Enh #3574: Add integrity check support for SQLite (zeeke)
- Enh: Added support for using sub-queries when building a DB query with `IN` condition (qiangxue) - Enh: Added support for using sub-queries when building a DB query with `IN` condition (qiangxue)
- Enh: Supported adding a new response formatter without the need to reconfigure existing formatters (qiangxue) - Enh: Supported adding a new response formatter without the need to reconfigure existing formatters (qiangxue)
- Enh: Added `yii\web\UrlManager::addRules()` to simplify adding new URL rules (qiangxue) - Enh: Added `yii\web\UrlManager::addRules()` to simplify adding new URL rules (qiangxue)
...@@ -67,11 +70,13 @@ Yii Framework 2 Change Log ...@@ -67,11 +70,13 @@ Yii Framework 2 Change Log
- Enh: Added support for using path alias with `FileDependency::fileName` (qiangxue) - Enh: Added support for using path alias with `FileDependency::fileName` (qiangxue)
- Enh: Added param `hideOnSinglePage` to `yii\widgets\LinkPager` (arturf) - Enh: Added param `hideOnSinglePage` to `yii\widgets\LinkPager` (arturf)
- Enh: Added support for array attributes in `in` validator (creocoder) - Enh: Added support for array attributes in `in` validator (creocoder)
- Chg #2898: `yii\console\controllers\AssetController` is now using hashes instead of timestamps (samdark)
- Chg #2913: RBAC `DbManager` is now initialized via migration (samdark) - Chg #2913: RBAC `DbManager` is now initialized via migration (samdark)
- Chg #3036: Upgraded Twitter Bootstrap to 3.1.x (qiangxue) - Chg #3036: Upgraded Twitter Bootstrap to 3.1.x (qiangxue)
- Chg #3175: InvalidCallException, InvalidParamException, UnknownMethodException are now extended from SPL BadMethodCallException (samdark) - Chg #3175: InvalidCallException, InvalidParamException, UnknownMethodException are now extended from SPL BadMethodCallException (samdark)
- Chg #3383: Added `$type` parameter to `IdentityInterface::findIdentityByAccessToken()` (qiangxue) - Chg #3383: Added `$type` parameter to `IdentityInterface::findIdentityByAccessToken()` (qiangxue)
- Chg #3531: \yii\grid\GridView now allows any character (except ":") in the attribute part of the shorthand syntax for columns (rawtaz) - Chg #3531: \yii\grid\GridView now allows any character (except ":") in the attribute part of the shorthand syntax for columns (rawtaz)
- Chg #3544: Added `$key` as a parameter to the callable specified via `yii\grid\DataColumn::value` (mdmunir)
- Chg: Replaced `clearAll()` and `clearAllAssignments()` in `yii\rbac\ManagerInterface` with `removeAll()`, `removeAllRoles()`, `removeAllPermissions()`, `removeAllRules()` and `removeAllAssignments()` (qiangxue) - Chg: Replaced `clearAll()` and `clearAllAssignments()` in `yii\rbac\ManagerInterface` with `removeAll()`, `removeAllRoles()`, `removeAllPermissions()`, `removeAllRules()` and `removeAllAssignments()` (qiangxue)
- Chg: Added `$user` as the first parameter of `yii\rbac\Rule::execute()` (qiangxue) - Chg: Added `$user` as the first parameter of `yii\rbac\Rule::execute()` (qiangxue)
- Chg: `yii\grid\DataColumn::getDataCellValue()` visibility is now `public` to allow accessing the value from a GridView directly (cebe) - Chg: `yii\grid\DataColumn::getDataCellValue()` visibility is now `public` to allow accessing the value from a GridView directly (cebe)
......
...@@ -37,3 +37,10 @@ Upgrade from Yii 2.0 Beta ...@@ -37,3 +37,10 @@ Upgrade from Yii 2.0 Beta
* If you are using `dropDownList()`, `listBox()`, `activeDropDownList()`, or `activeListBox()` * 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 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. 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}`.
\ No newline at end of file
...@@ -10,6 +10,7 @@ namespace yii\console\controllers; ...@@ -10,6 +10,7 @@ namespace yii\console\controllers;
use Yii; use Yii;
use yii\console\Exception; use yii\console\Exception;
use yii\console\Controller; use yii\console\Controller;
use yii\helpers\StringHelper;
use yii\helpers\VarDumper; use yii\helpers\VarDumper;
/** /**
...@@ -52,14 +53,13 @@ class AssetController extends Controller ...@@ -52,14 +53,13 @@ class AssetController extends Controller
* *
* ~~~ * ~~~
* 'app\config\AllAsset' => [ * 'app\config\AllAsset' => [
* 'js' => 'js/all-{ts}.js', * 'js' => 'js/all-{hash}.js',
* 'css' => 'css/all-{ts}.css', * 'css' => 'css/all-{hash}.css',
* 'depends' => [ ... ], * 'depends' => [ ... ],
* ] * ]
* ~~~ * ~~~
* *
* File names can contain placeholder "{ts}", which will be filled by current timestamp, while * File names can contain placeholder "{hash}", which will be filled by the hash of the resulting file.
* file creation.
*/ */
public $targets = []; public $targets = [];
/** /**
...@@ -138,14 +138,13 @@ class AssetController extends Controller ...@@ -138,14 +138,13 @@ class AssetController extends Controller
$this->loadConfiguration($configFile); $this->loadConfiguration($configFile);
$bundles = $this->loadBundles($this->bundles); $bundles = $this->loadBundles($this->bundles);
$targets = $this->loadTargets($this->targets, $bundles); $targets = $this->loadTargets($this->targets, $bundles);
$timestamp = time();
foreach ($targets as $name => $target) { foreach ($targets as $name => $target) {
echo "Creating output bundle '{$name}':\n"; echo "Creating output bundle '{$name}':\n";
if (!empty($target->js)) { if (!empty($target->js)) {
$this->buildTarget($target, 'js', $bundles, $timestamp); $this->buildTarget($target, 'js', $bundles);
} }
if (!empty($target->css)) { if (!empty($target->css)) {
$this->buildTarget($target, 'css', $bundles, $timestamp); $this->buildTarget($target, 'css', $bundles);
} }
echo "\n"; echo "\n";
} }
...@@ -282,14 +281,11 @@ class AssetController extends Controller ...@@ -282,14 +281,11 @@ class AssetController extends Controller
* @param \yii\web\AssetBundle $target output asset bundle * @param \yii\web\AssetBundle $target output asset bundle
* @param string $type either 'js' or 'css'. * @param string $type either 'js' or 'css'.
* @param \yii\web\AssetBundle[] $bundles source asset bundles. * @param \yii\web\AssetBundle[] $bundles source asset bundles.
* @param integer $timestamp current timestamp.
* @throws Exception on failure. * @throws Exception on failure.
*/ */
protected function buildTarget($target, $type, $bundles, $timestamp) protected function buildTarget($target, $type, $bundles)
{ {
$outputFile = strtr($target->$type, [ $tempFile = $target->basePath . '/' . strtr($target->$type, ['{hash}' => 'temp']);
'{ts}' => $timestamp,
]);
$inputFiles = []; $inputFiles = [];
foreach ($target->depends as $name) { foreach ($target->depends as $name) {
...@@ -302,10 +298,13 @@ class AssetController extends Controller ...@@ -302,10 +298,13 @@ class AssetController extends Controller
} }
} }
if ($type === 'js') { if ($type === 'js') {
$this->compressJsFiles($inputFiles, $target->basePath . '/' . $outputFile); $this->compressJsFiles($inputFiles, $tempFile);
} else { } else {
$this->compressCssFiles($inputFiles, $target->basePath . '/' . $outputFile); $this->compressCssFiles($inputFiles, $tempFile);
} }
$outputFile = $target->basePath . '/' . strtr($target->$type, ['{hash}' => md5_file($tempFile)]);
rename($tempFile, $outputFile);
$target->$type = [$outputFile]; $target->$type = [$outputFile];
} }
...@@ -599,8 +598,8 @@ return [ ...@@ -599,8 +598,8 @@ return [
'app\assets\AllAsset' => [ 'app\assets\AllAsset' => [
'basePath' => 'path/to/web', 'basePath' => 'path/to/web',
'baseUrl' => '', 'baseUrl' => '',
'js' => 'js/all-{ts}.js', 'js' => 'js/all-{hash}.js',
'css' => 'css/all-{ts}.css', 'css' => 'css/all-{hash}.css',
], ],
], ],
// Asset manager configuration: // Asset manager configuration:
......
...@@ -30,9 +30,9 @@ class QueryBuilder extends \yii\db\QueryBuilder ...@@ -30,9 +30,9 @@ class QueryBuilder extends \yii\db\QueryBuilder
Schema::TYPE_BIGINT => 'bigint', Schema::TYPE_BIGINT => 'bigint',
Schema::TYPE_FLOAT => 'double precision', Schema::TYPE_FLOAT => 'double precision',
Schema::TYPE_DECIMAL => 'numeric(10,0)', Schema::TYPE_DECIMAL => 'numeric(10,0)',
Schema::TYPE_DATETIME => 'timestamp', Schema::TYPE_DATETIME => 'timestamp(0)',
Schema::TYPE_TIMESTAMP => 'timestamp', Schema::TYPE_TIMESTAMP => 'timestamp(0)',
Schema::TYPE_TIME => 'time', Schema::TYPE_TIME => 'time(0)',
Schema::TYPE_DATE => 'date', Schema::TYPE_DATE => 'date',
Schema::TYPE_BINARY => 'bytea', Schema::TYPE_BINARY => 'bytea',
Schema::TYPE_BOOLEAN => 'boolean', Schema::TYPE_BOOLEAN => 'boolean',
......
...@@ -26,49 +26,83 @@ class Schema extends \yii\db\Schema ...@@ -26,49 +26,83 @@ class Schema extends \yii\db\Schema
/** /**
* @var array mapping from physical column types (keys) to abstract * @var array mapping from physical column types (keys) to abstract
* column types (values) * column types (values)
* @see http://www.postgresql.org/docs/current/static/datatype.html#DATATYPE-TABLE
*/ */
public $typeMap = [ public $typeMap = [
'abstime' => self::TYPE_TIMESTAMP,
'bit' => self::TYPE_STRING, 'bit' => self::TYPE_STRING,
'bit varying' => self::TYPE_STRING,
'varbit' => self::TYPE_STRING,
'bool' => self::TYPE_BOOLEAN, 'bool' => self::TYPE_BOOLEAN,
'boolean' => self::TYPE_BOOLEAN, 'boolean' => self::TYPE_BOOLEAN,
'box' => self::TYPE_STRING, 'box' => self::TYPE_STRING,
'circle' => self::TYPE_STRING,
'point' => self::TYPE_STRING,
'line' => self::TYPE_STRING,
'lseg' => self::TYPE_STRING,
'polygon' => self::TYPE_STRING,
'path' => self::TYPE_STRING,
'character' => self::TYPE_STRING, 'character' => self::TYPE_STRING,
'bytea' => self::TYPE_BINARY,
'char' => self::TYPE_STRING, 'char' => self::TYPE_STRING,
'character varying' => self::TYPE_STRING,
'varchar' => self::TYPE_STRING,
'text' => self::TYPE_TEXT,
'bytea' => self::TYPE_BINARY,
'cidr' => self::TYPE_STRING, 'cidr' => self::TYPE_STRING,
'circle' => self::TYPE_STRING, 'inet' => self::TYPE_STRING,
'date' => self::TYPE_DATE, 'macaddr' => self::TYPE_STRING,
'real' => self::TYPE_FLOAT, 'real' => self::TYPE_FLOAT,
'float4' => self::TYPE_FLOAT,
'double precision' => self::TYPE_FLOAT,
'float8' => self::TYPE_FLOAT,
'decimal' => self::TYPE_DECIMAL, 'decimal' => self::TYPE_DECIMAL,
'double precision' => self::TYPE_DECIMAL, 'numeric' => self::TYPE_DECIMAL,
'inet' => self::TYPE_STRING,
'money' => self::TYPE_MONEY,
'smallint' => self::TYPE_SMALLINT, 'smallint' => self::TYPE_SMALLINT,
'int2' => self::TYPE_INTEGER, 'int2' => self::TYPE_SMALLINT,
'int4' => self::TYPE_INTEGER, 'int4' => self::TYPE_INTEGER,
'int8' => self::TYPE_BIGINT, 'int' => self::TYPE_INTEGER,
'integer' => self::TYPE_INTEGER, 'integer' => self::TYPE_INTEGER,
'bigint' => self::TYPE_BIGINT, 'bigint' => self::TYPE_BIGINT,
'interval' => self::TYPE_STRING, 'int8' => self::TYPE_BIGINT,
'json' => self::TYPE_STRING,
'line' => self::TYPE_STRING,
'macaddr' => self::TYPE_STRING,
'money' => self::TYPE_MONEY,
'name' => self::TYPE_STRING,
'numeric' => self::TYPE_STRING,
'oid' => self::TYPE_BIGINT, // should not be used. it's pg internal! 'oid' => self::TYPE_BIGINT, // should not be used. it's pg internal!
'path' => self::TYPE_STRING,
'point' => self::TYPE_STRING, 'smallserial' => self::TYPE_SMALLINT,
'polygon' => self::TYPE_STRING, 'serial2' => self::TYPE_SMALLINT,
'text' => self::TYPE_TEXT, 'serial4' => self::TYPE_INTEGER,
'serial' => self::TYPE_INTEGER,
'bigserial' => self::TYPE_BIGINT,
'serial8' => self::TYPE_BIGINT,
'pg_lsn' => self::TYPE_BIGINT,
'date' => self::TYPE_DATE,
'interval' => self::TYPE_STRING,
'time without time zone' => self::TYPE_TIME, 'time without time zone' => self::TYPE_TIME,
'time' => self::TYPE_TIME,
'time with time zone' => self::TYPE_TIME,
'timetz' => self::TYPE_TIME,
'timestamp without time zone' => self::TYPE_TIMESTAMP, 'timestamp without time zone' => self::TYPE_TIMESTAMP,
'timestamp' => self::TYPE_TIMESTAMP,
'timestamp with time zone' => self::TYPE_TIMESTAMP, 'timestamp with time zone' => self::TYPE_TIMESTAMP,
'time with time zone' => self::TYPE_TIMESTAMP, 'timestamptz' => self::TYPE_TIMESTAMP,
'abstime' => self::TYPE_TIMESTAMP,
'tsquery' => self::TYPE_STRING,
'tsvector' => self::TYPE_STRING,
'txid_snapshot' => self::TYPE_STRING,
'unknown' => self::TYPE_STRING, 'unknown' => self::TYPE_STRING,
'uuid' => self::TYPE_STRING, 'uuid' => self::TYPE_STRING,
'bit varying' => self::TYPE_STRING, 'json' => self::TYPE_STRING,
'character varying' => self::TYPE_STRING, 'jsonb' => self::TYPE_STRING,
'xml' => self::TYPE_STRING 'xml' => self::TYPE_STRING
]; ];
......
...@@ -139,7 +139,7 @@ class QueryBuilder extends \yii\db\QueryBuilder ...@@ -139,7 +139,7 @@ class QueryBuilder extends \yii\db\QueryBuilder
*/ */
public function checkIntegrity($check = true, $schema = '', $table = '') public function checkIntegrity($check = true, $schema = '', $table = '')
{ {
throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.'); return 'PRAGMA foreign_keys='.(int)$check;
} }
/** /**
......
...@@ -51,7 +51,7 @@ class DataColumn extends Column ...@@ -51,7 +51,7 @@ class DataColumn extends Column
public $label; public $label;
/** /**
* @var string|\Closure an anonymous function that returns the value to be displayed for every data model. * @var string|\Closure an anonymous function that returns the value to be displayed for every data model.
* The signature of this function is `function ($model, $index, $widget)`. * The signature of this function is `function ($model, $key, $index, $widget)`.
* If this is not set, `$model[$attribute]` will be used to obtain the value. * If this is not set, `$model[$attribute]` will be used to obtain the value.
* *
* You may also set this property to a string representing the attribute name to be displayed in this column. * You may also set this property to a string representing the attribute name to be displayed in this column.
...@@ -176,7 +176,7 @@ class DataColumn extends Column ...@@ -176,7 +176,7 @@ class DataColumn extends Column
if (is_string($this->value)) { if (is_string($this->value)) {
return ArrayHelper::getValue($model, $this->value); return ArrayHelper::getValue($model, $this->value);
} else { } else {
return call_user_func($this->value, $model, $index, $this); return call_user_func($this->value, $model, $key, $index, $this);
} }
} elseif ($this->attribute !== null) { } elseif ($this->attribute !== null) {
return ArrayHelper::getValue($model, $this->attribute); return ArrayHelper::getValue($model, $this->attribute);
......
...@@ -129,7 +129,6 @@ class BaseHtml ...@@ -129,7 +129,6 @@ class BaseHtml
public static function tag($name, $content = '', $options = []) public static function tag($name, $content = '', $options = [])
{ {
$html = "<$name" . static::renderTagAttributes($options) . '>'; $html = "<$name" . static::renderTagAttributes($options) . '>';
return isset(static::$voidElements[strtolower($name)]) ? $html : "$html$content</$name>"; return isset(static::$voidElements[strtolower($name)]) ? $html : "$html$content</$name>";
} }
...@@ -337,7 +336,6 @@ class BaseHtml ...@@ -337,7 +336,6 @@ class BaseHtml
if ($url !== null) { if ($url !== null) {
$options['href'] = Url::to($url); $options['href'] = Url::to($url);
} }
return static::tag('a', $text, $options); return static::tag('a', $text, $options);
} }
...@@ -357,7 +355,6 @@ class BaseHtml ...@@ -357,7 +355,6 @@ class BaseHtml
public static function mailto($text, $email = null, $options = []) public static function mailto($text, $email = null, $options = [])
{ {
$options['href'] = 'mailto:' . ($email === null ? $text : $email); $options['href'] = 'mailto:' . ($email === null ? $text : $email);
return static::tag('a', $text, $options); return static::tag('a', $text, $options);
} }
...@@ -376,7 +373,6 @@ class BaseHtml ...@@ -376,7 +373,6 @@ class BaseHtml
if (!isset($options['alt'])) { if (!isset($options['alt'])) {
$options['alt'] = ''; $options['alt'] = '';
} }
return static::tag('img', '', $options); return static::tag('img', '', $options);
} }
...@@ -396,7 +392,6 @@ class BaseHtml ...@@ -396,7 +392,6 @@ class BaseHtml
public static function label($content, $for = null, $options = []) public static function label($content, $for = null, $options = [])
{ {
$options['for'] = $for; $options['for'] = $for;
return static::tag('label', $content, $options); return static::tag('label', $content, $options);
} }
...@@ -430,7 +425,6 @@ class BaseHtml ...@@ -430,7 +425,6 @@ class BaseHtml
public static function submitButton($content = 'Submit', $options = []) public static function submitButton($content = 'Submit', $options = [])
{ {
$options['type'] = 'submit'; $options['type'] = 'submit';
return static::button($content, $options); return static::button($content, $options);
} }
...@@ -448,7 +442,6 @@ class BaseHtml ...@@ -448,7 +442,6 @@ class BaseHtml
public static function resetButton($content = 'Reset', $options = []) public static function resetButton($content = 'Reset', $options = [])
{ {
$options['type'] = 'reset'; $options['type'] = 'reset';
return static::button($content, $options); return static::button($content, $options);
} }
...@@ -468,7 +461,6 @@ class BaseHtml ...@@ -468,7 +461,6 @@ class BaseHtml
$options['type'] = $type; $options['type'] = $type;
$options['name'] = $name; $options['name'] = $name;
$options['value'] = $value === null ? null : (string) $value; $options['value'] = $value === null ? null : (string) $value;
return static::tag('input', '', $options); return static::tag('input', '', $options);
} }
...@@ -485,7 +477,6 @@ class BaseHtml ...@@ -485,7 +477,6 @@ class BaseHtml
{ {
$options['type'] = 'button'; $options['type'] = 'button';
$options['value'] = $label; $options['value'] = $label;
return static::tag('input', '', $options); return static::tag('input', '', $options);
} }
...@@ -502,7 +493,6 @@ class BaseHtml ...@@ -502,7 +493,6 @@ class BaseHtml
{ {
$options['type'] = 'submit'; $options['type'] = 'submit';
$options['value'] = $label; $options['value'] = $label;
return static::tag('input', '', $options); return static::tag('input', '', $options);
} }
...@@ -518,7 +508,6 @@ class BaseHtml ...@@ -518,7 +508,6 @@ class BaseHtml
{ {
$options['type'] = 'reset'; $options['type'] = 'reset';
$options['value'] = $label; $options['value'] = $label;
return static::tag('input', '', $options); return static::tag('input', '', $options);
} }
...@@ -598,7 +587,6 @@ class BaseHtml ...@@ -598,7 +587,6 @@ class BaseHtml
public static function textarea($name, $value = '', $options = []) public static function textarea($name, $value = '', $options = [])
{ {
$options['name'] = $name; $options['name'] = $name;
return static::tag('textarea', static::encode($value), $options); return static::tag('textarea', static::encode($value), $options);
} }
...@@ -992,7 +980,6 @@ class BaseHtml ...@@ -992,7 +980,6 @@ class BaseHtml
$results[] = static::tag('li', $encode ? static::encode($item) : $item, $itemOptions); $results[] = static::tag('li', $encode ? static::encode($item) : $item, $itemOptions);
} }
} }
return static::tag($tag, "\n" . implode("\n", $results) . "\n", $options); return static::tag($tag, "\n" . implode("\n", $results) . "\n", $options);
} }
...@@ -1022,7 +1009,6 @@ class BaseHtml ...@@ -1022,7 +1009,6 @@ class BaseHtml
public static function ol($items, $options = []) public static function ol($items, $options = [])
{ {
$options['tag'] = 'ol'; $options['tag'] = 'ol';
return static::ul($items, $options); return static::ul($items, $options);
} }
...@@ -1051,7 +1037,6 @@ class BaseHtml ...@@ -1051,7 +1037,6 @@ class BaseHtml
$attribute = static::getAttributeName($attribute); $attribute = static::getAttributeName($attribute);
$label = isset($options['label']) ? $options['label'] : static::encode($model->getAttributeLabel($attribute)); $label = isset($options['label']) ? $options['label'] : static::encode($model->getAttributeLabel($attribute));
unset($options['label'], $options['for']); unset($options['label'], $options['for']);
return static::label($label, $for, $options); return static::label($label, $for, $options);
} }
...@@ -1118,7 +1103,6 @@ class BaseHtml ...@@ -1118,7 +1103,6 @@ class BaseHtml
$error = $model->getFirstError($attribute); $error = $model->getFirstError($attribute);
$tag = isset($options['tag']) ? $options['tag'] : 'div'; $tag = isset($options['tag']) ? $options['tag'] : 'div';
unset($options['tag']); unset($options['tag']);
return Html::tag($tag, Html::encode($error), $options); return Html::tag($tag, Html::encode($error), $options);
} }
...@@ -1142,7 +1126,6 @@ class BaseHtml ...@@ -1142,7 +1126,6 @@ class BaseHtml
if (!array_key_exists('id', $options)) { if (!array_key_exists('id', $options)) {
$options['id'] = static::getInputId($model, $attribute); $options['id'] = static::getInputId($model, $attribute);
} }
return static::input($type, $name, $value, $options); return static::input($type, $name, $value, $options);
} }
...@@ -1235,7 +1218,6 @@ class BaseHtml ...@@ -1235,7 +1218,6 @@ class BaseHtml
if (!array_key_exists('id', $options)) { if (!array_key_exists('id', $options)) {
$options['id'] = static::getInputId($model, $attribute); $options['id'] = static::getInputId($model, $attribute);
} }
return static::textarea($name, $value, $options); return static::textarea($name, $value, $options);
} }
...@@ -1518,7 +1500,6 @@ class BaseHtml ...@@ -1518,7 +1500,6 @@ class BaseHtml
if (!array_key_exists('id', $options)) { if (!array_key_exists('id', $options)) {
$options['id'] = static::getInputId($model, $attribute); $options['id'] = static::getInputId($model, $attribute);
} }
return static::$type($name, $selection, $items, $options); return static::$type($name, $selection, $items, $options);
} }
...@@ -1775,7 +1756,6 @@ class BaseHtml ...@@ -1775,7 +1756,6 @@ class BaseHtml
$result[trim($property[0])] = trim($property[1]); $result[trim($property[0])] = trim($property[1]);
} }
} }
return $result; return $result;
} }
...@@ -1899,7 +1879,6 @@ class BaseHtml ...@@ -1899,7 +1879,6 @@ class BaseHtml
public static function getInputId($model, $attribute) public static function getInputId($model, $attribute)
{ {
$name = strtolower(static::getInputName($model, $attribute)); $name = strtolower(static::getInputName($model, $attribute));
return str_replace(['[]', '][', '[', ']', ' ', '.'], ['', '-', '-', '', '-', '-'], $name);
return str_replace(['[]', '][', '[', ']', ' '], ['', '-', '-', '', '-'], $name);
} }
} }
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
<?php if ($method !== null): ?> <?php if ($method !== null): ?>
<span class="call"> <span class="call">
<?php if ($file !== null) echo '&ndash;' ?> <?php if ($file !== null) echo '&ndash;' ?>
<?= $class !== null ? $handler->addTypeLinks("$class::$method(" . $handler->argumentsToString($args) . ")") : $handler->htmlEncode($method) . '(' . $handler->argumentsToString($args) . ')' ?> <?= ($class !== null ? $handler->addTypeLinks("$class::$method") : $handler->htmlEncode($method)) . '(' . $handler->argumentsToString($args) . ')' ?>
</span> </span>
<?php endif; ?> <?php endif; ?>
<span class="at"><?php if ($line !== null) echo 'at line'; ?></span> <span class="at"><?php if ($line !== null) echo 'at line'; ?></span>
......
...@@ -156,11 +156,10 @@ class ErrorHandler extends \yii\base\ErrorHandler ...@@ -156,11 +156,10 @@ class ErrorHandler extends \yii\base\ErrorHandler
*/ */
public function addTypeLinks($code) public function addTypeLinks($code)
{ {
if (preg_match('/(.*?)::([^(]+)\((.*)\)/', $code, $matches)) { if (preg_match('/(.*?)::([^(]+)/', $code, $matches)) {
$class = $matches[1]; $class = $matches[1];
$method = $matches[2]; $method = $matches[2];
$args = $matches[3]; $text = $this->htmlEncode($class) . '::' . $this->htmlEncode($method);
$text = $this->htmlEncode($class) . '::' . $this->htmlEncode($method) . '(' . $args . ')';
} else { } else {
$class = $code; $class = $code;
$text = $this->htmlEncode($class); $text = $this->htmlEncode($class);
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
namespace yiiunit\framework\helpers; namespace yiiunit\framework\helpers;
use Yii; use Yii;
use yii\base\DynamicModel;
use yii\helpers\Html; use yii\helpers\Html;
use yiiunit\TestCase; use yiiunit\TestCase;
...@@ -157,6 +158,13 @@ class HtmlTest extends TestCase ...@@ -157,6 +158,13 @@ class HtmlTest extends TestCase
$this->assertEquals('<button type="reset" class="t" name="test" value="value">content<></button>', Html::resetButton('content<>', ['name' => 'test', 'value' => 'value', 'class' => 't'])); $this->assertEquals('<button type="reset" class="t" name="test" value="value">content<></button>', Html::resetButton('content<>', ['name' => 'test', 'value' => 'value', 'class' => 't']));
} }
public function testInputId()
{
$model = new DynamicModel(['test', 'relation.name']);
$this->assertEquals('<input type="text" id="dynamicmodel-test" name="DynamicModel[test]">', Html::activeTextInput($model, 'test'));
$this->assertEquals('<input type="text" id="dynamicmodel-relation-name" name="DynamicModel[relation.name]">', Html::activeTextInput($model, 'relation.name'));
}
public function testInput() public function testInput()
{ {
$this->assertEquals('<input type="text">', Html::input('text')); $this->assertEquals('<input type="text">', Html::input('text'));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment