@Strodj

Как организовать разные комментарии на каждой странице, YII2?

контроллер
public function actionView($id){

...

         $model = new BlogForm();

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


модель
class Blog extends ActiveRecord{

    public static function tableName(){
        return 'blog';
    }

        public function getCategory(){
        return $this->hasOne(Blog::className(), ['id' => 'id']);
    }

} 


class BlogForm extends Model
{
    public $nick ;
    public $email;
    public $body;

    /**
     * @return array the validation rules.
     */
    public function rules()
    {
        return [
            /* nick and comment body are both required */
            [[ 'body'], 'required'],
            [['email'], 'email'],
        ];
    }

    /**
     * Appends post to DB
     * @return boolean whether the post is appended successfully
     */
    public function post()
    {
        if ($this->validate()) {
            $db = Yii::$app->db;

            $nickSafe=Yii::$app->user->identity->email;
    

            $bodySafe = htmlspecialchars($this->body, ENT_QUOTES, "UTF-8");
            
            $db->createCommand('INSERT INTO comments (nick, body)' .
                ' VALUES (\'' . $nickSafe . '\',  REPLACE("' . $bodySafe . '", "\n", "<br />"));')->execute();
        
            return true;
        }
        return false;
    }
}


Представление

<div class="comments">
  <p >
      <?php Pjax::begin(); ?>
        <?php $form = ActiveForm::begin([
        'id' => 'post-comment-form',
        'options' => ['class' => 'form-horizontal'],
        'fieldConfig' => [
            'template' => "{label}\n<div class=\"col-lg-3\">{input}</div>\n<div class=\"col-lg-8\">{error}</div>",
            'labelOptions' => ['class' => 'col-lg-1 control-label'],
        ],
    ]); ?>

    <?php

    
    $field = $form->field($model, 'body', [
        'inputOptions' => [
            'placeholder' => $model->getAttributeLabel('body'),
        ],
    ])->label(false);
    $field->textArea([
        'rows' => '6'
    ]);
    echo $field;

    echo '<div class="form-group">';
    echo '<div class="col-lg-11">';
    echo Html::submitButton('Отправить', ['class' => 'btn btn-my']);
    echo '</div>';
    echo '</div>';
    
    ?>

    <?php ActiveForm::end(); ?>
     <?php Pjax::end(); ?>
    </p>

<div class="site-comments">
    <h3>Отзывы:</h3>

    <?php
    
    $db = Yii::$app->db;
    
    $comments = $db->createCommand('SELECT * FROM comments ORDER BY id DESC;')->queryAll();
    
    ?>

    <?php 
    $provider = new ArrayDataProvider([
        'allModels' => $comments,
        'pagination' => [
            'pageSize' => 10,
        ]
    ]);

        echo ListView::widget([
            'dataProvider' => $provider,
            'itemView' => function ($model, $key, $index, $widget) {
                if ($model['email']) {
                    return $this->renderDynamic('echo \'<b>' . $model['nick'] . '</b> (' . $model['email'] . '):<br>' . $model['body'] . '<br><br>\';');
                } else {
                    return $this->renderDynamic('echo \'<b>' . $model['nick'] . '</b>:<br>' . $model['body'] . '<br><br>\';');
                }
            },
            'emptyText' => 'Отзывов нет, будьте первым! '
        ])
    ?>
  </div>
</div>
  • Вопрос задан
  • 569 просмотров
Пригласить эксперта
Ответы на вопрос 4
kimono
@kimono
Web developer
Не делайте так, это может быть опасно:
$bodySafe = htmlspecialchars($this->body, ENT_QUOTES, "UTF-8");
            
            $db->createCommand('INSERT INTO comments (nick, body)' .
                ' VALUES (\'' . $nickSafe . '\',  REPLACE("' . $bodySafe . '", "\n", "<br />"));')->execute();
        
            return true;
        }
        return false;
    }


Делайте либо так:
$comment = new Comment([
  'nick' => Yii::$app->user->identity->email,
  'body' => $this->body,
  'model' => 'news',
  'model_id' => 1234
]);
return $comment->save();

либо так:
$result = $db->createCommand('INSERT INTO comments (nick, body, model, model_id) VALUES (:nick, :body, :model, :model_id)', [
  'nick' => Yii::$app->user->identity->email,
  'body' => $this->body,
  'model' => 'news',
  'model_id' => 1234
])->execute();
return $result;

Во вью выводите как Html::encode($body), зачем хранить HTML мусор в базе?
Ответ написан
Комментировать
slo_nik
@slo_nik Куратор тега Yii
Допустим есть две таблицы. В первой хранятся статьи, во второй комментарии для каждой статьи.
В таблице комментариев есть поле id_article, в котором хранится id статьи.
Вам надо вывести отдельную статью и комментарии, которые принадлежат этой статье.
Ссылка для просмотра статьи может выглядеть так:
echo Html::a('Title article', ['view', 'id' => $id]);

В контроллере есть действие view, для вывода отдельной статьи:
public function actionView($id)
{
    $comment = new Comments();
    $article = $this->findArticle($id);
    $query = Comments::find()->where('id_article=:id', [':id' => $id]);
    $dataProvider = new ActiveDataProvider([
        $query = $query
     ]);

     return $this->render('view', ['article' => $article, 'dataProvider' => $dataProvider, 'comment' => $comment])
}
public function findArticle($id)
{
   if(($model = Article::find()->where('id=:id', [':id' => $id])->one()) !== null){
        return $model;
   }
   else{
      throw new NotFoundHttpException();
   }
}

