Commit 302b7a7d by Tobias Munk

Merge commit '1ccad3d9' into feature/composer-docs

parents 36b41bad 1ccad3d9
......@@ -149,7 +149,7 @@ $email = $customer->email;
To change the value of a column, assign a new value to the associated property and save the object:
```
```php
$customer->email = 'jane@example.com';
$customer->save();
```
......
......@@ -114,9 +114,11 @@ There are several classes provided by framework:
- FileHelper
- Html
- HtmlPurifier
- Image
- Inflector
- Json
- Markdown
- Security
- StringHelper
- Url
- VarDumper
......@@ -120,7 +120,7 @@ adjust directory permissions so that your webserver is able to write to the dire
> Note: The code generated by gii is only a template that has to be adjusted to your needs. It is there
to help you create new things quickly but it is not something that creates ready to use code.
We often see people using the models generated by gii without change and just extend them to adjust
some parts of it. This is not how it is ment to be used. Code generated by gii may be incomplete or incorrect
some parts of it. This is not how it is meant to be used. Code generated by gii may be incomplete or incorrect
and has to be changed to fit your needs before you can use it.
......
......@@ -657,8 +657,7 @@ After a user is authenticated, you probably want to check if he has the permissi
action for the requested resource. This process is called *authorization* which is covered in detail in
the [Authorization chapter](authorization.md).
You may use the [[yii\web\AccessControl]] filter and/or the Role-Based Access Control (RBAC) component
to implementation authorization.
You may use the Role-Based Access Control (RBAC) component to implementation authorization.
To simplify the authorization check, you may also override the [[yii\rest\Controller::checkAccess()]] method
and then call this method in places where authorization is needed. By default, the built-in actions provided
......
......@@ -19,7 +19,7 @@ Creating URLs
-------------
The most important rule for creating URLs in your site is to always do so using the URL manager. The URL manager is a built-in application component named `urlManager`. This component is accessible from both web and console applications via
`\Yii::$app->urlManager`. The component makes availabe the two following URL creation methods:
`\Yii::$app->urlManager`. The component makes available the two following URL creation methods:
- `createUrl($params)`
- `createAbsoluteUrl($params, $schema = null)`
......
Yii2 Core framework code style
==============================
The following code style is used for Yii 2.x core and official extensions development. If you want to pull-request code into the core, consider using it. We aren't forcing you to use this code style for your application. Feel free to choose what suits you better.
The following code style is used for Yii 2.x core and official extensions development. If you want to pull-request code
into the core, consider using it. We aren't forcing you to use this code style for your application. Feel free to choose
what suits you better.
You can get a config for CodeSniffer here: https://github.com/yiisoft/yii2-coding-standards
1. Overview
-----------
Overall we're using [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)
compatible style so everything that applies to
[PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) is applied to our code
style as well.
- Files MUST use either `<?php` or `<?=` tags.
- There should be a newline at the end of file.
- Files MUST use only UTF-8 without BOM for PHP code.
- Code MUST use tabs for indenting, not spaces.
- Code MUST use 4 spaces for indenting, not tabs.
- Class names MUST be declared in `StudlyCaps`.
- Class constants MUST be declared in all upper case with underscore separators.
- Method names MUST be declared in `camelCase`.
......
(function() {
var ajax = function(url, settings) {
var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
settings = settings || {};
xhr.open(settings.method || 'GET', url, true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(state) {
if (xhr.readyState == 4) {
if (xhr.status == 200 && settings.success) {
settings.success(xhr);
} else if (xhr.status != 200 && settings.error) {
settings.error(xhr);
}
}
};
xhr.send(settings.data || '');
};
(function () {
var ajax = function (url, settings) {
var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
settings = settings || {};
xhr.open(settings.method || 'GET', url, true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function (state) {
if (xhr.readyState == 4) {
if (xhr.status == 200 && settings.success) {
settings.success(xhr);
} else if (xhr.status != 200 && settings.error) {
settings.error(xhr);
}
}
};
xhr.send(settings.data || '');
};
var e = document.getElementById('yii-debug-toolbar');
if (e) {
e.style.display = 'block';
var url = e.getAttribute('data-url');
ajax(url, {
success: function(xhr) {
var div = document.createElement('div');
div.innerHTML = xhr.responseText;
e.parentNode.replaceChild(div, e);
if (window.localStorage) {
var pref = localStorage.getItem('yii-debug-toolbar');
if (pref == 'minimized') {
document.getElementById('yii-debug-toolbar').style.display = 'none';
document.getElementById('yii-debug-toolbar-min').style.display = 'block';
}
}
},
error: function(xhr) {
e.innerHTML = xhr.responseText;
}
});
}
var e = document.getElementById('yii-debug-toolbar');
if (e) {
e.style.display = 'block';
var url = e.getAttribute('data-url');
ajax(url, {
success: function (xhr) {
var div = document.createElement('div');
div.innerHTML = xhr.responseText;
e.parentNode.replaceChild(div, e);
if (window.localStorage) {
var pref = localStorage.getItem('yii-debug-toolbar');
if (pref == 'minimized') {
document.getElementById('yii-debug-toolbar').style.display = 'none';
document.getElementById('yii-debug-toolbar-min').style.display = 'block';
}
}
},
error: function (xhr) {
e.innerHTML = xhr.responseText;
}
});
}
})();
......@@ -13,16 +13,16 @@ echo DetailView::widget([
'to',
'charset',
[
'name' => 'time',
'attribute' => 'time',
'value' => $timeFormatter->asDateTime($model['time'], 'short'),
],
'subject',
[
'name' => 'body',
'attribute' => 'body',
'label' => 'Text body',
],
[
'name' => 'isSuccessful',
'attribute' => 'isSuccessful',
'label' => 'Successfully sent',
'value' => $model['isSuccessful'] ? 'Yes' : 'No'
],
......@@ -30,7 +30,7 @@ echo DetailView::widget([
'bcc',
'cc',
[
'name' => 'file',
'attribute' => 'file',
'format' => 'html',
'value' => Html::a('Download eml', ['download-mail', 'file' => $model['file']]),
],
......
......@@ -70,7 +70,7 @@ class <?= $controllerClass ?> extends <?= StringHelper::basename($generator->bas
/**
* Displays a single <?= $modelClass ?> model.
* <?= implode("\n\t * ", $actionParamComments) . "\n" ?>
* <?= implode("\n * ", $actionParamComments) . "\n" ?>
* @return mixed
*/
public function actionView(<?= $actionParams ?>)
......@@ -101,7 +101,7 @@ class <?= $controllerClass ?> extends <?= StringHelper::basename($generator->bas
/**
* Updates an existing <?= $modelClass ?> model.
* If update is successful, the browser will be redirected to the 'view' page.
* <?= implode("\n\t * ", $actionParamComments) . "\n" ?>
* <?= implode("\n * ", $actionParamComments) . "\n" ?>
* @return mixed
*/
public function actionUpdate(<?= $actionParams ?>)
......@@ -120,7 +120,7 @@ class <?= $controllerClass ?> extends <?= StringHelper::basename($generator->bas
/**
* Deletes an existing <?= $modelClass ?> model.
* If deletion is successful, the browser will be redirected to the 'index' page.
* <?= implode("\n\t * ", $actionParamComments) . "\n" ?>
* <?= implode("\n * ", $actionParamComments) . "\n" ?>
* @return mixed
*/
public function actionDelete(<?= $actionParams ?>)
......@@ -133,7 +133,7 @@ class <?= $controllerClass ?> extends <?= StringHelper::basename($generator->bas
/**
* Finds the <?= $modelClass ?> model based on its primary key value.
* If the model is not found, a 404 HTTP exception will be thrown.
* <?= implode("\n\t * ", $actionParamComments) . "\n" ?>
* <?= implode("\n * ", $actionParamComments) . "\n" ?>
* @return <?= $modelClass ?> the loaded model
* @throws NotFoundHttpException if the model cannot be found
*/
......
......@@ -33,12 +33,12 @@ use <?= ltrim($generator->modelClass, '\\') . (isset($modelAlias) ? " as $modelA
*/
class <?= $searchModelClass ?> extends Model
{
public $<?= implode(";\n\tpublic $", $searchAttributes) ?>;
public $<?= implode(";\n public $", $searchAttributes) ?>;
public function rules()
{
return [
<?= implode(",\n\t\t\t", $rules) ?>,
<?= implode(",\n ", $rules) ?>,
];
}
......@@ -65,7 +65,7 @@ class <?= $searchModelClass ?> extends Model
return $dataProvider;
}
<?= implode("\n\t\t", $searchConditions) ?>
<?= implode("\n ", $searchConditions) ?>
return $dataProvider;
}
......
......@@ -33,11 +33,11 @@ use yii\widgets\ActiveForm;
<?= "<?php " ?>$form = ActiveForm::begin(); ?>
<?php foreach ($safeAttributes as $attribute) {
echo "\t\t<?= " . $generator->generateActiveField($attribute) . " ?>\n\n";
echo " <?= " . $generator->generateActiveField($attribute) . " ?>\n\n";
} ?>
<div class="form-group">
<?= "<?= " ?>Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
</div>
<div class="form-group">
<?= "<?= " ?>Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
</div>
<?= "<?php " ?>ActiveForm::end(); ?>
......
......@@ -32,16 +32,16 @@ use yii\widgets\ActiveForm;
$count = 0;
foreach ($generator->getColumnNames() as $attribute) {
if (++$count < 6) {
echo "\t\t<?= " . $generator->generateActiveSearchField($attribute) . " ?>\n\n";
echo " <?= " . $generator->generateActiveSearchField($attribute) . " ?>\n\n";
} else {
echo "\t\t<?php // echo " . $generator->generateActiveSearchField($attribute) . " ?>\n\n";
echo " <?php // echo " . $generator->generateActiveSearchField($attribute) . " ?>\n\n";
}
}
?>
<div class="form-group">
<?= "<?= " ?>Html::submitButton('Search', ['class' => 'btn btn-primary']) ?>
<?= "<?= " ?>Html::resetButton('Reset', ['class' => 'btn btn-default']) ?>
</div>
<div class="form-group">
<?= "<?= " ?>Html::submitButton('Search', ['class' => 'btn btn-primary']) ?>
<?= "<?= " ?>Html::resetButton('Reset', ['class' => 'btn btn-default']) ?>
</div>
<?= "<?php " ?>ActiveForm::end(); ?>
......
......@@ -48,18 +48,18 @@ $count = 0;
if (($tableSchema = $generator->getTableSchema()) === false) {
foreach ($generator->getColumnNames() as $name) {
if (++$count < 6) {
echo "\t\t\t'" . $name . "',\n";
echo " '" . $name . "',\n";
} else {
echo "\t\t\t// '" . $name . "',\n";
echo " // '" . $name . "',\n";
}
}
} else {
foreach ($tableSchema->columns as $column) {
$format = $generator->generateColumnFormat($column);
if (++$count < 6) {
echo "\t\t\t'" . $column->name . ($format === 'text' ? "" : ":" . $format) . "',\n";
echo " '" . $column->name . ($format === 'text' ? "" : ":" . $format) . "',\n";
} else {
echo "\t\t\t// '" . $column->name . ($format === 'text' ? "" : ":" . $format) . "',\n";
echo " // '" . $column->name . ($format === 'text' ? "" : ":" . $format) . "',\n";
}
}
}
......
......@@ -46,12 +46,12 @@ $this->params['breadcrumbs'][] = $this->title;
<?php
if (($tableSchema = $generator->getTableSchema()) === false) {
foreach ($generator->getColumnNames() as $name) {
echo "\t\t\t'" . $name . "',\n";
echo " '" . $name . "',\n";
}
} else {
foreach ($generator->getTableSchema()->columns as $column) {
$format = $generator->generateColumnFormat($column);
echo "\t\t\t'" . $column->name . ($format === 'text' ? "" : ":" . $format) . "',\n";
echo " '" . $column->name . ($format === 'text' ? "" : ":" . $format) . "',\n";
}
}
?>
......
......@@ -45,7 +45,7 @@ class <?= $className ?> extends <?= '\\' . ltrim($generator->baseClass, '\\') .
*/
public function rules()
{
return [<?= "\n\t\t\t" . implode(",\n\t\t\t", $rules) . "\n\t\t" ?>];
return [<?= "\n " . implode(",\n ", $rules) . "\n " ?>];
}
/**
......
......@@ -59,6 +59,7 @@ Yii Framework 2 Change Log
- Bug #2695: Fixed the issue that `FileValidator::isEmpty()` always returns true for validate multiple files (ZhandosKz)
- Bug #2739: Fixed the issue that `CreateAction::run()` was using obsolete `Controller::createAbsoluteUrl()` method (tonydspaniard)
- Bug #2740: Fixed the issue that `CaptchaAction::run()` was using obsolete `Controller::createUrl()` method (tonydspaniard)
- Bug #2760: Fixed GridView `filterUrl` parameters (qiangxue, AlexGx)
- Bug: Fixed `Call to a member function registerAssetFiles() on a non-object` in case of wrong `sourcePath` for an asset bundle (samdark)
- Bug: Fixed incorrect event name for `yii\jui\Spinner` (samdark)
- Bug: Json::encode() did not handle objects that implement JsonSerializable interface correctly (cebe)
......@@ -72,6 +73,7 @@ Yii Framework 2 Change Log
- Bug: `Query::queryScalar` wasn't making `SELECT DISTINCT` queries subqueries (jom)
- Enh #46: Added Image extension based on [Imagine library](http://imagine.readthedocs.org) (tonydspaniard)
- Enh #364: Improve Inflector::slug with `intl` transliteration. Improved transliteration char map. (tonydspaniard)
- Enh #497: Removed `\yii\log\Target::logUser` and added `\yii\log\Target::prefix` to support customizing message prefix (qiangxue)
- Enh #797: Added support for validating multiple columns by `UniqueValidator` and `ExistValidator` (qiangxue)
- Enh #802: Added support for retrieving sub-array element or child object property through `ArrayHelper::getValue()` (qiangxue, cebe)
- Enh #938: Added `yii\web\View::renderAjax()` and `yii\web\Controller::renderAjax()` (qiangxue)
......@@ -146,6 +148,7 @@ Yii Framework 2 Change Log
- Enh #2729: Added `FilterValidator::skipOnArray` so that filters like `trim` will not fail for array inputs (qiangxue)
- Enh #2735: Added support for `DateTimeInterface` in `Formatter` (ivokund)
- Enh #2756: Added support for injecting custom `isEmpty` check for all validators (qiangxue)
- Enh #2775: Added `yii\base\Application::bootstrap` to support running bootstrap classes when starting an application (qiangxue)
- Enh: Added support for using arrays as option values for console commands (qiangxue)
- Enh: Added `favicon.ico` and `robots.txt` to default application templates (samdark)
- Enh: Added `Widget::autoIdPrefix` to support prefixing automatically generated widget IDs (qiangxue)
......@@ -241,6 +244,7 @@ Yii Framework 2 Change Log
- Renamed `yii\web\User::returnUrlVar` to `returnUrlParam`
- Chg: Added `View::viewFile` and removed `ViewEvent::viewFile` (qiangxue)
- Chg: Changed `Controller::afterAction()`, `Module::afterAction()` and `ActionFilter::afterAction()` to pass `$result` by value instead of reference (qiangxue)
- Chg: `yii\base\Extension::init()` is renamed to `bootstrap()` (qiangxue)
- New #66: [Auth client library](https://github.com/yiisoft/yii2-authclient) OpenId, OAuth1, OAuth2 clients (klimov-paul)
- New #706: Added `yii\widgets\Pjax` and enhanced `GridView` to work with `Pjax` to support AJAX-update (qiangxue)
- New #1393: [Codeception testing framework integration](https://github.com/yiisoft/yii2-codeception) (Ragazzo)
......
......@@ -10,63 +10,63 @@
* @since 2.0
*/
(function ($) {
$.fn.yiiCaptcha = function (method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || !method) {
return methods.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on jQuery.yiiCaptcha');
return false;
}
};
$.fn.yiiCaptcha = function (method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || !method) {
return methods.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on jQuery.yiiCaptcha');
return false;
}
};
var defaults = {
refreshUrl: undefined,
hashKey: undefined
};
var defaults = {
refreshUrl: undefined,
hashKey: undefined
};
var methods = {
init: function (options) {
return this.each(function () {
var $e = $(this);
var settings = $.extend({}, defaults, options || {});
$e.data('yiiCaptcha', {
settings: settings
});
var methods = {
init: function (options) {
return this.each(function () {
var $e = $(this);
var settings = $.extend({}, defaults, options || {});
$e.data('yiiCaptcha', {
settings: settings
});
$e.on('click.yiiCaptcha', function() {
methods.refresh.apply($e);
return false;
});
$e.on('click.yiiCaptcha', function () {
methods.refresh.apply($e);
return false;
});
});
},
});
},
refresh: function () {
var $e = this,
settings = this.data('yiiCaptcha').settings;
$.ajax({
url: $e.data('yiiCaptcha').settings.refreshUrl,
dataType: 'json',
cache: false,
success: function(data) {
$e.attr('src', data.url);
$('body').data(settings.hashKey, [data.hash1, data.hash2]);
}
});
},
refresh: function () {
var $e = this,
settings = this.data('yiiCaptcha').settings;
$.ajax({
url: $e.data('yiiCaptcha').settings.refreshUrl,
dataType: 'json',
cache: false,
success: function (data) {
$e.attr('src', data.url);
$('body').data(settings.hashKey, [data.hash1, data.hash2]);
}
});
},
destroy: function () {
return this.each(function () {
$(window).unbind('.yiiCaptcha');
$(this).removeData('yiiCaptcha');
});
},
destroy: function () {
return this.each(function () {
$(window).unbind('.yiiCaptcha');
$(this).removeData('yiiCaptcha');
});
},
data: function() {
return this.data('yiiCaptcha');
}
};
data: function () {
return this.data('yiiCaptcha');
}
};
})(window.jQuery);
......@@ -10,120 +10,120 @@
* @since 2.0
*/
(function ($) {
$.fn.yiiGridView = function (method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || !method) {
return methods.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on jQuery.yiiGridView');
return false;
}
};
$.fn.yiiGridView = function (method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || !method) {
return methods.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on jQuery.yiiGridView');
return false;
}
};
var defaults = {
filterUrl: undefined,
filterSelector: undefined
};
var defaults = {
filterUrl: undefined,
filterSelector: undefined
};
var gridData = {};
var gridData = {};
var methods = {
init: function (options) {
return this.each(function () {
var $e = $(this);
var settings = $.extend({}, defaults, options || {});
gridData[$e.prop('id')] = {settings: settings};
var methods = {
init: function (options) {
return this.each(function () {
var $e = $(this);
var settings = $.extend({}, defaults, options || {});
gridData[$e.prop('id')] = {settings: settings};
var enterPressed = false;
$(document).off('change.yiiGridView keydown.yiiGridView', settings.filterSelector)
.on('change.yiiGridView keydown.yiiGridView', settings.filterSelector, function (event) {
if (event.type === 'keydown') {
if (event.keyCode !== 13) {
return; // only react to enter key
} else {
enterPressed = true;
}
} else {
// prevent processing for both keydown and change events
if (enterPressed) {
enterPressed = false;
return;
}
}
var enterPressed = false;
$(document).off('change.yiiGridView keydown.yiiGridView', settings.filterSelector)
.on('change.yiiGridView keydown.yiiGridView', settings.filterSelector, function (event) {
if (event.type === 'keydown') {
if (event.keyCode !== 13) {
return; // only react to enter key
} else {
enterPressed = true;
}
} else {
// prevent processing for both keydown and change events
if (enterPressed) {
enterPressed = false;
return;
}
}
methods.applyFilter.apply($e);
methods.applyFilter.apply($e);
return false;
});
});
},
return false;
});
});
},
applyFilter: function () {
var $grid = $(this);
var settings = gridData[$grid.prop('id')].settings;
var data = {};
$.each($(settings.filterSelector).serializeArray(), function () {
data[this.name] = this.value;
});
applyFilter: function () {
var $grid = $(this);
var settings = gridData[$grid.prop('id')].settings;
var data = {};
$.each($(settings.filterSelector).serializeArray(), function () {
data[this.name] = this.value;
});
$.each(yii.getQueryParams(settings.filterUrl), function (name, value) {
if (data[name] === undefined) {
data[name] = value;
}
});
$.each(yii.getQueryParams(settings.filterUrl), function (name, value) {
if (data[name] === undefined) {
data[name] = value;
}
});
var pos = settings.filterUrl.indexOf('?');
var url = pos < 0 ? settings.filterUrl : settings.filterUrl.substring(0, pos);
var pos = settings.filterUrl.indexOf('?');
var url = pos < 0 ? settings.filterUrl : settings.filterUrl.substring(0, pos);
$grid.find('form.gridview-filter-form').remove();
var $form = $('<form action="' + url + '" method="get" class="gridview-filter-form" style="display:none" data-pjax></form>').appendTo($grid);
$.each(data, function (name, value) {
$form.append($('<input type="hidden" name="t" value="" />').attr('name', name).val(value));
});
$form.submit();
},
$grid.find('form.gridview-filter-form').remove();
var $form = $('<form action="' + url + '" method="get" class="gridview-filter-form" style="display:none" data-pjax></form>').appendTo($grid);
$.each(data, function (name, value) {
$form.append($('<input type="hidden" name="t" value="" />').attr('name', name).val(value));
});
$form.submit();
},
setSelectionColumn: function (options) {
var $grid = $(this);
var id = $(this).prop('id');
gridData[id].selectionColumn = options.name;
if (!options.multiple) {
return;
}
var inputs = "#" + id + " input[name='" + options.checkAll + "']";
$(document).off('click.yiiGridView', inputs).on('click.yiiGridView', inputs, function () {
$grid.find("input[name='" + options.name + "']:enabled").prop('checked', this.checked);
});
$(document).off('click.yiiGridView', inputs + ":enabled").on('click.yiiGridView', inputs + ":enabled", function () {
var all = $grid.find("input[name='" + options.name + "']").length == $grid.find("input[name='" + options.name + "']:checked").length;
$grid.find("input[name='" + options.checkAll + "']").prop('checked', all);
});
},
setSelectionColumn: function (options) {
var $grid = $(this);
var id = $(this).prop('id');
gridData[id].selectionColumn = options.name;
if (!options.multiple) {
return;
}
var inputs = "#" + id + " input[name='" + options.checkAll + "']";
$(document).off('click.yiiGridView', inputs).on('click.yiiGridView', inputs, function () {
$grid.find("input[name='" + options.name + "']:enabled").prop('checked', this.checked);
});
$(document).off('click.yiiGridView', inputs + ":enabled").on('click.yiiGridView', inputs + ":enabled", function () {
var all = $grid.find("input[name='" + options.name + "']").length == $grid.find("input[name='" + options.name + "']:checked").length;
$grid.find("input[name='" + options.checkAll + "']").prop('checked', all);
});
},
getSelectedRows: function () {
var $grid = $(this);
var data = gridData[$grid.prop('id')];
var keys = [];
if (data.selectionColumn) {
$grid.find("input[name='" + data.selectionColumn + "']:checked").each(function () {
keys.push($(this).parent().closest('tr').data('key'));
});
}
return keys;
},
getSelectedRows: function () {
var $grid = $(this);
var data = gridData[$grid.prop('id')];
var keys = [];
if (data.selectionColumn) {
$grid.find("input[name='" + data.selectionColumn + "']:checked").each(function () {
keys.push($(this).parent().closest('tr').data('key'));
});
}
return keys;
},
destroy: function () {
return this.each(function () {
$(window).unbind('.yiiGridView');
$(this).removeData('yiiGridView');
});
},
destroy: function () {
return this.each(function () {
$(window).unbind('.yiiGridView');
$(this).removeData('yiiGridView');
});
},
data: function () {
var id = $(this).prop('id');
return gridData[id];
}
};
data: function () {
var id = $(this).prop('id');
return gridData[id];
}
};
})(window.jQuery);
......@@ -124,11 +124,20 @@ abstract class Application extends Module
* 'name' => 'extension name',
* 'version' => 'version number',
* 'bootstrap' => 'BootstrapClassName',
* 'alias' => [
* '@alias1' => 'to/path1',
* '@alias2' => 'to/path2',
* ],
* ]
* ~~~
*/
public $extensions = [];
/**
* @var array list of bootstrap classes. A bootstrap class must have a public static method named
* `bootstrap()`. The method will be called during [[init()]] for every bootstrap class.
*/
public $bootstrap = [];
/**
* @var \Exception the exception that is being handled currently. When this is not null,
* it means the application is handling some exception and extra care should be taken.
*/
......@@ -205,6 +214,10 @@ abstract class Application extends Module
public function init()
{
$this->initExtensions($this->extensions);
foreach ($this->bootstrap as $class) {
/** @var Extension $class */
$class::bootstrap();
}
parent::init();
}
......@@ -224,7 +237,7 @@ abstract class Application extends Module
if (isset($extension['bootstrap'])) {
/** @var Extension $class */
$class = $extension['bootstrap'];
$class::init();
$class::bootstrap();
}
}
}
......
......@@ -11,7 +11,7 @@ namespace yii\base;
* Extension is the base class that may be extended by individual extensions.
*
* Extension serves as the bootstrap class for extensions. When an extension
* is installed via composer, the [[init()]] method of its Extension class (if any)
* is installed via composer, the [[bootstrap()]] method of its Extension class (if any)
* will be invoked during the application initialization stage.
*
* @author Qiang Xue <qiang.xue@gmail.com>
......@@ -21,9 +21,9 @@ class Extension
{
/**
* Initializes the extension.
* This method is invoked at the end of [[Application::init()]].
* This method is invoked at the beginning of [[Application::init()]].
*/
public static function init()
public static function bootstrap()
{
}
}
......@@ -8,6 +8,7 @@
namespace yii\db;
use Yii;
use yii\base\InvalidConfigException;
use yii\helpers\Inflector;
use yii\helpers\StringHelper;
......@@ -376,6 +377,7 @@ class ActiveRecord extends BaseActiveRecord
public function insert($runValidation = true, $attributes = null)
{
if ($runValidation && !$this->validate($attributes)) {
Yii::info('Model not inserted due to validation error.', __METHOD__);
return false;
}
$db = static::getDb();
......@@ -493,6 +495,7 @@ class ActiveRecord extends BaseActiveRecord
public function update($runValidation = true, $attributes = null)
{
if ($runValidation && !$this->validate($attributes)) {
Yii::info('Model not updated due to validation error.', __METHOD__);
return false;
}
$db = static::getDb();
......
......@@ -219,7 +219,7 @@ class GridView extends BaseListView
*/
protected function getClientOptions()
{
$filterUrl = isset($this->filterUrl) ? $this->filterUrl : [Yii::$app->controller->action->id];
$filterUrl = isset($this->filterUrl) ? $this->filterUrl : Yii::$app->request->url;
$id = $this->filterRowOptions['id'];
$filterSelector = "#$id input, #$id select";
if (isset($this->filterSelector)) {
......
......@@ -10,6 +10,7 @@ namespace yii\log;
use Yii;
use yii\base\Component;
use yii\base\InvalidConfigException;
use yii\web\Request;
/**
* Target is the base class for all log target classes.
......@@ -52,17 +53,18 @@ abstract class Target extends Component
*/
public $except = [];
/**
* @var boolean whether to log a message containing the current user name and ID. Defaults to false.
* @see \yii\web\User
*/
public $logUser = false;
/**
* @var array list of the PHP predefined variables that should be logged in a message.
* Note that a variable must be accessible via `$GLOBALS`. Otherwise it won't be logged.
* Defaults to `['_GET', '_POST', '_FILES', '_COOKIE', '_SESSION', '_SERVER']`.
*/
public $logVars = ['_GET', '_POST', '_FILES', '_COOKIE', '_SESSION', '_SERVER'];
/**
* @var callable a PHP callable that returns a string to be prefix to every exported message.
* If not set, [[getMessagePrefix()]] will be used, which prefixes user IP, user ID and session ID
* to every message. The signature of the callable should be `function ($message)`.
*/
public $prefix;
/**
* @var integer how many messages should be accumulated before they are exported.
* Defaults to 1000. Note that messages will always be exported when the application terminates.
* Set this property to be 0 if you don't want to export messages until the application terminates.
......@@ -111,11 +113,6 @@ abstract class Target extends Component
protected function getContextMessage()
{
$context = [];
if ($this->logUser && ($user = Yii::$app->getComponent('user', false)) !== null) {
/** @var \yii\web\User $user */
$context[] = 'User: ' . $user->getId();
}
foreach ($this->logVars as $name) {
if (!empty($GLOBALS[$name])) {
$context[] = "\${$name} = " . var_export($GLOBALS[$name], true);
......@@ -233,8 +230,28 @@ abstract class Target extends Component
if (!is_string($text)) {
$text = var_export($text, true);
}
$ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1';
return date('Y/m/d H:i:s', $timestamp) . " [$ip] [$level] [$category] $text";
$prefix = $this->prefix ? call_user_func($this->prefix, $message) : $this->getMessagePrefix($message);
return date('Y/m/d H:i:s', $timestamp) . " $prefix [$level] [$category] $text";
}
/**
* Returns a string to be prefixed to the given message.
* The default implementation will return user IP, user ID and session ID as a prefix.
* @param array $message the message being exported
* @return string the prefix string
*/
public function getMessagePrefix($message)
{
$request = Yii::$app->getRequest();
$ip = $request instanceof Request ? $request->getUserIP() : '-';
/** @var \yii\web\User $user */
$user = Yii::$app->getComponent('user', false);
$userID = $user ? $user->getId(false) : '-';
/** @var \yii\web\Session $session */
$session = Yii::$app->getComponent('session', false);
$sessionID = $session && $session->getIsActive() ? $session->getId() : '-';
return "[$ip] [$userID] [$sessionID]";
}
}
......@@ -7,7 +7,7 @@ return [
'messagePath' => __DIR__,
// array, required, list of language codes that the extracted messages
// should be translated to. For example, ['zh-CN', 'de'].
'languages' => ['ar', 'da', 'de', 'el', 'es', 'fa-IR', 'fr', 'it', 'ja', 'kz', 'lv', 'pl', 'pt-BR', 'pt-PT', 'ro', 'ru', 'sk', 'sr', 'sr-Latn', 'uk', 'zh-CN'],
'languages' => ['ar', 'da', 'de', 'el', 'es', 'fa-IR', 'fi', 'fr', 'it', 'ja', 'kz', 'lv', 'pl', 'pt-BR', 'pt-PT', 'ro', 'ru', 'sk', 'sr', 'sr-Latn', 'uk', 'zh-CN'],
// string, the name of the function for translating messages.
// Defaults to 'Yii::t'. This is used as a mark to find the messages to be
// translated. You may use a string for single function name or an array for
......
<?php
/**
* Message translations.
*
* This file is automatically generated by 'yii message' command.
* It contains the localizable messages extracted from source code.
* You may modify this file by translating the extracted messages.
*
* Each array element represents the translation (value) of a message (key).
* If the value is empty, the message is considered as not translated.
* Messages that no longer need translation will have their translations
* enclosed between a pair of '@@' marks.
*
* Message string can be used with plural forms format. Check i18n section
* of the guide for details.
*
* NOTE: this file must be saved in UTF-8 encoding.
*/
return array (
'(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 extensions are allowed: {extensions}.' => 'Sallittuja ovat vain tiedostot, joiden tiedostopääte on: {extensions}.',
'Only files with these MIME types are allowed: {mimeTypes}.' => 'Sallittuja ovat vain tiedostot, joiden MIME-tyyppi on: {mimeTypes}.',
'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}}.',
'the input value' => 'tuloarvo',
'{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ä}}.',
'{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',
);
......@@ -72,7 +72,7 @@ return array (
'{attribute} must be less than "{compareValue}".' => '{attribute} moet minder zijn dan "{compareValue}".',
'{attribute} must be less than or equal to "{compareValue}".' => '{attribute} moet minder dan of gelijk aan "{compareValue}" zijn.',
'{attribute} must be no greater than {max}.' => '{attribute} mag niet groter zijn dan {max}.',
'{attribute} must be no less than {min}.' => '{attribute} mag niet kleiner zijn dan {max}.',
'{attribute} must be no less than {min}.' => '{attribute} mag niet kleiner zijn dan {min}.',
'{attribute} must be repeated exactly.' => '{attribute} moet exact herhaald worden.',
'{attribute} must not be equal to "{compareValue}".' => '{attribute} mag niet gelijk zijn aan "{compareValue}".',
'{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.' => '{attribute} moet minstens {min, number} {min, plural, one{karakter} other{karakters}} bevatten.',
......
......@@ -65,7 +65,7 @@ class YiiRequirementChecker
* If a string, it is treated as the path of the file, which contains the requirements;
* @return static self instance.
*/
public function check($requirements)
function check($requirements)
{
if (is_string($requirements)) {
$requirements = require($requirements);
......@@ -110,7 +110,7 @@ class YiiRequirementChecker
* Performs the check for the Yii core requirements.
* @return YiiRequirementChecker self instance.
*/
public function checkYii()
function checkYii()
{
return $this->check(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'requirements.php');
}
......@@ -137,7 +137,7 @@ class YiiRequirementChecker
* )
* ```
*/
public function getResult()
function getResult()
{
if (isset($this->result)) {
return $this->result;
......@@ -150,7 +150,7 @@ class YiiRequirementChecker
* Renders the requirements check result.
* The output will vary depending is a script running from web or from console.
*/
public function render()
function render()
{
if (!isset($this->result)) {
$this->usageError('Nothing to render!');
......@@ -171,7 +171,7 @@ class YiiRequirementChecker
* @param string $compare comparison operator, by default '>='
* @return boolean if PHP extension version matches.
*/
public function checkPhpExtensionVersion($extensionName, $version, $compare = '>=')
function checkPhpExtensionVersion($extensionName, $version, $compare = '>=')
{
if (!extension_loaded($extensionName)) {
return false;
......@@ -192,7 +192,7 @@ class YiiRequirementChecker
* @param string $name configuration option name.
* @return boolean option is on.
*/
public function checkPhpIniOn($name)
function checkPhpIniOn($name)
{
$value = ini_get($name);
if (empty($value)) {
......@@ -207,7 +207,7 @@ class YiiRequirementChecker
* @param string $name configuration option name.
* @return boolean option is off.
*/
public function checkPhpIniOff($name)
function checkPhpIniOff($name)
{
$value = ini_get($name);
if (empty($value)) {
......@@ -225,7 +225,7 @@ class YiiRequirementChecker
* @param string $compare comparison operator, by default '>='.
* @return boolean comparison result.
*/
public function compareByteSize($a, $b, $compare = '>=')
function compareByteSize($a, $b, $compare = '>=')
{
$compareExpression = '(' . $this->getByteSize($a) . $compare . $this->getByteSize($b) . ')';
......@@ -238,7 +238,7 @@ class YiiRequirementChecker
* @param string $verboseSize verbose size representation.
* @return integer actual size in bytes.
*/
public function getByteSize($verboseSize)
function getByteSize($verboseSize)
{
if (empty($verboseSize)) {
return 0;
......@@ -277,7 +277,7 @@ class YiiRequirementChecker
* @param string|null $max verbose file size maximum required value, pass null to skip maximum check.
* @return boolean success.
*/
public function checkUploadMaxFileSize($min = null, $max = null)
function checkUploadMaxFileSize($min = null, $max = null)
{
$postMaxSize = ini_get('post_max_size');
$uploadMaxFileSize = ini_get('upload_max_filesize');
......@@ -305,7 +305,7 @@ class YiiRequirementChecker
* @param boolean $_return_ whether the rendering result should be returned as a string
* @return string the rendering result. Null if the rendering result is not required.
*/
public function renderViewFile($_viewFile_, $_data_ = null, $_return_ = false)
function renderViewFile($_viewFile_, $_data_ = null, $_return_ = false)
{
// we use special variable names here to avoid conflict when extracting data
if (is_array($_data_)) {
......@@ -330,7 +330,7 @@ class YiiRequirementChecker
* @param integer $requirementKey requirement key in the list.
* @return array normalized requirement.
*/
public function normalizeRequirement($requirement, $requirementKey = 0)
function normalizeRequirement($requirement, $requirementKey = 0)
{
if (!is_array($requirement)) {
$this->usageError('Requirement must be an array!');
......@@ -369,7 +369,7 @@ class YiiRequirementChecker
* This method will then terminate the execution of the current application.
* @param string $message the error message
*/
public function usageError($message)
function usageError($message)
{
echo "Error: $message\n\n";
exit(1);
......@@ -380,7 +380,7 @@ class YiiRequirementChecker
* @param string $expression a PHP expression to be evaluated.
* @return mixed the expression result.
*/
public function evaluateExpression($expression)
function evaluateExpression($expression)
{
return eval('return ' . $expression . ';');
}
......@@ -389,7 +389,7 @@ class YiiRequirementChecker
* Returns the server information.
* @return string server information.
*/
public function getServerInfo()
function getServerInfo()
{
$info = isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : '';
......@@ -400,7 +400,7 @@ class YiiRequirementChecker
* Returns the now date if possible in string representation.
* @return string now date.
*/
public function getNowDate()
function getNowDate()
{
$nowDate = @strftime('%Y-%m-%d %H:%M', time());
......
......@@ -132,7 +132,7 @@ class ImageValidator extends FileValidator
$this->overHeight = Yii::t('yii', 'The image "{file}" is too large. The height cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.');
}
if ($this->wrongMimeType === null) {
$this->wrongMimeType = Yii::t('yii', 'Only files with these mimeTypes are allowed: {mimeTypes}.');
$this->wrongMimeType = Yii::t('yii', 'Only files with these MIME types are allowed: {mimeTypes}.');
}
if (!is_array($this->mimeTypes)) {
$this->mimeTypes = preg_split('/[\s,]+/', strtolower($this->mimeTypes), -1, PREG_SPLIT_NO_EMPTY);
......
......@@ -8,6 +8,8 @@
echo "<?php\n";
?>
use yii\db\Schema;
class <?= $className ?> extends \yii\db\Migration
{
public function up()
......
......@@ -265,6 +265,7 @@ class User extends Component
* This will remove authentication-related session data.
* If `$destroySession` is true, all session data will be removed.
* @param boolean $destroySession whether to destroy the whole session. Defaults to true.
* @return boolean whether the user is logged out
*/
public function logout($destroySession = true)
{
......@@ -279,24 +280,31 @@ class User extends Component
}
$this->afterLogout($identity);
}
return $this->getIsGuest();
}
/**
* Returns a value indicating whether the user is a guest (not authenticated).
* @param boolean $checkSession whether to check the session to determine if the user is a guest.
* Note that if this is false, it is possible that the user may not be a guest while this method still returns
* true. This is because the session is not checked.
* @return boolean whether the current user is a guest.
*/
public function getIsGuest()
public function getIsGuest($checkSession = true)
{
return $this->getIdentity() === null;
return $this->getIdentity($checkSession) === null;
}
/**
* Returns a value that uniquely represents the user.
* @param boolean $checkSession whether to check the session to determine the user ID.
* Note that if this is false, it is possible that this method returns null although the user may not
* be a guest. This is because the session is not checked.
* @return string|integer the unique identifier for the user. If null, it means the user is a guest.
*/
public function getId()
public function getId($checkSession = true)
{
$identity = $this->getIdentity();
$identity = $this->getIdentity($checkSession);
return $identity !== null ? $identity->getId() : null;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment