chiliec / yii2-vote

Provides voting for any model :+1: :-1:

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Обновить модель после голосования

loveorigami opened this issue · comments

Вывожу списком статьи через ListView.
Список кешируется. Кеш обновляется, если обновилась модель.

Голосование же идет по другому сценарию.
После факта голосования запись вставляется в таблицу rating.
Затем, после следующей выборки, обновляются поля в самой модели. Это если без кеша.

С кешем у меня эти поля не обновляются, т.к. не произошло обновления самой модели.
Получается, замкнутый круг: кеш не сбросился, т.к. не обновилась модель. Рейтинг не пересчитался, т.к. модель закеширована

Почему бы не объявлять массив моделей, т.к. они есть.

    'modules' => [
        'vote' => [
            'matchingModels' => [ // matching model names with whatever unique integer ID
                'common\models\Page' => 3, // or array with 'id' key
            ],
        ],
    ],

в виджете

                <?php echo Display::widget([
                    'model_name' => $model::className(), // common\models\Page
                    //'model_name' => 'aphorism', // вместо такой записи
                    'target_id' => $model->id, // id of current element
                ]);
                ?>

поведение

    /**
     * @inheritdoc
     */
    public function behaviors()
    {
       return [
            'class' => \chiliec\behaviors\RatingBehavior::className(),
            'model_name' => self::className(), // common\models\Page
        ];

    }

и тогда после вставки голоса в ratiing, имея готовый класс модели, запустить код, который находится в поведении RatingBehavior.

В таком случае, инвалидируется кеш, и список статей будет отображаться верно.

единственное, что заметил, это Post-ом шлется название модели без слешей, как commonmodelsPage
Тогда в проверках нужно вырезать слеши в matchingModels, а при совпадении вернуть правильную модель

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

Вот, немного похожее решение того, о чем я написал выше и в след. issue.
https://github.com/AkiraShirase/yii2-vote

Ну, тут особо кардинального изменения не произошло )...
было - page, стало - common\models\Page.
В предлагаемом выше модуле модель передается через crc32
https://github.com/AkiraShirase/yii2-vote/blob/master/widgets/Vote.php#L46
Единственное, что - после сохранения модели rating, выполнить метод afterFind поведения с привязкой к передаваемой модели..

В принципе - можно сделать отдельную ветку и там все это потестить).

В принципе и от настройки matchingModels тогда можно отказаться, если создать ещё одну табличку с PK и model_name и связать её с rating. Тогда вообще всё магически будет происходить. Правда существующим пользователям придётся в неё залезть чтобы настроить такие же соответствия, какие сейчас прописаны в конфиге...

Можно сделать, как один из вариантов... Во многих проектах такая табличка уже есть (у меня , по крайней мере), при привязке комментариев, избранного, и тп...

Также, такой подход удобен для выборки в личном кабинете всех проголосованных записей (типа - избранного)

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

Я не призывал убирать эту настройку )...
Как по мне - она вполне логична и видно, к какой модели применяется голосование и с какими настройками.
Вариант в конфиге с привязкой к namespace модели намного понятнее и удобнее (знаешь, где искать)

    'modules' => [
        'vote' => [
            'matchingModels' => [ // matching model names with whatever unique integer ID
                'common\models\Page' => 3,
                'my-local-module\models\Page' => ['id'=>2, 'allow_guests'=>false],
                'vendor\chiliec\module\page\models\Page' => ['id'=>4, 'allow_guests'=>true],
            ],
        ],
    ],

намного понятнее, чем

    'modules' => [
        'vote' => [
            'matchingModels' => [ // matching model names with whatever unique integer ID
                'page1' => 3,
                'page2' => ['id'=>2, 'allow_guests'=>false],
                'page3' => ['id'=>4, 'allow_guests'=>true],
            ],
        ],
    ],

Переделал name => id на id => name в конфиге, что, как мне кажется, более логично (индексы массива). Изменения в ветке develop, я поправил документацию, можете попробовать.
Теперь можно предположить, что у нас есть имя модели и можно подумать над тем, как сбросить её кэш...

посмотрел, толковое решение...
Ну раз начали переделывать ))), то можно еще в виджете вместо названия модели передать саму модель,

        'model' => $model, //*Obligatory parameter. Object for Like/Dislike.
        'primaryField' => 'id', //Name of primary key for model

