Проблема с отображением таблицы соединений Yii2 в виде сетки

Я пытаюсь отобразить данные в GridView, используя таблицу соединений через отношение «многие ко многим». При создании отношения «один ко многим» он работает нормально.

Я уже пробовал некоторые из опубликованных вопросов по этой проблеме, но не смог найти, что я делаю неправильно. Пожалуйста, взгляните на следующий код.

интерфейс\модели\Users.php

namespace frontend\models;

use Yii;

class Users extends \yii\db\ActiveRecord
{
    # @inheritdoc
    public static function tableName()
    {
        return 'users';
    }

    # @inheritdoc
    public function rules()
    {
        return [
            [['phone'], 'integer'],
            [['username', 'address'], 'string', 'max' => 255],
        ];
    }

    # @inheritdoc
    public function attributeLabels()
    {
        return [
            'id' => 'ID',
            'username' => 'Username',
            'address' => 'Address',
            'phone' => 'Phone',
        ];
    }

    public function getUserCourses()
    {
        // one-to-many
        return $this->hasMany(UserCourses::className(), ['users_id' => 'id']);
    }
}

интерфейс\модели\UsersSearch.php

namespace frontend\models;

use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use frontend\models\Users;

class UsersSearch extends Users
{
    # @inheritdoc
    public function rules()
    {
        return [
            [['id', 'phone'], 'integer'],
            [['username', 'address'], '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 = Users::find()->with('courses')->with('userCourses');

        // 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,
            'phone' => $this->phone,
        ]);

        $query->andFilterWhere(['like', 'username', $this->username])
            ->andFilterWhere(['like', 'address', $this->address]);

        return $dataProvider;
    }
}

интерфейс\модели\Courses.php

namespace frontend\models;

use Yii;

class Courses extends \yii\db\ActiveRecord
{
    # @inheritdoc
    public static function tableName()
    {
        return 'courses';
    }

    # @inheritdoc
    public function rules()
    {
        return [
            [['course'], 'string', 'max' => 255],
        ];
    }

    # @inheritdoc
    public function attributeLabels()
    {
        return [
            'id' => 'ID',
            'course' => 'Course',
        ];
    }

    public function getUserCourses()
    {
        // one-to-many
        return $this->hasMany(UserCourses::className(), ['courses_id' => 'id']);
    }

    public function getUsers()
    {
        // many-to-many: uses userGroups relation above which uses an ActiveRecord class
        return $this->hasMany(Users::className(), ['id' => 'users_id'])
            ->via('userCourses');
    }
}

интерфейс\модели\CoursesSearch.php

namespace frontend\models;

use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use frontend\models\Courses;

/**
 * CoursesSearch represents the model behind the search form about `frontend\models\Courses`.
 */
class CoursesSearch extends Courses
{
    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['id'], 'integer'],
            [['course'], '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 = Courses::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,
        ]);

        $query->andFilterWhere(['like', 'course', $this->course]);

        return $dataProvider;
    }
}

интерфейс\модели\UserCourses.php

namespace frontend\models;

use Yii;

class UserCourses extends \yii\db\ActiveRecord
{
    # @inheritdoc
    public static function tableName()
    {
        return 'user_cources';
    }

    # @inheritdoc
    public function rules()
    {
        return [
            [['users_id', 'courses_id'], 'integer'],
            [['courses_id'], 'exist', 'skipOnError' => true, 'targetClass' => Courses::className(), 'targetAttribute' => ['courses_id' => 'id']],
            [['users_id'], 'exist', 'skipOnError' => true, 'targetClass' => Users::className(), 'targetAttribute' => ['users_id' => 'id']],
        ];
    }

    # @inheritdoc
    public function attributeLabels()
    {
        return [
            'id' => 'ID',
            'users_id' => 'Users ID',
            'courses_id' => 'Courses ID',
        ];
    }

    # @return \yii\db\ActiveQuery
    public function getCourses()
    {
        return $this->hasOne(Courses::className(), ['id' => 'courses_id']); //->inverseOf('userCources');
    }

    # @return \yii\db\ActiveQuery
    public function getUsers()
    {
        return $this->hasOne(Users::tableName(), ['id' => 'users_id']); //->inverseOf('userCources');
    }
}

внешний интерфейс\представления\курсы\index.php

