In activerecord class i put this code
use yii\db\ActiveRecord;
use yii\behaviors\TimestampBehavior;
use yii\db\Expression;
public function behaviors()
{
return [
'class' => TimestampBehavior::className(),
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['create_time'],
ActiveRecord::EVENT_BEFORE_UPDATE => ['create_time'],
],
];
}
but it is throwing me an error
Invalid Configuration – yii\base\InvalidConfigException
Object configuration must be an array containing a "class" element.
I dont know where i am doing wrong . i also follow this link
TimestampBehavior is not working in Yii2
but this is also not solving my problem.
Here is the corrected version:
public function behaviors()
{
return [
[
'class' => TimestampBehavior::className(),
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['create_time'],
ActiveRecord::EVENT_BEFORE_UPDATE => ['create_time'],
],
],
];
}
Here is deeper explanation.
The main problem is you forgot to wrap behavior config into its own array, that's why the error is thrown. This config as all others is processed by Yii::createObject() method. So you need array containing at least class element. In case you want default config you can omit this for brevity with just specifying class name, for example:
public function behaviors()
{
return [
TimestampBehavior::className(),
],
];
}
Besides that, you also forgot to close square bracket after attribute.
And finally, you should not specify attributes like that. It was like that at initial stage of this behavior, then it was refactored. Now you only need to specify according attribute names, for example:
public function behaviors()
{
return [
[
'class' => TimestampBehavior::className(),
'createdAtAttribute' => 'created_at', // This is by default, you can omit that
'updatedAtAttribute' => 'updated_at', // This is by default, you can omit that
],
],
];
}
Also I don't think that having the same column for tracking create and update time is a good idea.
Additionally you can specify value used to update these columns:
use yii\db\Expression;
...
'value' => new Expression('NOW()'),
This will involve database to calculate time, if you want to do it on server side via PHP, you can do use closure for example like this:
'value' => function () {
return date('Y-m-d H:i:s');
}
And one more thing even if it's not directly related with this problem - you can set alias for every behavior by setting a key of configuration array. This is called named behavior:
public function behaviors()
{
return [
'timestamp' => [
...
],
],
];
}
This was mentioned by #GAMITG in his answer.
You can try this code.
public function behaviors()
{
return [
'timestamp' => [
'class' => 'yii\behaviors\TimestampBehavior',
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['create_time'],
ActiveRecord::EVENT_BEFORE_UPDATE => ['create_time'],
],
],
];
}
Related
How I can restrict access to RBAC Module itself?
I'm using yii\rbac\DbManager and I have created a module(Authorization) in backend for permission assignment,create auth items, now I want to make sure only admin can access this module!
In controller I have used something this and it's working fine.
use yii\filters\AccessControl;
class MyController extends Controller
{
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['index', 'view', 'create', 'update', 'delete'], //only be applied to
'rules' => [
[
'allow' => true,
'actions' => ['index', 'view', 'create', 'update','delete'],
'roles' => ['admin'],
],
],
],
.........
I have put this in Authorization.php init function but nothing happen, all auth controllers are accessable.
public function init()
{
if(\Yii::$app->user->can('admin'))
parent::init();
// custom initialization code goes here
}
Update
backend/config/main.php
'modules' => [
'authorization' => [
'class' => 'backend\modules\authorization\Authorization',
],
],
In your module class you can add this method
public function beforeAction($action)
{
if (!parent::beforeAction($action)) {
return false;
}
if (!\Yii::$app->user->can('admin')) {
throw new \yii\web\ForbiddenHttpException('You are not allowed to access this page.');
}
return true;
}
I am currently using the following lines of code on every controller in the API module in order to return JSON response/data.
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['contentNegotiator']['formats']['text/html'] = Response::FORMAT_JSON;
return $behaviors;
}
It works well. But how can i achieve the same using main configuration file?
I tried the following on my frontend/config/main.php
'api' => [
'class' => 'app\modules\api\Module',
'components' => [
'user' => [
'class' => 'yii\web\User',
'identityClass' => 'common\models\User',
'enableSession' => false,
'loginUrl' => null,
],
'response' => [
'class' => \yii\filters\ContentNegotiator::className(),
'formats' => [
'application/json' => \yii\web\Response::FORMAT_JSON,
],
]
],// Module component
],
above configuration still returns XML response only. What is the correct configuration to set all the controllers in the API module to return JSON data.Thanks
Configure your response component as follows:
'response' => [
'format' => yii\web\Response::FORMAT_JSON,
// ...
]
formats is an array containing the available formats. format is the actual output format.
Add this is your config/main-local.php
use yii\web\Response;
$config['bootstrap'][]=
[
'class' => '\yii\filters\ContentNegotiator',
'formats' => [
'text/html' => Response::FORMAT_JSON,
]
];
How to override the class module in the config of my theme? I tried so impossible.
return [
...
'modules' => [
'shop' => [
'class' => 'app\modules\shop\ShopModule',
'components' => [
'manager' => [
'class' => 'app\web\theme\modules\shop\Customer',
],
],
],
...
],
];
Overriding controllers
Sometimes you may need to override default Yii2-user controllers. It is pretty easy and takes two steps.
Step 1: Create new controller
First of all you need to create new controller under your own namespace (we’d recommend app\controllers\user) and extend it from needed Yii2-user controller.
For example, if you want to override AdminController you should create app\controllers\user\AdminController and extend it from dektrium\user\controllers\AdminController:
<?php
namespace app\controllers\user;
use dektrium\user\controllers\AdminController as BaseAdminController;
class AdminController extends BaseAdminController
{
public function actionCreate()
{
// do your magic
}
}
Step 2: Add your controller to controller map
To let Yii2-user know about your controller you should add it to controller map as follows:
<?php return [
...
'modules' => [
...
'user' => [
'class' => 'dektrium\user\Module',
'controllerMap' => [
'admin' => 'app\controllers\user\AdminController'
],
...
],
...
],
For overriding view click here
I have a model with two values that has to be unique together.
Yii2 has a validation rule for this:
[['object_id', 'created_by'], 'unique', 'targetAttribute' => ['object_id', 'created_by']]
The created_by attribute is generated with blameable behavior:
public function behaviors()
{
return [
'blameable' => [
'class' => BlameableBehavior::className(),
'createdByAttribute' => 'created_by',
'updatedByAttribute' => 'updated_by',
],
];
}
The validating is done before the behavior input is stored in the model. (I know this, because if created_by is required in the rules, the model will not save - validation error.)
Is there a good yii2-way to validate a behavior-generated attribute like this?
You can specify the events that the attributes will be created on by using the 'attributes' property of the behavior, so you can amend your model like this:
public function behaviors()
{
return [
'blameable' => [
'class' => BlameableBehavior::className(),
'createdByAttribute' => 'created_by',
'updatedByAttribute' => 'updated_by',
'attributes' => [
ActiveRecord::EVENT_BEFORE_VALIDATE => ['updated_by', 'created_by']
]
],
];
}
I have a lot of models using created_time. And I want all of the GridViews to show the models sorted by created_time DESC.
Right now I write something like this
$dataProvider = new \yii\data\ActiveDataProvider([
'query' => MyModel::find(),
'sort' => [
'defaultOrder' => [
'created_time' => SORT_DESC
]
],
]);
Instead of writing all of sort configuration I tried ways below but nothing works.
Using container
\Yii::$container->set(\yii\data\ActiveDataProvider::class,
[
'sort' => [
'defaultOrder' => [
'created_time' => SORT_DESC
]
]
]);
Overriding the sort in extended class.
class ActiveDataProvider extends \yii\data\ActiveDataProvider {
public $sort = [
'defaultOrder' => [
'created_time' => SORT_DESC
]
];
}
Overriding before init() in the extended class works, but it won't work if the instantiation tries to override again.
class ActiveDataProvider extends \yii\data\ActiveDataProvider {
public function init() {
$this->sort = [
'defaultOrder' => [
'created_time' => SORT_DESC
]
];
parent::init();
}
}
//but this won't work if I want to use the ascending
$dataProvider = new \app\components\data\ActiveDataProvider([
'query' => MyModel::find(),
'sort' => [
'defaultOrder' => [
'created_time' => SORT_ASC
]
],
]);
To do this for a single GridView, you can add 'defaultOrder' => ['created_time' => SORT_DESC] to the array that is accepted by setSort():
$dataProvider->setSort([
'attributes' => [
'id',
...
],
'defaultOrder' => ['created_time' => SORT_DESC]
]);
You should do this for yii\data\Sort and not for yii\data\ActiveDataProvider. See the documentation to $sort property.
1) With container:
use Yii;
...
Yii::$container->set(\yii\data\Sort::className(),
'defaultOrder' => [
'created_time' => SORT_DESC,
],
]);
2) Overriding class:
class Sort extends yii\data\Sort
{
public $defaultOrder' = [
'created_time' => SORT_DESC,
];
}