Override default sort for ActiveDataProvider in Yii2 - yii2

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,
];
}

Related

What's the difference between ActiveDataProvider and SQLDataProvider?

I'm a little bit confused. I'm wondering what is the difference between Yii2 ActiveDataProvider and SQLDataProvider? I was looking in the documentation for it, but couldn't get it too.
Could someone explain me when should I use one or another? And what is the difference between it?
Thank you for your time.
SqlDataProvider works with a raw SQL statement which is used to fetch the needed data and ActiveDataProvider can take either a yii\db\Query or yii\db\ActiveQuery object.
SqlDataProvider example:
$provider = new SqlDataProvider([
'sql' => 'SELECT * FROM post WHERE status=:status', //HERE
'params' => [':status' => 1],
'totalCount' => $count,
'pagination' => [
'pageSize' => 10,
],
'sort' => [
'attributes' => [
'title',
'view_count',
'created_at',
],
],
]);
ActiveDataProvider example:
$query = Post::find()->where(['status' => 1]); // ActiveQuery here
$provider = new ActiveDataProvider([
'query' => $query, // and here
'pagination' => [
'pageSize' => 10,
],
'sort' => [
'defaultOrder' => [
'created_at' => SORT_DESC,
'title' => SORT_ASC,
]
],
]);

Yii2 all controllers and actions require login, need to add some exceptions. How can I do it?

I've found a lot of answers on how to create Access Control that requires login to all controllers and actions.
The following post shows how I did all controllers require login:
Yii2 require all Controller and Action to login
I've used the code below under my components:
'as beforeRequest' => [
'class' => 'yii\filters\AccessControl',
'rules' => [
[
'allow' => true,
'actions' => ['login', 'error'],
],
[
'allow' => true,
'roles' => ['#'],
],
]
],
But, I want to add some exceptions to it. Some controllers need to have some actions visible to Guest.
I've tried to use this code inside my behaviors on ReportsController:
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'allow' => true,
'actions' => ['share'],
'roles' => ['?'],
],
],
]
Still get redirected to login.
I'm trying to to make actionShare($param) {} public to guests.
What am I missing?
Thanks for all your help!
First execute
yii migrate --migrationPath=#yii/rbac/migrations
from command prompt to create RBAC table in data base.
Then create RbacController in component folder
namespace app\components;
use yii;
use yii\web\Controller;
use yii\filters\AccessControl;
class RbacController extends Controller
{
public function RbacRule($modules = false)
{
$rules = false;
if ($modules){
$rules = [
'allow' => true,
'roles' => ['#'],
'matchCallback' => function ($rule, $action) {
$module = Yii::$app->controller->module->id;
$action = Yii::$app->controller->action->id;
$controller = Yii::$app->controller->id;
$route = "/$module/$controller/$action";
$post = Yii::$app->request->post();
if (\Yii::$app->user->can($route)) {
return true;
}
}
];
}else{
$rules = [
'allow' => true,
'roles' => ['#'],
'matchCallback' => function ($rule, $action) {
//$module = Yii::$app->controller->module->id;
$action = Yii::$app->controller->action->id;
$controller = Yii::$app->controller->id;
$route = "/$controller/$action";
$post = Yii::$app->request->post();
if (\Yii::$app->user->can($route)) {
return true;
}
}
];
}
return $rules;
// return true;
}
}
then extend to your controller using this RbacController instead of controller.
use app\components\RbacController;
class AdminController extends RbacController
{
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
// [
// 'actions' => ['login', 'logout'],
// 'allow' => true,
// 'roles' => ['?'],
// ],
parent::RbacRule(),
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['post'],
'bulk-delete' => ['post'],
],
],
];
}
.......
}
If your controller is inside Modules folder then you have to use
parent::RbacRule(TRUE) instead of parent::RbacRule(),

Yii2 enablePrettyUrl fail and frontend post request fail

i was trying to make
this url
http://localhost/advanced/frontend/web/index.php?r=test
into
htttp://localhost/advanced/frontend/web/tests in yii2
also to receive post request
this in my codding in common/config/main.php
<?php
return [
'vendorPath' => dirname(dirname(__DIR__)) . '/vendor',
'components' => [
'cache' => [
'class' => 'yii\caching\FileCache',
],
'urlManager' => [
],
'urlManagerFrontEnd' => [
'enablePrettyUrl' => true,
'rules' => [
[
'class' => 'yii\rest\UrlRule',
'controller' => ['test'],
'only' => ['index', 'create'],
],
],
'showScriptName' => false,
],
],
];
this in my frontend testController
namespace frontend\controllers;
use Yii;
use yii\rest\ActiveController;
use common\models\Test;
use yii\data\ActiveDataProvider;
class TestController extends ActiveController {
public $modelClass = 'common\models\Test';
public function actions(){
$actions = parent::actions();
unset($actions['create']);
return $actions;
}
public function actionCreate(){
$model = new Test();
$model->load(Yii::$app->request->post(),'');
$model->save();
return $model;
}
}
i have a problem in the post request when i tried
Postman result jpg
so i have 2 problem the first is the prettyUrl and the post request
if u have a solution please make it easy because i just learn php yii2 html css etc for 1 month

yii2 change database for admin and site panel

