I am new in yii2. I don't know much about table relation. I have a 3 tables shops promotions and promotion_details. promotion_details contains promotion id and shop id. promotion has status like active or inactive. i want display in shop view only active promotions. How can i Do that? Thanks in advance
In you promotion_detail view add a getter function for relation and a getter function for the field
/* ActiveRelation */
public function getPropomition()
{
return $this->hasOne(Promotion::className(), ['id' => 'promotion_id']);
}
/* Getter for status name */
public function getStatus() {
return $this->prpmotion->status;
}
in view
echo GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'id',
.......
'status',
['class' => 'yii\grid\ActionColumn'],
]
]);
this guide could be useful http://www.yiiframework.com/wiki/621/filter-sort-by-calculated-related-fields-in-gridview-yii-2-0/
Related
i have a table buss_catgry_mst
fields:- buss_catgry_mst_id , category_name ,parent_id, depth.
i want to create nested category using select_2_nested in backpack laravel.
ex:-
buss_catgry_mst_id=1 , category_name=restaurent ,parent_id=0, depth=1.
i want to create it's sub category and i want to take depth value which is +1 from it's main category depth value.
code in crud controller:-
{
CRUD::setValidation(StoreRequest::class);
//for nested
CRUD::addField([
'name' => 'parent_id',
'label' => "Category",
'type' => 'select2_nested',
'entity' => 'category', // the method that defines the relationship in your Model
'attribute' => 'category_name', // foreign key attribute that is shown to user
'model' => "App\Models\BussCatgryMst",
]); ```
***model buss_catgry_mst***
public function category()
{
return $this->hasMany(BussCatgryMst::class);
}
public function children()
{
return $this->hasMany('App\Models\BussCatgryMst','parent_id');
}
I have two models :Product and category
which are linked by a one-to-many relationship. A category has several products. I would like to select specific columns from each model.
Here is the query I have, but I have all the columns with category_id, but I want the category name instead of id. How can I do that. Thank you in advance.
here is the method in controller
$products = Product::with('categories:id,name')->get();
if ($products) {
$response = ['api_status' => 1, 'api_message' => 'success', 'data' => $products];
return response()->json($response);
} else {
$response = ['api_status' => 0, 'api_message' => 'Error'];
return response()->json($response);
}
Here is category model
class Categorie extends Model
{
use HasFactory, SoftDeletes;
protected $fillable =['name','redirect'];
public function products()
{
return $this->hasMany(product::class);
}
}
and the product model is:
class Product extends Model
{
use HasFactory, SoftDeletes;
protected $fillable = [
'name',
'description',
'detail', 'img',
'categorie_id', 'onSale',
'costPrice', 'inStock', 'salePrice'
];
public function categories()
{
return $this->belongsTo(Categorie::class);
}
}
here is the response:
To modify the output of your model I'd suggest using an API resource. This will give you more granular control about how a resource is returned by the API. A resource is also the best point to modify certain values.
use Illuminate\Http\Resources\Json\JsonResource;
class ProductResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'description' => $this->description,
'detail' => $this->detail,
'img' => $this->img,
'category_id' => $this->categorie->name,
'category_name' => $this->categorie->name,
'onSale' => $this->onSale,
'costPrice' => $this->costPrice,
'inStock' => $this->inStock,
'salePrice' => $this->salePrice,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
'deleted_at' => $this->deleted_at,
'categories' => $this->categories ?? null,
];
}
}
This way you can manually specify which values your response should have.
In your controller you can include the populated array in your response by manually filling the toArray method with the current request object or just by using the resolve method which basically does the previous task for you:
$response = [
'api_status' => 1,
'api_message' => 'success',
'data' => ProductResource::collection($products)->resolve()
];
You can select particular fields from the relationship but you always need to select any keys involved in the relationship:
$products = Product::with('categories:id,name')->get();
Now each Product has its 'categories' loaded and those Category models only have the id and name fields.
Importantly:
The relationship categories is named incorrectly, it should be categorie in this case as the foreign key on Product is categorie_id and it is a singular relationship, it does not return multiple results.
Product::with('categorie:id,name')->get()
If you want to keep the name categories you would have to define the foreign key used when defining the belongsTorelationship, the second argument.
If you need to transform the structure of any of this that is a different thing and you will be walking into transformers or an API Resource.
Not sure how you want your data to look but this is the structure you will have by eager loading records, so if you need a different structure then what you get you will have to show an example.
I generated a model which got the function attributeLabels():
public function attributeLabels()
{
return [
'column1' => 'name of column1',
'column2' => 'name of column2',
];
}
I also wrote a function in my model, which creates a SQL statement:
public function getReminders()
{
$sql = Yii::$app->db->createCommand('SELECT
[[column1]], [[column2]]
FROM {{%table}}
WHERE column1 > :value')
-> bindValue(':value', '10');
return $sql;
}
Then I created a controller with an actionIndex() function:
public function actionIndex()
{
$model = new TestObject();
$testmodels= new ActiveDataProvider([
'models' => $model->getReminders()->queryAll(),
]);
return $this->render('index', [
'testmodels' => $testmodels,
]);
Finally I created a View
GridView::widget([
'dataProvider' => $testmodels,
'layout' => '{items}{pager}',
'columns' => ['column1', column2,],
]);
For some reason, the column names of the resulting page are column1 and column2. I have tried to create a listView and got the correct names for the columns. How comes that the column names are not set by attributeLabels() in this case? I really don't want to use the label property in the gridview.
Thank you in advance!
If you just need to change the label for the gridview column you can configure you column with proper value for label
GridView::widget([
'dataProvider' => $testmodels,
'layout' => '{items}{pager}',
'columns' => [
[
'attribute'=> column1',
'label' => 'Your Lable for column 1',
],
[
'attribute'=> column2',
'label' => 'Your Lable for column 2',
],
],
]);
you can take a look at thsi for a brief guide http://www.yiiframework.com/doc-2.0/guide-output-data-widgets.html or here for ref http://www.yiiframework.com/doc-2.0/yii-grid-datacolumn.html
I would do the following:
make the base class for the TestObject be ActiveRecord
Override tableName
Simplify getReminders, make it static, and let it return Query not a Command
class TestModel extends yii\db\ActiveRecord
{
...
public static function tableName()
{
return {{%table}};
}
public static function getReminders()
{
$query = self::find()->select(['column1', 'column2'])
->where(['>', 'column1', 10]);
return $query;
}
...
}
Don't set models of the ActiveDataProvier and instead set query
'models' => TestObject::getReminders(),
scenario is crm with tables account, account_contact, contact and account_contact_role. The latter contains roles like 'project lead' or 'account manager' for the combos defined in the junction table.
My challenge is the account view, that is listing also the connected persons with their roles. I want my grid to show: Doe | John | employee.
The problem is now when the contact has 2+ entries in the junction table. How can I print the correct role for the row? As you can see in the code I solved it the static way which shows only 1 out of n times the correct value. Tried it with inner join without success. Is it a problem of the search in the model or with the access in the view?
the relation from the account model to the contacts:
public function getContacts($role = null)
{
// many-to-many
return $this->hasMany(ContactRecord::className(), ['id' => 'contact_id'])
->via('accountContacts')
->innerJoinWith(['accountContacts.role'])
->andWhere(['account_contact.account_id' => $this->id])
->andWhere(['account_contact_role.type' => $role])
;
}
the view
<?= \yii\grid\GridView::widget([
'dataProvider' => new \yii\data\ActiveDataProvider([
'query' => $model->getContacts('internal'),
'pagination' => false
]),
'columns' => [
'lastname',
'firstname',
[
'label' => 'Role',
'attribute' => 'accountContacts.0.role.name',
],
[
'class' => \yii\grid\ActionColumn::className(),
'controller' => 'contacts',
'header' => Html::a('<i class="glyphicon glyphicon-plus"></i> Add New', ['contact-records/create', 'account_id' => $model->id]),
'template' => '{update}{delete}',
]
]
]); ?>
defined relations are:
account has many accountContacts has one contact
accountContacts has one accountContactRole
Many thanks in advance!
You are showing account's contacts, so you have to list from Contact model.
Inside Contact model (or Contact ActiveQuery file):
public static function queryContactsFromAccountAndRole($account, $role = null)
{
// many-to-many
return ContactRecord::find()->innerJoinWith(['accountContacts' => function($q) use($account, $role) {
$q->innerJoinWith(['accountContactsRole'])
->andWhere(['account_contact.account_id' => $account->id])
->andWhere(['account_contact_role.type' => $role]);
}])
->andWhere(['account_contact.account_id' => $account->id]);
}
Now you have one record for each contact and the gridview will show all contacts.
Eselect2 is the extension am using and myADropDown() fetches the data and displays but then my need is concatenate two or more columns in the dropdown
model1 view
<?php $this->widget('ext.select2.ESelect2', array(
'name' => 'id',
'model' => $model,
'options' => array(
'placeholder' => $model->getAttributeLabel('id'),
),
'data' => $model->myADropDown(),
));?>
model1
public function getConcatened()
{
return $this->name.' '.$this->locate.' '.$this->rating;
}
public function myADropDown()
{
$vid=Yii::app()->SESSION['vid'];
$gid=Model2::model()->xyz($vid);
$list=CHtml::listData($gid,'id','concatened');
return $list;
}
// id is fk in another tbl
in the dropdownlist my need is name ,location,rating for each person , am unable to do so
Please Let me know how do i achieve it
For concatenating the table fields in listdata, Please check this Yii forum answer:
Link
As per the link suggestion, you need to add a function in model to get concatenated string.
public function __get($key){
$action = 'get'.str_replace(' ','',ucwords(str_replace('_',' ',$key)));
if(method_exists($this, $action)) return $this->$action();
return parent::__get($key);
}