Browse Source

Merge branch 'master' into docs-guide-ja-0302

tags/2.0.4
Nobuo Kihara 10 years ago
parent
commit
972a43e75c
  1. 111
      docs/guide/db-query-builder.md
  2. 12
      docs/guide/input-file-upload.md
  3. 4
      docs/guide/runtime-routing.md
  4. 2
      docs/guide/start-installation.md
  5. 22
      docs/internals/versions.md
  6. 1
      extensions/jui/InputWidget.php
  7. 2
      extensions/jui/README.md
  8. 5
      framework/CHANGELOG.md
  9. 11
      framework/base/Component.php
  10. 4
      framework/base/Object.php
  11. 60
      framework/console/controllers/HelpController.php
  12. 40
      framework/helpers/BaseConsole.php
  13. 21
      framework/helpers/BaseHtml.php
  14. 31
      framework/helpers/BaseStringHelper.php
  15. 79
      framework/messages/el/yii.php
  16. 4
      framework/web/AssetManager.php
  17. 4
      framework/web/Response.php
  18. 80
      framework/widgets/ActiveField.php
  19. 2
      tests/unit/data/postgres.sql
  20. 9
      tests/unit/framework/helpers/StringHelperTest.php
  21. 19
      tests/unit/framework/web/ResponseTest.php

111
docs/guide/db-query-builder.md

@ -1,65 +1,88 @@
Query Builder and Query Query Builder
======================= =============
> Note: This section is under development. > Note: This section is under development.
Yii provides a basic database access layer as described in the [Database basics](db-dao.md) section. Built on top of [Database Access Objects](db-dao.md), query builder allows you to construct a SQL statement
The database access layer provides a low-level way to interact with the database. While useful in some situations, in a programmatic way. Compared to writing raw SQLs, using query builder will help you write more readable
it can be tedious and error-prone to write raw SQLs. An alternative approach is to use the Query Builder. SQL-related code and generate more secure SQL statements.
The Query Builder provides an object-oriented vehicle for generating queries to be executed.
A typical usage of the query builder looks like the following: Using query builder usually involves two steps:
1. Build a [[yii\db\Query]] object to represent different parts (e.g. `SELECT`, `FROM`) of a SELECT SQL statement.
2. Execute a query method (e.g. `all()`) of [[yii\db\Query]].
Behind the scene, [[yii\db\QueryBuilder]] is invoked in the second step to convert a [[yii\db\Query]] object into
a SQL statement for the particular DBMS.
The following code shows a typical use case of query builder:
```php ```php
$rows = (new \yii\db\Query()) $rows = (new \yii\db\Query())
->select('id, name') ->select('id, email')
->from('user') ->from('user')
->where(['name' => 'Smith'])
->limit(10) ->limit(10)
->all(); ->all();
```
// which is equivalent to the following code: It generates and executes the following SQL statement:
$query = (new \yii\db\Query())
->select('id, name')
->from('user')
->limit(10);
// Create a command. You can get the actual SQL using $command->sql
$command = $query->createCommand();
// Execute the command: ```sql
$rows = $command->queryAll(); SELECT `id`, `email`
FROM `user`
WHERE `name` = :name
LIMIT 10
``` ```
Query Methods where the `:name` parameter is bound with the string `'Smith'`. Depending on the DBMS being used, query builder
------------- will properly quote the column and table names and bind parameter values to the generated SQL statement.
As you can see, [[yii\db\Query]] is the main player that you need to deal with. Behind the scenes, ## Query Methods <span id="query-methods"></span>
`Query` is actually only responsible for representing various query information. The actual query
building logic is done by [[yii\db\QueryBuilder]] when you call the `createCommand()` method,
and the query execution is done by [[yii\db\Command]].
For convenience, [[yii\db\Query]] provides a set of commonly used query methods that will build [[yii\db\Query]] provides a whole set of methods for different query purposes:
the query, execute it, and return the result. For example,
- [[yii\db\Query::all()|all()]]: builds the query, executes it and returns all results as an array. - [[yii\db\Query::all()|all()]]: returns an array of rows with each row being an associative array of name-value pairs.
- [[yii\db\Query::one()|one()]]: returns the first row of the result. - [[yii\db\Query::one()|one()]]: returns the first row of the result.
- [[yii\db\Query::column()|column()]]: returns the first column of the result. - [[yii\db\Query::column()|column()]]: returns the first column of the result.
- [[yii\db\Query::scalar()|scalar()]]: returns the first column in the first row of the result. - [[yii\db\Query::scalar()|scalar()]]: returns a scalar value located at the first row and first column of the result.
- [[yii\db\Query::exists()|exists()]]: returns a value indicating whether the query results in anything. - [[yii\db\Query::exists()|exists()]]: returns a value indicating whether the query contains any result.
- [[yii\db\Query::count()|count()]]: returns the result of a `COUNT` query. Other similar methods - [[yii\db\Query::count()|count()]]: returns the result of a `COUNT` query.
include `sum($q)`, `average($q)`, `max($q)` and `min($q)`, which support the so-called aggregational data query. The `$q` - Other aggregation query methods, including [[yii\db\Query::sum()|sum($q)]], [[yii\db\Query::average()|average($q)]],
parameter is mandatory for these methods and can be either the column name or expression. [[yii\db\Query::max()|max($q)]], [[yii\db\Query::min()|min($q)]]. The `$q` parameter is mandatory for these methods
and can be either a column name or a DB expression.
All of the above methods take an optional `$db` parameter representing the [[yii\db\Connection|DB connection]] that
should be used to perform a DB query. If you omit this parameter, the `db` application component will be used
as the DB connection.
Building Query Given a [[yii\db\Query]], you can create a [[yii\db\Command]] and further work with this command object. For example,
--------------
In the following, we will explain how to build various clauses in a SQL statement. For simplicity, ```php
we use `$query` to represent a [[yii\db\Query]] object. $command = (new \yii\db\Query())
->select('id, email')
->from('user')
->where(['name' => 'Smith'])
->limit(10)
->createCommand();
// show the SQL statement
echo $command->sql;
// returns all rows of the query result
$rows= $command->queryAll();
```
### `SELECT` ## Building Queries <span id="building-queries"></span>
To build a [[yii\db\Query]] object, you call different query building methods to specify different parts of
a SQL statement. The names of these methods resemble the SQL keywords used in the corresponding parts of the SQL
statement. For example, to specify the `FROM` part, you would call the `from()` method. In the following, we will
describe in detail the usage of each query building method.
### `SELECT` <span id="select"></span>
In order to form a basic `SELECT` query, you need to specify what columns to select and from what table: In order to form a basic `SELECT` query, you need to specify what columns to select and from what table:
@ -100,7 +123,7 @@ To select distinct rows, you may call `distinct()`, like the following:
$query->select('user_id')->distinct()->from('post'); $query->select('user_id')->distinct()->from('post');
``` ```
### `FROM` ### `FROM` <span id="from"></span>
To specify which table(s) to select data from, call `from()`: To specify which table(s) to select data from, call `from()`:
@ -133,7 +156,7 @@ $query->select('*')->from(['u' => $subQuery]);
``` ```
### `WHERE` ### `WHERE` <span id="where"></span>
Usually data is selected based upon certain criteria. Query Builder has some useful methods to specify these, the most powerful of which being `where`. It can be used in multiple ways. Usually data is selected based upon certain criteria. Query Builder has some useful methods to specify these, the most powerful of which being `where`. It can be used in multiple ways.
@ -321,7 +344,7 @@ A value is *empty* if it is null, an empty string, a string consisting of whites
You may also use `andFilterWhere()` and `orFilterWhere()` to append more filter conditions. You may also use `andFilterWhere()` and `orFilterWhere()` to append more filter conditions.
### `ORDER BY` ### `ORDER BY` <span id="order-by"></span>
For ordering results `orderBy` and `addOrderBy` could be used: For ordering results `orderBy` and `addOrderBy` could be used:
@ -420,9 +443,11 @@ $anotherQuery->select('id, type, name')->from('user')->limit(10);
$query->union($anotherQuery); $query->union($anotherQuery);
``` ```
## Indexing Query Results <span id="indexing-query-results"></span>
TBD
Batch Query ## Batch Query <span id="batch-query"></span>
-----------
When working with large amounts of data, methods such as [[yii\db\Query::all()]] are not suitable When working with large amounts of data, methods such as [[yii\db\Query::all()]] are not suitable
because they require loading all data into the memory. To keep the memory requirement low, Yii because they require loading all data into the memory. To keep the memory requirement low, Yii