I have the following config file
common/main-local.php
return [
'components' => [
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=aishwariya_basic2',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
// 'db' => $db,
'db2' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=aishwariya_basic',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
'viewPath' => '#common/mail',
],
// autoloading model and component classes
'import'=> [
'class' => 'yii2-widget-linkpager',
'application.extensions.MyLinkPager.*',
],
],
];
Admincontroller
namespace frontend\controllers;
use Yii;
use frontend\models\Site_login;
use frontend\models\EntryForm_model;
use frontend\models\Asal_page_model;
use frontend\models\Interest_page_model;
use frontend\models\Return_page_model;
use frontend\models\Daily_report_model;
use frontend\models\Changepassword;
use yii\base\InvalidParamException;
use yii\web\BadRequestHttpException;
use yii\web\Controller;
use yii\filters\VerbFilter;
use yii\filters\AccessControl;
use yii\helpers\ArrayHelper;
use yii\db\Query;
class AdminController extends Controller
{
/**
* #inheritdoc
*/
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['index', 'signup'],
'rules' => [
[
'actions' => ['index'],
'allow' => true,
'roles' => ['?'],
],
[
'actions' => ['settings','changepassword'],
'allow' => true,
'roles' => ['#'],
],
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'logout' => ['post'],
],
],
];
}
/**
* #inheritdoc
*/
public function actions()
{
return [
'error' => [
'class' => 'yii\web\ErrorAction',
],
'captcha' => [
'class' => 'yii\captcha\CaptchaAction',
'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
],
];
}
#####Action index code starts here
public function actionIndex()
{
$this->layout = 'admin';
$my2DbConn = Yii::$app->db;
$model = new Site_login();
if ($model->load(Yii::$app->request->post()) )
{
if ($model->validate()) {
$url = Yii::$app->getUrlManager()->getBaseUrl()."/admin/search";
return $this->redirect($url);
}
}
return $this->render('index', ['model' => $model]);
}
Site controller
public function actionInitial()
{
$this->layout = 'site';
$my2DbConn = Yii::$app->db2;
$model=new Initial_model();
if ($model->load(Yii::$app->request->post()))
{
}
return $this->render('initial',['model'=>$model]);
}
I would like to change the database belongs to controller. Please give me some help. I have used two db but it tooks first db file.
You can configure more then a db in config
return [
'components' => [
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=testdb',
'username' => 'demo',
'password' => 'demo',
],
'db2' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=testdb2',
'username' => 'demo2',
'password' => 'demo2',
],
],
];
and obtain your db (this is if you want use direct command in controller and not for activeRecord)
class yourController extends \yii\web\Controller
{
public function actionYourAction()
{
...
$my2DbConn = Yii::$app->db2;
....
}
Or you can manage programmatically with the proper setting
If for your model (like you have in your code ) you want to use a different database connection other than the db component, you should override the getDb() method in your related ActiveRecord MODEL (see the doc .. link at the bottom):
class YourModel extends ActiveRecord // eg: Initial_model
{
// ...
public static function getDb()
{
// use the "db2" application component
return \Yii::$app->db2;
}
}
and not assign $my2DbConn = Yii::$app->db; in controller this is for createCommand (direct sql commend) and not for activeRecord like you need ..
see this guide http://www.yiiframework.com/doc-2.0/guide-db-active-record.html or this reference for related param http://www.yiiframework.com/doc-2.0/yii-db-connection.html

TimestampBehavior is not working in Yii2

public function behaviors()
{
return [
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['post'],
],
],
'access' => [
'class' => AccessControl::className(),
'only' => ['create', 'update', 'delete', 'view', 'index'],
'rules' => [
// allow authenticated users
[
'allow' => true,
'roles' => ['#'],
],
// everything else is denied by default
],
],
[
'class' => TimestampBehavior::className(),
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['create_time', 'update_time'],
ActiveRecord::EVENT_BEFORE_UPDATE => ['update_time'],
],
],
];
}
Above code is for my controller behavior function. While creating or updating, 'create_time' and 'update_time' fields are not getting updated by current time. Type of those fields are set to datetime. Please need your help.
You have to declare it in the behaviors method of your model.
To use TimestampBehavior, insert the following code to your ActiveRecord class
public function behaviors()
{
return [
'class' => TimestampBehavior::className(),
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['create_time', 'update_time'],
ActiveRecord::EVENT_BEFORE_UPDATE => ['update_time'],
],
];
}
Try this, it works for me:
use yii\db\Expression;
...
[
'class' => TimestampBehavior::className(),
'updatedAtAttribute' => 'update_time',
'value' => new Expression('NOW()'),
],
You can also use
'value' => date('Y-m-d H:i:s')
if you would like to use the PHP datetime.
I used new Expression('NOW()') to store current timestamp. But It does't store the date based on current timezone. Instead it stores based on server time.
I just used normal php date function to solve this.
eg :
use yii\behaviors\TimestampBehavior;
use yii\db\Expression;
public function behaviors()
{
return [
'timestamp' => [
'class' => 'yii\behaviors\TimestampBehavior',
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'],
ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at'],
],
'value' => date('Y-m-d H:i:s'),
],
];
}
You must also add the value and use the class Expression
use yii\behaviors\TimestampBehavior;
use yii\db\Expression;
public function behaviors()
{
return [
'timestamp' => [
'class' => 'yii\behaviors\TimestampBehavior',
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'],
ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at'],
],
'value' => new Expression('NOW()'),
],
];
}