chiliec / yii2-vote

Provides voting for any model :+1: :-1:
BSD 3-Clause "New" or "Revised" License
72 stars 29 forks source link

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

Open loveorigami opened 8 years ago

loveorigami commented 8 years ago

Вывожу списком статьи через 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.

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

loveorigami commented 8 years ago

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

chiliec commented 8 years ago

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

loveorigami commented 8 years ago

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

loveorigami commented 8 years ago

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

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

chiliec commented 8 years ago

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

loveorigami commented 8 years ago

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

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

chiliec commented 8 years ago

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

loveorigami commented 8 years ago

Я не призывал убирать эту настройку )... Как по мне - она вполне логична и видно, к какой модели применяется голосование и с какими настройками. Вариант в конфиге с привязкой к 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],
            ],
        ],
    ],
chiliec commented 8 years ago

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

loveorigami commented 8 years ago

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

        '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();

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

chiliec commented 8 years ago

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

loveorigami commented 8 years ago

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

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

loveorigami commented 8 years ago

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

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

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

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

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

chiliec commented 8 years ago

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

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

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

loveorigami commented 8 years ago

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

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

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

chiliec commented 8 years ago

Примерно, как тут 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 сделать если сработает.

loveorigami commented 8 years ago

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

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

chiliec commented 8 years ago

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

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

loveorigami commented 8 years ago

Я на днях тут делал 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