Yii2 apply parameters to DB sort - mysql

I have the following search function in my BlogPostSearch ActiveRecord:
public function search($params)
{
$query = BlogPost::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort' => [
'attributes' => [
'publishDate' => [
'asc' => ['(CASE state
WHEN '.static::STATE_ONLINE.' THEN published_at
WHEN '.static::STATE_OFFLINE.' THEN updated_at
END)' => SORT_ASC],
'desc' => ['(CASE state
WHEN '.static::STATE_ONLINE.' THEN published_at
WHEN '.static::STATE_OFFLINE.' THEN updated_at
END)' => SORT_DESC],
'default' => SORT_DESC
],
],
],
]);
return $dataProvider;
}
But part of my soul dies every time I concatenate a parameter into SQL. Is it possible to bind variables in here?
Something like:
...
'asc' => [
'expression'=> [
'(CASE state
WHEN :online THEN published_at
WHEN :offline THEN updated_at
END)' => SORT_ASC
],
'params' => [
'online' => static::STATE_ONLINE,
'offline' => static::STATE_OFFLINE,
],
],
...

Related

DatePicker widget filter a datetime field

Friends, how do I get my DatePicker component below (in Yii2 Framewok), filter a field of type datetime? Since in the component I can only specify the date format.
_search.php file:
<?php
echo DatePicker::widget([
'model' => $model,
'attribute' => 'start_date',
'attribute2' => 'end_date',
'language' => 'pt',
'type' => DatePicker::TYPE_RANGE,
'separator' => 'até',
'options' => [
'placeholder' => '',
],
'pluginOptions' => [
'autoclose'=>true,
'todayHighlight' => true,
'format' => 'yyyy-mm-dd',
]
]);
?>
UPDATE
public function search($params)
{
$query = Report::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort' => [
'defaultOrder' => [
'created' => SORT_DESC,
]
],
'pagination' => [
'pageSize' => 100,
],
]);
$this->load($params);
if (!$this->validate()) {
return $dataProvider;
}
$query->andFilterWhere([
'id' => $this->id,
'created' => $this->created,
'updated' => $this->updated,
'closed' => $this->closed,
'user_id' => $this->user_id,
'status_id' => $this->status_id,
'location_id' => $this->location_id,
'typeperson_id' => $this->typeperson_id,
'field_cpfcnpj' => $this->field_cpfcnpj,
]);
$query->andFilterWhere(['between', 'created', $this->start_date, $this->end_date]);
$query->andFilterWhere(['between', 'closed', $this->start_closed, $this->end_closed]);
return $dataProvider;
}
If i understand correctly, you want to submit form using the date range which should filter the records using the given range.
Looking at you search() method it looks like you have declared 2 public properties/fields in the search model with the name start_date and end_date which you are using with the DatePicker and you are trying to compare the range with the column created.
You need to do the following in order to filter the records correctly
Make sure for the following
The start_date and end_date are declared inside the safe rules for the ReportSearch model.
You need to use the \yii\db\Expression to convert the date in the column to the desired format, and use the php:date to format the given date ranges i.e start_date and end_date.
Add the following before you return the $dataProvider in the search() method
if ($this->start_date !== null && $this->end_date !== null) {
$query->andFilterWhere(
[
'BETWEEN',
new Expression(
'DATE_FORMAT(created,"%Y/%m/%d")'
),
date("Y/m/d", strtotime($this->start_date)),
date("Y/m/d", strtotime($this->end_date)),
]
);
}
Note: if you have the created column saved as timestamp then you need to wrap the field name in the existing query with FROM_UNIXTIME like below, otherwise if the column is of DATE or DATETIME the above will work.
Column type is of TIMESTAMP
if ($this->start_date !== null && $this->end_date !== null) {
$query->andFilterWhere(
[
'BETWEEN',
new Expression(
'DATE_FORMAT(FROM_UNIXTIME(created),"%Y/%m/%d")'
),
date("Y/m/d", strtotime($this->start_date)),
date("Y/m/d", strtotime($this->end_date)),
]
);
}
Your complete search() method will look like below
public function search($params)
{
$query = Report::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort' => [
'defaultOrder' => [
'created' => SORT_DESC,
]
],
'pagination' => [
'pageSize' => 100,
],
]);
$this->load($params);
if (!$this->validate()) {
return $dataProvider;
}
$query->andFilterWhere([
'id' => $this->id,
'created' => $this->created,
'updated' => $this->updated,
'closed' => $this->closed,
'user_id' => $this->user_id,
'status_id' => $this->status_id,
'location_id' => $this->location_id,
'typeperson_id' => $this->typeperson_id,
'field_cpfcnpj' => $this->field_cpfcnpj,
]);
if ($this->start_date !== null && $this->end_date !== null) {
$query->andFilterWhere(
[
'BETWEEN',
new Expression(
'DATE_FORMAT(created_at,"%Y/%m/%d")'
),
date("Y/m/d", strtotime($this->start_date)),
date("Y/m/d", strtotime($this->end_date)),
]
);
}
$query->andFilterWhere(['between', 'closed', $this->start_closed, $this->end_closed]);
return $dataProvider;
}

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:my dataprovider not sort true

