mirror of
				https://github.com/yiisoft/yii2.git
				synced 2025-11-04 06:37:55 +08:00 
			
		
		
		
	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
This commit is contained in:
		@ -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
 | 
			
		||||
],
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -161,15 +161,13 @@ You may configure [[yii\base\Application::controllerMap|controller map]] in the
 | 
			
		||||
```php
 | 
			
		||||
[
 | 
			
		||||
    'controllerMap' => [
 | 
			
		||||
        [
 | 
			
		||||
            // declares "account" controller using a class name
 | 
			
		||||
            'account' => 'app\controllers\UserController',
 | 
			
		||||
        // declares "account" controller using a class name
 | 
			
		||||
        'account' => 'app\controllers\UserController',
 | 
			
		||||
 | 
			
		||||
            // declares "article" controller using a configuration array
 | 
			
		||||
            'article' => [
 | 
			
		||||
                'class' => 'app\controllers\PostController',
 | 
			
		||||
                'enableCsrfValidation' => false,
 | 
			
		||||
            ],
 | 
			
		||||
        // declares "article" controller using a configuration array
 | 
			
		||||
        'article' => [
 | 
			
		||||
            'class' => 'app\controllers\PostController',
 | 
			
		||||
            '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"
 | 
			
		||||
      }
 | 
			
		||||
  });
 | 
			
		||||
  ```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -22,6 +22,66 @@
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    var events = {
 | 
			
		||||
        /**
 | 
			
		||||
         * beforeValidate event is triggered before validating the whole form and each attribute.
 | 
			
		||||
         * The signature of the event handler should be:
 | 
			
		||||
         *     function (event, messages, deferreds, attribute)
 | 
			
		||||
         * where
 | 
			
		||||
         *  - event: an Event object. You can set event.isValid to be false to stop validating the form or attribute
 | 
			
		||||
         *  - messages: error messages. When attribute is undefined, this parameter is an associative array
 | 
			
		||||
         *    with keys being attribute IDs and values being error messages for the corresponding attributes.
 | 
			
		||||
         *    When attribute is given, this parameter is an array of the error messages for that attribute.
 | 
			
		||||
         *  - deferreds: an array of Deferred objects. You can use deferreds.add(callback) to add a new deferred validation.
 | 
			
		||||
         *  - attribute: an attribute object. Please refer to attributeDefaults for the structure.
 | 
			
		||||
         *    If this is undefined, it means the event is triggered before validating the whole form.
 | 
			
		||||
         *    Otherwise it means the event is triggered before validating the specified attribute.
 | 
			
		||||
         */
 | 
			
		||||
        beforeValidate: 'beforeValidate',
 | 
			
		||||
        /**
 | 
			
		||||
         * afterValidate event is triggered after validating the whole form and each attribute.
 | 
			
		||||
         * The signature of the event handler should be:
 | 
			
		||||
         *     function (event, messages, attribute)
 | 
			
		||||
         * where
 | 
			
		||||
         *  - event: an Event object.
 | 
			
		||||
         *  - messages: error messages. When attribute is undefined, this parameter is an associative array
 | 
			
		||||
         *    with keys being attribute IDs and values being error messages for the corresponding attributes.
 | 
			
		||||
         *    When attribute is given, this parameter is an array of the error messages for that attribute.
 | 
			
		||||
         *    If the array length is greater than 0, it means the attribute has validation errors.
 | 
			
		||||
         *  - attribute: an attribute object. Please refer to attributeDefaults for the structure.
 | 
			
		||||
         *    If this is undefined, it means the event is triggered before validating the whole form.
 | 
			
		||||
         *    Otherwise it means the event is triggered before validating the specified attribute.
 | 
			
		||||
         */
 | 
			
		||||
        afterValidate: 'afterValidate',
 | 
			
		||||
        /**
 | 
			
		||||
         * beforeSubmit event is triggered before submitting the form (after all validations pass).
 | 
			
		||||
         * The signature of the event handler should be:
 | 
			
		||||
         *     function (event)
 | 
			
		||||
         * where event is an Event object.
 | 
			
		||||
         */
 | 
			
		||||
        beforeSubmit: 'beforeSubmit',
 | 
			
		||||
        /**
 | 
			
		||||
         * ajaxBeforeSend event is triggered before sending an AJAX request for AJAX-based validation.
 | 
			
		||||
         * The signature of the event handler should be:
 | 
			
		||||
         *     function (event, jqXHR, settings)
 | 
			
		||||
         * where
 | 
			
		||||
         *  - event: an Event object.
 | 
			
		||||
         *  - jqXHR: a jqXHR object
 | 
			
		||||
         *  - settings: the settings for the AJAX request
 | 
			
		||||
         */
 | 
			
		||||
        ajaxBeforeSend: 'ajaxBeforeSend',
 | 
			
		||||
        /**
 | 
			
		||||
         * ajaxComplete event is triggered after completing an AJAX request for AJAX-based validation.
 | 
			
		||||
         * The signature of the event handler should be:
 | 
			
		||||
         *     function (event, jqXHR, textStatus)
 | 
			
		||||
         * where
 | 
			
		||||
         *  - event: an Event object.
 | 
			
		||||
         *  - jqXHR: a jqXHR object
 | 
			
		||||
         *  - settings: the status of the request ("success", "notmodified", "error", "timeout", "abort", or "parsererror").
 | 
			
		||||
         */
 | 
			
		||||
        ajaxComplete: 'ajaxComplete'
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // NOTE: If you change any of these defaults, make sure you update yii\widgets\ActiveForm::getClientOptions() as well
 | 
			
		||||
    var defaults = {
 | 
			
		||||
        // whether to encode the error summary
 | 
			
		||||
@ -41,28 +101,7 @@
 | 
			
		||||
        // the type of data that you're expecting back from the server
 | 
			
		||||
        ajaxDataType: 'json',
 | 
			
		||||
        // the URL for performing AJAX-based validation. If not set, it will use the the form's action
 | 
			
		||||
        validationUrl: undefined,
 | 
			
		||||
        // a callback that is called before submitting the form. The signature of the callback should be:
 | 
			
		||||
        // function ($form) { ...return false to cancel submission...}
 | 
			
		||||
        beforeSubmit: undefined,
 | 
			
		||||
        // a callback that is called before validating each attribute. The signature of the callback should be:
 | 
			
		||||
        // function ($form, attribute, messages) { ...return false to cancel the validation...}
 | 
			
		||||
        beforeValidate: undefined,
 | 
			
		||||
        // a callback that is called before validation starts (This callback is only called when the form is submitted). This signature of the callback should be:
 | 
			
		||||
        // function($form, data) { ...return false to cancel the validation...}
 | 
			
		||||
        beforeValidateAll: undefined,
 | 
			
		||||
        // a callback that is called after an attribute is validated. The signature of the callback should be:
 | 
			
		||||
        // function ($form, attribute, messages)
 | 
			
		||||
        afterValidate: undefined,
 | 
			
		||||
        // a callback that is called after all validation has run (This callback is only called when the form is submitted). The signature of the callback should be:
 | 
			
		||||
        // function ($form, data, messages)
 | 
			
		||||
        afterValidateAll: undefined,
 | 
			
		||||
        // a pre-request callback function on AJAX-based validation. The signature of the callback should be:
 | 
			
		||||
        // function ($form, jqXHR, textStatus)
 | 
			
		||||
        ajaxBeforeSend: undefined,
 | 
			
		||||
        // a function to be called when the request finishes on AJAX-based validation. The signature of the callback should be:
 | 
			
		||||
        // function ($form, jqXHR, textStatus)
 | 
			
		||||
        ajaxComplete: undefined
 | 
			
		||||
        validationUrl: undefined
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // NOTE: If you change any of these defaults, make sure you update yii\widgets\ActiveField::getClientOptions() as well
 | 
			
		||||
@ -151,7 +190,7 @@
 | 
			
		||||
            var $form = $(this),
 | 
			
		||||
                attributes = $form.data('yiiActiveForm').attributes,
 | 
			
		||||
                index = -1,
 | 
			
		||||
                attribute;
 | 
			
		||||
                attribute = undefined;
 | 
			
		||||
            $.each(attributes, function (i) {
 | 
			
		||||
                if (attributes[i]['id'] == id) {
 | 
			
		||||
                    index = i;
 | 
			
		||||
@ -168,7 +207,8 @@
 | 
			
		||||
 | 
			
		||||
        // find an attribute config based on the specified attribute ID
 | 
			
		||||
        find: function (id) {
 | 
			
		||||
            var attributes = $(this).data('yiiActiveForm').attributes, result;
 | 
			
		||||
            var attributes = $(this).data('yiiActiveForm').attributes,
 | 
			
		||||
                result = undefined;
 | 
			
		||||
            $.each(attributes, function (i) {
 | 
			
		||||
                if (attributes[i]['id'] == id) {
 | 
			
		||||
                    result = attributes[i];
 | 
			
		||||
@ -189,66 +229,120 @@
 | 
			
		||||
            return this.data('yiiActiveForm');
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        validate: function () {
 | 
			
		||||
            var $form = $(this),
 | 
			
		||||
                data = $form.data('yiiActiveForm'),
 | 
			
		||||
                needAjaxValidation = false,
 | 
			
		||||
                messages = {},
 | 
			
		||||
                deferreds = deferredArray();
 | 
			
		||||
 | 
			
		||||
            if (data.submitting) {
 | 
			
		||||
                var event = $.Event(events.beforeValidate, {'isValid': true});
 | 
			
		||||
                $form.trigger(event, [messages, deferreds]);
 | 
			
		||||
                if (!event.isValid) {
 | 
			
		||||
                    data.submitting = false;
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // client-side validation
 | 
			
		||||
            $.each(data.attributes, function () {
 | 
			
		||||
                // perform validation only if the form is being submitted or if an attribute is pending validation
 | 
			
		||||
                if (data.submitting || this.status === 2 || this.status === 3) {
 | 
			
		||||
                    var msg = messages[this.id];
 | 
			
		||||
                    if (msg === undefined) {
 | 
			
		||||
                        msg = [];
 | 
			
		||||
                        messages[this.id] = msg;
 | 
			
		||||
                    }
 | 
			
		||||
                    var event = $.Event(events.beforeValidate, {'isValid': true});
 | 
			
		||||
                    $form.trigger(event, [msg, deferreds, this]);
 | 
			
		||||
                    if (event.isValid) {
 | 
			
		||||
                        if (this.validate) {
 | 
			
		||||
                            this.validate(this, getValue($form, this), msg, deferreds);
 | 
			
		||||
                        }
 | 
			
		||||
                        if (this.enableAjaxValidation) {
 | 
			
		||||
                            needAjaxValidation = true;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // ajax validation
 | 
			
		||||
            $.when.apply(this, deferreds).always(function() {
 | 
			
		||||
                // Remove empty message arrays
 | 
			
		||||
                for (var i in messages) {
 | 
			
		||||
                    if (0 === messages[i].length) {
 | 
			
		||||
                        delete messages[i];
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                if (needAjaxValidation && (!data.submitting || $.isEmptyObject(messages))) {
 | 
			
		||||
                    // Perform ajax validation when at least one input needs it.
 | 
			
		||||
                    // If the validation is triggered by form submission, ajax validation
 | 
			
		||||
                    // should be done only when all inputs pass client validation
 | 
			
		||||
                    var $button = data.submitObject,
 | 
			
		||||
                        extData = '&' + data.settings.ajaxParam + '=' + $form.prop('id');
 | 
			
		||||
                    if ($button && $button.length && $button.prop('name')) {
 | 
			
		||||
                        extData += '&' + $button.prop('name') + '=' + $button.prop('value');
 | 
			
		||||
                    }
 | 
			
		||||
                    $.ajax({
 | 
			
		||||
                        url: data.settings.validationUrl,
 | 
			
		||||
                        type: $form.prop('method'),
 | 
			
		||||
                        data: $form.serialize() + extData,
 | 
			
		||||
                        dataType: data.settings.ajaxDataType,
 | 
			
		||||
                        complete: function (jqXHR, textStatus) {
 | 
			
		||||
                            $form.trigger(events.ajaxComplete, [jqXHR, textStatus]);
 | 
			
		||||
                        },
 | 
			
		||||
                        beforeSend: function (jqXHR, settings) {
 | 
			
		||||
                            $form.trigger(events.ajaxBeforeSend, [jqXHR, settings]);
 | 
			
		||||
                        },
 | 
			
		||||
                        success: function (msgs) {
 | 
			
		||||
                            if (msgs !== null && typeof msgs === 'object') {
 | 
			
		||||
                                $.each(data.attributes, function () {
 | 
			
		||||
                                    if (!this.enableAjaxValidation) {
 | 
			
		||||
                                        delete msgs[this.id];
 | 
			
		||||
                                    }
 | 
			
		||||
                                });
 | 
			
		||||
                                updateInputs($form, $.extend(messages, msgs));
 | 
			
		||||
                            } else {
 | 
			
		||||
                                updateInputs($form, messages);
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        error: function () {
 | 
			
		||||
                            data.submitting = false;
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
                } else if (data.submitting) {
 | 
			
		||||
                    // delay callback so that the form can be submitted without problem
 | 
			
		||||
                    setTimeout(function () {
 | 
			
		||||
                        updateInputs($form, messages);
 | 
			
		||||
                    }, 200);
 | 
			
		||||
                } else {
 | 
			
		||||
                    updateInputs($form, messages);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        submitForm: function () {
 | 
			
		||||
            var $form = $(this),
 | 
			
		||||
                data = $form.data('yiiActiveForm');
 | 
			
		||||
            if (data.validated) {
 | 
			
		||||
                if (data.settings.beforeSubmit !== undefined) {
 | 
			
		||||
                    if (data.settings.beforeSubmit($form) == false) {
 | 
			
		||||
                        data.validated = false;
 | 
			
		||||
                        data.submitting = false;
 | 
			
		||||
                        return false;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                // continue submitting the form since validation passes
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (data.settings.timer !== undefined) {
 | 
			
		||||
                clearTimeout(data.settings.timer);
 | 
			
		||||
            }
 | 
			
		||||
            data.submitting = true;
 | 
			
		||||
            
 | 
			
		||||
            if (data.settings.beforeValidateAll && !data.settings.beforeValidateAll($form, data)) {
 | 
			
		||||
                data.submitting = false;
 | 
			
		||||
            if (data.validated) {
 | 
			
		||||
                var event = $.Event(events.beforeSubmit, {'isValid': true});
 | 
			
		||||
                $form.trigger(event, [$form]);
 | 
			
		||||
                if (!event.isValid) {
 | 
			
		||||
                    data.validated = false;
 | 
			
		||||
                    data.submitting = false;
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
                return true;   // continue submitting the form since validation passes
 | 
			
		||||
            } else {
 | 
			
		||||
                if (data.settings.timer !== undefined) {
 | 
			
		||||
                    clearTimeout(data.settings.timer);
 | 
			
		||||
                }
 | 
			
		||||
                data.submitting = true;
 | 
			
		||||
                methods.validate.call($form);
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            validate($form, function (messages) {
 | 
			
		||||
                var errors = [];
 | 
			
		||||
                $.each(data.attributes, function () {
 | 
			
		||||
                    if (updateInput($form, this, messages)) {
 | 
			
		||||
                        errors.push(this.input);
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
                
 | 
			
		||||
                if (data.settings.afterValidateAll) {
 | 
			
		||||
                    data.settings.afterValidateAll($form, data, messages);
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                updateSummary($form, messages);
 | 
			
		||||
                if (errors.length) {
 | 
			
		||||
                    var top = $form.find(errors.join(',')).first().offset().top;
 | 
			
		||||
                    var wtop = $(window).scrollTop();
 | 
			
		||||
                    if (top < wtop || top > wtop + $(window).height) {
 | 
			
		||||
                        $(window).scrollTop(top);
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    data.validated = true;
 | 
			
		||||
                    var $button = data.submitObject || $form.find(':submit:first');
 | 
			
		||||
                    // TODO: if the submission is caused by "change" event, it will not work
 | 
			
		||||
                    if ($button.length) {
 | 
			
		||||
                        $button.click();
 | 
			
		||||
                    } else {
 | 
			
		||||
                        // no submit button in the form
 | 
			
		||||
                        $form.submit();
 | 
			
		||||
                    }
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                data.submitting = false;
 | 
			
		||||
            }, function () {
 | 
			
		||||
                data.submitting = false;
 | 
			
		||||
            });
 | 
			
		||||
            return false;
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        resetForm: function () {
 | 
			
		||||
@ -275,31 +369,6 @@
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    var watchAttributes = function ($form, attributes) {
 | 
			
		||||
        $.each(attributes, function (i, attribute) {
 | 
			
		||||
            var $input = findInput($form, attribute);
 | 
			
		||||
            if (attribute.validateOnChange) {
 | 
			
		||||
                $input.on('change.yiiActiveForm',function () {
 | 
			
		||||
                    validateAttribute($form, attribute, false);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            if (attribute.validateOnBlur) {
 | 
			
		||||
                $input.on('blur.yiiActiveForm', function () {
 | 
			
		||||
                    if (attribute.status == 0 || attribute.status == 1) {
 | 
			
		||||
                        validateAttribute($form, attribute, !attribute.status);
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            if (attribute.validateOnType) {
 | 
			
		||||
                $input.on('keyup.yiiActiveForm', function () {
 | 
			
		||||
                    if (attribute.value !== getValue($form, attribute)) {
 | 
			
		||||
                        validateAttribute($form, attribute, false);
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    var watchAttribute = function ($form, attribute) {
 | 
			
		||||
        var $input = findInput($form, attribute);
 | 
			
		||||
        if (attribute.validateOnChange) {
 | 
			
		||||
@ -356,14 +425,7 @@
 | 
			
		||||
                    $form.find(this.container).addClass(data.settings.validatingCssClass);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            validate($form, function (messages) {
 | 
			
		||||
                var hasError = false;
 | 
			
		||||
                $.each(data.attributes, function () {
 | 
			
		||||
                    if (this.status === 2 || this.status === 3) {
 | 
			
		||||
                        hasError = updateInput($form, this, messages) || hasError;
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
            methods.validate.call($form);
 | 
			
		||||
        }, data.settings.validationDelay);
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
@ -379,88 +441,52 @@
 | 
			
		||||
        };
 | 
			
		||||
        return array;
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Performs validation.
 | 
			
		||||
     * @param $form jQuery the jquery representation of the form
 | 
			
		||||
     * @param successCallback function the function to be invoked if the validation completes
 | 
			
		||||
     * @param errorCallback function the function to be invoked if the ajax validation request fails
 | 
			
		||||
     * Updates the error messages and the input containers for all applicable attributes
 | 
			
		||||
     * @param $form the form jQuery object
 | 
			
		||||
     * @param messages array the validation error messages
 | 
			
		||||
     */
 | 
			
		||||
    var validate = function ($form, successCallback, errorCallback) {
 | 
			
		||||
        var data = $form.data('yiiActiveForm'),
 | 
			
		||||
            needAjaxValidation = false,
 | 
			
		||||
            messages = {},
 | 
			
		||||
            deferreds = deferredArray();
 | 
			
		||||
    var updateInputs = function ($form, messages) {
 | 
			
		||||
        var data = $form.data('yiiActiveForm');
 | 
			
		||||
 | 
			
		||||
        $.each(data.attributes, function () {
 | 
			
		||||
            if (data.submitting || this.status === 2 || this.status === 3) {
 | 
			
		||||
                var msg = [];
 | 
			
		||||
                messages[this.id] = msg;
 | 
			
		||||
                if (!data.settings.beforeValidate || data.settings.beforeValidate($form, this, msg)) {
 | 
			
		||||
                    if (this.validate) {
 | 
			
		||||
                        this.validate(this, getValue($form, this), msg, deferreds);
 | 
			
		||||
                    }
 | 
			
		||||
                    if (this.enableAjaxValidation) {
 | 
			
		||||
                        needAjaxValidation = true;
 | 
			
		||||
                    }
 | 
			
		||||
        if (data.submitting) {
 | 
			
		||||
            var errorInputs = [];
 | 
			
		||||
            $.each(data.attributes, function () {
 | 
			
		||||
                if (updateInput($form, this, messages)) {
 | 
			
		||||
                    errorInputs.push(this.input);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        $.when.apply(this, deferreds).always(function() {
 | 
			
		||||
            //Remove empty message arrays
 | 
			
		||||
            for (var i in messages) {
 | 
			
		||||
                if (0 === messages[i].length) {
 | 
			
		||||
                    delete messages[i];
 | 
			
		||||
            $form.trigger(events.afterValidate, [messages]);
 | 
			
		||||
 | 
			
		||||
            updateSummary($form, messages);
 | 
			
		||||
 | 
			
		||||
            if (errorInputs.length) {
 | 
			
		||||
                var top = $form.find(errorInputs.join(',')).first().offset().top;
 | 
			
		||||
                var wtop = $(window).scrollTop();
 | 
			
		||||
                if (top < wtop || top > wtop + $(window).height) {
 | 
			
		||||
                    $(window).scrollTop(top);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (needAjaxValidation && (!data.submitting || $.isEmptyObject(messages))) {
 | 
			
		||||
                // Perform ajax validation when at least one input needs it.
 | 
			
		||||
                // If the validation is triggered by form submission, ajax validation
 | 
			
		||||
                // should be done only when all inputs pass client validation
 | 
			
		||||
                var $button = data.submitObject,
 | 
			
		||||
                    extData = '&' + data.settings.ajaxParam + '=' + $form.prop('id');
 | 
			
		||||
                if ($button && $button.length && $button.prop('name')) {
 | 
			
		||||
                    extData += '&' + $button.prop('name') + '=' + $button.prop('value');
 | 
			
		||||
                }
 | 
			
		||||
                $.ajax({
 | 
			
		||||
                    url: data.settings.validationUrl,
 | 
			
		||||
                    type: $form.prop('method'),
 | 
			
		||||
                    data: $form.serialize() + extData,
 | 
			
		||||
                    dataType: data.settings.ajaxDataType,
 | 
			
		||||
                    complete: function (jqXHR, textStatus) {
 | 
			
		||||
                        if (data.settings.ajaxComplete) {
 | 
			
		||||
                            data.settings.ajaxComplete($form, jqXHR, textStatus);
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    beforeSend: function (jqXHR, textStatus) {
 | 
			
		||||
                        if (data.settings.ajaxBeforeSend) {
 | 
			
		||||
                            data.settings.ajaxBeforeSend($form, jqXHR, textStatus);
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    success: function (msgs) {
 | 
			
		||||
                        if (msgs !== null && typeof msgs === 'object') {
 | 
			
		||||
                            $.each(data.attributes, function () {
 | 
			
		||||
                                if (!this.enableAjaxValidation) {
 | 
			
		||||
                                    delete msgs[this.id];
 | 
			
		||||
                                }
 | 
			
		||||
                            });
 | 
			
		||||
                            successCallback($.extend({}, messages, msgs));
 | 
			
		||||
                        } else {
 | 
			
		||||
                            successCallback(messages);
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    error: errorCallback
 | 
			
		||||
                });
 | 
			
		||||
            } else if (data.submitting) {
 | 
			
		||||
                // delay callback so that the form can be submitted without problem
 | 
			
		||||
                setTimeout(function () {
 | 
			
		||||
                    successCallback(messages);
 | 
			
		||||
                }, 200);
 | 
			
		||||
                data.submitting = false;
 | 
			
		||||
            } else {
 | 
			
		||||
                successCallback(messages);
 | 
			
		||||
                data.validated = true;
 | 
			
		||||
                var $button = data.submitObject || $form.find(':submit:first');
 | 
			
		||||
                // TODO: if the submission is caused by "change" event, it will not work
 | 
			
		||||
                if ($button.length) {
 | 
			
		||||
                    $button.click();
 | 
			
		||||
                } else {
 | 
			
		||||
                    // no submit button in the form
 | 
			
		||||
                    $form.submit();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        } else {
 | 
			
		||||
            $.each(data.attributes, function () {
 | 
			
		||||
                if (this.status === 2 || this.status === 3) {
 | 
			
		||||
                    updateInput($form, this, messages);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -475,12 +501,14 @@
 | 
			
		||||
            $input = findInput($form, attribute),
 | 
			
		||||
            hasError = false;
 | 
			
		||||
 | 
			
		||||
        if (data.settings.afterValidate) {
 | 
			
		||||
            data.settings.afterValidate($form, attribute, messages);
 | 
			
		||||
        if (!$.isArray(messages[attribute.id])) {
 | 
			
		||||
            messages[attribute.id] = [];
 | 
			
		||||
        }
 | 
			
		||||
        $form.trigger(events.afterValidate, [messages[attribute.id], attribute]);
 | 
			
		||||
 | 
			
		||||
        attribute.status = 1;
 | 
			
		||||
        if ($input.length) {
 | 
			
		||||
            hasError = messages && $.isArray(messages[attribute.id]) && messages[attribute.id].length;
 | 
			
		||||
            hasError = messages[attribute.id].length > 0;
 | 
			
		||||
            var $container = $form.find(attribute.container);
 | 
			
		||||
            var $error = $container.find(attribute.error);
 | 
			
		||||
            if (hasError) {
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -1541,7 +1544,7 @@ class BaseHtml
 | 
			
		||||
        $groups = isset($tagOptions['groups']) ? $tagOptions['groups'] : [];
 | 
			
		||||
        unset($tagOptions['prompt'], $tagOptions['options'], $tagOptions['groups']);
 | 
			
		||||
        $options['encodeSpaces'] = ArrayHelper::getValue($options, 'encodeSpaces', $encodeSpaces);
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        foreach ($items as $key => $value) {
 | 
			
		||||
            if (is_array($value)) {
 | 
			
		||||
                $groupAttrs = isset($groups[$key]) ? $groups[$key] : [];
 | 
			
		||||
 | 
			
		||||
@ -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,91 +16,101 @@
 | 
			
		||||
 *
 | 
			
		||||
 * 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.',
 | 
			
		||||
  '(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?',
 | 
			
		||||
  'Delete' => 'Poista',
 | 
			
		||||
  'Error' => 'Virhe',
 | 
			
		||||
  'File upload failed.' => 'Tiedoston lähetys epäonnistui.',
 | 
			
		||||
  'Home' => 'Koti',
 | 
			
		||||
  'Invalid data received for parameter "{param}".' => 'Parametri "{param}" vastaanotti virheellistä dataa.',
 | 
			
		||||
  'Login Required' => 'Kirjautuminen vaaditaan',
 | 
			
		||||
  'Missing required arguments: {params}' => 'Pakolliset argumentit puuttuu: {params}',
 | 
			
		||||
  'Missing required parameters: {params}' => 'Pakolliset parametrit puuttuu: {params}',
 | 
			
		||||
  'No' => 'Ei',
 | 
			
		||||
  'No help for unknown command "{command}".' => 'Ei ohjetta tuntemattomalle komennolle "{command}".',
 | 
			
		||||
  'No help for unknown sub-command "{command}".' => 'Ei ohjetta tuntemattomalle alikomennolle "{command}".',
 | 
			
		||||
  'No results found.' => 'Ei tuloksia.',
 | 
			
		||||
  'Only files with these MIME types are allowed: {mimeTypes}.' => 'Sallittuja ovat vain tiedostot, joiden MIME-tyyppi on: {mimeTypes}.',
 | 
			
		||||
  'Only files with these extensions are allowed: {extensions}.' => 'Sallittuja ovat vain tiedostot, joiden tiedostopääte on: {extensions}.',
 | 
			
		||||
  'Page not found.' => 'Sivua ei löytynyt.',
 | 
			
		||||
  'Please fix the following errors:' => 'Korjaa seuraavat virheet:',
 | 
			
		||||
  'Please upload a file.' => 'Lähetä tiedosto.',
 | 
			
		||||
  'Showing <b>{begin, number}-{end, number}</b> of <b>{totalCount, number}</b> {totalCount, plural, one{item} other{items}}.' => 'Näytetään <b>{begin, number}-{end, number}</b> kaikkiaan <b>{totalCount, number}</b> {totalCount, plural, one{tuloksesta} other{tuloksesta}}.',
 | 
			
		||||
  'The file "{file}" is not an image.' => 'Tiedosto "{file}" ei ole kuva.',
 | 
			
		||||
  'The file "{file}" is too big. Its size cannot exceed {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'Tiedosto "{file}" on liian iso. Sen koko ei voi olla suurempi kuin {limit, number} {limit, plural, one{tavu} other{tavua}}.',
 | 
			
		||||
  'The file "{file}" is too small. Its size cannot be smaller than {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'Tiedosto "{file}" on liian pieni. Sen koko ei voi olla pienempi kuin {limit, number} {limit, plural, one{tavu} other{tavua}}.',
 | 
			
		||||
  'The format of {attribute} is invalid.' => 'Attribuutin {attribute} formaatti on virheellinen.',
 | 
			
		||||
  'The image "{file}" is too large. The height cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Kuva "{file}" on liian suuri. Korkeus ei voi olla suurempi kuin {limit, number} {limit, plural, one{pikseli} other{pikseliä}}.',
 | 
			
		||||
  '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 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.',
 | 
			
		||||
  'Unknown command "{command}".' => 'Tuntematon komento "{command}".',
 | 
			
		||||
  'Unknown option: --{name}' => 'Tuntematon valinta: --{name}',
 | 
			
		||||
  'Update' => 'Päivitä',
 | 
			
		||||
  'View' => 'Näytä',
 | 
			
		||||
  'Yes' => 'Kyllä',
 | 
			
		||||
  'You are not allowed to perform this action.' => 'Sinulla ei ole tarvittavia oikeuksia toiminnon suorittamiseen.',
 | 
			
		||||
  'You can upload at most {limit, number} {limit, plural, one{file} other{files}}.' => 'Voit lähettää enintään {limit, number} {limit, plural, one{tiedoston} other{tiedostoa}}.',
 | 
			
		||||
  'in {delta, plural, =1{a day} other{# days}}' => '{delta, plural, =1{päivässä} other{# päivässä}}',
 | 
			
		||||
  'in {delta, plural, =1{a minute} other{# minutes}}' => '{delta, plural, =1{minuutissa} other{# minuutissa}}',
 | 
			
		||||
  'in {delta, plural, =1{a month} other{# months}}' => '{delta, plural, =1{kuukaudessa} other{# kuukaudessa}}',
 | 
			
		||||
  'in {delta, plural, =1{a second} other{# seconds}}' => '{delta, plural, =1{sekunnissa} other{# sekunnissa}}',
 | 
			
		||||
  'in {delta, plural, =1{a year} other{# years}}' => '{delta, plural, =1{vuodessa} other{# vuodessa}}',
 | 
			
		||||
  'in {delta, plural, =1{an hour} other{# hours}}' => '{delta, plural, =1{tunnissa} other{# tunnissa}}',
 | 
			
		||||
  'the input value' => 'syötetty arvo',
 | 
			
		||||
  '{attribute} "{value}" has already been taken.' => '{attribute} "{value}" on jo käytössä.',
 | 
			
		||||
  '{attribute} cannot be blank.' => '{attribute} ei voi olla tyhjä.',
 | 
			
		||||
  '{attribute} is invalid.' => '{attribute} on virheellinen.',
 | 
			
		||||
  '{attribute} is not a valid URL.' => '{attribute} on virheellinen URL.',
 | 
			
		||||
  '{attribute} is not a valid email address.' => '{attribute} on virheellinen sähköpostiosoite.',
 | 
			
		||||
  '{attribute} must be "{requiredValue}".' => '{attribute} täytyy olla "{requiredValue}".',
 | 
			
		||||
  '{attribute} must be a number.' => '{attribute} täytyy olla luku.',
 | 
			
		||||
  '{attribute} must be a string.' => '{attribute} täytyy olla merkkijono.',
 | 
			
		||||
  '{attribute} must be an integer.' => '{attribute} täytyy olla kokonaisluku.',
 | 
			
		||||
  '{attribute} must be either "{true}" or "{false}".' => '{attribute} täytyy olla joko {true} tai {false}.',
 | 
			
		||||
  '{attribute} must be greater than "{compareValue}".' => '{attribute} täytyy olla suurempi kuin "{compareValue}".',
 | 
			
		||||
  '{attribute} must be greater than or equal to "{compareValue}".' => '{attribute} täytyy olla suurempi tai yhtä suuri kuin "{compareValue}".',
 | 
			
		||||
  '{attribute} must be less than "{compareValue}".' => '{attribute} täytyy olla pienempi kuin "{compareValue}".',
 | 
			
		||||
  '{attribute} must be less than or equal to "{compareValue}".' => '{attribute} täytyy olla pienempi tai yhtä suuri kuin "{compareValue}".',
 | 
			
		||||
  '{attribute} must be no greater than {max}.' => '{attribute} ei saa olla suurempi kuin "{max}".',
 | 
			
		||||
  '{attribute} must be no less than {min}.' => '{attribute} ei saa olla pienempi kuin "{min}".',
 | 
			
		||||
  '{attribute} must be repeated exactly.' => '{attribute} täytyy toistaa täsmälleen.',
 | 
			
		||||
  '{attribute} must not be equal to "{compareValue}".' => '{attribute} ei saa olla yhtä suuri kuin "{compareValue}".',
 | 
			
		||||
  '{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.' => '{attribute} tulisi sisältää vähintään {min, number} {min, plural, one{merkki} other{merkkiä}}.',
 | 
			
		||||
  '{attribute} should contain at most {max, number} {max, plural, one{character} other{characters}}.' => '{attribute} tulisi sisältää enintään {max, number} {max, plural, one{merkki} other{merkkiä}}.',
 | 
			
		||||
  '{attribute} should contain {length, number} {length, plural, one{character} other{characters}}.' => '{attribute} tulisi sisältää {length, number} {length, plural, one{merkki} other{merkkiä}}.',
 | 
			
		||||
  '{delta, plural, =1{a day} other{# days}} ago' => '{delta, plural, =1{päivä} other{# päivää}} sitten',
 | 
			
		||||
  '{delta, plural, =1{a minute} other{# minutes}} ago' => '{delta, plural, =1{minuutti} other{# minuuttia}} sitten',
 | 
			
		||||
  '{delta, plural, =1{a month} other{# months}} ago' => '{delta, plural, =1{kuukausi} other{# kuukautta}} sitten',
 | 
			
		||||
  '{delta, plural, =1{a second} other{# seconds}} ago' => '{delta, plural, =1{sekunti} other{# sekuntia}} sitten',
 | 
			
		||||
  '{delta, plural, =1{a year} other{# years}} ago' => '{delta, plural, =1{vuosi} other{# vuotta}} sitten',
 | 
			
		||||
  '{delta, plural, =1{an hour} other{# hours}} ago' => '{delta, plural, =1{tunti} other{# tuntia}} sitten',
 | 
			
		||||
  '{n, plural, =1{# byte} other{# bytes}}' => '{n, plural, =1{# tavu} other{# tavua}}',
 | 
			
		||||
  '{n, plural, =1{# gigabyte} other{# gigabytes}}' => '{n, plural, =1{# gigatavu} other{# gigatavua}}',
 | 
			
		||||
  '{n, plural, =1{# kilobyte} other{# kilobytes}}' => '{n, plural, =1{# kilotavu} other{# kilotavua}}',
 | 
			
		||||
  '{n, plural, =1{# megabyte} other{# megabytes}}' => '{n, plural, =1{# megatavu} other{# megatavua}}',
 | 
			
		||||
  '{n, plural, =1{# petabyte} other{# petabytes}}' => '{n, plural, =1{# petatavu} other{# petatavua}}',
 | 
			
		||||
  '{n, plural, =1{# terabyte} other{# terabytes}}' => '{n, plural, =1{# teratavu} other{# teratavua}}',
 | 
			
		||||
  '{n} B' => '{n} t',
 | 
			
		||||
  '{n} GB' => '{n} Gt',
 | 
			
		||||
  '{n} KB' => '{n} kt',
 | 
			
		||||
  '{n} MB' => '{n} Mt',
 | 
			
		||||
  '{n} PB' => '{n} Pt',
 | 
			
		||||
  '{n} TB' => '{n} Tt',
 | 
			
		||||
);
 | 
			
		||||
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?',
 | 
			
		||||
    'Delete' => 'Poista',
 | 
			
		||||
    'Error' => 'Virhe',
 | 
			
		||||
    'File upload failed.' => 'Tiedoston lähetys epäonnistui.',
 | 
			
		||||
    'Home' => 'Koti',
 | 
			
		||||
    'Invalid data received for parameter "{param}".' => 'Parametri "{param}" vastaanotti virheellistä dataa.',
 | 
			
		||||
    'Login Required' => 'Kirjautuminen vaaditaan',
 | 
			
		||||
    'Missing required arguments: {params}' => 'Pakolliset argumentit puuttuu: {params}',
 | 
			
		||||
    'Missing required parameters: {params}' => 'Pakolliset parametrit puuttuu: {params}',
 | 
			
		||||
    'No' => 'Ei',
 | 
			
		||||
    'No help for unknown command "{command}".' => 'Ei ohjetta tuntemattomalle komennolle "{command}".',
 | 
			
		||||
    'No help for unknown sub-command "{command}".' => 'Ei ohjetta tuntemattomalle alikomennolle "{command}".',
 | 
			
		||||
    'No results found.' => 'Ei tuloksia.',
 | 
			
		||||
    'Only files with these MIME types are allowed: {mimeTypes}.' => 'Sallittuja ovat vain tiedostot, joiden MIME-tyyppi on: {mimeTypes}.',
 | 
			
		||||
    'Only files with these extensions are allowed: {extensions}.' => 'Sallittuja ovat vain tiedostot, joiden tiedostopääte on: {extensions}.',
 | 
			
		||||
    'Page not found.' => 'Sivua ei löytynyt.',
 | 
			
		||||
    'Please fix the following errors:' => 'Korjaa seuraavat virheet:',
 | 
			
		||||
    'Please upload a file.' => 'Lähetä tiedosto.',
 | 
			
		||||
    'Showing <b>{begin, number}-{end, number}</b> of <b>{totalCount, number}</b> {totalCount, plural, one{item} other{items}}.' => 'Näytetään <b>{begin, number}-{end, number}</b> kaikkiaan <b>{totalCount, number}</b> {totalCount, plural, one{tuloksesta} other{tuloksesta}}.',
 | 
			
		||||
    'The file "{file}" is not an image.' => 'Tiedosto "{file}" ei ole kuva.',
 | 
			
		||||
    'The file "{file}" is too big. Its size cannot exceed {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'Tiedosto "{file}" on liian iso. Sen koko ei voi olla suurempi kuin {limit, number} {limit, plural, one{tavu} other{tavua}}.',
 | 
			
		||||
    'The file "{file}" is too small. Its size cannot be smaller than {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'Tiedosto "{file}" on liian pieni. Sen koko ei voi olla pienempi kuin {limit, number} {limit, plural, one{tavu} other{tavua}}.',
 | 
			
		||||
    'The format of {attribute} is invalid.' => 'Attribuutin {attribute} formaatti on virheellinen.',
 | 
			
		||||
    'The image "{file}" is too large. The height cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Kuva "{file}" on liian suuri. Korkeus ei voi olla suurempi kuin {limit, number} {limit, plural, one{pikseli} other{pikseliä}}.',
 | 
			
		||||
    '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.',
 | 
			
		||||
    'Unknown command "{command}".' => 'Tuntematon komento "{command}".',
 | 
			
		||||
    'Unknown option: --{name}' => 'Tuntematon valinta: --{name}',
 | 
			
		||||
    'Update' => 'Päivitä',
 | 
			
		||||
    'View' => 'Näytä',
 | 
			
		||||
    'Yes' => 'Kyllä',
 | 
			
		||||
    'You are not allowed to perform this action.' => 'Sinulla ei ole tarvittavia oikeuksia toiminnon suorittamiseen.',
 | 
			
		||||
    'You can upload at most {limit, number} {limit, plural, one{file} other{files}}.' => 'Voit lähettää enintään {limit, number} {limit, plural, one{tiedoston} other{tiedostoa}}.',
 | 
			
		||||
    'in {delta, plural, =1{a day} other{# days}}' => '{delta, plural, =1{päivässä} other{# päivässä}}',
 | 
			
		||||
    'in {delta, plural, =1{a minute} other{# minutes}}' => '{delta, plural, =1{minuutissa} other{# minuutissa}}',
 | 
			
		||||
    'in {delta, plural, =1{a month} other{# months}}' => '{delta, plural, =1{kuukaudessa} other{# kuukaudessa}}',
 | 
			
		||||
    'in {delta, plural, =1{a second} other{# seconds}}' => '{delta, plural, =1{sekunnissa} other{# sekunnissa}}',
 | 
			
		||||
    'in {delta, plural, =1{a year} other{# years}}' => '{delta, plural, =1{vuodessa} other{# vuodessa}}',
 | 
			
		||||
    'in {delta, plural, =1{an hour} other{# hours}}' => '{delta, plural, =1{tunnissa} other{# tunnissa}}',
 | 
			
		||||
    'the input value' => 'syötetty arvo',
 | 
			
		||||
    '{attribute} "{value}" has already been taken.' => '{attribute} "{value}" on jo käytössä.',
 | 
			
		||||
    '{attribute} cannot be blank.' => '{attribute} ei voi olla tyhjä.',
 | 
			
		||||
    '{attribute} is invalid.' => '{attribute} on virheellinen.',
 | 
			
		||||
    '{attribute} is not a valid URL.' => '{attribute} on virheellinen URL.',
 | 
			
		||||
    '{attribute} is not a valid email address.' => '{attribute} on virheellinen sähköpostiosoite.',
 | 
			
		||||
    '{attribute} must be "{requiredValue}".' => '{attribute} täytyy olla "{requiredValue}".',
 | 
			
		||||
    '{attribute} must be a number.' => '{attribute} täytyy olla luku.',
 | 
			
		||||
    '{attribute} must be a string.' => '{attribute} täytyy olla merkkijono.',
 | 
			
		||||
    '{attribute} must be an integer.' => '{attribute} täytyy olla kokonaisluku.',
 | 
			
		||||
    '{attribute} must be either "{true}" or "{false}".' => '{attribute} täytyy olla joko {true} tai {false}.',
 | 
			
		||||
    '{attribute} must be greater than "{compareValue}".' => '{attribute} täytyy olla suurempi kuin "{compareValue}".',
 | 
			
		||||
    '{attribute} must be greater than or equal to "{compareValue}".' => '{attribute} täytyy olla suurempi tai yhtä suuri kuin "{compareValue}".',
 | 
			
		||||
    '{attribute} must be less than "{compareValue}".' => '{attribute} täytyy olla pienempi kuin "{compareValue}".',
 | 
			
		||||
    '{attribute} must be less than or equal to "{compareValue}".' => '{attribute} täytyy olla pienempi tai yhtä suuri kuin "{compareValue}".',
 | 
			
		||||
    '{attribute} must be no greater than {max}.' => '{attribute} ei saa olla suurempi kuin "{max}".',
 | 
			
		||||
    '{attribute} must be no less than {min}.' => '{attribute} ei saa olla pienempi kuin "{min}".',
 | 
			
		||||
    '{attribute} must be repeated exactly.' => '{attribute} täytyy toistaa täsmälleen.',
 | 
			
		||||
    '{attribute} must not be equal to "{compareValue}".' => '{attribute} ei saa olla yhtä suuri kuin "{compareValue}".',
 | 
			
		||||
    '{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.' => '{attribute} tulisi sisältää vähintään {min, number} {min, plural, one{merkki} other{merkkiä}}.',
 | 
			
		||||
    '{attribute} should contain at most {max, number} {max, plural, one{character} other{characters}}.' => '{attribute} tulisi sisältää enintään {max, number} {max, plural, one{merkki} other{merkkiä}}.',
 | 
			
		||||
    '{attribute} should contain {length, number} {length, plural, one{character} other{characters}}.' => '{attribute} tulisi sisältää {length, number} {length, plural, one{merkki} other{merkkiä}}.',
 | 
			
		||||
    '{delta, plural, =1{a day} other{# days}} ago' => '{delta, plural, =1{päivä} other{# päivää}} sitten',
 | 
			
		||||
    '{delta, plural, =1{a minute} other{# minutes}} ago' => '{delta, plural, =1{minuutti} other{# minuuttia}} sitten',
 | 
			
		||||
    '{delta, plural, =1{a month} other{# months}} ago' => '{delta, plural, =1{kuukausi} other{# kuukautta}} sitten',
 | 
			
		||||
    '{delta, plural, =1{a second} other{# seconds}} ago' => '{delta, plural, =1{sekunti} other{# sekuntia}} sitten',
 | 
			
		||||
    '{delta, plural, =1{a year} other{# years}} ago' => '{delta, plural, =1{vuosi} other{# vuotta}} sitten',
 | 
			
		||||
    '{delta, plural, =1{an hour} other{# hours}} ago' => '{delta, plural, =1{tunti} other{# tuntia}} sitten',
 | 
			
		||||
    '{n, plural, =1{# byte} other{# bytes}}' => '{n, plural, =1{# tavu} other{# tavua}}',
 | 
			
		||||
    '{n, plural, =1{# gigabyte} other{# gigabytes}}' => '{n, plural, =1{# gigatavu} other{# gigatavua}}',
 | 
			
		||||
    '{n, plural, =1{# kilobyte} other{# kilobytes}}' => '{n, plural, =1{# kilotavu} other{# kilotavua}}',
 | 
			
		||||
    '{n, plural, =1{# megabyte} other{# megabytes}}' => '{n, plural, =1{# megatavu} other{# megatavua}}',
 | 
			
		||||
    '{n, plural, =1{# petabyte} other{# petabytes}}' => '{n, plural, =1{# petatavu} other{# petatavua}}',
 | 
			
		||||
    '{n, plural, =1{# terabyte} other{# terabytes}}' => '{n, plural, =1{# teratavu} other{# teratavua}}',
 | 
			
		||||
    '{n} B' => '{n} t',
 | 
			
		||||
    '{n} GB' => '{n} Gt',
 | 
			
		||||
    '{n} KB' => '{n} kt',
 | 
			
		||||
    '{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';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										76
									
								
								framework/test/ArrayFixture.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								framework/test/ArrayFixture.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,76 @@
 | 
			
		||||
<?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.
 | 
			
		||||
@ -145,79 +144,6 @@ class ActiveForm extends Widget
 | 
			
		||||
     * @var string the type of data that you're expecting back from the server.
 | 
			
		||||
     */
 | 
			
		||||
    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.
 | 
			
		||||
@ -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"]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										58
									
								
								tests/unit/framework/test/ArrayFixtureTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								tests/unit/framework/test/ArrayFixtureTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,58 @@
 | 
			
		||||
<?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();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								tests/unit/framework/test/data/array_fixture.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								tests/unit/framework/test/data/array_fixture.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
return [
 | 
			
		||||
    'customer1' => [
 | 
			
		||||
        'email' => 'customer1@example.com',
 | 
			
		||||
        'name' => 'customer1',
 | 
			
		||||
        'address' => 'address1',
 | 
			
		||||
        'status' => 1,
 | 
			
		||||
    ],
 | 
			
		||||
    'customer2' => [
 | 
			
		||||
        'email' => 'customer2@example.com',
 | 
			
		||||
        'name' => 'customer2',
 | 
			
		||||
        'address' => 'address2',
 | 
			
		||||
        'status' => 2,
 | 
			
		||||
    ],
 | 
			
		||||
];
 | 
			
		||||
		Reference in New Issue
	
	Block a user