Всем привет!
У меня реализованы рейтинги на сайте. За определённые действия пользователя я присваиваю ему рейтинг. Есть несколько модулей yii:
мероприятия,
назначения,
новости... В каждом модуле есть соответствующие модели AR
Чтобы сейчас присвоить рейтинг пользователю я использую поведения от Yii, которое подключаю в модели AR. В поведении добавляю новый метод который будет обрабатывать событие (пока что использую стандартные события модели AR). В методе поведения я размещаю всю основную логику присвоения, удаления рейтинга. Если логика отрабатывает, то я, с помощью метода модели
RatingUser add()
, записываю рейтинг в базу и увеличиваю счетчик рейтинга пользователя.
Сейчас мне хотелось бы оптимизировать код в соотвествии с
принципом единой отвественности (каждый объект отвечает за то, что должен отвечать). Прошу у вас помощи и советов по данной задаче.
Когда начинаю оптимизировать код — голова кругом)) Возникает много вопросов....
1. Может быть лучше подписываться на свои события не используя поведения?
2. Может что-то вынести в отдельные классы и наследовать их в каждом модуле?
3. Либо вынести в компонент?
Кроме того нужно ведь предусмотреть на скорое будущее... Рейтинг может быть не только у пользователей, но у постов, мероприятий, клубов... Логика примерно будет одинаковой.
Сейчас покажу как всё устроено...
Таблица rating_user
id|user_id|value|rating_type_id|table|record_id|created_at
Где,
user_id - ИД пользователя
value - значение рейтинга
rating_type_id - тип рейтинга
table - имя таблицы, по которой присвоен рейтинг (для отката рейтинга при удалении)
record_id - ИД записи, за которую был присвоен рейтинг (для отката рейтинга при удалении)
created_at - дата и веремя присвоения
Сейчас я записываю рейтинг через события используя поведения...
Подключение
'RatingUser' => [
* 'class' => 'backend\modules\user\behaviors\RatingUser',
* ],
Поведение:
class RatingUserBehaviors extends Behavior
{
//Подписываемся на события
public function events(): array
{
return ArrayHelper::merge(parent::events(), [
Appointment::EVENT_AFTER_INSERT => 'appointmentAdd',
Appointment::EVENT_AFTER_UPDATE => 'appointmentAdd',
Appointment::EVENT_AFTER_DELETE => 'appointmentDel',
Event::EVENT_AFTER_INSERT => 'eventAdd',
Event::EVENT_AFTER_DELETE => 'eventDel',
]);
}
/**
* Добавить рейтинг за назначения
*
* @param $event
* @return bool
*/
public function appointmentAdd($event)
{
/** @var Appointment $model */
$model = $event->sender;
$certification = $model->certification;
$user_id = $certification->user_id;
$table = $model::tableName();
$record_id = $model->id;
//Если назначение подтверждено
if ($model->isConfirmed) {
if ($certification->role == 'chief_judge') {
if ($model->isAppointed) {
$this->model->add($user_id, 4, $table, $record_id);
} else if ($model->status == $model::STATUS_REFUSED) {
$this->model->add($user_id, 5, $table, $record_id);
}
} else if ($certification->role == 'judge') {
if ($model->status == $model::STATUS_APPOINTED) {
$this->model->add($user_id, 1, $table, $record_id);
} else if ($model->status == $model::STATUS_REPLASED) {
$this->model->add($user_id, 2, $table, $record_id);
} else if ($model->status == $model::STATUS_REFUSED) {
$this->model->add($user_id, 3, $table, $record_id);
}
}
}
return true;
}
}
Модель рейтинга:/**
* This is the model class for table "rating_user".
*
* @property int $id
* @property int $user_id
* @property int $value
* @property int $rating_type_id
* @property int $table
* @property int $record_id
* @property int $created_at
* @property User $user
* @property Profile $profile
*/
class RatingUser extends \yii\db\ActiveRecord
{
....
/**
* Добавить рейтинг пользователю
*
* @param int $user_id
* @param int $rating_type_id
* @param string|null $table
* @param int|null $record_id
* @return bool
*/
public function add(int $user_id, int $rating_type_id, string $table = null, int $record_id = null)
{
$value = $this->getValueType($rating_type_id);
$attributes = [
'user_id' => $user_id,
'rating_type_id' => $rating_type_id,
'table' => $table,
'record_id' => $record_id,
];
if (!$this->getExistsRatingByUser($attributes)) {
$attributes['value'] = $value;
$this->attributes = $attributes;
$this->user->updateCounters(['rating_count' => $value]);
$this->user->save(false);
$this->save();
return true;
}
return false;
}
/**
* Удалить рейтинг у пользователя
*
* @param string|null $table
* @param int|null $record_id
* @return bool
* @throws \Throwable
* @throws \yii\db\StaleObjectException
*/
public function del(string $table = null, int $record_id = null)
{
$ratings = $this::find()->where(['table' => $table, 'record_id' => $record_id])->all();
foreach ($ratings as $rating) {
$rating->user->updateCounters(['rating_count' => -$rating->value]);
$rating->user->save();
$rating->delete();
}
return true;
}
}