12
docs/guide/input-file-upload.md

@ -141,18 +141,24 @@ It is wise to validate the type of file uploaded. FileValidator has the property
public function rules() public function rules()
{ {
return [ return [
[['file'], 'file', 'extensions' => 'gif, jpg',], [['file'], 'file', 'extensions' => 'gif, jpg'],
]; ];
} }
``` ```
Keep in mind that only the file extension will be validated, but not the actual file content. In order to validate the content as well, use the `mimeTypes` property of `FileValidator`: By default it will validate against file content mime type corresponding to extension specified. For gif it will be
`image/gif`, for `jpg` it will be `image/jpeg`.
Note that some mime types can't be detected properly by PHP's fileinfo extension that is used by `file` validator. For
example, `csv` files are detected as `text/plain` instead of `text/csv`. You can turn off such behavior by setting
`checkExtensionByMimeType` to `false` and specifying mime types manually:
```php ```php
public function rules() public function rules()
{ {
return [ return [
[['file'], 'file', 'extensions' => 'jpg, png', 'mimeTypes' => 'image/jpeg, image/png',], [['file'], 'file', 'checkExtensionByMimeType' => false, 'extensions' => 'csv', 'mimeTypes' => 'text/plain'],
]; ];
} }
``` ```

4
docs/guide/runtime-routing.md

@ -42,7 +42,7 @@ The [[yii\web\UrlManager|URL manager]] supports two URL formats: the default URL
The default URL format uses a query parameter named `r` to represent the route and normal query parameters The default URL format uses a query parameter named `r` to represent the route and normal query parameters
to represent the query parameters associated with the route. For example, the URL `/index.php?r=post/view&id=100` represents to represent the query parameters associated with the route. For example, the URL `/index.php?r=post/view&id=100` represents
the route `post/view` and the `id` query parameter 100. The default URL format does not require any configuration about the route `post/view` and the `id` query parameter 100. The default URL format does not require any configuration of
the [[yii\web\UrlManager|URL manager]] and works in any Web server setup. the [[yii\web\UrlManager|URL manager]] and works in any Web server setup.
The pretty URL format uses the extra path following the entry script name to represent the route and the associated The pretty URL format uses the extra path following the entry script name to represent the route and the associated
@ -275,7 +275,7 @@ The rest of the properties are optional. However, their configuration shown abov
A URL rule is an instance of [[yii\web\UrlRule]] or its child class. Each URL rule consists of a pattern used A URL rule is an instance of [[yii\web\UrlRule]] or its child class. Each URL rule consists of a pattern used
for matching the path info part of URLs, a route, and a few query parameters. A URL rule can be used to parse a request for matching the path info part of URLs, a route, and a few query parameters. A URL rule can be used to parse a request
if its pattern matches the requested URL and a URL rule can be used to create a URL if its route and query parameter if its pattern matches the requested URL. A URL rule can be used to create a URL if its route and query parameter
names match those that are given. names match those that are given.
When the pretty URL format is enabled, the [[yii\web\UrlManager|URL manager]] uses the URL rules declared in its When the pretty URL format is enabled, the [[yii\web\UrlManager|URL manager]] uses the URL rules declared in its

2
docs/guide/start-installation.md

