Универсальный модуль комментарии

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
nepster
Сообщения: 838
Зарегистрирован: 2013.01.02, 03:35

Универсальный модуль комментарии

Сообщение nepster »

Собственно возник такой вопрос. Я разбираюсь с yii2 на примере создания своего небольшого проекта. К примеру у меня есть несколько модулей:
- фотогалерея
- новости
- статьи
- отзывы

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


Для примера будем использовать модуль статьи

Я создал виджет, который выводит все комментарии на страницу исходя из параметров и вызываю его в нужном месте:

Код: Выделить всё

 <?php   
                echo frontend\modules\comments\widgets\CommentsList::widget([
                    'find'  => ['post_id'=>$article->article_id, 'type'=>'article'],
                    'model' => 'common\modules\articles\models\Articles'
                ]);
            ?>

В таблице комментария есть поля:
post_id - идентификатор записи комментария
type - тип записи (для каждого модуля он может быть разным). В данном случае для модуля Статьи тип комментариев article


Далее все комментарии вывелись на страницу (есть 2 типа вида: древовидные комментарии и обычные через пагинацию), в данном случае древовидные.

Тут собственно и возникает первый самый главный вопрос.
У нас есть форма для добавления комментариев и когда пользователь добавляет новый комментарий, когда данные попадают в экшин комментария у нас теряется связь. Тоесть куда, к чему, зачем, почему был добавлен комментарий.
Для этого я тяну строку 'common\modules\articles\models\Articles' и добавляю ее в форму:

Код: Выделить всё

 
...
echo '<div class="clearfix formElementMargin">' . $form->field($model, 'text')->textarea() . '</div>';
    echo Html::activeHiddenInput($model, 'post_id');
    echo Html::activeHiddenInput($model, 'type');
    echo Html::activeHiddenInput($model, 'parent_comm_id');
    echo Html::activeHiddenInput($model, 'postModel');
...
 
Далее когда это все дело попадает в нужный экшин, в моделе

Код: Выделить всё

    
    /**
     * Проверяем пост 
     */
    public function checkPost($attribute)
    {
        if($post = @call_user_func($this->postModel .'::className')) {
            
            if($post::findOne($this->post_id)) {
            
               // Указываем тип комментария 
               $this->type = $post::getCommentsType();
            }
            else {
               $this->addError($attribute, Yii::t('comments.main', 'Записи с ID{id} не существует', ['id'=> $this->post_id]));
            }
       
        }
        else {
            $this->addError($attribute, Yii::t('comments.main', 'Ошибка при выборе записи'));
        }
    } 
как-то так я проверяю все это дело и так-же мне нужно в моделе статей обновить счетчик комментариев.

В общем ничего кроме как тянуть за собой строку common\modules\articles\models\Articles я не придумал. Подскажите пожалуйста на сколько это плохо, и есть ли другие варианты ?

Основная суть сделать 1 модуль комментарии полностью универсальным для всех других необходимых модулей.

Аватара пользователя
yiijeka
Сообщения: 3091
Зарегистрирован: 2012.01.28, 09:14
Откуда: Беларусь
Контактная информация:

Re: Универсальный модуль комментарии

Сообщение yiijeka »

Возможно вам лучше сделать не в качестве модуля, а в качестве поведения? Как YiiShoppingCart сделано для yii1.

mickgeek
Сообщения: 957
Зарегистрирован: 2014.05.31, 20:50
Откуда: Санкт-Петербург
Контактная информация:

Re: Универсальный модуль комментарии

Сообщение mickgeek »

В проекте на Yii 1.1 я использовал похожую архитектуру:

Код: Выделить всё

<?php $this->widget('comments.components.CommentWidget', array('module' => Comment::MODULE_BLOG, 'rowId' => $post->id)); ?>

Код: Выделить всё

class CommentWidget extends CWidget
{
    public $module;
    public $rowId;

    public function init()
    {
        if($this->module === null || $this->rowId === null)
            throw new CException(Yii::t('CommentsModule.comment_components', '{class} must specify "module" and "rowId" property values.', array('{class}' => get_class($this))));
    }

    public function run()
    {
        ...
    }

    public function getCount()
    {
        $comment = Comment::model()->totalCount()->findAllByAttributes(array('module' => $this->module, 'row_id' => $this->rowId));

        return $comment[0]->count;
    }
}
В представлении виджета, помимо самих комментариев, было и представление с счётчиком и добавлением нового комментария:

Код: Выделить всё

<?php $this->render('commentViews.default.header', array(
    'comment' => $comment,
    'module' => $module,
    'rowId' => $rowId,
    'count' => $this->count,
)); ?>
В котором находилась форма со скрытыми полями:

Код: Выделить всё

<?php echo $form->hiddenField($comment, 'module', array('value' => $module)); ?>
<?php echo $form->hiddenField($comment, 'row_id', array('value' => $rowId)); ?>
Моя функция getCount() кэшировалась, но можно добавить и отдельную таблицу с ID поста и счётчиком, а в экшенах сверять ID и увеличивать/уменьшать значение последнего. Удобно, если комментарии имеют функцию включения/отключения (нет лишнего столбца в таблице с постами).

