Commit 2b38d6ab by Carsten Brandt

Merge branch 'master' into Erik-r-2359-formatter-refactored

* master: (22 commits) Fixes #4971: Fixed hardcoded table names in `viaTable` expression in model generator Fixed test break. Fixes #4955: Replaced callbacks with events for `ActiveForm` Fix brackets Rename `\yii\web\User` component param for consistency Html::button() type is `button` by default Fix bug in Estonian translation Typo fixed inside \yii\rest\CreateAction Fixed test break. Fixed test case. note about validation rules order Return a fixtures cleanup in case of a failing test Update finnish translation skip fixture controller test on HHVM Make unit tests cleanup a DB after finish Fixes #4945: Added `yii\test\ArrayFixture` added array fixture class minor doc adjustment [skip ci] Fixes #4948. Thanks, @johan162 Fixes #4947 ... Conflicts: framework/UPGRADE.md
parents 0723f409 38476309
......@@ -97,6 +97,7 @@ When the `validate()` method is called, it does the following steps to perform v
2. Determine which rules should be applied by checking the current [[yii\base\Model::scenario|scenario]]
against the rules declared in [[yii\base\Model::rules()]]. These rules are the active rules.
3. Use each active rule to validate each active attribute which is associated with the rule.
The validation rules are evaluated in the order they are listed.
According to the above validation steps, an attribute will be validated if and only if it is
an active attribute declared in `scenarios()` and is associated with one or multiple active rules
......
......@@ -17,7 +17,6 @@ Transfer-Encoding: chunked
Content-Type: application/json; charset=UTF-8
{
"type": "yii\\web\\NotFoundHttpException",
"name": "Not Found Exception",
"message": "The requested resource was not found.",
"code": 0,
......@@ -42,3 +41,55 @@ The following list summarizes the HTTP status code that are used by the Yii REST
* `422`: Data validation failed (in response to a `POST` request, for example). Please check the response body for detailed error messages.
* `429`: Too many requests. The request was rejected due to rate limiting.
* `500`: Internal server error. This could be caused by internal program errors.
## Customizing Error Response <a name="customizing-error-response"></a>
Sometimes you may want to customize the default error response format. For example, instead of relying on
using different HTTP statuses to indicate different errors, you would like to always use 200 as HTTP status
and enclose the actual HTTP status code as part of the JSON structure in the response, like shown in the following,
```
HTTP/1.1 200 OK
Date: Sun, 02 Mar 2014 05:31:43 GMT
Server: Apache/2.2.26 (Unix) DAV/2 PHP/5.4.20 mod_ssl/2.2.26 OpenSSL/0.9.8y
Transfer-Encoding: chunked
Content-Type: application/json; charset=UTF-8
{
"success": false,
"data": {
"name": "Not Found Exception",
"message": "The requested resource was not found.",
"code": 0,
"status": 404
}
}
```
To achieve this goal, you can respond to the `beforeSend` event of the `response` component in the application configuration:
```php
return [
// ...
'components' => [
'response' => [
'class' => 'yii\web\Response',
'on beforeSend' => function ($event) {
$response = $event->sender;
if ($response->data !== null && !empty(Yii::$app->request->get['suppress_response_code'])) {
$response->data = [
'success' => $response->isSuccessful,
'data' => $response->data,
];
$response->statusCode = 200;
}
},
],
],
];
```
The above code will reformat the response (for both successful and failed responses) as explained when
`suppress_response_code` is passed as a `GET` parameter.
......@@ -43,6 +43,16 @@ Thanks to that line, your application is in development mode, and will have alre
http://hostname/index.php?r=gii
```
> Note: If you are accessing Gii from a machine other than localhost, the access will be denied by default
> for security purpose. You can configure Gii to add the allowed IP addresses as follows,
>
```php
'gii' => [
'class' => 'yii\gii\Module',
'allowedIPs' => ['127.0.0.1', '::1', '192.168.0.*', '192.168.178.20'] // adjust this to your needs
],
```
![Gii](images/start-gii.png)
......
......@@ -161,7 +161,6 @@ You may configure [[yii\base\Application::controllerMap|controller map]] in the
```php
[
'controllerMap' => [
[
// declares "account" controller using a class name
'account' => 'app\controllers\UserController',
......@@ -171,7 +170,6 @@ You may configure [[yii\base\Application::controllerMap|controller map]] in the
'enableCsrfValidation' => false,
],
],
],
]
```
......
......@@ -40,7 +40,7 @@ $this->title = 'Login';
Within a view, you can access `$this` which refers to the [[yii\web\View|view component]] managing
and rendering this view template.
Besides `$this`, there may be other predefined variables in a view, such as `$form` and `$model` in the above
Besides `$this`, there may be other predefined variables in a view, such as `$model` in the above
example. These variables represent the data that are *pushed* into the view by [controllers](structure-controllers.md)
or other objects whose trigger the [view rendering](#rendering-views).
......
......@@ -90,6 +90,7 @@ class TestCase extends Test
protected function tearDown()
{
$this->destroyApplication();
$this->unloadFixtures();
parent::tearDown();
}
......
......@@ -9,6 +9,7 @@ Yii Framework 2 gii extension Change Log
- Bug #3265: Fixed incorrect controller class name validation (suralc)
- Bug #3693: Fixed broken Gii preview when a file is unchanged (cebe)
- Bug #4410: Fixed Gii to preserve database column order in generated _form.php (kmindi)
- Bug #4971: Fixed hardcoded table names in `viaTable` expression in model generator (stepanselyuk)
- Enh #2018: Search model is not required anymore in CRUD generator (johonunu)
- Enh #3088: The gii module will manage their own URL rules now (qiangxue)
- Enh #3222: Added `useTablePrefix` option to the model generator for Gii (horizons2)
......
......@@ -354,7 +354,7 @@ class Generator extends \yii\gii\Generator
$viaLink = $this->generateRelationLink([$table->primaryKey[0] => $fks[$table->primaryKey[0]][1]]);
$relationName = $this->generateRelationName($relations, $className0, $db->getTableSchema($table0), $table->primaryKey[1], true);
$relations[$className0][$relationName] = [
"return \$this->hasMany($className1::className(), $link)->viaTable('{$table->name}', $viaLink);",
"return \$this->hasMany($className1::className(), $link)->viaTable('{" . $this->generateTableName($table->name) . "}', $viaLink);",
$className1,
true,
];
......@@ -363,7 +363,7 @@ class Generator extends \yii\gii\Generator
$viaLink = $this->generateRelationLink([$table->primaryKey[1] => $fks[$table->primaryKey[1]][1]]);
$relationName = $this->generateRelationName($relations, $className1, $db->getTableSchema($table1), $table->primaryKey[0], true);
$relations[$className1][$relationName] = [
"return \$this->hasMany($className0::className(), $link)->viaTable('{$table->name}', $viaLink);",
"return \$this->hasMany($className0::className(), $link)->viaTable('{" . $this->generateTableName($table->name) . "}', $viaLink);",
$className0,
true,
];
......
......@@ -20,7 +20,7 @@ namespace <?= $generator->ns ?>;
use Yii;
/**
* This is the model class for table "<?= $tableName ?>".
* This is the model class for table "<?= $generator->generateTableName($tableName) ?>".
*
<?php foreach ($tableSchema->columns as $column): ?>
* @property <?= "{$column->phpType} \${$column->name}\n" ?>
......
......@@ -261,6 +261,9 @@ Yii Framework 2 Change Log
- Chg #4591: `yii\helpers\Url::to()` will no longer prefix relative URLs with the base URL (qiangxue)
- Chg #4595: `yii\widgets\LinkPager`'s `nextPageLabel`, `prevPageLabel`, `firstPageLabel`, `lastPageLabel` are now taking `false` instead of `null` for "no label" (samdark)
- Chg #4911: Changed callback signature used in `yii\base\ArrayableTrait::fields()` from `function ($field, $model) {` to `function ($model, $field) {` (samdark)
- Chg #4955: Replaced callbacks with events for `ActiveForm` (qiangxue)
- Removed `beforeValidate()`, `beforeValidateAll()`, `afterValidate()`, `afterValidateAll()`, `ajaxBeforeSend()` and `ajaxComplete()` from `ActiveForm`.
- Added `beforeValidate`, `afterValidate`, `beforeSubmit`, `ajaxBeforeSend` and `ajaxComplete` events to `yii.activeForm`.
- 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: `yii\grid\DataColumn::getDataCellValue()` visibility is now `public` to allow accessing the value from a GridView directly (cebe)
......@@ -274,6 +277,7 @@ Yii Framework 2 Change Log
- Chg: When an ID is found to be in both `Application::controllerMap` and `Application::modules`, the former will take precedence (qiangxue)
- New #3911: Added `yii\behaviors\SluggableBehavior` that fills the specified model attribute with the transliterated and adjusted version to use in URLs (creocoder)
- New #4193: Added `yii\filters\Cors` CORS filter to allow Cross Origin Resource Sharing (pgaultier)
- New #4945: Added `yii\test\ArrayFixture` (Ragazzo)
- New: Added `yii\base\InvalidValueException` (qiangxue)
- New: Added `yii\caching\ArrayCache` (cebe)
......
......@@ -244,3 +244,18 @@ new ones save the following code as `convert.php` that should be placed in the s
The specification of the date and time formats is now using the ICU pattern format even if PHP intl extension is not installed.
You can prefix a date format with `php:` to use the old format of the PHP `date()`-function.
* `beforeValidate()`, `beforeValidateAll()`, `afterValidate()`, `afterValidateAll()`, `ajaxBeforeSend()` and `ajaxComplete()`
are removed from `ActiveForm`. The same functionality is now achieved via JavaScript event mechanism. For example,
if you want to do something before performing validation on the client side, you can write the following
JavaScript code:
```js
$('#myform').on('beforeValidate', function (event, messages, deferreds, attribute) {
if (attribute === undefined) {
// the event is triggered when submitting the form
} elseif (attribute.id === 'something') {
// the event is triggered before validating "something"
}
});
```
......@@ -425,6 +425,9 @@ class BaseHtml
*/
public static function button($content = 'Button', $options = [])
{
if (!isset($options['type'])) {
$options['type'] = 'button';
}
return static::tag('button', $content, $options);
}
......
......@@ -85,7 +85,7 @@ return array (
'{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.' => '{attribute} peab sisaldama vähemalt {min, number} {min, plural, one{märki} other{märki}}.',
'{attribute} should contain at most {max, number} {max, plural, one{character} other{characters}}.' => '{attribute} tohib sisaldada maksimaalselt {max, number} {max, plural, one{märki} other{märki}}.',
'{attribute} should contain {length, number} {length, plural, one{character} other{characters}}.' => '{attribute} peab sisaldama {length, number} {length, plural, one{märki} other{märki}}.',
'{delta, plural, =1{a day} other{# days}} ago' => 'delta, plural, =1{üks päev} other{# päeva}} tagasi',
'{delta, plural, =1{a day} other{# days}} ago' => '{delta, plural, =1{üks päev} other{# päeva}} tagasi',
'{delta, plural, =1{a minute} other{# minutes}} ago' => '{delta, plural, =1{üks minut} other{# minutit}} tagasi',
'{delta, plural, =1{a month} other{# months}} ago' => '{delta, plural, =1{kuu aega} other{# kuud}} tagasi',
'{delta, plural, =1{a second} other{# seconds}} ago' => '{delta, plural, =1{üks sekund} other{# sekundit}} tagasi',
......
......@@ -16,8 +16,17 @@
*
* NOTE: this file must be saved in UTF-8 encoding.
*/
return array (
'The requested view "{name}" was not found.' => 'Pyydettyä näkymää "{name}" ei löytynyt.',
return [
'{n, plural, =1{# gibibyte} other{# gibibytes}}' => '{n, plural, =1{# gibitavu} other{# gibitavua}}',
'{n, plural, =1{# kibibyte} other{# kibibytes}}' => '{n, plural, =1{# kibitavu} other{# kibitavua}}',
'{n, plural, =1{# mebibyte} other{# mebibytes}}' => '{n, plural, =1{# mebitavu} other{# mebitavua}}',
'{n, plural, =1{# pebibyte} other{# pebibytes}}' => '{n, plural, =1{# pebitavu} other{# pebitavua}}',
'{n, plural, =1{# tebibyte} other{# tebibytes}}' => '{n, plural, =1{# tebitavu} other{# tebitavua}}',
'{n} GiB' => 'GiB',
'{n} KiB' => 'KiB',
'{n} MiB' => 'MiB',
'{n} PiB' => 'PiB',
'{n} TiB' => 'TiB',
'(not set)' => '(ei asetettu)',
'An internal server error occurred.' => 'Sisäinen palvelinvirhe.',
'Are you sure you want to delete this item?' => 'Haluatko varmasti poistaa tämän?',
......@@ -47,6 +56,7 @@ return array (
'The image "{file}" is too large. The width cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Kuva "{file}" on liian suuri. Leveys ei voi olla suurempi kuin {limit, number} {limit, plural, one{pikseli} other{pikseliä}}.',
'The image "{file}" is too small. The height cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Kuva "{file}" on liian pieni. Korkeus ei voi olla pienempi kuin {limit, number} {limit, plural, one{pikseli} other{pikseliä}}.',
'The image "{file}" is too small. The width cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Kuva "{file}" on liian pieni. Leveys ei voi olla pienempi kuin {limit, number} {limit, plural, one{pikseli} other{pikseliä}}.',
'The requested view "{name}" was not found.' => 'Pyydettyä näkymää "{name}" ei löytynyt.',
'The verification code is incorrect.' => 'Vahvistuskoodi on virheellinen.',
'Total <b>{count, number}</b> {count, plural, one{item} other{items}}.' => 'Yhteensä <b>{count, number}</b> {count, plural, one{tulos} other{tulosta}}.',
'Unable to verify your data submission.' => 'Tietojen lähetystä ei voida varmistaa.',
......@@ -103,4 +113,4 @@ return array (
'{n} MB' => '{n} Mt',
'{n} PB' => '{n} Pt',
'{n} TB' => '{n} Tt',
);
];
......@@ -24,7 +24,7 @@ class CreateAction extends Action
*/
public $scenario = Model::SCENARIO_DEFAULT;
/**
* @var string the name of the view action. This property is need to create the URL when the mode is successfully created.
* @var string the name of the view action. This property is need to create the URL when the model is successfully created.
*/
public $viewAction = 'view';
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\test;
use Yii;
use yii\base\ArrayAccessTrait;
use yii\base\InvalidConfigException;
/**
* ArrayFixture represents arbitrary fixture that can be loaded from PHP files.
*
* @author Mark Jebri <mark.github@yandex.ru>
* @since 2.0
*/
class ArrayFixture extends Fixture implements \IteratorAggregate, \ArrayAccess, \Countable
{
use ArrayAccessTrait;
/**
* @var array the data rows. Each array element represents one row of data (column name => column value).
*/
public $data = [];
/**
* @var string|boolean the file path or path alias of the data file that contains the fixture data
* to be returned by [[getData()]]. You can set this property to be false to prevent loading any data.
*/
public $dataFile;
/**
* Loads the fixture.
*
* The default implementation simply stores the data returned by [[getData()]] in [[data]].
* You should usually override this method by putting the data into the underlying database.
*/
public function load()
{
$this->data = $this->getData();
}
/**
* Returns the fixture data.
*
* The default implementation will try to return the fixture data by including the external file specified by [[dataFile]].
* The file should return the data array that will be stored in [[data]] after inserting into the database.
*
* @return array the data to be put into the database
* @throws InvalidConfigException if the specified data file does not exist.
*/
protected function getData()
{
if ($this->dataFile === false || $this->dataFile === null) {
return [];
}
$dataFile = Yii::getAlias($this->dataFile);
if (is_file($dataFile)) {
return require($dataFile);
} else {
throw new InvalidConfigException("Fixture data file does not exist: {$this->dataFile}");
}
}
/**
* @inheritdoc
*/
public function unload()
{
parent::unload();
$this->data = [];
}
}
......@@ -345,7 +345,7 @@ class Response extends \yii\base\Response
$headers = $this->getHeaders();
foreach ($headers as $name => $values) {
$name = str_replace(' ', '-', ucwords(str_replace('-', ' ', $name)));
// set replace for first occurance of header but false afterwards to allow multiple
// set replace for first occurrence of header but false afterwards to allow multiple
$replace = true;
foreach ($values as $value) {
header("$name: $value", $replace);
......
......@@ -131,7 +131,7 @@ class User extends Component
* @var string the session variable name used to store the value of absolute expiration timestamp of the authenticated state.
* This is used when [[absoluteAuthTimeout]] is set.
*/
public $absoluteAuthTimeoutParam = '__absolute_expire';
public $absoluteAuthTimeoutParam = '__absoluteExpire';
/**
* @var string the session variable name used to store the value of [[returnUrl]].
*/
......
......@@ -15,7 +15,6 @@ use yii\helpers\ArrayHelper;
use yii\helpers\Url;
use yii\helpers\Html;
use yii\helpers\Json;
use yii\web\JsExpression;
/**
* ActiveForm is a widget that builds an interactive HTML form for one or multiple data models.
......@@ -146,79 +145,6 @@ class ActiveForm extends Widget
*/
public $ajaxDataType = 'json';
/**
* @var string|JsExpression a JS callback that will be called when the form is being submitted.
* The signature of the callback should be:
*
* ~~~
* function ($form) {
* ...return false to cancel submission...
* }
* ~~~
*/
public $beforeSubmit;
/**
* @var string|JsExpression a JS callback that is called before validating an attribute.
* The signature of the callback should be:
*
* ~~~
* function ($form, attribute, messages) {
* ...return false to cancel the validation...
* }
* ~~~
*/
public $beforeValidate;
/**
* @var string|JsExpression a JS callback that is called before any validation has run (Only called when the form is submitted).
* The signature of the callback should be:
*
* ~~~
* function ($form, data) {
* ...return false to cancel the validation...
* }
* ~~~
*/
public $beforeValidateAll;
/**
* @var string|JsExpression a JS callback that is called after validating an attribute.
* The signature of the callback should be:
*
* ~~~
* function ($form, attribute, messages) {
* }
* ~~~
*/
public $afterValidate;
/**
* @var string|JsExpression a JS callback that is called after all validation has run (Only called when the form is submitted).
* The signature of the callback should be:
*
* ~~~
* function ($form, data, messages) {
* }
* ~~~
*/
public $afterValidateAll;
/**
* @var string|JsExpression a JS pre-request callback function on AJAX-based validation.
* The signature of the callback should be:
*
* ~~~
* function ($form, jqXHR, textStatus) {
* }
* ~~~
*/
public $ajaxBeforeSend;
/**
* @var string|JsExpression a JS callback to be called when the request finishes on AJAX-based validation.
* The signature of the callback should be:
*
* ~~~
* function ($form, jqXHR, textStatus) {
* }
* ~~~
*/
public $ajaxComplete;
/**
* @var array the client validation options for individual attributes. Each element of the array
* represents the validation options for a particular attribute.
* @internal
......@@ -282,11 +208,6 @@ class ActiveForm extends Widget
if ($this->validationUrl !== null) {
$options['validationUrl'] = Url::to($this->validationUrl);
}
foreach (['beforeSubmit', 'beforeValidate', 'beforeValidateAll', 'afterValidate', 'afterValidateAll', 'ajaxBeforeSend', 'ajaxComplete'] as $name) {
if (($value = $this->$name) !== null) {
$options[$name] = $value instanceof JsExpression ? $value : new JsExpression($value);
}
}
// only get the options that are different from the default ones (set in yii.activeForm.js)
return array_diff_assoc($options, [
......
......@@ -24,6 +24,11 @@ class FixtureControllerTest extends TestCase
{
parent::setUp();
if (defined('HHVM_VERSION')) {
// https://github.com/facebook/hhvm/issues/1447
$this->markTestSkipped('Can not test on HHVM because require is cached.');
}
$this->mockApplication();
$this->_fixtureController = Yii::createObject([
......
......@@ -140,8 +140,8 @@ class HtmlTest extends TestCase
public function testButton()
{
$this->assertEquals('<button>Button</button>', Html::button());
$this->assertEquals('<button name="test" value="value">content<></button>', Html::button('content<>', ['name' => 'test', 'value' => 'value']));
$this->assertEquals('<button type="button">Button</button>', Html::button());
$this->assertEquals('<button type="button" name="test" value="value">content<></button>', Html::button('content<>', ['name' => 'test', 'value' => 'value']));
$this->assertEquals('<button type="submit" class="t" name="test" value="value">content<></button>', Html::button('content<>', ['type' => 'submit', 'name' => 'test', 'value' => 'value', 'class' => "t"]));
}
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yiiunit\framework\test;
use yiiunit\TestCase;
use yii\test\ArrayFixture;
class ArrayFixtureTest extends TestCase
{
/**
* @var \yii\test\ArrayFixture
*/
private $_fixture;
protected function setUp()
{
parent::setUp();
$this->_fixture = new ArrayFixture();
}
public function testLoadUnloadParticularFile()
{
$this->_fixture->dataFile = '@yiiunit/framework/test/data/array_fixture.php';
$this->assertEmpty($this->_fixture->data, 'fixture data should be empty');
$this->_fixture->load();
$this->assertCount(2, $this->_fixture->data, 'fixture data should match needed total count');
$this->assertEquals('customer1', $this->_fixture['customer1']['name'], 'first fixture data should match');
$this->assertEquals('customer2@example.com', $this->_fixture['customer2']['email'], 'second fixture data should match');
}
public function testNothingToLoad()
{
$this->_fixture->dataFile = false;
$this->assertEmpty($this->_fixture->data, 'fixture data should be empty');
$this->_fixture->load();
$this->assertEmpty($this->_fixture->data, 'fixture data should not be loaded');
}
/**
* @expectedException \yii\base\InvalidConfigException
*/
public function testWrongDataFileException()
{
$this->_fixture->dataFile = 'wrong/fixtures/data/path/alias';
$this->_fixture->load();
}
}
<?php
return [
'customer1' => [
'email' => 'customer1@example.com',
'name' => 'customer1',
'address' => 'address1',
'status' => 1,
],
'customer2' => [
'email' => 'customer2@example.com',
'name' => 'customer2',
'address' => 'address2',
'status' => 2,
],
];
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