@ -185,7 +185,7 @@ server {
root /path/to/basic/web; root /path/to/basic/web;
index index.php; index index.php;
access_log /path/to/basic/log/access.log main; access_log /path/to/basic/log/access.log;
error_log /path/to/basic/log/error.log; error_log /path/to/basic/log/error.log;
location / { location / {

22
docs/internals/versions.md

@ -1,10 +1,22 @@
Yii Versioning Yii Versioning
============== ==============
This document summarizes the versioning policy of Yii. In general, Yii follows the [Semantic Versioning](http://semver.org/). This document summarizes the versioning policy of Yii. Our current versioning strategy can be
described as [ferver](https://github.com/jonathanong/ferver), which we considered is more practical
and reasonable than [Semantic Versioning](http://semver.org/) (See [#7408](https://github.com/yiisoft/yii2/issues/7408) for more references).
Within the core developer team, we have emphasized several times that it is important to keep 2.0.x releases 100% BC-compatible.
But this is an ideal plan. The ferver article has given out a real world example that this is hard to achieve in practice,
regardless you are using semver or not.
In summary, our versioning policy is as follows:
## Patch Releases `2.x.Y` ## Patch Releases `2.x.Y`
Patch releases, which should be 100% BC-compatible. Ideally, we hope they contain bug fixes only so that it reduces
the chance of breaking BC. Practically, since 2.0.x is released more frequently, we are also adding minor features
to it so that users can enjoy them earlier.
* Maintained on a branch named `2.x` * Maintained on a branch named `2.x`
* Mainly contain bug fixes and minor feature enhancements * Mainly contain bug fixes and minor feature enhancements
* No major features. * No major features.
@ -16,6 +28,9 @@ This document summarizes the versioning policy of Yii. In general, Yii follows t
## Minor Releases `2.X.0` ## Minor Releases `2.X.0`
BC-breaking releases, which contains major features and changes that may break BC. Upgrading from earlier versions may
not be trivial, but a complete upgrade guide or even script will be available.
* Developed on master branch * Developed on master branch
* Mainly contain new features and bug fixes * Mainly contain new features and bug fixes
* Contain minor features and bug fixes merged from patch releases * Contain minor features and bug fixes merged from patch releases
@ -27,4 +42,5 @@ This document summarizes the versioning policy of Yii. In general, Yii follows t
## Major Releases `X.0.0` ## Major Releases `X.0.0`
None in plan. It's like 2.0 over 1.0. We expect this only happens every 3 to 5 years, depending on external technology advancement
(such as PHP upgraded from 5.0 to 5.4).

1
extensions/jui/InputWidget.php

@ -8,7 +8,6 @@
namespace yii\jui; namespace yii\jui;
use yii\base\Model; use yii\base\Model;
use yii\base\InvalidConfigException;
use yii\helpers\Html; use yii\helpers\Html;
/** /**

2
extensions/jui/README.md

@ -30,7 +30,7 @@ to the require section of your `composer.json` file.
Usage Usage
----- -----
Fhe following The following
single line of code in a view file would render a [JQuery UI DatePicker](http://api.jqueryui.com/datepicker/) widget: single line of code in a view file would render a [JQuery UI DatePicker](http://api.jqueryui.com/datepicker/) widget:
```php ```php

5
framework/CHANGELOG.md

@ -4,7 +4,10 @@ Yii Framework 2 Change Log
2.0.4 under development 2.0.4 under development
----------------------- -----------------------
- no changes in this release. - Bug #7529: Fixed `yii\web\Response::sendContentAsFile()` that was broken in 2.0.3 (samdark)
- Enh #7488: Added `StringHelper::explode` to perform explode with trimming and skipping of empty elements (SilverFire, nineinchnick, creocoder, samdark)
- Enh #7562: `yii help` now lists all sub-commands by default (callmez)
- Enh: Added `yii\helper\Console::wrapText()` method to wrap indented text by console window width and used it in `yii help` command (cebe)
2.0.3 March 01, 2015 2.0.3 March 01, 2015

11
framework/base/Component.php

@ -199,16 +199,18 @@ class Component extends Object
} }
/** /**
* Checks if a property value is null. * Checks if a property is set, i.e. defined and not null.
* This method will check in the following order and act accordingly: * This method will check in the following order and act accordingly:
* *
* - a property defined by a setter: return whether the property value is null * - a property defined by a setter: return whether the property is set
* - a property of a behavior: return whether the property value is null * - a property of a behavior: return whether the property is set
* - return `false` for non existing properties
* *
* Do not call this method directly as it is a PHP magic method that * Do not call this method directly as it is a PHP magic method that
* will be implicitly called when executing `isset($component->property)`. * will be implicitly called when executing `isset($component->property)`.
* @param string $name the property name or the event name * @param string $name the property name or the event name
* @return boolean whether the named property is null * @return boolean whether the named property is set
* @see http://php.net/manual/en/function.isset.php
*/ */
public function __isset($name) public function __isset($name)
{ {
@ -238,6 +240,7 @@ class Component extends Object
* will be implicitly called when executing `unset($component->property)`. * will be implicitly called when executing `unset($component->property)`.
* @param string $name the property name * @param string $name the property name
* @throws InvalidCallException if the property is read only. * @throws InvalidCallException if the property is read only.
* @see http://php.net/manual/en/function.unset.php
*/ */
public function __unset($name) public function __unset($name)
{ {

4
framework/base/Object.php

@ -163,7 +163,7 @@ class Object implements Configurable
} }
/** /**
* Checks if the named property is set (not null). * Checks if a property is set, i.e. defined and not null.
* *
* Do not call this method directly as it is a PHP magic method that * Do not call this method directly as it is a PHP magic method that
* will be implicitly called when executing `isset($object->property)`. * will be implicitly called when executing `isset($object->property)`.
@ -171,6 +171,7 @@ class Object implements Configurable
* Note that if the property is not defined, false will be returned. * Note that if the property is not defined, false will be returned.
* @param string $name the property name or the event name * @param string $name the property name or the event name
* @return boolean whether the named property is set (not null). * @return boolean whether the named property is set (not null).
* @see http://php.net/manual/en/function.isset.php
*/ */
public function __isset($name) public function __isset($name)
{ {
@ -192,6 +193,7 @@ class Object implements Configurable
* If the property is read-only, it will throw an exception. * If the property is read-only, it will throw an exception.
* @param string $name the property name * @param string $name the property name
* @throws InvalidCallException if the property is read only. * @throws InvalidCallException if the property is read only.
* @see http://php.net/manual/en/function.unset.php
*/ */
public function __unset($name) public function __unset($name)
{ {

60
framework/console/controllers/HelpController.php

@ -187,14 +187,56 @@ class HelpController extends Controller
$this->stdout("\nThe following commands are available:\n\n", Console::BOLD); $this->stdout("\nThe following commands are available:\n\n", Console::BOLD);
$len = 0; $len = 0;
foreach ($commands as $command => $description) { foreach ($commands as $command => $description) {
if (($l = strlen($command)) > $len) { $result = Yii::$app->createController($command);
if ($result !== false) {
/** @var $controller Controller */
list($controller, $actionID) = $result;
$actions = $this->getActions($controller);
if (!empty($actions)) {
$prefix = $controller->getUniqueId();
foreach ($actions as $action) {
$string = $prefix . '/' . $action;
if ($action === $controller->defaultAction) {
$string .= ' (default)';
}
if (($l = strlen($string)) > $len) {
$len = $l;
}
}
}
} elseif (($l = strlen($command)) > $len) {
$len = $l; $len = $l;
} }
} }
foreach ($commands as $command => $description) { foreach ($commands as $command => $description) {
$this->stdout("- " . $this->ansiFormat($command, Console::FG_YELLOW)); $this->stdout('- ' . $this->ansiFormat($command, Console::FG_YELLOW));
$this->stdout(str_repeat(' ', $len + 3 - strlen($command)) . $description); $this->stdout(str_repeat(' ', $len + 4 - strlen($command)));
$this->stdout(Console::wrapText($description, $len + 4 + 2), Console::BOLD);
$this->stdout("\n"); $this->stdout("\n");
$result = Yii::$app->createController($command);
if ($result !== false) {
list($controller, $actionID) = $result;
$actions = $this->getActions($controller);
if (!empty($actions)) {
$prefix = $controller->getUniqueId();
foreach ($actions as $action) {
$string = ' ' . $prefix . '/' . $action;
$this->stdout(' ' . $this->ansiFormat($string, Console::FG_GREEN));
if ($action === $controller->defaultAction) {
$string .= ' (default)';
$this->stdout(' (default)', Console::FG_YELLOW);
}
$summary = $controller->getActionHelpSummary($controller->createAction($action));
if ($summary !== '') {
$this->stdout(str_repeat(' ', $len + 4 - strlen($string)));
$this->stdout(Console::wrapText($summary, $len + 4 + 2));
}
$this->stdout("\n");
}
}
$this->stdout("\n");
}
} }
$scriptName = $this->getScriptName(); $scriptName = $this->getScriptName();
$this->stdout("\nTo see the help of each command, enter:\n", Console::BOLD); $this->stdout("\nTo see the help of each command, enter:\n", Console::BOLD);
@ -223,14 +265,24 @@ class HelpController extends Controller
if (!empty($actions)) { if (!empty($actions)) {
$this->stdout("\nSUB-COMMANDS\n\n", Console::BOLD); $this->stdout("\nSUB-COMMANDS\n\n", Console::BOLD);
$prefix = $controller->getUniqueId(); $prefix = $controller->getUniqueId();
$maxlen = 5;
foreach ($actions as $action) {
$len = strlen($prefix.'/'.$action) + 2 + ($action === $controller->defaultAction ? 10 : 0);
if ($maxlen < $len) {
$maxlen = $len;
}
}
foreach ($actions as $action) { foreach ($actions as $action) {
$this->stdout('- ' . $this->ansiFormat($prefix.'/'.$action, Console::FG_YELLOW)); $this->stdout('- ' . $this->ansiFormat($prefix.'/'.$action, Console::FG_YELLOW));
$len = strlen($prefix.'/'.$action) + 2;
if ($action === $controller->defaultAction) { if ($action === $controller->defaultAction) {
$this->stdout(' (default)', Console::FG_GREEN); $this->stdout(' (default)', Console::FG_GREEN);
$len += 10;
} }
$summary = $controller->getActionHelpSummary($controller->createAction($action)); $summary = $controller->getActionHelpSummary($controller->createAction($action));
if ($summary !== '') { if ($summary !== '') {
$this->stdout(': ' . $summary); $this->stdout(str_repeat(' ', $maxlen - $len + 2) . Console::wrapText($summary, $maxlen + 2));
} }
$this->stdout("\n"); $this->stdout("\n");
} }

40
framework/helpers/BaseConsole.php

@ -636,6 +636,46 @@ class BaseConsole
} }
/** /**
* Word wrap text with indentation to fit the screen size
*
* If screen size could not be detected, or the indentation is greater than the screen size, the text will not be wrapped.
*
* The first line will **not** be indented, so `Console::wrapText("Lorem ipsum dolor sit amet.", 4)` will result in the
* following output, given the screen width is 16 characters:
*
* ```
* Lorem ipsum
* dolor sit
* amet.
* ```
*
* @param string $text the text to be wrapped
* @param integer $indent number of spaces to use for indentation.
* @param boolean $refresh whether to force refresh of screen size.
* This will be passed to [[getScreenSize()]].
* @return string the wrapped text.
* @since 2.0.3
*/
public static function wrapText($text, $indent = 0, $refresh = false)
{
$size = static::getScreenSize($refresh);
if ($size === false || $size[0] <= $indent) {
return $text;
}
$pad = str_repeat(' ', $indent);
$lines = explode("\n", wordwrap($text, $size[0] - $indent, "\n", true));
$first = true;
foreach($lines as $i => $line) {
if ($first) {
$first = false;
continue;
}
$lines[$i] = $pad . $line;
}
return implode("\n", $lines);
}
/**
* Gets input from STDIN and returns a string right-trimmed for EOLs. * Gets input from STDIN and returns a string right-trimmed for EOLs.
* *
* @param boolean $raw If set to true, returns the raw string without trimming * @param boolean $raw If set to true, returns the raw string without trimming

21
framework/helpers/BaseHtml.php

@ -839,7 +839,7 @@ class BaseHtml
* - encode: boolean, whether to HTML-encode the checkbox labels. Defaults to true. * - encode: boolean, whether to HTML-encode the checkbox labels. Defaults to true.
* This option is ignored if `item` option is set. * This option is ignored if `item` option is set.
* - separator: string, the HTML code that separates items. * - separator: string, the HTML code that separates items.
* - itemOptions: array, the options for generating the radio button tag using [[checkbox()]]. * - itemOptions: array, the options for generating the checkbox tag using [[checkbox()]].
* - item: callable, a callback that can be used to customize the generation of the HTML code * - item: callable, a callback that can be used to customize the generation of the HTML code
* corresponding to a single item in $items. The signature of this callback must be: * corresponding to a single item in $items. The signature of this callback must be:
* *
@ -903,8 +903,10 @@ class BaseHtml
* @param string|array $selection the selected value(s). * @param string|array $selection the selected value(s).
* @param array $items the data item used to generate the radio buttons. * @param array $items the data item used to generate the radio buttons.
* The array keys are the radio button values, while the array values are the corresponding labels. * The array keys are the radio button values, while the array values are the corresponding labels.
* @param array $options options (name => config) for the radio button list. The following options are supported: * @param array $options options (name => config) for the radio button list container tag.
* The following options are specially handled:
* *
* - tag: string, the tag name of the container element.
* - unselect: string, the value that should be submitted when none of the radio buttons is selected. * - unselect: string, the value that should be submitted when none of the radio buttons is selected.
* By setting this option, a hidden input will be generated. * By setting this option, a hidden input will be generated.
* - encode: boolean, whether to HTML-encode the checkbox labels. Defaults to true. * - encode: boolean, whether to HTML-encode the checkbox labels. Defaults to true.
@ -1287,7 +1289,6 @@ class BaseHtml
* *
* The rest of the options will be rendered as the attributes of the resulting tag. The values will * The rest of the options will be rendered as the attributes of the resulting tag. The values will
* be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered. * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered.
*
* See [[renderTagAttributes()]] for details on how attributes are being rendered. * See [[renderTagAttributes()]] for details on how attributes are being rendered.
* *
* @return string the generated radio button tag * @return string the generated radio button tag
@ -1473,12 +1474,17 @@ class BaseHtml
* @param array $items the data item used to generate the checkboxes. * @param array $items the data item used to generate the checkboxes.
* The array keys are the checkbox values, and the array values are the corresponding labels. * The array keys are the checkbox values, and the array values are the corresponding labels.
* Note that the labels will NOT be HTML-encoded, while the values will. * Note that the labels will NOT be HTML-encoded, while the values will.
* @param array $options options (name => config) for the checkbox list. The following options are specially handled: * @param array $options options (name => config) for the checkbox list container tag.
* The following options are specially handled:
* *
* - tag: string, the tag name of the container element.
* - unselect: string, the value that should be submitted when none of the checkboxes is selected. * - unselect: string, the value that should be submitted when none of the checkboxes is selected.
* You may set this option to be null to prevent default value submission. * You may set this option to be null to prevent default value submission.
* If this option is not set, an empty string will be submitted. * If this option is not set, an empty string will be submitted.
* - encode: boolean, whether to HTML-encode the checkbox labels. Defaults to true.
* This option is ignored if `item` option is set.
* - separator: string, the HTML code that separates items. * - separator: string, the HTML code that separates items.
* - itemOptions: array, the options for generating the checkbox tag using [[checkbox()]].
* - item: callable, a callback that can be used to customize the generation of the HTML code * - item: callable, a callback that can be used to customize the generation of the HTML code
* corresponding to a single item in $items. The signature of this callback must be: * corresponding to a single item in $items. The signature of this callback must be:
* *
@ -1509,12 +1515,17 @@ class BaseHtml
* @param array $items the data item used to generate the radio buttons. * @param array $items the data item used to generate the radio buttons.
* The array keys are the radio values, and the array values are the corresponding labels. * The array keys are the radio values, and the array values are the corresponding labels.
* Note that the labels will NOT be HTML-encoded, while the values will. * Note that the labels will NOT be HTML-encoded, while the values will.
* @param array $options options (name => config) for the radio button list. The following options are specially handled: * @param array $options options (name => config) for the radio button list container tag.
* The following options are specially handled:
* *
* - tag: string, the tag name of the container element.
* - unselect: string, the value that should be submitted when none of the radio buttons is selected. * - unselect: string, the value that should be submitted when none of the radio buttons is selected.
* You may set this option to be null to prevent default value submission. * You may set this option to be null to prevent default value submission.
* If this option is not set, an empty string will be submitted. * If this option is not set, an empty string will be submitted.
* - encode: boolean, whether to HTML-encode the checkbox labels. Defaults to true.
* This option is ignored if `item` option is set.
* - separator: string, the HTML code that separates items. * - separator: string, the HTML code that separates items.
* - itemOptions: array, the options for generating the radio button tag using [[radio()]].
* - item: callable, a callback that can be used to customize the generation of the HTML code * - item: callable, a callback that can be used to customize the generation of the HTML code
* corresponding to a single item in $items. The signature of this callback must be: * corresponding to a single item in $items. The signature of this callback must be:
* *

31
framework/helpers/BaseStringHelper.php

@ -234,4 +234,35 @@ class BaseStringHelper
return mb_strtolower(mb_substr($string, -$bytes, null, '8bit'), Yii::$app->charset) === mb_strtolower($with, Yii::$app->charset); return mb_strtolower(mb_substr($string, -$bytes, null, '8bit'), Yii::$app->charset) === mb_strtolower($with, Yii::$app->charset);
} }
} }
/**
* Explodes string into array, optionally trims values and skips empty ones
*
* @param string $string String to be exploded.
* @param string $delimiter Delimiter. Default is ','.
* @param mixed $trim Whether to trim each element. Can be:
* - boolean - to trim normally;
* - string - custom characters to trim. Will be passed as a second argument to `trim()` function.
* - callable - will be called for each value instead of trim. Takes the only argument - value.
* @param boolean $skipEmpty Whether to skip empty strings between delimiters. Default is false.
* @return array
*/
public static function explode($string, $delimiter = ',', $trim = true, $skipEmpty = false) {
$result = explode($delimiter, $string);
if ($trim) {
if ($trim === true) {
$trim = 'trim';
} elseif (!is_callable($trim)) {
$trim = function($v) use ($trim) {
return trim($v, $trim);
};
}
$result = array_map($trim, $result);
}
if ($skipEmpty) {
// Wrapped with array_values to make array keys sequential after empty values removing
$result = array_values(array_filter($result));
}
return $result;
}
} }

79
framework/messages/el/yii.php

@ -17,49 +17,9 @@
* NOTE: this file must be saved in UTF-8 encoding. * NOTE: this file must be saved in UTF-8 encoding.
*/ */
return [ return [
'Are you sure you want to delete this item?' => 'Είστε σίγουροι για τη διαγραφή του αντικειμένου;',
'Only files with these MIME types are allowed: {mimeTypes}.' => 'Επιτρέπονται μόνο αρχεία με τους ακόλουθους τύπους MIME: {mimeTypes}.',
'The requested view "{name}" was not found.' => 'Δε βρέθηκε η αιτούμενη όψη "{name}".',
'in {delta, plural, =1{a day} other{# days}}' => 'σε {delta, plural, =1{μία ημέρα} other{# ημέρες}}',
'in {delta, plural, =1{a minute} other{# minutes}}' => 'σε {delta, plural, =1{ένα λεπτό} other{# λεπτά}}',
'in {delta, plural, =1{a month} other{# months}}' => 'σε {delta, plural, =1{ένα μήνα} other{# μήνες}}',
'in {delta, plural, =1{a second} other{# seconds}}' => 'σε {delta, plural, =1{ένα δευτερόλεπτο} other{# δευτερόλεπτα}}',
'in {delta, plural, =1{a year} other{# years}}' => 'σε {delta, plural, =1{ένα έτος} other{# έτη}}',
'in {delta, plural, =1{an hour} other{# hours}}' => 'σε {delta, plural, =1{μία ώρα} other{# ώρες}}',
'just now' => 'μόλις τώρα',
'{delta, plural, =1{a day} other{# days}} ago' => 'πριν {delta, plural, =1{μία ημέρα} other{# ημέρες}}',
'{delta, plural, =1{a minute} other{# minutes}} ago' => 'πριν {delta, plural, =1{ένα λεπτό} other{# λεπτά}}',
'{delta, plural, =1{a month} other{# months}} ago' => 'πριν {delta, plural, =1{ένα μήνα} other{# μήνες}}',
'{delta, plural, =1{a second} other{# seconds}} ago' => 'πριν {delta, plural, =1{ένα δευτερόλεπτο} other{# δευτερόλεπτα}}',
'{delta, plural, =1{a year} other{# years}} ago' => 'πριν {delta, plural, =1{ένα έτος} other{# έτη}}',
'{delta, plural, =1{an hour} other{# hours}} ago' => 'πριν {delta, plural, =1{μία ώρα} other{# ώρες}}',
'{nFormatted} B' => '{nFormatted} B',
'{nFormatted} GB' => '{nFormatted} GB',
'{nFormatted} GiB' => '{nFormatted} GiB',
'{nFormatted} KB' => '{nFormatted} KB',
'{nFormatted} KiB' => '{nFormatted} KiB',
'{nFormatted} MB' => '{nFormatted} MB',
'{nFormatted} MiB' => '{nFormatted} MiB',
'{nFormatted} PB' => '{nFormatted} PB',
'{nFormatted} PiB' => '{nFormatted} PiB',
'{nFormatted} TB' => '{nFormatted} TB',
'{nFormatted} TiB' => '{nFormatted} TiB',
'{nFormatted} {n, plural, =1{byte} other{bytes}}' => '{nFormatted} {n, plural, =1{byte} other{bytes}}',
'{nFormatted} {n, plural, =1{gibibyte} other{gibibytes}}' => '{nFormatted} {n, plural, =1{gibibyte} other{gibibytes}}',
'{nFormatted} {n, plural, =1{gigabyte} other{gigabytes}}' => '{nFormatted} {n, plural, =1{gigabyte} other{gigabytes}}',
'{nFormatted} {n, plural, =1{kibibyte} other{kibibytes}}' => '{nFormatted} {n, plural, =1{kibibyte} other{kibibytes}}',
'{nFormatted} {n, plural, =1{kilobyte} other{kilobytes}}' => '{nFormatted} {n, plural, =1{kilobyte} other{kilobytes}}',
'{nFormatted} {n, plural, =1{mebibyte} other{mebibytes}}' => '{nFormatted} {n, plural, =1{mebibyte} other{mebibytes}}',
'{nFormatted} {n, plural, =1{megabyte} other{megabytes}}' => '{nFormatted} {n, plural, =1{megabyte} other{megabytes}}',
'{nFormatted} {n, plural, =1{pebibyte} other{pebibytes}}' => '{nFormatted} {n, plural, =1{pebibyte} other{pebibytes}}',
'{nFormatted} {n, plural, =1{petabyte} other{petabytes}}' => '{nFormatted} {n, plural, =1{petabyte} other{petabytes}}',
'{nFormatted} {n, plural, =1{tebibyte} other{tebibytes}}' => '{nFormatted} {n, plural, =1{tebibyte} other{tebibytes}}',
'{nFormatted} {n, plural, =1{terabyte} other{terabytes}}' => '{nFormatted} {n, plural, =1{terabyte} other{terabytes}}',
'No help for unknown command "{command}".' => 'Δεν υπάρχει βοήθεια για την άγνωστη εντολή "{command}".',
'No help for unknown sub-command "{command}".' => 'Δεν υπάρχει βοήθεια για την άγνωστη υπό-εντολή "{command}".',
'Unknown command "{command}".' => 'Άγνωστη εντολή "{command}".',
'(not set)' => '(μη ορισμένο)', '(not set)' => '(μη ορισμένο)',
'An internal server error occurred.' => 'Υπήρξε ένα εσωτερικό σφάλμα του διακομιστή.', 'An internal server error occurred.' => 'Υπήρξε ένα εσωτερικό σφάλμα του διακομιστή.',
'Are you sure you want to delete this item?' => 'Είστε σίγουροι για τη διαγραφή του αντικειμένου;',
'Delete' => 'Διαγραφή', 'Delete' => 'Διαγραφή',
'Error' => 'Σφάλμα', 'Error' => 'Σφάλμα',
'File upload failed.' => 'Η μεταφόρτωση απέτυχε.', 'File upload failed.' => 'Η μεταφόρτωση απέτυχε.',
@ -70,6 +30,7 @@ return [
'Missing required parameters: {params}' => 'Απουσιάζουν απαραίτητες παράμετροι: {params}', 'Missing required parameters: {params}' => 'Απουσιάζουν απαραίτητες παράμετροι: {params}',
'No' => 'Όχι', 'No' => 'Όχι',
'No results found.' => 'Δε βρέθηκαν αποτελέσματα.', 'No results found.' => 'Δε βρέθηκαν αποτελέσματα.',
'Only files with these MIME types are allowed: {mimeTypes}.' => 'Επιτρέπονται μόνο αρχεία με τους ακόλουθους τύπους MIME: {mimeTypes}.',
'Only files with these extensions are allowed: {extensions}.' => 'Επιτρέπονται αρχεία μόνο με καταλήξεις: {extensions}.', 'Only files with these extensions are allowed: {extensions}.' => 'Επιτρέπονται αρχεία μόνο με καταλήξεις: {extensions}.',
'Page not found.' => 'Η σελίδα δε βρέθηκε.', 'Page not found.' => 'Η σελίδα δε βρέθηκε.',
'Please fix the following errors:' => 'Παρακαλώ διορθώστε τα παρακάτω σφάλματα:', 'Please fix the following errors:' => 'Παρακαλώ διορθώστε τα παρακάτω σφάλματα:',
@ -83,6 +44,7 @@ return [
'The image "{file}" is too large. The width cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Η εικόνα «{file}» είναι πολύ μεγάλη. Το πλάτος δεν μπορεί να είναι μεγαλύτερο από {limit, number} {limit, plural, one{pixel} few{pixels} many{pixels} other{pixels}}.', 'The image "{file}" is too large. The width cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Η εικόνα «{file}» είναι πολύ μεγάλη. Το πλάτος δεν μπορεί να είναι μεγαλύτερο από {limit, number} {limit, plural, one{pixel} few{pixels} many{pixels} other{pixels}}.',
'The image "{file}" is too small. The height cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Η εικόνα «{file}» είναι πολύ μικρή. To ύψος δεν μπορεί να είναι μικρότερο από {limit, number} {limit, plural, one{pixel} few{pixels} many{pixels} other{pixels}}.', 'The image "{file}" is too small. The height cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Η εικόνα «{file}» είναι πολύ μικρή. To ύψος δεν μπορεί να είναι μικρότερο από {limit, number} {limit, plural, one{pixel} few{pixels} many{pixels} other{pixels}}.',
'The image "{file}" is too small. The width cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Η εικόνα «{file}» είναι πολύ μικρή. Το πλάτος του δεν μπορεί να είναι μικρότερο από {limit, number} {limit, plural, one{pixel} few{pixels} many{pixels} other{pixels}}.', 'The image "{file}" is too small. The width cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Η εικόνα «{file}» είναι πολύ μικρή. Το πλάτος του δεν μπορεί να είναι μικρότερο από {limit, number} {limit, plural, one{pixel} few{pixels} many{pixels} other{pixels}}.',
'The requested view "{name}" was not found.' => 'Δε βρέθηκε η αιτούμενη όψη "{name}".',
'The verification code is incorrect.' => 'Ο κωδικός επαλήθευσης είναι εσφαλμένος.', 'The verification code is incorrect.' => 'Ο κωδικός επαλήθευσης είναι εσφαλμένος.',
'Total <b>{count, number}</b> {count, plural, one{item} other{items}}.' => 'Συνολικά <b>{count, number}</b> {count, plural, one{αντικείμενο} few{αντικείμενα} many{αντικείμενα} other{αντικείμενα}}.', 'Total <b>{count, number}</b> {count, plural, one{item} other{items}}.' => 'Συνολικά <b>{count, number}</b> {count, plural, one{αντικείμενο} few{αντικείμενα} many{αντικείμενα} other{αντικείμενα}}.',
'Unable to verify your data submission.' => 'Δεν ήταν δυνατή η επαλήθευση των απεσταλμένων δεδομένων.', 'Unable to verify your data submission.' => 'Δεν ήταν δυνατή η επαλήθευση των απεσταλμένων δεδομένων.',
@ -92,6 +54,13 @@ return [
'Yes' => 'Ναι', 'Yes' => 'Ναι',
'You are not allowed to perform this action.' => 'Δεν επιτρέπεται να εκτελέσετε αυτή την ενέργεια.', 'You are not allowed to perform this action.' => 'Δεν επιτρέπεται να εκτελέσετε αυτή την ενέργεια.',
'You can upload at most {limit, number} {limit, plural, one{file} other{files}}.' => 'Μπορείτε να ανεβάσετε το πολύ {limit, number} {limit, plural, one{αρχείο} few{αρχεία} many{αρχεία} other{αρχεία}}.', 'You can upload at most {limit, number} {limit, plural, one{file} other{files}}.' => 'Μπορείτε να ανεβάσετε το πολύ {limit, number} {limit, plural, one{αρχείο} few{αρχεία} many{αρχεία} other{αρχεία}}.',
'in {delta, plural, =1{a day} other{# days}}' => 'σε {delta, plural, =1{μία ημέρα} other{# ημέρες}}',
'in {delta, plural, =1{a minute} other{# minutes}}' => 'σε {delta, plural, =1{ένα λεπτό} other{# λεπτά}}',
'in {delta, plural, =1{a month} other{# months}}' => 'σε {delta, plural, =1{ένα μήνα} other{# μήνες}}',
'in {delta, plural, =1{a second} other{# seconds}}' => 'σε {delta, plural, =1{ένα δευτερόλεπτο} other{# δευτερόλεπτα}}',
'in {delta, plural, =1{a year} other{# years}}' => 'σε {delta, plural, =1{ένα έτος} other{# έτη}}',
'in {delta, plural, =1{an hour} other{# hours}}' => 'σε {delta, plural, =1{μία ώρα} other{# ώρες}}',
'just now' => 'μόλις τώρα',
'the input value' => 'η τιμή εισόδου', 'the input value' => 'η τιμή εισόδου',
'{attribute} "{value}" has already been taken.' => 'Το {attribute} «{value}» έχει ήδη καταχωρηθεί.', '{attribute} "{value}" has already been taken.' => 'Το {attribute} «{value}» έχει ήδη καταχωρηθεί.',
'{attribute} cannot be blank.' => 'Το «{attribute}» δεν μπορεί να είναι κενό.', '{attribute} cannot be blank.' => 'Το «{attribute}» δεν μπορεί να είναι κενό.',
@ -114,4 +83,32 @@ return [
'{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.' => 'Το «{attribute}» πρέπει να περιέχει το λιγότερο {min, number} {min, plural, one{χαρακτήρα} few{χαρακτήρες} many{χαρακτήρες} other{χαρακτήρες}}.', '{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.' => 'Το «{attribute}» πρέπει να περιέχει το λιγότερο {min, number} {min, plural, one{χαρακτήρα} few{χαρακτήρες} many{χαρακτήρες} other{χαρακτήρες}}.',
'{attribute} should contain at most {max, number} {max, plural, one{character} other{characters}}.' => 'Το «{attribute}» πρέπει να περιέχει το πολύ {max, number} {max, plural, one{χαρακτήρα} few{χαρακτήρες} many{χαρακτήρες} other{χαρακτήρες}}.', '{attribute} should contain at most {max, number} {max, plural, one{character} other{characters}}.' => 'Το «{attribute}» πρέπει να περιέχει το πολύ {max, number} {max, plural, one{χαρακτήρα} few{χαρακτήρες} many{χαρακτήρες} other{χαρακτήρες}}.',
'{attribute} should contain {length, number} {length, plural, one{character} other{characters}}.' => 'Το «{attribute}» πρέπει να περιέχει {length, number} {length, plural, one{χαρακτήρα} few{χαρακτήρες} many{χαρακτήρες} other{χαρακτήρες}}.', '{attribute} should contain {length, number} {length, plural, one{character} other{characters}}.' => 'Το «{attribute}» πρέπει να περιέχει {length, number} {length, plural, one{χαρακτήρα} few{χαρακτήρες} many{χαρακτήρες} other{χαρακτήρες}}.',
'{delta, plural, =1{a day} other{# days}} ago' => 'πριν {delta, plural, =1{μία ημέρα} other{# ημέρες}}',
'{delta, plural, =1{a minute} other{# minutes}} ago' => 'πριν {delta, plural, =1{ένα λεπτό} other{# λεπτά}}',
'{delta, plural, =1{a month} other{# months}} ago' => 'πριν {delta, plural, =1{ένα μήνα} other{# μήνες}}',
'{delta, plural, =1{a second} other{# seconds}} ago' => 'πριν {delta, plural, =1{ένα δευτερόλεπτο} other{# δευτερόλεπτα}}',
'{delta, plural, =1{a year} other{# years}} ago' => 'πριν {delta, plural, =1{ένα έτος} other{# έτη}}',
'{delta, plural, =1{an hour} other{# hours}} ago' => 'πριν {delta, plural, =1{μία ώρα} other{# ώρες}}',
'{nFormatted} B' => '{nFormatted} B',
'{nFormatted} GB' => '{nFormatted} GB',
'{nFormatted} GiB' => '{nFormatted} GiB',
'{nFormatted} KB' => '{nFormatted} KB',
'{nFormatted} KiB' => '{nFormatted} KiB',
'{nFormatted} MB' => '{nFormatted} MB',
'{nFormatted} MiB' => '{nFormatted} MiB',
'{nFormatted} PB' => '{nFormatted} PB',
'{nFormatted} PiB' => '{nFormatted} PiB',
'{nFormatted} TB' => '{nFormatted} TB',
'{nFormatted} TiB' => '{nFormatted} TiB',
'{nFormatted} {n, plural, =1{byte} other{bytes}}' => '{nFormatted} {n, plural, =1{byte} other{bytes}}',
'{nFormatted} {n, plural, =1{gibibyte} other{gibibytes}}' => '{nFormatted} {n, plural, =1{gibibyte} other{gibibytes}}',
'{nFormatted} {n, plural, =1{gigabyte} other{gigabytes}}' => '{nFormatted} {n, plural, =1{gigabyte} other{gigabytes}}',
'{nFormatted} {n, plural, =1{kibibyte} other{kibibytes}}' => '{nFormatted} {n, plural, =1{kibibyte} other{kibibytes}}',
'{nFormatted} {n, plural, =1{kilobyte} other{kilobytes}}' => '{nFormatted} {n, plural, =1{kilobyte} other{kilobytes}}',
'{nFormatted} {n, plural, =1{mebibyte} other{mebibytes}}' => '{nFormatted} {n, plural, =1{mebibyte} other{mebibytes}}',
'{nFormatted} {n, plural, =1{megabyte} other{megabytes}}' => '{nFormatted} {n, plural, =1{megabyte} other{megabytes}}',
'{nFormatted} {n, plural, =1{pebibyte} other{pebibytes}}' => '{nFormatted} {n, plural, =1{pebibyte} other{pebibytes}}',
'{nFormatted} {n, plural, =1{petabyte} other{petabytes}}' => '{nFormatted} {n, plural, =1{petabyte} other{petabytes}}',
'{nFormatted} {n, plural, =1{tebibyte} other{tebibytes}}' => '{nFormatted} {n, plural, =1{tebibyte} other{tebibytes}}',
'{nFormatted} {n, plural, =1{terabyte} other{terabytes}}' => '{nFormatted} {n, plural, =1{terabyte} other{terabytes}}',
]; ];

4
framework/web/AssetManager.php

@ -64,11 +64,11 @@ class AssetManager extends Component
*/ */
public $bundles = []; public $bundles = [];
/** /**
* @return string the root directory storing the published asset files. * @var string the root directory storing the published asset files.
*/ */
public $basePath = '@webroot/assets'; public $basePath = '@webroot/assets';
/** /**
* @return string the base URL through which the published asset files can be accessed. * @var string the base URL through which the published asset files can be accessed.
*/ */
public $baseUrl = '@web/assets'; public $baseUrl = '@web/assets';
/** /**

4
framework/web/Response.php

@ -934,7 +934,9 @@ class Response extends \yii\base\Response
throw new InvalidConfigException("The '{$this->format}' response formatter is invalid. It must implement the ResponseFormatterInterface."); throw new InvalidConfigException("The '{$this->format}' response formatter is invalid. It must implement the ResponseFormatterInterface.");
} }
} elseif ($this->format === self::FORMAT_RAW) { } elseif ($this->format === self::FORMAT_RAW) {
$this->content = $this->data; if ($this->data !== null) {
$this->content = $this->data;
}
} else { } else {
throw new InvalidConfigException("Unsupported response format: {$this->format}"); throw new InvalidConfigException("Unsupported response format: {$this->format}");
} }

80
framework/widgets/ActiveField.php

@ -550,24 +550,9 @@ class ActiveField extends Component
* *
* Note, the values and labels will be automatically HTML-encoded by this method, and the blank spaces in * Note, the values and labels will be automatically HTML-encoded by this method, and the blank spaces in
* the labels will also be HTML-encoded. * the labels will also be HTML-encoded.
* @param array $options the tag options in terms of name-value pairs. The following options are specially handled: * @param array $options the tag options in terms of name-value pairs.
*
* - prompt: string, a prompt text to be displayed as the first option;
* - options: array, the attributes for the select option tags. The array keys must be valid option values,
* and the array values are the extra attributes for the corresponding option tags. For example,
* *
* ~~~ * For the list of available options please refer to the `$options` parameter of [[\yii\helpers\Html::activeDropDownList()]].
* [
* 'value1' => ['disabled' => true],
* 'value2' => ['label' => 'value 2'],
* ];
* ~~~
*
* - groups: array, the attributes for the optgroup tags. The structure of this is similar to that of 'options',
* except that the array keys represent the optgroup labels specified in $items.
*
* The rest of the options will be rendered as the attributes of the resulting tag. The values will
* be HTML-encoded using [[Html::encode()]]. If a value is null, the corresponding attribute will not be rendered.
* *
* If you set a custom `id` for the input element, you may need to adjust the [[$selectors]] accordingly. * If you set a custom `id` for the input element, you may need to adjust the [[$selectors]] accordingly.
* *
@ -593,28 +578,9 @@ class ActiveField extends Component
* *
* Note, the values and labels will be automatically HTML-encoded by this method, and the blank spaces in * Note, the values and labels will be automatically HTML-encoded by this method, and the blank spaces in
* the labels will also be HTML-encoded. * the labels will also be HTML-encoded.
* @param array $options the tag options in terms of name-value pairs. The following options are specially handled: * @param array $options the tag options in terms of name-value pairs.
*
* - prompt: string, a prompt text to be displayed as the first option;
* - options: array, the attributes for the select option tags. The array keys must be valid option values,
* and the array values are the extra attributes for the corresponding option tags. For example,
*
* ~~~
* [
* 'value1' => ['disabled' => true],
* 'value2' => ['label' => 'value 2'],
* ];
* ~~~
* *
* - groups: array, the attributes for the optgroup tags. The structure of this is similar to that of 'options', * For the list of available options please refer to the `$options` parameter of [[\yii\helpers\Html::activeListBox()]].
* except that the array keys represent the optgroup labels specified in $items.
* - unselect: string, the value that will be submitted when no option is selected.
* When this attribute is set, a hidden field will be generated so that if no option is selected in multiple
* mode, we can still obtain the posted unselect value. If you do not want any hidden input,
* you should explicitly set this option as null.
*
* The rest of the options will be rendered as the attributes of the resulting tag. The values will
* be HTML-encoded using [[Html::encode()]]. If a value is null, the corresponding attribute will not be rendered.
* *
* If you set a custom `id` for the input element, you may need to adjust the [[$selectors]] accordingly. * If you set a custom `id` for the input element, you may need to adjust the [[$selectors]] accordingly.
* *
@ -636,23 +602,8 @@ class ActiveField extends Component
* The selection of the checkbox list is taken from the value of the model attribute. * The selection of the checkbox list is taken from the value of the model attribute.
* @param array $items the data item used to generate the checkboxes. * @param array $items the data item used to generate the checkboxes.
* The array values are the labels, while the array keys are the corresponding checkbox values. * The array values are the labels, while the array keys are the corresponding checkbox values.
* Note that the labels will NOT be HTML-encoded, while the values will. * @param array $options options (name => config) for the checkbox list.
* @param array $options options (name => config) for the checkbox list. The following options are specially handled: * For the list of available options please refer to the `$options` parameter of [[\yii\helpers\Html::activeCheckboxList()]].
*
* - unselect: string, the value that should be submitted when none of the checkboxes is selected.
* By setting this option, a hidden input will be generated. If you do not want any hidden input,
* you should explicitly set this option as null.
* - separator: string, the HTML code that separates items.
* - item: callable, a callback that can be used to customize the generation of the HTML code
* corresponding to a single item in $items. The signature of this callback must be:
*
* ~~~
* function ($index, $label, $name, $checked, $value)
* ~~~
*
* where $index is the zero-based index of the checkbox in the whole list; $label
* is the label for the checkbox; and $name, $value and $checked represent the name,
* value and the checked status of the checkbox input.
* @return static the field object itself * @return static the field object itself
*/ */
public function checkboxList($items, $options = []) public function checkboxList($items, $options = [])
@ -669,23 +620,8 @@ class ActiveField extends Component
* The selection of the radio buttons is taken from the value of the model attribute. * The selection of the radio buttons is taken from the value of the model attribute.
* @param array $items the data item used to generate the radio buttons. * @param array $items the data item used to generate the radio buttons.
* The array values are the labels, while the array keys are the corresponding radio values. * The array values are the labels, while the array keys are the corresponding radio values.
* Note that the labels will NOT be HTML-encoded, while the values will. * @param array $options options (name => config) for the radio button list.
* @param array $options options (name => config) for the radio button list. The following options are specially handled: * For the list of available options please refer to the `$options` parameter of [[\yii\helpers\Html::activeRadioList()]].
*
* - unselect: string, the value that should be submitted when none of the radio buttons is selected.
* By setting this option, a hidden input will be generated. If you do not want any hidden input,
* you should explicitly set this option as null.
* - separator: string, the HTML code that separates items.
* - item: callable, a callback that can be used to customize the generation of the HTML code
* corresponding to a single item in $items. The signature of this callback must be:
*
* ~~~
* function ($index, $label, $name, $checked, $value)
* ~~~
*
* where $index is the zero-based index of the radio button in the whole list; $label
* is the label for the radio button; and $name, $value and $checked represent the name,
* value and the checked status of the radio button input.
* @return static the field object itself * @return static the field object itself
*/ */
public function radioList($items, $options = []) public function radioList($items, $options = [])

2
tests/unit/data/postgres.sql

@ -125,7 +125,7 @@ CREATE TABLE "bool_values" (
); );
CREATE TABLE `animal` ( CREATE TABLE "animal" (
id serial primary key, id serial primary key,
type varchar(255) not null type varchar(255) not null
); );

9
tests/unit/framework/helpers/StringHelperTest.php

@ -227,4 +227,13 @@ class StringHelperTest extends TestCase
$this->assertTrue(StringHelper::endsWith('string', 'nG', false)); $this->assertTrue(StringHelper::endsWith('string', 'nG', false));
$this->assertTrue(StringHelper::endsWith('BüЯйΨ', 'ÜяЙΨ', false)); $this->assertTrue(StringHelper::endsWith('BüЯйΨ', 'ÜяЙΨ', false));
} }
public function testExplode()
{
$this->assertEquals(['It', 'is', 'a first', 'test'], StringHelper::explode("It, is, a first, test"));
$this->assertEquals(['It', 'is', 'a second', 'test'], StringHelper::explode("It+ is+ a second+ test", '+'));
$this->assertEquals(['Save', '', '', 'empty trimmed string'], StringHelper::explode("Save, ,, empty trimmed string", ','));
$this->assertEquals(['Здесь', 'multibyte', 'строка'], StringHelper::explode("Здесь我 multibyte我 строка", '我'));
$this->assertEquals(['Disable', ' trim ', 'here but ignore empty'], StringHelper::explode("Disable, trim ,,,here but ignore empty", ',', false, true));
}
} }

19
tests/unit/framework/web/ResponseTest.php

@ -82,4 +82,23 @@ class ResponseTest extends \yiiunit\TestCase
{ {
return '12ёжик3456798áèabcdefghijklmnopqrstuvwxyz!"§$%&/(ёжик)=?'; return '12ёжик3456798áèabcdefghijklmnopqrstuvwxyz!"§$%&/(ёжик)=?';
} }
/**
* https://github.com/yiisoft/yii2/issues/7529
*/
public function testSendContentAsFile()
{
ob_start();
$this->response->sendContentAsFile('test', 'test.txt')->send([
'mimeType' => 'text/plain'
]);
$content = ob_get_clean();
static::assertEquals('test', $content);
static::assertEquals(200, $this->response->statusCode);
$headers = $this->response->headers;
static::assertEquals('application/octet-stream', $headers->get('Content-Type'));
static::assertEquals('attachment; filename="test.txt"', $headers->get('Content-Disposition'));
static::assertEquals(4, $headers->get('Content-Length'));
}
} }

Loading…
Cancel
Save