in index.php :
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'ID_REQUEST',
'NOMOR_SURAT',
[
'label' => 'Nama Depan',
'attribute' => 'ID_KARYAWAN',
'value' => 'iDKARYAWAN.FIRST_NAME'
],
[
'label' => 'Nama Belakang',
'attribute' => 'ID_KARYAWAN',
'value' => 'iDKARYAWAN.LAST_NAME'
],
which is iDKARYAWAN is relation from another table in my model
class Request extends \yii\db\ActiveRecord {
/**
* #inheritdoc
*/
public static function tableName() {
return 'ytms_it.request';
}
public function getIDKARYAWAN() {
return $this->hasOne(Karyawan::className(), ['ID_KARYAWAN' => 'ID_KARYAWAN'])->from(Karyawan::tableName(). ' b');
}
How to merge those two column ?
For the elp, thanks.
Create method called getFullName() in related model and calculate full name using PHP concatenation:
use yii\helpers\Html;
...
/**
* #return string
*/
public function getFullName()
{
return Html::encode($this->name . ' ' . $this->surname);
}
Optionally define a label for it in attributeLabels() method of related model:
`fullName` => 'Label for full name',
Then in GridView it's possible to display full name of related model in one column like so:
1) The shortest form:
'relatedModel.fullName',
2) Overriding the label:
[
'attribute' => 'relatedModel.fullName',
'label' => 'Overrided label',
],
3) Using closure:
[
'attribute' => 'relatedModel.fullName', // The attribute name can be different in this case
'value' => function ($model) {
// You can calculate full name here.
// But it's better to just call according method since view is only for display.
return $model->author->fullName;
},
],
Another way is to calculate full name using SQL and include as a part of query result in separate column.
Use Active Record - Selecting extra fields official docs section as a guide, also see this related issue on Github - JoinWith - assign a column aliases to an attribute of related model.
Add $fullName as public property of related model class. Modify query like so:
use yii\db\Expression;
...
->joinWith(['relatedModel' => function (\yii\db\ActiveQuery $query) {
$query->addSelect('fullName' => new Expression("CONCAT(name, ' ', surname)")]);
}]
Then to display it in GridView column you can use one of the options desribed above, for example:
'relatedModel.fullName'
Related
I have gridview with some columns. I want to create one colums like
'columns' => [
['class' => 'yii\grid\SerialColumn'],
['header' => 'Manager',
//'value' => 'first'],
Column name is Manager and all fields equels 'first'? How could I do this?
Based on info provided, this is easy to achieve with custom grid column:
<?php
namespace app\components;
class CommonValueColumn extends Column
{
public $commonValue = 'Default value for common value';
protected function renderDataCellContent($model, $key, $index)
{
return $commonValue;
}
}
Then use it in GridView widget like this:
'columns' => [
// ...
[
'class' => 'app\components\CommonValueColumn',
'header' => 'Manager',
'commonValue' => 'First',
],
// ...
],
Note that if the manager is a model attribute and the value needs to be taken from database, this is a wrong way to do it.
Information about GridView widget is available in the official docs.
I would like to have a CRUD table, and to be specific I don't need to edit/delete records, only the part with filtering results, which appears at the top of the CRUD generated table, is the part that I want to have. My table contains data from 1 table in database, but I have one column that is not connected to this or any other table in database (it's a comment, that is auto-generated, based on one column from the table). I generate my table manually, but I'd like to add the part with filtering. I have no idea how to do it though. Is it possible in Yii2 to do it manually, or do I have to use CRUD generator?
I don't use CRUD generator as it doesn't generate the code I want (and I think it also doesn't generate filters?). I use a basic template which fits to nearly all gridviews I need to display. Here's one example that can give you a filter:
use yii\grid\GridView;
/** #var array $userTypes All user types (classes) */
// ...
echo GridView::widget([
'dataProvider' => $modelProvider,
'filterModel' => $model,
'columns' => [
[
'attribute' => 'id',
'format' => 'raw',
'filter' => Html::input('text', 'User[id]', $model->id, ['class' => 'form-control', 'placeholder' => 'Filter ID']),
[
'attribute' => 'type',
'format' => 'raw',
'filter' => Html::activeDropDownList($model, 'type', $userTypes, ['class' => 'form-control', 'prompt' => 'All types']),
],
]);
In here I use 2 different input field types (text and dropdown).
For Html::input, first is type (text), then full attribute name (model name + attribute name), then default value and finally other options.
For Html::activeDropDownList we have model first, then attribute name (only), that items list (array) and finally other options.
I guess you are talking about GridView, if yes then you can have your own columns in it, no problem. lets call that column comment as you mentioned
If you use basic template, generated by Gii, and you also generate search class for that model, then you comment to safe attributes and add code for that code to be able to filter it.
If you could be more detailed about mentioned column, possible values or algorythm you might get more suitable answers...
Also take look at Yii 2.0: Displaying, Sorting and Filtering Model Relations on a GridView
Lets say your model is called Xyz as you did not provided any. Also I named column from your table as column_from_your_table and your virtual column as comment
In your model Xyz you will add relation (method with specific name to define it)
public function getComment()
{
$column_from_your_table = $this->column_from_your_table;
$comment = '';
// your code to specify the relation
// ...
// this is value dislpayed in column grid
return $comment;
}
and in file XyzSearch.php in \app\models\
you will have something like this (edit to your needs ofcourse)
<?php
namespace app\models;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use yii\db\Expression;
/**
* XyzSearch represents the model behind the search form about `app\models\Xyz`.
*/
class XyzSearch extends Xyz
{
public $comment; // your virtual column
/**
* #inheritdoc
*/
public function rules()
{
return [
// add it to safe attributes
[['comment'], 'safe'],
// you will have more rules for your other columns from DB probably
];
}
/**
* #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 = Xyz::find();
// add conditions that should always apply here
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
// I dont know your how it is your comment column autogenerated
// or what is the relation, so I give you just basic idea
// your algorythm needs to be able to be rewritten in SQL
// otherwise I dont know how you could possibly sort it
$dataProvider->sort->attributes['comment'] = [
'asc' => [Xyz::tableName().'.column_from_your_table' => SORT_ASC],
'desc' => [Xyz::tableName().'.column_from_your_table' => SORT_DESC],
'default' => SORT_ASC,
];
$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;
}
// again, you will have more filtering conditions from your generated code
// then you will add your custom filtering condition
// I dont know your how it is your comment column autogenerated
// or what is the relation, so I give you just basic idea
$query->andFilterWhere(['like', Xyz::tableName().'.column_from_your_table', $this->comment]);
return $dataProvider;
}
}
finaly in your view file add your virutal column
<?php echo GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
// other columns from database
// ...
'comment',
['class' => 'yii\grid\ActionColumn'],
]
]); ?>
I add another table field in my view , but the search button disappeared , How can I retrieve this form button ?
SaleItems = And a table mysql database.
<?php
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'formatter' => ['class' => 'yii\i18n\Formatter','nullDisplay' => ''],
'columns' => [
['class' => 'yii\grid\SerialColumn'],
**[
'attribute' => 'Data',
'content' => function(SaleItems $model, $key, $index, $column) {
return date('d/m/Y', strtotime($model->sale->date));
},
'header' => 'DATA'
],**
]); ?>
</div>
The search field disappears because in not setted properly in searchModel ..
for this you must extend the related modelSeacrh adding the relation with the related model and the filter for the field you need ..
for this you must set in the base mode, the relation
public function getSale()
{
return $this->hasOne(Sale::className(), ['id' => 'sale_id']);
}
/* Getter for sale data */
public function getSaleData() {
return $this->sale->data;
}
then setting up the search model declaring
/* your calculated attribute */
public $date;
/* setup rules */
public function rules() {
return [
/* your other rules */
[['data'], 'safe']
];
}
and extending
public function search($params) {
adding proper sort, for data
$dataProvider->setSort([
'attributes' => [
.....
'data' => [
'asc' => ['tbl_sale.data' => SORT_ASC],
'desc' => ['tbl_sale.data' => SORT_DESC],
'label' => 'Data'
]
]
]);
proper relation
if (!($this->load($params) && $this->validate())) {
/**
* The following line will allow eager loading with country data
* to enable sorting by country on initial loading of the grid.
*/
$query->joinWith(['sale']);
return $dataProvider;
}
and proper filter condition
// filter by sale data
$query->joinWith(['sale' => function ($q) {
$q->where('sale.data = ' . $this->data . ' ');
}]);
Once you do al this the searchModel contain the information for filter and the search field is showed in gridview
What in this answer is just a list of suggestion
you can find detailed tutorial in this doc (see the scenario 2 and adapt to your need)
http://www.yiiframework.com/wiki/621/filter-sort-by-calculated-related-fields-in-gridview-yii-2-0/
I'm going to use 1st normalization form in my Yii2 project, so I've added table like this | id | post_id | tag_id |and when I'm to posts model I've writed this:
public function getTags()
{
return $this->hasMany(PostTags::className(), ['post_id' => 'id']);
}
In view widget I've added 'tags.tag_id', but it shows no data.
Is there any way to show this tags in DetailView and GridView widgets?
May be, I can write "group_concat" somewhere?
I'd recommend to write a widget for displaying a links list of related records. It's reusable, prevents HTML generation in model / controller, reduces the amount of code in view.
<?php
namespace common\widgets;
use yii\base\Widget;
use yii\helpers\Html;
/**
* Widget for display list of links to related models
*/
class RelatedList extends Widget
{
/**
* #var \yii\db\ActiveRecord[] Related models
*/
public $models = [];
/**
* #var string Base to build text content of the link.
* You should specify attribute name. In case of dynamic generation ('getFullName()') you should specify just 'fullName'.
*/
public $linkContentBase = 'name';
/**
* #var string Route to build url to related model
*/
public $viewRoute;
/**
* #inheritdoc
*/
public function run()
{
if (!$this->models) {
return null;
}
$items = [];
foreach ($this->models as $model) {
$items[] = Html::a($model->{$this->linkContentBase}, [$this->viewRoute, 'id' => $model->id]);
}
return Html::ul($items, [
'class' => 'list-unstyled',
'encode' => false,
]);
}
}
Here are some examples (assuming tag name is stored in name column).
Usage in GridView:
[
'attribute' => 'tags',
'format' => 'raw',
'value' => function ($model) {
/* #var $model common\models\Post */
return RelatedList::widget([
'models' => $model->tags,
'viewRoute' => '/tags/view',
]);
},
],
Usage in DetailView:
/* #var $model common\models\Post */
...
[
'attribute' => 'tags',
'format' => 'raw',
'value' => RelatedList::widget([
'models' => $model->tags,
'viewRoute' => '/tags/view',
]),
],
Don't forget to set format raw, because by default content is rendered as plain text to prevent XSS attacks (html special characters are escaped).
You can modify this to fit your needs, this is just an example.
I am trying to setup the filter for related model in Yii2's GridView widget, but I am keep getting the error like the filter value must be an integer.
I have followed this question. Now, I have a two models Services.php and ServiceCharge.php.
In ServiceCharge.php the relation is setup like:
public function getServiceName()
{
return $this->hasOne(Services::className(),['id'=>'service_name']);
}
In the ServiceChargeSearch.php the code is like this:
<?php
namespace app\models;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use app\models\ServiceCharges;
/**
* ServiceChargesSearch represents the model behind the search form about `app\models\ServiceCharges`.
*/
class ServiceChargesSearch extends ServiceCharges
{
/**
* #inheritdoc
*/
public function attributes()
{
// add related fields to searchable attributes
return array_merge(parent::attributes(), ['serviceName.services']);
}
public function rules()
{
return [
[['id'], 'integer'],
[['charges_cash', 'charges_cashless'], 'number'],
[['id', 'serviceName.services', 'room_category'], '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 = ServiceCharges::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$dataProvider->sort->attributes['serviceName.services'] = [
'asc' => ['serviceName.services' => SORT_ASC],
'desc' => ['serviceName.services' => SORT_DESC],
];
$query->joinWith(['serviceName']);
$this->load($params);
if (!$this->validate()) {
// uncomment the following line if you do not want to any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
$query->andFilterWhere([
'id' => $this->id,
// 'service_name' => $this->service_name,
'room_category' => $this->room_category,
'charges_cash' => $this->charges_cash,
'charges_cashless' => $this->charges_cashless,
])
->andFilterWhere(['LIKE', 'serviceName.services', $this->getAttribute('serviceName.services')]);
return $dataProvider;
}
}
and in my Gridview it is setup like this:
[
'attribute'=>'service_name',
'value'=>'serviceName.services',
],
Which is showing the services name from the related model correctly.
I am not able to see what I am doing wrong, but the filter field for the attribute for service is not showing at all.
Actually it is much simpler than it seems.
add the column_name to safe attribute.
Note: this should be relation Name
add the join with query - like - $query->joinWith(['serviceName','roomCategory']);
add the filter condition like:
->andFilterWhere(['like', 'services.services', $this->service_name])
->andFilterWhere(['like', 'room_category.room_category', $this->room_category]);
if like to add sorting add the code like:
$dataProvider->sort->attributes['service_name'] = [
'asc' => ['services.services' => SORT_ASC],
'desc' => ['services.services' => SORT_DESC],
];
$dataProvider->sort->attributes['room_category'] = [
'asc' => ['room_category.room_category' => SORT_ASC],
'desc' => ['room_category.room_category' => SORT_DESC],
];
5 you should also set the relation name say public $roomCategory
That's it. Both sorting and filtering for related table works perfectly.
Note: Remove default validation like integer for related column and default filtering generated by gii otherwise it will generate an error.
Update on Latest version:
Adding Public $attribute is not needed.
Adding safe attribute for relation is also not needed.
but the attribute in your current model, which you want filter is
to added to safe attribute that is a must.
and most importantly in your gridview, the related attribute has to
be in closure format.
that is example
[
'attribute=>'attribute_name',
'value=function($data){
return $data->relationname->related_table_attribute_name
}
],
remember it you are using relation_name.related_table_attribute_name filter somehow doesn't work for me.
There is a fairly comprehensive set of instructions on the Yii Framework website. The only thing to note is that the search model complains about the following lines, but everything appears to work as intended without them:
$this->addCondition(...);
For a model, PaymentEvent (table: subs_payment_event), which has a currency_id field linked to model Currency, this is the complete set of additional code (using the Basic template):
In the main model, PaymentEvent.php:
public function getCurrencyName()
{
return $this->currency->name;
}
In the search model, PaymentEventSearch.php:
public $currencyName;
In its rules:
[['currencyName'], 'safe'],
In the attributes of its setSort statement, include:
'currencyName' => [
'asc' => ['subs_currency.name' => SORT_ASC],
'desc' => ['subs_currency.name' => SORT_DESC],
'label' => 'Currency'
],
Before the grid filtering conditions:
$query->joinWith(['currency' => function ($q) {
$q->where('subs_currency.name LIKE "%' . $this->currencyName . '%"');
}]);
Finally, in the GridView columns array in the view (including my usual link across to the related model records):
[
'attribute' => 'currencyName',
'label' => 'Currency',
'format' => 'raw',
'value' => function ($data) {
return Html::a($data->currency->name, ['/currency/' . $data->currency_id]);
},
],