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:
Carsten Brandt
2014-09-10 19:26:04 +02:00
24 changed files with 573 additions and 375 deletions

View File

@ -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)

View File

@ -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"
}
});
```

View File

@ -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) {

View File

@ -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] : [];

View File

@ -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',

View File

@ -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',
];

View File

@ -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';

View 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 = [];
}
}

View File

@ -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);

View File

@ -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]].
*/

View File

@ -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, [