I have dataprovider to get 9 posts order by create time but my order and limit not worked
$dataProviderlatenew=new ActiveDataProvider([
'query'=>Post::find()->limit(9)->orderBy('create_time DESC'),
'sort' => [
'defaultOrder' => [
'create_time' => SORT_DESC,
],
],
]);
Remember that if pagination is not false the limit is managed automatically and not using the limit you have in query .. so for the order
$dataProviderlatenew=new ActiveDataProvider([
'query'=>Post::find(),
'sort' => [
'defaultOrder' => [ 'create_time' => SORT_DESC, ],
],
]);
otherwise set aproper pagination (so you can use limit(9) ) and don't impose an order in select and a default order in dataProvider (is a non sense)
eg:
$dataProviderlatenew=new ActiveDataProvider([
'query'=>Post::find(),
'pagination' =>['pagesize' =>9],
'sort' => [
'defaultOrder' => [ 'create_time' => SORT_DESC, ],
],
]);
or
$dataProviderlatenew=new ActiveDataProvider([
'query'=>Post::find()->limit(9),
'pagination' =>false,
'sort' => [
'defaultOrder' => [ 'create_time' => SORT_DESC, ],
],
]);
Try This :
$dataProviderlatenew=new ActiveDataProvider([
'query'=>Post::find(),
'pagination'=>['pagesize'=>9],
'sort' => [
'defaultOrder' => [ 'create_time' => SORT_DESC],
],
]);
Refer : http://www.yiiframework.com/doc-2.0/guide-output-data-providers.html

Log not working in yii2

i want to put a log in app.log ,My config file
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
'file' => [
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
'logFile' => '#root/console/runtime/logs/app.log',
],
]
]
in controller action
public function actionRankCalculation()
{
$allConest = Contest::find()->where('isActive = 1')->all();
Yii::trace('start calculating average revenue');
$response = [];
/** #var Contest $contest */
foreach ($allConest as $contest) {
$videoQuery = Video::find()->where('contest_id = ' . $contest->id);
$videoQuery->andWhere('isActive = 1');
$videoQuery->orderBy([
'global_likes' => SORT_DESC,
'id' => SORT_ASC,
]);
}
But Yii::trace('start calculating average revenue'); not working
You try this.Use categories. For example like below
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error'],
'categories' => ['test1'],
'logFile' => '#app/Test/test1.log',
],
And use below one in controller action
public function actionIndex(){
Yii::error('Test index action', $category = 'test1'); }
Try to set both flushInterval and exportInterval to 1 in console config:
return [
'bootstrap' => ['log'],
'components' => [
'log' => [
'targets' => [
[
'class' => 'yii\log\FileTarget',
'exportInterval' => 1,
],
],
'flushInterval' => 1,
],
],
];
It makes each log message appearing immediately in logs.

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