**how can i add girdView search to my relation table column ?
i have all girlview search box except my relation table
(developersActivity.developer_point) and ('developersActivity.project_done')
i have thier value but widget search box not apear above them**
my controller
$searchModel = new DeveloperSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('dashboard', [
'dataProvider' => $dataProvider,
'searchModel' => $searchModel
]);
my search model
class DeveloperSearch extends Developers
{
public function rules()
{
return parent::rules();
}
public function scenarios()
{
return Model::scenarios();
}
public function search($param)
{
$query = Developers::find();
$dataProvider = new ActiveDataProvider([
'query' => $query
]);
$this->load($param);
$query->joinWith('developersActivity');
$dataProvider->setSort([
'attributes'=> [
'name',
'developersActivity.developer_point'=>[
'asc'=>['developer_point'=>SORT_ASC],
'desc'=>['developer_point'=>SORT_DESC],
]
]
]);
$query->andFilterWhere([
'developer_id' => $this->developer_id,
]);
$query->andFilterWhere(['like', 'name', $this->name])
->andFilterWhere(['like', 'phone', $this->phone])
->andFilterWhere(['like', 'email', $this->email]);
return $dataProvider;
}
}
the model
class Developers extends ActiveRecord
{
public static function tableName()
{
return 'developers';
}
public function rules()
{
return [
[['name',
'family',
'phone',
'email',
'address',
'brithday',
'age',
'ability',
'role',
'join_date',
], 'required'],
[['developer_id'], 'integer'],
['email','email'],
[['phone'],'integer', 'min' => 10],
[['address'], 'string', 'max' => 100],
[['name'], 'string', 'min' => 3],
];
}
public function getDevelopersActivity(){
return $this->hasOne(DevelopersActivity::className(),['developer_activity_id' => 'developer_id']);
}
}
and developersActivity model class
class DevelopersActivity extends ActiveRecord
{
public function rules()
{
return [
[['developer_activity_id',
'developer_point',
'project_done',
'free_rate',
'address',
'estimate_for_next_project',
'date_project_done',
'number_of_project',
'activity_rate',
], 'safe'],
];
}
}
here is the view
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
'developer_id',
'name',
'email',
'phone',
'email',
'developersActivity.developer_point',
'developersActivity.project_done'
// 'value'=>'developersActivity.point',
//'contentOptions'=>['style'=>'width: 120px;']
],
]);
?>
in your model add a getter for the field (assuming the field is named actvityname)
/* Getter for deleveloer activity name */
public function getDevelopersActivityName() {
return $this->developersActivity->activityname;
}
in your searchModel
add a public var for your related field and declare as safe in rules
/* your calculated attribute */
public $activityName;
/* setup rules */
public function rules() {
return [
/* your other rules */
[['activityName'], 'safe']
];
}
and in the filter you can add the filter for your field
// filter by developer activity
$query->joinWith(['developersActivity' => function ($q) {
$q->where('yor_develeoper_activity_table.your_developer_activity_column LIKE "%' . $this->activityName. '%"');
}]);
return $dataProvider;
in gridview you can refer directly using
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'id',
'fullName',
'activityName',
['class' => 'yii\grid\ActionColumn'],
]
you can take a look ad this tutorial for some suggestions http://www.yiiframework.com/wiki/621/filter-sort-by-calculated-related-fields-in-gridview-yii-2-0/
Related
I have two models with related data fbl_leagues and fbl_country tables. fbl_leagues have a column country_id which is related to fbl_country, now in yii2 gridView i was able to do something like [
'attribute' => 'country_id',
'value' => 'country.name',
], which gives the name of the country rather than the countries id, then i also want to enable searching by country name rather than country_id but i get the below error
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'country.name' in 'where clause'
The SQL being executed was: SELECT COUNT(*) FROM `fbl_leagues` LEFT JOIN `fbl_country` ON `fbl_leagues`.`country_id` = `fbl_country`.`id` WHERE `country`.`name` LIKE '%s%'
Below is my LeagueSearch model
class LeagueSearch extends League
{
/**
* {#inheritdoc}
*/
public function rules()
{
return [
[['id', 'created_at', 'updated_at'], 'integer'],
[['name','country_id'], 'safe'],
];
}
/**
* {#inheritdoc}
*/
public function scenarios()
{
// bypass scenarios() implementation in the parent class
return Model::scenarios();
}
/**
* Creates data provider instance with search query applied
*
* #param array $params
*
* #return ActiveDataProvider
*/
public function search($params)
{
$query = League::find();
$query->joinWith('country');
// add conditions that should always apply here
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$this->load($params);
if (!$this->validate()) {
// uncomment the following line if you do not want to return any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
// grid filtering conditions
$query->andFilterWhere([
'id' => $this->id,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
]);
$query->andFilterWhere(['like', 'name', $this->name])
->andFilterWhere(['like', 'country.name',$this->country_id]);
return $dataProvider;
}
}
and my league model
{
return [
[['country_id', 'created_at', 'updated_at'], 'integer'],
[['name','country_id'], 'required'],
[['name'], 'string', 'max' => 100],
[['country_id'], 'exist', 'skipOnError' => true, 'targetClass' => Country::className(), 'targetAttribute' => ['country_id' => 'id']],
];
}
/**
* {#inheritdoc}
*/
public function attributeLabels()
{
return [
'id' => Yii::t('app', 'ID'),
'country_id' => Yii::t('app', 'Country Name'),
'name' => Yii::t('app', 'Name'),
'created_at' => Yii::t('app', 'Created At'),
'updated_at' => Yii::t('app', 'Updated At'),
];
}
/**
* #return \yii\db\ActiveQuery
*/
public function getCountry()
{
return $this->hasOne(Country::className(), ['id' => 'country_id']);
}
/**
* #return \yii\db\ActiveQuery
*/
public function getPerfectSelections()
{
return $this->hasMany(PerfectSelection::className(), ['league_id' => 'id']);
}
Now i noticed that when i comment out $query->joinWith('country'); then there will be no error but searching not working as expected
Hmm silly me i guess i later figure out the problem the table name is fbl_country so i suppose write fbl_country.name but wrote country.name in my search model, it's being a long day though, thanks for all
Good day everyone. I'm trying to add a filter for the associated phone_digital field but I get the following error
Structure -
1 table - ClientClient - first_name, patronymic, last_name, age.
2 table - ClientPhone - client_id, phone_digital.
ClientClient (model)
class ClientClient extends \yii\db\ActiveRecord
{
public static function tableName(){
return 'client_client';
}
public function rules(){
return [
[['age'], 'integer'],
[['first_name', 'patronymic', 'last_name'], 'string', 'max' => 255],
];
}
public function attributeLabels(){
return [
'id' => 'ID',
'first_name' => 'First Name',
'patronymic' => 'Patronymic',
'last_name' => 'Last Name',
'age' => 'Age',
'phone_digital' => 'Phone Digital',
];
}
public function getclientPhone(){
return $this->hasOne(clientPhone::class, ['client_id' => 'id']);
}
public function getPhone(){
return $this->hasOne(clientPhone::class, ['phone_digital' => 'id']);
}
public function getDigital(){
return $this->hasOne(ClientPhone::className(), ['id' => 'phone_digital']);
}
public function getPhoneDigital(){
return $this->phone->phone_digital;
}
}
ClientSearch (model)
class ClientSearch extends Clientclient
{
public $phonedigital;
public function rules(){
return [
[['id', 'age'], 'integer'],
[['first_name', 'phonedigital', 'patronymic', 'last_name'], 'safe'],
];
}
public function scenarios(){
// bypass scenarios() implementation in the parent class
return Model::scenarios();
}
public function search($params){
$query = Clientclient::find()->orderBy('phone_digital');
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
$query->joinWith(['phonedigital' => function($query) { $query->from(['phonedigital' => 'ClientPhone']); }]);
$dataProvider->sort->attributes['phone'] = [
'asc' => ['phonedigital.phone_digital' => SORT_ASC],
'desc' => ['phonedigital.phone_digital' => SORT_DESC],
];
$query->andFilterWhere([
'id' => $this->id,
'age' => $this->age,
]);
$query->andFilterWhere(['like', 'first_name', $this->first_name])
->andFilterWhere(['like', 'patronymic', $this->patronymic])
->andFilterWhere(['like', 'last_name', $this->last_name])
->andFilterWhere(['like', 'phonedigital.phone_digital', $this->getAttribute('phonedigital')]);
return $dataProvider;
}
}
What do I need to do to make this work?
I guess you should put your orderBy after your join
check the commented lines:
public function search($params){
// do not put the join of a related table at the beginning because it's not related yet
$query = Clientclient::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
$query->joinWith(['phonedigital' => function($query) { $query->from(['phonedigital' => 'ClientPhone']); }]);
// orderBy only after call the relacion
$query->orderBy('phonedigital.phone_digital');
$dataProvider->sort->attributes['phone'] = [
'asc' => ['phonedigital.phone_digital' => SORT_ASC],
'desc' => ['phonedigital.phone_digital' => SORT_DESC],
];
$query->andFilterWhere([
'id' => $this->id,
'age' => $this->age,
]);
$query->andFilterWhere(['like', 'first_name', $this->first_name])
->andFilterWhere(['like', 'patronymic', $this->patronymic])
->andFilterWhere(['like', 'last_name', $this->last_name])
->andFilterWhere(['like', 'phonedigital.phone_digital', $this->getAttribute('phonedigital')]);
return $dataProvider;
}
I hope it helps you, and sorry about my ingles
I want to save multilingual record in my table but some error occurs - Call to a member function getPrimaryKey() on string. I am using multilingual behavior
and it is not for first time. Made two tables system_information and system_informationLang. This is my model:
<?php
namespace app\models;
use backend\models\CActiveRecord;
use Yii;
use omgdef\multilingual\MultilingualBehavior;
use omgdef\multilingual\MultilingualQuery;
/**
* This is the model class for table "system_information".
*
* #property int $id
* #property int $city_id
*
* #property SystemInformationlang[] $systemInformationlangs
*/
class SystemInformation extends CActiveRecord
{
public static function find()
{
return new MultilingualQuery(get_called_class());
}
public function behaviors()
{
$allLanguages = [];
foreach (Yii::$app->params['languages'] as $title => $language) {
$allLanguages[$title] = $language;
}
return [
'ml' => [
'class' => MultilingualBehavior::className(),
'languages' => $allLanguages,
//'languageField' => 'language',
//'localizedPrefix' => '',
//'requireTranslations' => false',
//'dynamicLangClass' => true',
//'langClassName' => PostLang::className(), // or namespace/for/a/class/PostLang
'defaultLanguage' => Yii::$app->params['languageDefault'],
'langForeignKey' => 'system_id',
'tableName' => "{{%system_informationlang}}",
'attributes' => [
'name',
'email',
'phone',
'address',
'facebook',
'instagram',
'google',
'linkin',
'fax',
'owner',
'latitude',
'longitude'
]
],
];
}
/**
* #inheritdoc
*/
public static function tableName()
{
return 'system_information';
}
/**
* #inheritdoc
*/
public function rules()
{
$string_255_lang = $this->multilingualFields([
'name',
'email',
'phone',
'address',
'facebook',
'instagram',
'google',
'linkin',
'fax',
'owner',
'latitude',
'longitude'
]);
$string_255 = [
'name',
'email',
'phone',
'address',
'facebook',
'instagram',
'google',
'linkin',
'fax',
'owner',
'latitude',
'longitude'
];
$require = ['name', 'phone', 'email', 'owner', 'address'];
$email_lang = $this->multilingualFields(['email']);
$email = ['email'];
return [
[$require, 'required'],
[$string_255, 'string', 'max' => 255],
[$string_255_lang, 'string', 'max' => 255],
[['city_id'], 'integer'],
[$email_lang, 'email'],
['email', 'email'],
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => Yii::t('app', 'ID'),
'city_id' => Yii::t('app', 'City ID'),
];
}
}
This is custom function for language fields creating :
protected function multilingualFields($fields){
$output = [];
foreach ($fields as $field){
foreach (Yii::$app->params['languages'] as $language) {
if(Yii::$app->params['languageDefault'] != $language){
$output[] = "{$field}_{$language}";
}
}
}
return $output;
}
And finally my controller:
public function actionCreate()
{
$model = new SystemInformation();
if ($model->load(Yii::$app->request->post())) {
$model->multilingualLoad($model, [
'name',
'email',
'phone',
'address',
'facebook',
'instagram',
'google',
'linkin',
'fax',
'owner',
'latitude',
'longitude'
]);
var_dump($model->save());
var_dump($model->getErrors());die;
if($model->save()){
return $this->redirect(['view', 'id' => $model->id]);
}else{
Yii::$app->session->setFlash('error', Yii::t('app', 'Something went wrong. Please, try again later!'));
return $this->render('create', [
'model' => $model,
]);
}
}
return $this->render('create', [
'model' => $model,
]);
}
multilingualLoad is also a custom function for filling the lingual fields:
public function multilingualLoad($model, $props = []){
$model_name = explode('\\', get_class($model));
$model_name = end($model_name);
foreach (Yii::$app->params['languages'] as $language){
if(Yii::$app->params['languageDefault'] != $language){
foreach ($props as $property){
$prop_lang = "{$property}_{$language}";
$model->$prop_lang = Yii::$app->request->post($model_name)["{$property}_{$language}"];
}
}
}
}
I got a picture of the Yii2 error. I guess it is searching for the lang table but somehow $owner gets value of a string.
Thank you in advance!
I'm searching four tables and joined them and got the output I want. But unable to sort or filter the output. Please tell me how I can search it by district or a sell range or collection range.
PartiesSearch model is -
<?php
namespace frontend\modules\districtreport\models;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use frontend\modules\districtreport\models\Parties;
use frontend\modules\districtreport\models\Bills;
use frontend\modules\districtreport\models\Payment;
use yii\db\Query;
use yii\db\Command;
$query = \Yii::$app->db;
/**
* PartiesSearch represents the model behind the search form about `frontend\modules\districtreport\models\Parties`.
*/
class PartiesSearch extends Parties
{
/**
* #inheritdoc
*/
public function rules()
{
return [
[['party_id'], 'integer'],
[['parties_partyname', 'address', 'parties_district', 'name_manager', 'transport', 'dlno', 'instruction', 'con', 'district','sale','sell','collection'], 'safe'],
];
}
/**
* #inheritdoc
*/
public function scenarios()
{
// bypass scenarios() implementation in the parent class
return Model::scenarios();
}
/**
* Creates data provider instance with search query applied
*
* #param array $params
*
* #return ActiveDataProvider
*/
public function search($params)
{
$sql = 'select
tsell.district as district,
tsell.totalsale as sell,
coalesce(tcollection.collection,0) as collection
from
(SELECT
district,
coalesce(sell.sale,0) as totalsale
FROM `districts`
left join
(SELECT
parties_district,
billdate,
sum(billamount) as sale
FROM `bills`
left join parties on bills.bills_partyname = parties.parties_partyname
group by parties_district) as sell
on sell.parties_district = districts.district) as tsell
left join
(SELECT
parties_district,
payment_date,
COALESCE(sum(payment_amount),0) as collection
FROM `payment`
left join parties on payment.payment_partyname = parties.parties_partyname
group by parties_district) as tcollection
on tsell.district = tcollection.parties_district';
$query = Parties::findBySql($sql);
// add conditions that should always apply here
$dataProvider = new ActiveDataProvider([
'query' => $query,
//'sort'=> ['defaultOrder' => ['district'=>SORT_DESC]]
]);
$dataProvider->setSort([
'attributes' => [
'sell' => [
'asc' => ['sell' => SORT_ASC],
'desc' => ['sell' => SORT_DESC],
'label' => 'Sell'
],
'collection' => [
'asc' => ['collection' => SORT_ASC],
'desc' => ['collection' => SORT_DESC],
'label' => 'Collection'
],
'district' => [
'asc' => ['tsell.district' => SORT_ASC],
'desc' => ['tsell.district' => SORT_DESC],
'label' => 'District'
]
]
]);
$this->load($params);
if (!$this->validate()) {
// uncomment the following line if you do not want to return any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
// grid filtering conditions
$query->andFilterWhere([
'party_id' => $this->party_id,
]);
$query->andFilterWhere(['like', 'parties_partyname', $this->parties_partyname])
->andFilterWhere(['like', 'address', $this->address])
->andFilterWhere(['like', 'parties_district', $this->parties_district])
->andFilterWhere(['like', 'name_manager', $this->name_manager])
->andFilterWhere(['like', 'transport', $this->transport])
->andFilterWhere(['like', 'dlno', $this->dlno])
->andFilterWhere(['like', 'instruction', $this->instruction])
->andFilterWhere(['like', 'con', $this->con])
->andFilterWhere(['like', 'sell', $this->sell])
->andFilterWhere(['like', 'collection', $this->collection])
->andFilterWhere(['like', 'district', $this->district]);
return $dataProvider;
}
}
Parties Model
<?php
namespace frontend\modules\districtreport\models;
use Yii;
/**
* This is the model class for table "parties".
*
* #property integer $party_id
* #property string $parties_partyname
* #property string $address
* #property string $parties_district
* #property string $name_manager
* #property string $transport
* #property string $dlno
* #property string $instruction
* #property string $con
*/
class Parties extends \yii\db\ActiveRecord
{
public $sale;
public $district;
public $sell;
public $collection;
public $bills;
public $partyname;
public $billdate;
//public $sale;
/**
* #inheritdoc
*/
public static function tableName()
{
return 'parties';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['parties_partyname', 'parties_district', 'name_manager'], 'required'],
[['parties_partyname'], 'string', 'max' => 60],
[['address', 'instruction'], 'string', 'max' => 100],
[['parties_district'], 'string', 'max' => 20],
[['name_manager', 'transport', 'dlno'], 'string', 'max' => 30],
[['con'], 'string', 'max' => 10],
[['parties_partyname'], 'unique'],
[['name_manager'], 'exist', 'skipOnError' => true, 'targetClass' => Managers::className(), 'targetAttribute' => ['name_manager' => 'manager_managername']],
[['con'], 'exist', 'skipOnError' => true, 'targetClass' => Console::className(), 'targetAttribute' => ['con' => 'console']],
[['parties_district'], 'exist', 'skipOnError' => true, 'targetClass' => Districts::className(), 'targetAttribute' => ['parties_district' => 'district']],
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'party_id' => 'Party ID',
'parties_partyname' => 'Parties Partyname',
'address' => 'Address',
'parties_district' => 'Parties District',
'name_manager' => 'Name Manager',
'transport' => 'Transport',
'dlno' => 'Dlno',
'instruction' => 'Instruction',
'con' => 'Con',
];
}
public function getDistricts()
{
return $this->hasOne(Districts::className(), ['district' => 'parties_district']);
}
public function getBills()
{
return $this->hasMany(Bills::className(), ['bills_partyname' => 'parties_partyname']);
}
public function getPayment()
{
return $this->hasMany(Payment::className(), ['payment_partyname' => 'parties_partyname']);
}
}
index.php
<?php
use yii\helpers\Html;
use kartik\grid\GridView;
//use kartik\widgets\DatePicker;
use kartik\daterange\DateRangePicker;
use kartik\form\ActiveForm;
use dosamigos\datepicker\DatePicker;
use frontend\modules\districtreport\models\ExpartiesSearch;
/* #var $this yii\web\View */
/* #var $searchModel frontend\modules\districtreport\models\PartiesSearch */
/* #var $dataProvider yii\data\ActiveDataProvider */
$this->title = 'Parties';
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="parties-index">
<h1><?= Html::encode($this->title) ?></h1>
<?php // echo $this->render('_search', ['model' => $searchModel]); ?>
<!-- <p>
<?= Html::a('Create Parties', ['create'], ['class' => 'btn btn-success']) ?>
</p> -->
<!-- <div class="custom-filter">
Date range:
<input name="start" />
<input name="end" />
</div> -->
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'export' => false,
'columns' => [
[
//['class' => 'yii\grid\SerialColumn'],
'class' => 'kartik\grid\ExpandRowColumn',
'value' => function($model, $key, $index, $column){
return GridView::ROW_COLLAPSED;
},
'detail' => function($model, $key, $index, $column){
$searchModel = new ExpartiesSearch();
$searchModel-> district = $model->district;
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return Yii::$app->controller->renderPartial('_exparties', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
},
],
//['class' => 'yii\grid\SerialColumn'],
'district',
// [
// 'attribute' => 'date',
// 'value' => 'tsell.date',
// 'filter' => \yii\jui\DatePicker::widget(['language' => 'ru', 'dateFormat' => 'dd-MM-yyyy']),
// 'format' => 'html',
// ],
'sell',
'collection',
//['class' => 'yii\grid\ActionColumn'],
],
]); ?>
</div>
In this picture we can see that though the sell sort is there but it's not sorting the data actually.
In picture 2 we can see that though the data assam is passed to the next level of kartik expandrow, it's not filtering.
According to yii2's docs you're using an ActiveDataProvider with an ActiveRecord inside. Here's the example docs page for your case.
I think what you want to do is to return $dataProvider->getModels() rather than just return $dataProvider. This will return presumably all rows, since I don't see a pagination mechanism (there could be a default pagination count).
For sorting, you could try sorting on the $query rather than the $dataProvider. Try something like:
$query->orderBy([
'tsell.sell' => SORT_ASC
]);
Setup a grid view with a data provider and filter model.
In your view:
<?= GridView::widget([
'dataProvider'=> $dataProvider,
'filterModel' => $searchModel,
'columns' => [
'parties_partyname',
'address',
'parties_district',
'name_manager',
'transport',
'dlno',
'instruction',
'con',
'district',
'sale',
'sell',
'collection'
]
]); ?>
In your controller (replace index with the name of your view file):
$searchModel = new \frontend\modules\districtreport\models\PartiesSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
Try removing $dataProvider->setSort() from your search model.
Also, in your detail of your gridview you are using the same variable name for both search models and data providers. They are two separate models so the variables should not be the same.
<?php
namespace frontend\modules\districtreport\models;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use frontend\modules\districtreport\models\Parties;
use frontend\modules\districtreport\models\Bills;
use frontend\modules\districtreport\models\Payment;
use yii\db\Query;
use yii\db\Command;
/**
* PartiesSearch represents the model behind the search form about `frontend\modules\districtreport\models\Parties`.
*/
class PartiesSearch extends Parties
{
/**
* #inheritdoc
*/
public function rules()
{
return [
[['party_id'], 'integer'],
[['parties_partyname', 'address', 'parties_district', 'name_manager', 'transport', 'dlno', 'instruction', 'con', 'district','sale','sell','collection'], 'safe'],
];
}
/**
* #inheritdoc
*/
public function scenarios()
{
// bypass scenarios() implementation in the parent class
return Model::scenarios();
}
/**
* Creates data provider instance with search query applied
*
* #param array $params
*
* #return ActiveDataProvider
*/
public function search($params)
{
$sql = 'select
tsell.district as district,
tsell.totalsale as sell,
coalesce(tcollection.collection,0) as collection
from
(SELECT
district,
coalesce(sell.sale,0) as totalsale
FROM `districts`
left join
(SELECT
parties_district,
billdate,
sum(billamount) as sale
FROM `bills`
left join parties on bills.bills_partyname = parties.parties_partyname
group by parties_district) as sell
on sell.parties_district = districts.district) as tsell
left join
(SELECT
parties_district,
payment_date,
COALESCE(sum(payment_amount),0) as collection
FROM `payment`
left join parties on payment.payment_partyname = parties.parties_partyname
group by parties_district) as tcollection
on tsell.district = tcollection.parties_district';
$query = Parties::findBySql($sql);
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$this->load($params);
if (!$this->validate()) {
// uncomment the following line if you do not want to return any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
$query->andFilterWhere([
'party_id' => $this->party_id,
'parties_partyname' => $this->parties_partyname,
'address' => $this->address,
'parties_district' => $this->parties_district,
'name_manager' => $this->name_manager,
'transport' => $this->transport,
'dlno' => $this->dlno,
'instruction' => $this->instruction,
'con' => $this->con,
'sell' => $this->sell,
'collection' => $this->collection,
'district' => $this->district,
]);
return $dataProvider;
}
}
Simplified Search Model that works for me:
<?php
namespace common\models\event;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use common\models\Model;
class ModelSearch extends Model
{
/**
* #inheritdoc
*/
public function rules()
{
return [
[['id', 'name'], 'safe'],
];
}
/**
* #inheritdoc
*/
public function scenarios()
{
// bypass scenarios() implementation in the parent class
return Model::scenarios();
}
/**
* Creates data provider instance with search query applied
*
* #param array $params
*
* #return ActiveDataProvider
*/
public function search($params)
{
$query = Model::find()->indexBy('id');
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => false
]);
$this->load($params);
if (!$this->validate()) {
// uncomment the following line if you do not want to return any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
$query->andFilterWhere([
'id' => $this->id,
'name' => $this->name,
]);
return $dataProvider;
}
}
According to http://www.yiiframework.com/doc-2.0/yii-db-activerecord.html#findBySql%28 code with findbysql cannot be sorted or filtered.
However, it can be sorderd by building query following page - http://www.yiiframework.com/doc-2.0/guide-db-query-builder.html
The query will be like -
$subQuery1 = (new Query())->select(['parties_district','billdate','sum(billamount) as sale'])->from ('parties')->join('LEFT JOIN','bills','bills.bills_partyname = parties.parties_partyname')->groupby('parties_district')->where('billdate != "NULL"');
$subQuery2 = (new Query())->select(['district','coalesce(sell.sale,0) as totalsale'])->from('districts')->leftJoin(['sell' => $subQuery1],'sell.parties_district = districts.district');
$subQuery3 = (new Query())->select(['parties_district','payment_date','COALESCE(sum(payment_amount),0) as collection'])->from('payment')->join('LEFT JOIN','parties','payment.payment_partyname = parties.parties_partyname')->groupby('parties_district');
$query = (new Query())->select(['tsell.district as district','tsell.totalsale as sell','coalesce(tcollection.collection,0) as collection'])->from(['tsell'=> $subQuery2])->leftJoin(['tcollection' => $subQuery3],'tcollection.parties_district = tsell.district');
Should anyone run into this issue all these years later: queries built with the findBySql method will be sortable (and pagination will work too, which doesn't with ActiveDataProvider + findBySql) if you pass them to an ArrayDataProvider instead of an ActiveDataProvider, like this:
$query = MyModel::findBySql("SELECT * FROM ...");
$dataProvider = new ArrayDataProvider([
'allModels' => $query->all(),
'sort' => [
'attributes' => [
'model_id',
'model_name'
],
'defaultOrder' => [
'model_name' => SORT_ASC
]
],
'pagination' => [
'pageSize' => 30
]
]);
The traditional filtering methods won't work. From the findBySql() docs:
Note that because the SQL statement is already specified, calling additional query modification methods (such as where(), order()) on the created yii\db\ActiveQuery instance will have no effect.
I've come up with a workaround, it requires slightly more work than using the interface methods, but for complex queries (which I assume is why you are trying to use findBySql) it works:
public function search($params)
{
$this->load($params);
$filters = [];
if ($this->model_id) $filters[] = ' "table"."model_id" = '.$this->model_id.' ';
if ($this->model_name) $filters[] = ' "table"."model_name" ILIKE \'%'.$this->model_name.'%\' ';
// ugly ifs can be put into a foreach if you don't need to customize each condition too much
$filterCondition = count($filters) > 0 ? ' AND ' . implode(' AND ', $filters) : ' ';
$query = MyModel::findBySql(
// your query here
.$filterCondition.
// group by, order by etc.
);
// assemble the ArrayDataProvider (see above)
return $dataProvider;
}
Yii version: 2.0.34, PHP version: 7.3.18, PostgreSQL version: 12.2
While updating image using Yii2 I'm facing a problem with the validation.Its always asking me to upload an image. But I don't want this. Always updating an image is not necessary.
I tried skipOnEmpty but its not working properly it cause effect while uploading a photo, which is also incorrect.
Please help!!
Model
public function rules()
{
return [
[['carid', 'name'], 'required'],
[['carid', 'coverphoto', 'status'], 'integer'],
[['name'], 'string', 'max' => 200],
[['imageFiles'], 'image','extensions' => 'png, jpg, jpeg, gif', 'maxFiles' => 4, 'minWidth' => 100, 'maxWidth' => 800, 'minHeight' => 100, 'maxHeight'=>600,'skipOnEmpty' => true],
];
}
Controller
public function actionUpdate($id)
{
$model = $this->findModel($id);
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->photoid]);
} else {
return $this->render('update', [
'model' => $model,
]);
}
}
You should to use scenario for update.
Like as,
Add on condition in model's rule for applying scenario .
[['imageFiles'], 'image','extensions' => 'png, jpg, jpeg, gif', 'maxFiles' => 4, 'minWidth' => 100, 'maxWidth' => 800, 'minHeight' => 100, 'maxHeight'=>600,'skipOnEmpty' => true, 'on' => 'update-photo-upload'],
And use that scenario in controller's action.
public function actionUpdate($id)
{
$model = $this->findModel($id);
$model->scenario = 'update-photo-upload';
........
.....
}
try rule as
[
['imageFiles'], 'file',
'extensions' => 'png, jpg, jpeg, gif',
'mimeTypes' => 'image/jpeg, image/png',
'maxFiles' => 4,
'minWidth' => 100,
'maxWidth' => 800,
'minHeight' => 100,
'maxHeight'=>600,
'skipOnEmpty' => true
],
This is working in my case, hope it works for you too.
**Your View Like This**
<?php use yii\widgets\ActiveForm;?>
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>
<?= $form->field($model, 'imageFiles')->fileInput() ?>
<div class="form-group">
<?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
</div>
<?php ActiveForm::end() ?>
*** Your Controller Like This******
use Yii;
use yii\web\Controller;
use app\models\UploadForm;
use yii\web\UploadedFile;
class SiteController extends Controller
{
public function actionUpdate()
{
$model = new UploadForm ();
$model->scenario = 'update';
if (Yii::$app->request->isPost) {
$model->imageFiles= UploadedFile::getInstance($model, 'imageFiles');
if ($model->upload()) {
// file is uploaded successfully
return;
}
}
return $this->render('update', ['model' => $model]);
}
}
***** Your ModelLike This ******
use yii\base\Model;
use yii\web\UploadedFile;
class UploadForm extends Model
{
/**
* #var UploadedFile[]
*/
public $imageFiles;
public function rules()
{
return [
[['carid', 'name'], 'required'],
[['carid', 'coverphoto', 'status'], 'integer'],
[['name'], 'string', 'max' => 200],
[['imageFiles'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg', 'maxFiles' => 4,'on'=>'update'],
];
}
public function upload()
{
if ($this->validate()) {
foreach ($this->imageFiles as $file) {
$file->saveAs('uploads/' . $file->baseName . '.' . $file->extension);
}
return true;
} else {
return false;
}
}
function scenario()
{
return [
'create' => ['imageFiles ', 'carid','name','coverphoto','status'],
'update' => ['imageFiles ', 'carid','name','coverphoto','status'],
];
}
}