How to bring the relationship one-to-many and mamy-to-many in code generator gii CRUD operations in yii framework?

Good day! Searched many sites but have not found how to output connection one-to-many and many-to-many. I found only how to implement them during the migration so that our database tables were linked by primary and foreign keys, but instead a foreign key value and not found. And still before me the task - to realize it's not clinging to the bulky design of htlm and php code in a foreach and echo each page, and all funds framework (there is a suspicion that we probably need to add a few words of code in the model or in the controller). Actually the problem itself. There are 3 tables. product(id, name, id_category, id_country, s_description, description, price). country(id, country). category(id, category). The product table has a foreign key to table country (id_country => id) and the category table (id_country => id).
Migration:
The category table
public function safeUp()
{
 $this->createTable('category', [
 'id' => $this->primaryKey(),
 'category' => $this->string(),
]);
 $this->alterColumn('category','id',$this->smallInteger(8).'NOT NULL AUTO_INCREMENT'); 
}
 public function safeDown()
{
$this->dropTable('category');
 }

The "country" table
public function safeUp()
{
 $this->createTable('country', [
 'id' => $this->primaryKey(),
 'country' => $this->string(),
]);
 $this->alterColumn('country','id',$this->smallInteger(8).'NOT NULL AUTO_INCREMENT');
}
 public function safeDown()
{
$this->dropTable('country');
 }

The product table
public function safeUp()
{
 $this->createTable('product', [
 'id' => $this->primaryKey(),
 'name' => $this->string(),
 'id_category' => $this->smallInteger(8),
 'id_country' => $this->smallInteger(8),
 's_description' => $this->string(),
 'description' => $this->string(),
 'price' => $this->integer(),
]);
 $this->alterColumn('product','id',$this->smallInteger(8).'NOT NULL AUTO_INCREMENT');

$this->addForeignKey(
'product_to_category',
'product',
'id_category',
'category',
'id',
'CASCADE'
);

$this->addForeignKey(
'product_to_country',
'product',
'id_country',
'country',
'id',
'CASCADE'
);
}
 public function safeDown()
{
$this->dropTable('product');
 }

Model:
Category:
...
public function getProducts()
{
 return $this->hasMany(Product::className(), ['id_category' => 'id']);
 }

Country:
...
public function getProducts()
{
 return $this->hasMany(Product::className(), ['id_country' => 'id']);
 }

Product:
...
/**
 * @return \yii\db\ActiveQuery
*/
 public function getCategory()
{
 return $this->hasOne(Category::className(), ['id' => 'id_category']);
}

/**
 * @return \yii\db\ActiveQuery
*/
 public function getCountry()
{
 return $this->hasOne(Country::className(), ['id' => 'id_country']);
 }

Controllers:
CategoryController:
...
public function actionIndex()
{
 $searchModel = new CategorySearch();
 $dataProvider = $searchModel->search(Yii::$app->request->queryParams);

 return $this->render('index', [
 'searchModel' => $searchModel,
 'dataProvider' => $dataProvider,
]);
}
...

CountryController
...
public function actionIndex()
{
 $searchModel = new CountrySearch();
 $dataProvider = $searchModel->search(Yii::$app->request->queryParams);

 return $this->render('index', [
 'searchModel' => $searchModel,
 'dataProvider' => $dataProvider,
]);
}
...

ProductController
...
public function actionIndex()
{
 $searchModel = new ProductSearch();
 $dataProvider = $searchModel->search(Yii::$app->request->queryParams);

 return $this->render('index', [
 'searchModel' => $searchModel,
 'dataProvider' => $dataProvider,
]);
}
...

Again, in the end, it is required to output data from the product table, not the key and id_category id_country, and their value from the tables. And, if not difficult, tell me more please, how will it be implemented for communication many-to-many. In advance all those who respond, thanks for the help!
March 23rd 20 at 19:40
1 answer
March 23rd 20 at 19:42
Solution
Good afternoon.
That's too much all migrations
$this->alterColumn('category','id',$this->smallInteger(8).'NOT NULL AUTO_INCREMENT');

If you want the GridView to the id and the category name, for example, the value indicative via
// for hasOne()
'value' => function($model){
 return $model->country->name ?? null;
}

If You have a connection goes through a hasMany(), You will get multiple values to bring them all through implode()
// for hasMany()
'value' => function($model){
 return implode(',', ArrayHelper::map($model->country, 'id', 'name'));
}

Can be displayed without the anonymous function, just specify the relation name and the attribute name
'value' => 'country.name'
And can you tell me where in what file and where it is necessary to specify?
'value' => function($model){
return $model->country->name ?? null;
} - Tyre commented on March 23rd 20 at 19:45
@Tyre, in a gridview, You also need to display in gridView? In the detailView is almost the same. - wendell_Hin commented on March 23rd 20 at 19:48
@Tyre, this is for php >= 7.0

<?= GridView::widget([
 'dataProvider' => $dataProvider,
 'columns' => [
[
 'attribute' => 'country_id',
 'value' => function($model){
 return $model->country->name ?? null;
 } 
]
],
]) ?>
- wendell_Hin commented on March 23rd 20 at 19:51
PHP Parse Error – yii\base\ErrorException
syntax error, unexpected '?' - Tyre commented on March 23rd 20 at 19:54
My server only supports php 5.6. - Tyre commented on March 23rd 20 at 19:57
@Tyre,
return $model->country->name ? $model->country->name : null
- wendell_Hin commented on March 23rd 20 at 20:00
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],


'id',
'name',
'id_category' => 'category.category',
'id_country' => 'country.country',
's_description',
//'description',
//'price',

['class' => 'yii\grid\ActionColumn'],
],
]); ?>

In principle, the framing is excellent, but I would like to ask if, when you create and edit the same to write not to select values from the drop-down list? - Tyre commented on March 23rd 20 at 20:03
@Tyre, always, necessarily, use special tags to insert code in the reply or comment.
Remember this as the "our father")))
Yes, you can do everything you can, it would wish.
To do this, use ArrayHelper::map() and third parameter specify the name using the connection.
ArrayHelper::map(Model::findAll(), 'id', 'country.name')
- wendell_Hin commented on March 23rd 20 at 20:06
@Tyre, here, to see and outline. - wendell_Hin commented on March 23rd 20 at 20:09
@Tyre, if the first question is solved, mark the solution. - wendell_Hin commented on March 23rd 20 at 20:12

Find more questions by tags Yii