I have a database having relationship of three levels. cheque->account->customer. Now I am trying to retrieve data from all three table at same time using the following method.
$query = Cheque::find();
$query->joinWith(['account.customer']);
$query->orderBy('sr desc');
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
Cheque Model:
class Cheque extends \common\components\db\ActiveRecord {
/**
* #inheritdoc
*/
public static function tableName() {
return 'cheque';
}
/**
* #inheritdoc
*/
public function rules() {
return [
[['sr'], 'integer'],
[['ID', 'account_ID'], 'required'],
[['ID', 'account_ID', 'created_by', 'branch_ID', 'application_ID'], 'string'],
[['serial_start', 'serial_end', 'status'], 'number'],
[['created_on'], 'safe']
];
}
/**
* #inheritdoc
*/
public function attributeLabels() {
return [
'ID' => 'ID',
'account_ID' => 'Account ID',
'serial_start' => 'Serial Start',
'serial_end' => 'Serial End',
'created_on' => 'Created On',
'created_by' => 'Created By',
'branch_ID' => 'Branch ID',
'application_ID' => 'Application ID',
'status' => 'Status',
'sr' => 'ID'
];
}
/**
* #return \yii\db\ActiveQuery
*/
public function getAccount() {
return $this->hasOne(Account::className(), ['ID' => 'account_ID']);
}
public static function getActiveChequeBook($account_ID) {
return Cheque::findAll(['account_ID' => $account_ID, 'status' => array_search('Active', \common\models\Lookup::$cheque_status)]);
}
}
But executing this I get the following error:
pre>Exception 'yii\base\InvalidCallException' with message 'Setting read-only property: common\models\Account::customer'
Property customer in your common\models\Account model has no setter (only getCustomer method exists). Check you model and add appropriate property to class.
Related
The connection between the modules does not work, and because of this, the data in the table is not displayed. I can not understand why
Code in the controller
public function actionIndex()
{
$searchModel = new SuggestedNewsSearch();
$dataProvider = $searchModel->getAllNews(Yii::$app->request->queryParams);
return $this->render('index', [
'dataProvider' => $dataProvider,
'searchModel' => $searchModel
]);
}
code in suggestedNewsSearch.php
class SuggestedNewsSearch extends SuggestedNews
{
public function getAllNews($params)
{
$query = $this::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
if ($this->validate() AND !($this->load($params))) {
return $dataProvider;
}
if (!empty($this->getAttribute('title'))) {
$query->andFilterWhere(['LIKE', 'title', $this->getAttribute('title')]);
}
if (!empty($this->getAttribute('category'))) {
$query->andFilterWhere(['LIKE', 'category', $this->getAttribute('category')]);
}
if (!empty($this->getAttribute('status'))) {
switch (mb_strtolower($this->getAttribute('status'))) {
case $this::APPROVED:
$status = $this::ACTIVE_STATUS;
break;
case $this::NOT_APPROVED:
$status = $this::DEACTIVATED_STATUS;
break;
}
$query->andFilterWhere(['=', 'status', $status]);
}
return $dataProvider;
}
}
code on SuggestedNews.php
class SuggestedNews extends \yii\db\ActiveRecord
{
CONST ACTIVE_NEWS = 1;
CONST ACTIVE_STATUS = 1;
CONST DEACTIVATED_STATUS = 0;
CONST APPROVED = 'одобренно';
CONST NOT_APPROVED = 'не одобренно';
/**
* {#inheritdoc}
*/
public static function tableName()
{
return 'suggested_news';
}
/**
* {#inheritdoc}
*/
public function rules()
{
return [
[['news'], 'string'],
[['category', 'status'], 'integer'],
[['date'], 'safe'],
[['title', 'news_source'], 'string', 'max' => 255],
[['category'], 'exist', 'skipOnError' => true, 'targetClass' => Category::className(), 'targetAttribute' => ['category' => 'id']],
];
}
/**
* {#inheritdoc}
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'title' => 'Title',
'news' => 'News',
'category' => 'Category',
'status' => 'Status',
'date' => 'Date',
'news_source' => 'News Source',
];
}
/**
* #return \yii\db\ActiveQuery
*/
public function getCategory()
{
return $this->hasOne(Category::className(), ['id' => 'category']);
}
public function deleteNewsById($id)
{
$customer = $this::findOne($id);
if ($customer->delete()) return true;
else return false;
}
public function getNewsByIdWithCategory($id){
return $this::find()->where(['id' => $id])->with('category')->one();
}
}
code on Category.php
class Category extends \yii\db\ActiveRecord
{
CONST STATUS_CATEGORY_OFF = 0;
CONST STATUS_CATEGORY_ON = 1;
CONST NEW_CATEGORY_INTEGER = 01;
CONST NEW_CATEGORY_NAME = 'New Category';
/**
* {#inheritdoc}
*/
public static function tableName()
{
return 'category';
}
/**
* {#inheritdoc}
*/
public function rules()
{
return [
[['name', 'status_category'], 'required'],
[['status_category'], 'integer'],
[['name'], 'string', 'max' => 255],
];
}
/**
* {#inheritdoc}
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'name' => 'Name',
'status_category' => 'Status Category',
];
}
/**
* #return \yii\db\ActiveQuery
*/
public function getSuggestedNews()
{
return $this->hasMany(SuggestedNews::className(), ['category' => 'id']);
}
public function getAllCategories(){
return $this::find()->where(['status_category' => $this::STATUS_CATEGORY_ON])->all();
}
}
my index.php file(view)
<?php echo GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'id',
[
'attribute' => 'title',
'format' => 'text',
'label' => 'title',
'filter' => true,
],
[
'attribute' => 'category.Category',
'format' => 'text',
'label' => 'Category',
],
[
'attribute' => 'status',
'filter' => true,
'value' => function($model) {
if($model->status == 1){
return $model::APPROVED;
}else{
return $model::NOT_APPROVED;
}
}
],
'date',
[
'class' => 'yii\grid\ActionColumn',
],
],
]);
?>
and on result i have this:result table
enter image description here
table category
table suggested_news
You field name and relation are the same, so You have to change Category relation name like this:
/**
* #return \yii\db\ActiveQuery
*/
public function getCategory1()
{
return $this->hasOne(Category::className(), ['id' => 'category']);
}
//Gridview
//...
[
'attribute' => 'category',
'label' => 'Category',
'value' => function($model){
return $model->category1->name;
}
],
//...
//or
//...
[
'attribute' => 'category1.name',
'format' => 'text',
'label' => 'Category',
],
Hope it will helps.
I've read all the Yii2 Framework documentation but it's confusing when trying to implement it.
I have a view of Customer where it shows all the fields in customer table, including the address_id field in the address table.
I want to implement a join query using MySQL in the Yii2 Framework but the generated code is the following:
CustomerSearch in the models:
class CustomerSearch extends Customer{
/**
* {#inheritdoc}
*/
public function rules()
{
return [
[['customer_id', 'store_id', 'address_id', 'active'], 'integer'],
[['first_name', 'last_name', 'email', 'create_date', 'last_update'], '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 = Customer::find();
// 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([
'customer_id' => $this->customer_id,
'store_id' => $this->store_id,
'address_id' => $this->address_id,
'active' => $this->active,
'create_date' => $this->create_date,
'last_update' => $this->last_update,
]);
$query->andFilterWhere(['like', 'first_name', $this->first_name])
->andFilterWhere(['like', 'last_name', $this->last_name])
->andFilterWhere(['like', 'email', $this->email]);
return $dataProvider;
}
Customer class:
class Customer extends \yii\db\ActiveRecord{
/**
* {#inheritdoc}
*/
public static function tableName()
{
return 'customer';
}
/**
* {#inheritdoc}
*/
public function rules()
{
return [
[['store_id', 'first_name', 'last_name', 'address_id'], 'required'],
[['store_id', 'address_id', 'active'], 'integer'],
[['create_date', 'last_update'], 'safe'],
[['first_name', 'last_name'], 'string', 'max' => 45],
[['email'], 'string', 'max' => 50],
];
}
/**
* {#inheritdoc}
*/
public function attributeLabels()
{
return [
'customer_id' => 'Customer ID',
'store_id' => 'Store ID',
'first_name' => 'First Name',
'last_name' => 'Last Name',
'email' => 'Email',
'address_id' => 'Address ID',
'active' => 'Active',
'create_date' => 'Create Date',
'last_update' => 'Last Update',
];
}
}
You need to declare some relations in your ActiveRecord models...
See here in the official docs for Working with Relational Data
If you are storing the address_id in your customer table then you will be tied to each customer having 1 single address (i.e. a one-to-one relationship), which is a rather bad design. Or you could use a junction table. You are better off storing the customer_id in each address record and defining a one-to-many relation, enabling each customer to store multiple addresses (more like in real life, i.e. for home, work address etc).
For example, in your Customer model, you would define a has-many relation for customer addresses:
use app\models\Address;
class Customer extends \yii\db\ActiveRecord
{
/**
* {#inheritdoc}
*/
public static function tableName()
{
return 'customer';
}
/**
* {#inheritdoc}
*/
public function rules()
{
return [
[['store_id', 'first_name', 'last_name', 'primary_address_id'], 'required'],
[['store_id', 'primary_address_id', 'active'], 'integer'],
[['create_date', 'last_update'], 'safe'],
[['first_name', 'last_name'], 'string', 'max' => 45],
[['email'], 'string', 'max' => 50],
];
}
/**
* {#inheritdoc}
*/
public function attributeLabels()
{
return [
'customer_id' => 'Customer ID',
'store_id' => 'Store ID',
'first_name' => 'First Name',
'last_name' => 'Last Name',
'email' => 'Email',
'primary_address_id' => 'Primary Address ID',
'active' => 'Active',
'create_date' => 'Create Date',
'last_update' => 'Last Update',
];
}
/**
* #return \yii\db\ActiveQuery
*/
public function getAddresses()
{
return $this->hasMany(Address::className(), ['customer_id' => 'id']);
}
}
And in your Address model you would have the inverse has-one relation defined:
/**
* #return \yii\db\ActiveQuery
*/
public function getCustomer()
{
return $this->hasOne(Customer::className(), ['id' => 'customer_id']);
}
You can then Access relational data from model instances via defined relation names, for example:
// SELECT * FROM `customer` WHERE `id` = 123
$customer = Customer::findOne(123);
// SELECT * FROM `address` WHERE `customer_id` = 123
// $addresses is an array of Address objects
$addresses = $customer->addresses;
Also note, if you define proper primary/foreign keys in your schema, the Gii Model/CRUD generators will automatically create the boilerplate relations code in your models and CRUD files.
my grid view filter is not filtering categories, I have given category_id to nesserray places but yet it is not filtering my posts according to their category_id, please help me.
here are my source codes:
post-->index.php
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'title',
[
'attribute'=>'category_id',
'value'=>function($model) {
return $model->category->name;
},
'filter'=>$category
],
[
'attribute'=>'user_id',
'value'=>function($model) {
return $model->user->fullname;
},
'filter'=>$user,
'label'=>'user'
],
'category.name',
'user.fullname',
// 'user_id',
// 'description',
// 'content:html',
'count_view',
'status',
'created_at',
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
and here is model/postSearch.php
<?php
namespace app\models\search;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use app\models\post;
/**
* PostSearch represents the model behind the search form about `app\models\post`.
*/
class PostSearch extends post
{
/**
* #inheritdoc
*/
public function rules()
{
return [
[['id', 'user_id','category_id', 'count_view'], 'integer'],
[['title', 'description', 'content', 'status', 'created_at'], '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 = post::find();
// 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,
'category_id' => $this->category_id,
'user_id' => $this->user_id,
'count_view' => $this->count_view,
'created_at' => $this->created_at,
]);
$query->andFilterWhere(['like', 'title', $this->title])
->andFilterWhere(['like', 'description', $this->description])
->andFilterWhere(['like', 'content', $this->content])
->andFilterWhere(['like', 'status', $this->status]);
return $dataProvider;
}
}
it worked, I had to removle jQuery files
I have to implementing export excel using moonland PHP excel extension. When I implemented it, it throws the error:
"Call to a member function getAttributeLabel() on null".
Code
$dataProvider = new \app\models\Details;
\moonland\phpexcel\Excel::widget([
'models' => $dataProvider,
'mode' => 'export', //default value as 'export'
'columns' => ['id','name','address'], //without header working, because the header will be get label from attribute label.
//'header' => ['id' => 'Header Column 1','name' => 'Header Column 2', 'address' => 'Header Column 3'],
]);
My model
class Details extends \yii\db\ActiveRecord
{
/**
* #inheritdoc
*/
public static function tableName()
{
return 'details';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['id'], 'required'],
[['id'], 'integer'],
[['name', 'address'], 'string', 'max' => 50],
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
/* return [
'id' => Yii::t('app', 'ID'),
'name' => Yii::t('app', 'Name'),
'address' => Yii::t('app', 'Address'),
];*/
return [
'id' => 'ID',
'name' => 'Name',
'address' =>'Address',
];
}
}
Table
May i know what is the problem in that, thanks in advance for your idea
This is my model Riders:
<?php
namespace backend\models;
use Yii;
class Riders extends \yii\db\ActiveRecord
{
public static function tableName()
{
return 'riders';
}
public function rules()
{
return [
[['cagories_category_id', 'rider_firstname', 'rider_no_tlpn', 'rider_ucinumber', 'countries_id', 'rider_province', 'rider_city', 'rider_dateofbirth', 'rider_gender'], 'required'],
[['user_id', 'countries_id'], 'integer'],
[['rider_dateofbirth', 'cagories_category_id'], 'safe'],
[['rider_gender', 'rider_status'], 'string'],
[['rider_firstname', 'rider_lastname', 'rider_nickname', 'rider_province', 'rider_city'], 'string', 'max' => 45],
[['rider_email', 'rider_sponsor', 'rider_birthcertificate_url', 'rider_parental_consent_url'], 'string', 'max' => 100],
[['rider_no_tlpn'], 'string', 'max' => 15],
[['rider_ucinumber'], 'string', 'max' => 11]
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'rider_id' => 'rider_id',
'cagories_category_id' => 'Category Name',
'user_id' => 'User Team',
'rider_firstname' => 'Rider Firstname',
'rider_lastname' => 'Rider Lastname',
'rider_nickname' => 'Rider Nickname',
'rider_email' => 'Rider Email',
'rider_no_tlpn' => 'Rider No Tlpn',
'rider_ucinumber' => 'Rider Ucinumber',
'countries_id' => 'Country Name',
'rider_province' => 'Rider Province',
'rider_city' => 'Rider City',
'rider_sponsor' => 'Rider Sponsor',
'rider_dateofbirth' => 'Rider Dateofbirth',
'rider_gender' => 'Rider Gender',
'rider_birthcertificate_url' => 'Rider Birthcertificate Url',
'rider_parental_consent_url' => 'Rider Parental Consent Url',
'rider_status' => 'Rider Status',
];
}
/**
* #return \yii\db\ActiveQuery
*/
public function getRegistrations()
{
return $this->hasMany(Registrations::className(), ['riders_rider_id' => 'rider_id']);
}
/**
* #return \yii\db\ActiveQuery
*/
public function getCagoriesCategory()
{
return $this->hasOne(Categories::className(), ['category_id' => 'cagories_category_id']);
}
/**
* #return \yii\db\ActiveQuery
*/
public function getUser()
{
return $this->hasOne(User::className(), ['id' => 'user_id']) -> from(user::tableName() . 'ud');
}
/**
* #return \yii\db\ActiveQuery
*/
public function getUserDesc()
{
return $this->hasOne(UserDesc::className(), ['desc_id' => 'user_id']) -> from(['ud' => userDesc::tableName()]);
}
/**
* #return \yii\db\ActiveQuery
*/
public function getCountries()
{
return $this->hasOne(Countries::className(), ['id' => 'countries_id']);
}
}
This my Controller actionIndex:
$searchModel = new RidersSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
$totalCount = Yii::$app->db->createCommand('SELECT COUNT(*) FROM riders WHERE user_id = :user_id',
[':user_id' => Yii::$app->user->identity->id])->queryScalar();
$dataProvider = new SqlDataProvider([
'sql' => 'SELECT * FROM riders WHERE user_id = :user_id',
'params' => [':user_id' => Yii::$app->user->identity->id],
'totalCount' => $totalCount,
'key' => 'rider_id',
'pagination' => [
'pageSize' => 10,
],
'sort' => [
'attributes' => [
'cagories_category_id',
'rider_id',
'rider_firstname',
'rider_email:email',
'rider_no_tlpn',
]
]
]);
$models = $dataProvider->getModels();
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
This is my view index:
<?= GridView::widget([
'dataProvider' => $dataProvider,
// 'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
[
'label' => 'Category Name',
'attribute'=>'cagories_category_id',
'value' => 'cagoriesCategory.category_name', <---Can't work again
],
[
'label' => 'BIB',
'attribute'=>'rider_id',
],
'rider_firstname',
'rider_email:email',
'rider_no_tlpn',
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
Before I use sqldataprovider, it can call from model function have relation, after use sqldataprovider can't work. How to get relation table value???
then before use it, i can to merge rider_firstname and rider_lastname with return $model->rider_firstname . " " . rider_lastname; after use sqldataprovider can't work too??
SqlDataProvider returns data as an array so You can't able to access related object with $dataProvider->models()
either you have to use ActiveDataProvider or change your Sql of SqlDataProvider with join condition
sql='sql' => 'SELECT * FROM riders inner join '. Categories::tableName() .' as c on c.category_id=riders.cagories_category_id WHERE user_id = :user_id'