Во втором Yii я пока такое не делал, но планирую нечто похожее, немного улучшив.

Аватара пользователя
vova07
Сообщения: 1004
Зарегистрирован: 2012.11.29, 14:52
Откуда: Chisinau, Moldova

Re: Универсальный модуль комментарии

Сообщение vova07 »

Сам почти также делал, но в новом модуле который щас как раз пишу, перешел на поведения. Это не так гибко и независимо, но более безопастно.

nepster
Сообщения: 838
Зарегистрирован: 2013.01.02, 03:35

Re: Универсальный модуль комментарии

Сообщение nepster »

подскажите пожалуйста, вот я не могу понять логику, как делать через поведение ?

Тоесть поведение нужно добавить в модель комментариев ? Как тогда получить данные, к какому модулю добавлен комментарий ?

Аватара пользователя
yiijeka
Сообщения: 3091
Зарегистрирован: 2012.01.28, 09:14
Откуда: Беларусь
Контактная информация:

Re: Универсальный модуль комментарии

Сообщение yiijeka »

Поведение "Комментарии" добавляется к любой модели. В поведении эта модель будет доступна через $this->owner

Аватара пользователя
slavcodev
Сообщения: 3134
Зарегистрирован: 2009.04.02, 21:42
Откуда: Valencia
Контактная информация:

Re: Универсальный модуль комментарии

Сообщение slavcodev »

Я запутался. Зачем пытаться делать независимый модуль комментариев, но при этом завязывать на этот модуль модели, подключая поведение внутри модели? :/
Это не так гибко и независимо, но более безопастно.
Можно подробнее про "безопасность"? (можно не в этой теме)

Еще один вариант

1) Сделать модуль для комментариев
2) Который имеет контролер для работы с комментарием
3) Добавлять по одному контролеру для каждой комментируемой модели

Код: Выделить всё

class CommentModule extends CWebModule
{
  public $models = [
    'post' => 'Post',
  ];

  public function init()
  {
    foreach ($this->models as $controllerId => $modelClass) {
       $this->controllersMap[$controllerId] = [
           'class' => 'CommentController',
           'ownerModelClass' => $modelClass,
       ]
    }
  }
}
как-то так, плюсы

1) Через UrlManager можем иметь красивые урл `localhost/comments/post/create`
2) Простое управление доступом к работе с комментами для каждой комментируемой сущности

может еще есть, но надо искать, эти пришли сразу
Жду Yii 3!

nepster
Сообщения: 838
Зарегистрирован: 2013.01.02, 03:35

Re: Универсальный модуль комментарии

Сообщение nepster »

А подскажите пожалуйста саму суть поведения ?

Код: Выделить всё

            'CommentBehavior' => [
                'class' => \common\modules\comments\behaviors\CommentBehavior::className(),
            ], 

В данном случае если я пропишу это поведение в модуле articles, а содержимое евентов:

Код: Выделить всё

   /**
    * Назначаем обработчик для [[owner]] событий
    * @return array события (array keys) с назначеными им обработчиками (array values)
    */
    public function events()
    {
        return [
            ActiveRecord::EVENT_AFTER_VALIDATE  => 'test1',
            ActiveRecord::EVENT_BEFORE_VALIDATE => 'test2',
        ];
    }
 
То оно будет вызвано при добавлении записи. А мне получается нужно что-бы оно вызывалось при добавлении комментария. Вот я тут запутался.



slavcodev, если честно я бы вообще не хотел пихать в модуль комментария что-либо связанное с модулями, к которым будут принадлежать комментарии.

Аватара пользователя
slavcodev
Сообщения: 3134
Зарегистрирован: 2009.04.02, 21:42
Откуда: Valencia
Контактная информация:

Re: Универсальный модуль комментарии

Сообщение slavcodev »

Я и не предлагал этого делать. Я показал пример, но свойство $models настраивается в конфиге, при подключении модуля.
Жду Yii 3!

nepster
Сообщения: 838
Зарегистрирован: 2013.01.02, 03:35

Re: Универсальный модуль комментарии

Сообщение nepster »

Ага по поводу передач параметров понял, но походу в Yii2 нет возможности так сделать. Ругает, что модуль не знает свойство controllersMap

Аватара пользователя
slavcodev
Сообщения: 3134
Зарегистрирован: 2009.04.02, 21:42
Откуда: Valencia
Контактная информация:

Re: Универсальный модуль комментарии

Сообщение slavcodev »

моя опечатка - controllerMap, без "s"
Жду Yii 3!

nepster
Сообщения: 838
Зарегистрирован: 2013.01.02, 03:35

Re: Универсальный модуль комментарии

Сообщение nepster »

все-же я не могу понять что мы сделали и как получить данные ?

Тоесть когда у нас есть форма добавления комментария и данные летят в контроллер, то я уже не могу получить модуль для которого принадлежат комментарии.

Аватара пользователя
slavcodev
Сообщения: 3134
Зарегистрирован: 2009.04.02, 21:42
Откуда: Valencia
Контактная информация:

Re: Универсальный модуль комментарии

Сообщение slavcodev »