GridView::widget([
    'dataProvider' => $dataProvider,
    // 'filterModel' => $searchModel,
    'columns' => [
        ['class' => 'yii\grid\SerialColumn'],

        [
            "attribute" => "users.username",
            "value" => "username"
        ],
        'course',

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

интерфейс\контроллеры\CoursesController.php

namespace frontend\controllers;

use Yii;
use frontend\models\Courses;
use frontend\models\CoursesSearch;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;

/**
 * CoursesController implements the CRUD actions for Courses model.
 */
class CoursesController extends Controller
{
    /**
     * @inheritdoc
     */
    public function behaviors()
    {
        return [
            'verbs' => [
                'class' => VerbFilter::className(),
                'actions' => [
                    'delete' => ['POST'],
                ],
            ],
        ];
    }

    /**
     * Lists all Courses models.
     * @return mixed
     */
    public function actionIndex()
    {
        $searchModel = new CoursesSearch();
        $dataProvider = $searchModel->search(Yii::$app->request->queryParams);

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

    /**
     * Displays a single Courses model.
     * @param integer $id
     * @return mixed
     */
    public function actionView($id)
    {
        return $this->render('view', [
            'model' => $this->findModel($id),
        ]);
    }

    /**
     * Creates a new Courses model.
     * If creation is successful, the browser will be redirected to the 'view' page.
     * @return mixed
     */
    public function actionCreate()
    {
        $model = new Courses();

        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            return $this->redirect(['view', 'id' => $model->id]);
        } else {
            return $this->render('create', [
                'model' => $model,
            ]);
        }
    }

    /**
     * Updates an existing Courses model.
     * If update is successful, the browser will be redirected to the 'view' page.
     * @param integer $id
     * @return mixed
     */
    public function actionUpdate($id)
    {
        $model = $this->findModel($id);

        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            return $this->redirect(['view', 'id' => $model->id]);
        } else {
            return $this->render('update', [
                'model' => $model,
            ]);
        }
    }

    /**
     * Deletes an existing Courses model.
     * If deletion is successful, the browser will be redirected to the 'index' page.
     * @param integer $id
     * @return mixed
     */
    public function actionDelete($id)
    {
        $this->findModel($id)->delete();

        return $this->redirect(['index']);
    }

    /**
     * Finds the Courses model based on its primary key value.
     * If the model is not found, a 404 HTTP exception will be thrown.
     * @param integer $id
     * @return Courses the loaded model
     * @throws NotFoundHttpException if the model cannot be found
     */
    protected function findModel($id)
    {
        if (($model = Courses::findOne($id)) !== null) {
            return $model;
        } else {
            throw new NotFoundHttpException('The requested page does not exist.');
        }
    }
}

База данных

CREATE TABLE IF NOT EXISTS `courses` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `course` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `cource` (`course`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=9 ;

INSERT INTO `courses` (`id`, `course`) VALUES
(8, 'ASP'),
(1, 'C'),
(2, 'C++'),
(6, 'Java'),
(3, 'MySql'),
(4, 'Networking'),
(7, 'PHP'),
(5, 'System Administrator');

CREATE TABLE IF NOT EXISTS `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `address` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `username` (`username`),
  KEY `address` (`address`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;

INSERT INTO `users` (`id`, `username`, `address`) VALUES
(1, 'Parminder', 'ABC-125'),
(2, 'Manpreet', 'WZ-128'),
(3, 'Kanwaljeet', 'NA-123');

CREATE TABLE IF NOT EXISTS `user_cources` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `users_id` int(11) DEFAULT NULL,
  `courses_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `users_id` (`users_id`),
  KEY `courses_id` (`courses_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=9 ;

INSERT INTO `user_cources` (`id`, `users_id`, `courses_id`) VALUES
(1, 1, 1),
(2, 1, 2),
(3, 1, 3),
(4, 1, 6),
(5, 1, 7),
(6, 1, 8),
(7, 2, 4),
(8, 2, 5);

ALTER TABLE `user_cources`
  ADD CONSTRAINT `FK_uc_courses` FOREIGN KEY (`courses_id`) REFERENCES `courses` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  ADD CONSTRAINT `FK_uc_users` FOREIGN KEY (`users_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;

person MrSingh    schedule 07.05.2016    source источник
comment
Не могли бы вы опубликовать код CourseController, определяющий ActiveDataProvider для курсов/index.php   -  person MacGyer    schedule 07.05.2016
comment
Кстати: у вас есть опечатка в имени вашей таблицы: user_cources должно быть user_courses (здесь нет ошибки, потому что ваша таблица имеет соответствующее имя)   -  person MacGyer    schedule 07.05.2016
comment
Спасибо, MacGyer, я исправлю опечатку в коде. Также я добавил CoursesController, пожалуйста, проверьте.   -  person MrSingh    schedule 08.05.2016
comment
спасибо... Я пропустил, что вы не разместили код CoursesSearch.php. Не могли бы вы добавить это?   -  person MacGyer    schedule 08.05.2016
comment
Я этого не создавал, нужно ли иметь модель поиска для каждой базовой модели, если она есть в связанной модели?   -  person MrSingh    schedule 12.05.2016
comment
Я сгенерировал модель CoursesSearch, также исправил тип в проекте, но все еще не работает. Пожалуйста, посмотрите   -  person MrSingh    schedule 12.05.2016


Ответы (1)


просто чтобы убедиться, попробуйте следующее в frontend\controllers\CoursesController:

public function actionIndex()
{
    $query = frontend\models\Courses::find()->with('users');
    $dataProvider = new yii\data\ActiveDataProvider();
    $dataProvider->query = $query;

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

И в вашем интерфейсе\представления\курсы\index.php:

GridView::widget([
    'dataProvider' => $dataProvider,
    'columns' => [
        ['class' => 'yii\grid\SerialColumn'],

        [
            'attribute' => 'users',
            'value' => 'username',
        ],
        'course',

        ['class' => 'yii\grid\ActionColumn'],
    ],
]);
person MacGyer    schedule 12.05.2016
comment
Спасибо, MacGrey, я попробовал ваше решение, но, к сожалению, оно все еще не работает. Я создаю репозиторий, чтобы исправить эту проблему. Я буду URL здесь также. - person MrSingh; 16.05.2016
comment
Вот репозиторий [email protected]/pammysayshello/ . Пожалуйста, скажите мне, что я делаю неправильно. - person MrSingh; 17.05.2016
comment
Привет, ребята, я исправил проблему и обновил репозиторий. Я надеюсь, что этот пример может быть немного полезен для кого-то. - person MrSingh; 21.05.2016