а затем, после сохранения голоса, например тут
https://github.com/Chiliec/yii2-vote/blob/master/actions/VoteAction.php#L77

запустить метод записи в модель, аналогичный
https://github.com/Chiliec/yii2-vote/blob/master/behaviors/RatingBehavior.php#L38

типа

$model::afterFind();

И поскольку обновится запись, кеш у меня автоматически сбросится...

Я вот всё думаю как бы поменьше действий делать для подключения. Подключение поведения уже происходит динамически, теперь хочется ещё вынести рейтинг во внешнюю таблицу. Хотелось бы формировать его на лету (ведь по сути это всё вычисляемые избыточные данные), но похоже не получится, ведь необходимо оставить возможность делать выборку с учетом рейтинга. Надо ещё подумать, возможно найдется какой-то вариант.
Кстати, а как у Вас кэширование происходит?

За кеширование у меня отвечает тоже поведение.
Кеш сбрасывается по времени, или если модель обновилась.

Примерно, как тут
https://github.com/trntv/yii2-starter-kit/blob/master/common/behaviors/CacheInvalidateBehavior.php

Выборку с учетом рейтинга делать надо ). У меня сортировка ListView содержит параметр "по рейтингу". А еще понадобится выборка в личном кабинете всех записей, за которые отдан голос или добавленных в избранное.

Насчет подключения - тоже не очевидно. Можно оставить как вариант через bootstrap.

Так получается, что поведение будет цепляться к каждой модели и перебирать массив моделей из конфига... А на самом деле в проекте у меня поведение нужно в 4-5 моделях из более чем 40.

Тем более, что есть уже четкие сформировавшиеся методики подключения поведений.
Если я его подключил к определенной модели, то я знаю, что это поведение делает... И в случае чего могу отключить (или заменить на другое)...

К примеру, давно хотел предложить (или сделать у себя) добавить возможность добавлять в избранное. Это тоже своего рода "голосование". Просто удобно одним виджетом вывести эти три кнопки. У себя еще на CodeIgniter я делал такой модуль
http://new.loveorigami.info/world

Возможность выборки с учетом рейтинга - обязательное условие, без которого и нет смысла выносить рейтинг во внешнюю таблицу. Главное теперь понять как это сделать :neckbeard:

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

Насчет избранного надо подумать, возможно отдельный issue создать, пока в концепции данного модуля применения не особо вижу, всё же это несколько иная функциональность.

Насчет избранного надо подумать, возможно отдельный issue создать, пока в концепции данного модуля применения не особо вижу, всё же это несколько иная функциональность.

открыл issue #19 под избранное.

Там я описал функциональность - все аналогично и проще - по крайней мере я у себя так делал.
А вот когда голосуешь, всегда есть желание понравившуюся запись иметь у себя в закладках (избранном)...

Примерно, как тут
https://github.com/trntv/yii2-starter-kit/blob/master/common/behaviors/CacheInvalidateBehavior.php

Ну тогда мне кажется можно добавить вот это:

$modelName = static::getModelNameById($modelId);
$model = $modelName::findOne($targetId);
$model->trigger($modelName::EVENT_AFTER_UPDATE);

после этой строчки https://github.com/Chiliec/yii2-vote/blob/develop/models/Rating.php#L189
Ну или что-нибудь вроде того. Можете PR сделать если сработает.

пока не делаю, т.к. отключил кеширование при разработке и тестировании этого модуля.
При кешировании, если помните, у меня не подгружается js.
Так что сам action не будет срабатывать.

Если получится нам переделать через asset - тогда буду пробовать

Если получится нам переделать через asset

Очень не хочется отказываться от переопределения методов, выполняющихся после голосования. Но, возможно, это можно сделать не из PHP, формируя js-код, а перегружая их прямо в Javascript в другом месте. Это бы решило проблему #18.

Я на днях тут делал PR в ajax-modal
https://github.com/karnbrockgmbh/yii2-modal-ajax/blob/master/README.md

Так вот, там скрипт написан в виде плагина, с возможностью call-back- ов, который можно написать прямо на странице в виде

$('.voted').on('kbModalShow', function(event, data, status, xhr) {
    console.log('kbModalShow');
});

Реализуются они при помощи триггеров
https://github.com/karnbrockgmbh/yii2-modal-ajax/blob/master/assets/js/kb-modal-ajax.js#L54