Модуль у тебя один для всех моделей. А вот контролер отделный для каждой модели. Причем контролер имеет свойсво $ownerModelClass, вместо того чтоб передавать его запросом.

Дальше все стандартно
форма отсылает данные комментария на адрес moduleName/controllerName/create/ownerModelId
контроллер из модуля ничего не знает от других моделях, все что ему надо знать это API модели комментария и переданное настройкой класс коментируемой модели

Код: Выделить всё

function createAction($ownerModelId)
{
  $ownerModel = $this->loadOwnerModel($ownerModelId);
  
  $comment = new Comment();
  ...
}

protected loadOwnerModel($id)
{
  $model = CActiveRecord::model($this->ownerModelClass)->findByPk($id);

  if (!$model) {
     throw new CHttpException(400);
  }

  return $model;
}
Жду Yii 3!

nepster
Сообщения: 838
Зарегистрирован: 2013.01.02, 03:35

Re: Универсальный модуль комментарии

Сообщение nepster »

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

Аватара пользователя
slavcodev
Сообщения: 3134
Зарегистрирован: 2009.04.02, 21:42
Откуда: Valencia
Контактная информация:

Re: Универсальный модуль комментарии

Сообщение slavcodev »

У меня сплавился мозг. Сходи прочитай документацию по модулям Yii, пжл. Потом вернемся к обсуждению.
Жду Yii 3!

Аватара пользователя
mihail_dev
Сообщения: 242
Зарегистрирован: 2013.07.17, 00:51
Откуда: Молдова
Контактная информация:

Re: Универсальный модуль комментарии

Сообщение mihail_dev »

nepster писал(а):нет нет, один модуль для всех это не наш выбор. Моя задача сделать такой модуль, который бы никак не был связан с другими моделями других модулей. Они там даже подключатся не должны.
ну я тоже в свой время писал такой модуль под yii1 и там делал привязку не к модулям и к чему то ещё а привязку к ссылке на странице
есть сложность с удалением комментов когда удаляется страница но и это легко обойти если ссылка формируется в моделе то можно повесить срабатывание удаление коментов на ивент
и если вы решите сменить ссылку (через урл мэнеджер) коменты соответсвенно слетят

то есть у вас в итоге должен получится модуль отвечающий только за работу комментов которые привязаны к странице по ссылке
и виджет который вы будете внедрять там где вам нужно вывести комменты
Изображение

nepster
Сообщения: 838
Зарегистрирован: 2013.01.02, 03:35

Re: Универсальный модуль комментарии

Сообщение nepster »

я точно уверен что можно сделать все куда проще и интереснее. Нужно просто подумать и просто родить идею. В общем ушел бросать попытки в принятии родов идеи как это все организовать.

Аватара пользователя
vova07
Сообщения: 1004
Зарегистрирован: 2012.11.29, 14:52
Откуда: Chisinau, Moldova

Re: Универсальный модуль комментарии

Сообщение vova07 »

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

Идеальная ситуация передачи данных сводится примерно к такому сценарию. С фронтенда, где данные могут быть изменены из вне, должны приходить только непосредственная ифнормация коммента которая была введена пользователем, + id родительского комментария. Все остальное не должно быть возможно редактировать из вне приложения. В случае с передачей названия класса модели, это уже проблема, и все это дело нужно решать. Конечно на стороне сервера нужна еще проверка на возможность комментирования родителя, ибо как ид предка может быть измененен вручную (в случае использования срытых полей)

Можно еще передавать данные через доп параметры в JS скрипте это чуток усложнит жизни тем кто хотят испортить логику приложения, но не сильно.

На данный момент пока не решил 100% как делать данный модуль, но эта тема вынудила написать заметку касательно него. Логику нужно пересмотреть, и когда дойдет окончательно дело до данного модуля, нужно решить красиво проблему.

Аватара пользователя
slavcodev
Сообщения: 3134
Зарегистрирован: 2009.04.02, 21:42
Откуда: Valencia
Контактная информация:

Re: Универсальный модуль комментарии

Сообщение slavcodev »

Ясно. Согласен передавать вместе с данными комментария одновременно название класса к которой прицеплен коммент некрасиво.
Так же как мне не нравится добавлять поведение к модели поста. С чего бы ей (модели) знать о комментариях?
Еще получается нужно создать объект поста чтоб добавить коммент? Не лишнее ли это?

Поэтому мое предложение использовать отдельный контролер для каждой комментируемой сущности.
Жду Yii 3!

Аватара пользователя
vova07
Сообщения: 1004
Зарегистрирован: 2012.11.29, 14:52
Откуда: Chisinau, Moldova

Re: Универсальный модуль комментарии

Сообщение vova07 »

Честно ни одно из решений мне не по душе. У тех что было раньше озвучены есть свои минусы, вы их уже написали, и я полностью согласен. У вашего тоже есть большой жирный минус. Модуль должен быть универсальным, и совсем не хочется писать под все модели свой контроллер, тогда пропадает смысл универсальности. Нужен другой вариант, отмечу себе тему, вернусь к ней когда буду решать вопрос, напишу свои результаты.

Ответить