init(); } /** * @return static */ public static function i() { bff()->singletonIf('listings.items.favorite', static::class); return bff('listings.items.favorite'); } /** * Максимально допустимое кол-во избранных объявлений * @return int */ public function getLimit() { return $this->config('listings.items.favorite.limit', 200, TYPE_UINT); } /** * Добавление объявления в избранные авторизованного пользователя * @param int $itemID ID объявления * @param int $userID ID пользователя * @param bool $toggle удаляем из списка избранных если уже находится в данном списке * @return array|bool текущее кол-во избранных объявлений у пользователя или false (ошибка) */ public function add($itemID, $userID, $toggle = true) { if (! $itemID || ! $userID) { return false; } $favorite = $this->isFavorite($itemID, $userID); if ($favorite) { if ($toggle) { $this->deleteFromDatabase($userID, $itemID); $favorite = false; } } else { $total = $this->getList($userID, true); if ($total >= $this->getLimit()) { $this->errors->set(_t('listings', 'You have reached the limit of the number of listings in your favorites')); return false; } $this->saveToDatabase($userID, [$itemID]); $favorite = true; } $total = $this->getList($userID, true); # актулизируем счетчик избранных объявлений пользователя $this->updateUserCounter($userID, $total); return compact('total', 'favorite'); } /** * Удаление всех избранных объявлений пользователя * @param int $userID ID пользователя или 0 * @return void */ public function deleteAll($userID) { if ($userID) { $this->deleteFromDatabase($userID); $this->updateUserCounter($userID, 0); } else { $this->guestStorage('delete'); } } /** * Актуализируем данные списка избранных объявлений пользователя * @param array|null $favorite список ID избранных объявлений * @param int $userID ID пользователя или 0 * @return void */ public function actualize(?array $favorite = null, $userID = 0) { $favorite = $favorite ?? $this->getList($userID); $existing = Listings::model()->itemsSearch([ 'id' => $favorite, 'is_publicated' => 1, 'status' => Listings::STATUS_PUBLICATED, ], ['context' => 'favorites-actualize']); # Количество избранных не совпадает с реальным данными об объявлениях # Возможно некоторые были сняты с публикации if (sizeof($favorite) != sizeof($existing)) { if ($userID) { $delete = []; foreach ($favorite as $id) { if (! in_array($id, $existing)) { $delete[] = $id; } } if (! empty($delete)) { $this->deleteFromDatabase($userID, $delete); $this->updateUserCounter($userID, sizeof($existing)); } } else { # обновим данные неавторизованного пользователя $this->guestStorage($existing); } } else { # актулизируем только счетчик избранных пользователя if ($userID) { $this->updateUserCounter($userID, sizeof($favorite)); } } } /** * Проверяем, находится ли объявление в списке избранных * @param int $itemID ID объявления * @param int $userID ID пользователя или 0 * @return bool */ public function isFavorite($itemID, $userID) { if (empty($itemID)) { return false; } return $this->getList($userID, true, [$itemID]) > 0; } /** * Получаем ID объявлений, добавленных текущим пользователем в избранные * @param int $userID ID пользователя или 0 * @param bool $countOnly только счетчик кол-ва * @param array $filterByID фильтр по ID объявлений * @return array|int ID избранных объявлений или только счетчик */ public function getList($userID = 0, bool $countOnly = false, array $filterByID = []) { if ($userID) { # для авторизованного $itemsID = Listings::model()->itemsFavData($userID, $filterByID); if (empty($itemsID)) { $itemsID = []; } } else { # для неавторизованного $itemsID = $this->guestStorage(); if (! empty($itemsID)) { if (! empty($filterByID)) { foreach ($itemsID as $key => $id) { if (! in_array($id, $filterByID)) { unset($itemsID[$key]); } } } } } if ($countOnly) { return sizeof($itemsID); } return $itemsID; } /** * Обрабатываем событие авторизации пользователя * @param int $userID ID авторизованного пользователя * @return void */ public function onUserLogin($userID) { if ($userID) { $this->guestToUser($userID); } } /** * Сохраняем избранные объявления пользователя в database * @param int $userID ID пользователя * @return void */ public function guestToUser($userID) { do { if (! $userID) { break; } # объявления неавторизованного пользователя $guestList = $this->getList(); if (empty($guestList)) { break; } # объявления в database $existedList = $this->getList($userID); # пропускаем уже существующие в database if (! empty($existedList)) { $newList = []; foreach ($guestList as $id) { if (!in_array($id, $existedList)) { $newList[] = $id; } } } else { $newList = $guestList; } if (! empty($newList)) { # сохраняем $result = $this->saveToDatabase($userID, $newList); # чистим список избранных неавторизованного пользователя if (!empty($result)) { $this->guestStorage('delete'); } # обновляем счетчик избранных объявлений авторизованного пользователя $this->updateUserCounter($userID, sizeof($existedList) + sizeof($newList)); } } while (false); } /** * Сохранить избранные объявления пользователя в базу данных * @param int $userID ID пользователя * @param array $itemsList ID избранных объявлений * @return mixed */ protected function saveToDatabase($userID, array $itemsList) { return Listings::model()->itemsFavSave($userID, $itemsList); } /** * Удалить избранные объявления пользователя из базы данных * @param int $userID ID пользователя * @param mixed $itemsFilter ID объявления|нескольких объявлений|FALSE - все объявления * @return mixed */ protected function deleteFromDatabase($userID, $itemsFilter = false) { return Listings::model()->itemsFavDelete($userID, $itemsFilter); } /** * Работа с избранными объявлениями неавторизованного пользователя * @param null|string|array $action * @return array|bool */ public function guestStorage(?string $action = null) { $key = $this->app->cookieKey('fav'); if ($action === null) { # Get $items = $this->input->cookie($key); if (! empty($items)) { $items = explode('.', $items); $this->input->clean($items, TYPE_ARRAY_UINT); $items = array_unique($items); return $items; } return []; } if ($action === 'delete') { # Delete Response::deleteCookie($key); return true; } if (is_array($action)) { # Save Response::setCookie($key, join('.', $action), 2); return true; } return false; } /** * Обновим текущее значение счетчика избранных объявлений пользователя * @param int $userID ID пользователя * @param int $counter кол-во избранных объявлений * @return void */ protected function updateUserCounter($userID, $counter) { if ($userID) { Users::model()->userCounterSave($userID, $this->counterKey, $counter, false); } } }