В представлении:
echo $article->title;
// вывод комментариев
        echo ListView::widget([
            'dataProvider' => $dataProvider,
           'itemView' => 'path_to_view'
        ])

В форме подачи комментария скрытое поле для id статьи:
$form->field($comment, 'id_article')->hiddenInput(['value' => $article->id])

Вот как-то так.
Всё!

p.s. На ошибки не проверял. Написал всё на скорую руку.

p.s.s.
Пример модели комментариев с минимальным набором полей. Namespace укажите свой
Comments
<?php

namespace app\modules\comments\models;

use Yii;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;

/**
 * This is the model class for table "{{%comments}}".
 *
 * @property int $id
 * @property string $body
 * @property int $id_article
 * @property int $created_at
 * @property int $update_at
 * @property int $status
 */
class Comments extends ActiveRecord
{
    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return '{{%comments}}';
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['body', 'status', 'id_article'], 'required'],
            [['id_article', 'created_at', 'update_at', 'status'], 'integer'],
            [['body'], 'string', 'max' => 300],
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'id' => Yii::t('app', 'ID'),
            'body' => Yii::t('app', 'Body'),
            'id_article' => Yii::t('app', 'Article ID'),
            'created_at' => Yii::t('app', 'Created At'),
            'update_at' => Yii::t('app', 'Update At'),
            'status' => Yii::t('app', 'Status'),
        ];
    }

    public function behaviors()
    {
        return TimestampBehavior::class;
    }
}



p.s.s.s.
Начнём сначала. Без foreach, pjax, вообще, без всяких лишних деталей.
Comments
<?php

namespace app\modules\comments\models; // укажите свой namespace

use Yii;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;

/**
 * This is the model class for table "{{%comments}}".
 *
 * @property int $id
 * @property string $body
 * @property int $id_article
 * @property int $created_at
 * @property int $update_at
 * @property int $status
 */
class Comments extends ActiveRecord
{
    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return '{{%comments}}';
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['body', 'status', 'id_article'], 'required'],
            [['id_article', 'created_at', 'update_at', 'status'], 'integer'],
            [['body'], 'string', 'max' => 300],
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'id' => Yii::t('app', 'ID'),
            'body' => Yii::t('app', 'Body'),
            'id_article' => Yii::t('app', 'Article ID'),
            'created_at' => Yii::t('app', 'Created At'),
            'update_at' => Yii::t('app', 'Update At'),
            'status' => Yii::t('app', 'Status'),
        ];
    }

    public function behaviors()
    {
        return TimestampBehavior::class;
    }
}

Действие в контроллере
public function actionView($id)
{
    $comment = new Comments();
    
    $query = Comments::find()->where('id_article=:id', [':id' => $id]);

    $article = $this->findArticle($id);

    $dataProvider = new ActiveDataProvider([
        'query' => $query
    ]);  

    render $this->render('view', ['comment' => $comment, 'dataProvider' => $dataProvider, 'article' => $article);
}

public function findArticle($id)
{
   if(($model = Blog::find()->where('id=:id', [':id' => $id])->one()) !== null){
        return $model;
   }
   else{
      throw new NotFoundHttpException();
   }

}



В представлении view, выводим заголовок одной новости, комментарии к этой новости и форму для комментариев.

view.php
<?php
// через use подключаете необходимые классы, виджеты и тому подобное

// выводим заголовок новости.
echo $article->title;

// выводим комментарии
echo ListView::widget([
  'dataProvider' => $dataProvider
  'itemView' => '_view_comment' // содержимое файла будет ниже.
])

// выводим форму для комментариев
$form = ActiveForm::begin([
   'action' => 'путь_к_действию_создания_комментария'
])
echo $form->field($comment, 'body')->textInput(['placeholder' => 'Текст комментария')->label(false)
echo Html::submitButton('Отправить')
ActiveForm::end();
?>



Файл _view_comment.php для виджета ListView();. Положить рядом с файлом view.php
<div>
 <?= $model->body; ?>
</div>

Кстати, модель Blog у Вас подозрительная. Вы полностью её код показали?
Всё.
Ответ написан
@Strodj Автор вопроса
slo_nik, разделил, а потом решил добавить, что вы написали
$dataProvider = new ActiveDataProvider([
        $query = $query
     ]);

Ошибка
Class 'app\controllers\ActiveDataProvider' not found

Но я добавил use app\controllers\ActiveDataProvider;
Ответ написан
webinar
@webinar Куратор тега Yii
Учим yii: https://youtu.be/-WRMlGHLgRg
Как организовать разные комментарии на каждой странице, YII2?

Выводить на каждой странице разные. Видимо хранить в БД принадлежность комментария той или иной странице. Например класс модели и ее id.
А зачем Вы код свой привели?
Кстати вот это во view недопустимо:
$comments = $db->createCommand('SELECT * FROM comments ORDER BY id DESC;')->queryAll();

Пишите поведение, которое добавляет связь в модель с комментариями и дергаете именно связь.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы