From 5103fabf25a379ce7a43717957f5ff4d6696cc3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D?= Date: Sun, 10 Mar 2024 00:27:19 +0100 Subject: [PATCH] chore(tests): UT for Notification repository MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rubén D --- .../Items/NotificationsController.php | 4 +- .../Notification/NotificationViewBase.php | 2 +- app/modules/web/Forms/NotificationForm.php | 2 +- .../views/notification/notification.inc | 2 +- lib/SP/DataModel/Notification.php | 230 ------- .../Notification/Models/Notification.php | 94 +++ .../Ports/NotificationRepository.php | 143 ++-- .../Ports/NotificationServiceInterface.php | 2 +- .../Services/NotificationService.php | 22 +- .../Repositories/Notification.php | 414 ++++++++++++ .../NotificationBaseRepository.php | 628 ------------------ .../Notification/NotificationHandler.php | 4 +- .../Generators/NotificationDataGenerator.php | 53 ++ .../Repositories/ItemPresetTest.php | 4 + .../Repositories/NotificationTest.php | 504 ++++++++++++++ 15 files changed, 1187 insertions(+), 921 deletions(-) delete mode 100644 lib/SP/DataModel/Notification.php create mode 100644 lib/SP/Domain/Notification/Models/Notification.php create mode 100644 lib/SP/Infrastructure/Notification/Repositories/Notification.php delete mode 100644 lib/SP/Infrastructure/Notification/Repositories/NotificationBaseRepository.php create mode 100644 tests/SPT/Generators/NotificationDataGenerator.php create mode 100644 tests/SPT/Infrastructure/Notification/Repositories/NotificationTest.php diff --git a/app/modules/web/Controllers/Items/NotificationsController.php b/app/modules/web/Controllers/Items/NotificationsController.php index 3a99674b..2faaa038 100644 --- a/app/modules/web/Controllers/Items/NotificationsController.php +++ b/app/modules/web/Controllers/Items/NotificationsController.php @@ -25,10 +25,10 @@ namespace SP\Modules\Web\Controllers\Items; use SP\Core\Application; -use SP\DataModel\Notification; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; use SP\Domain\Core\Exceptions\SPException; +use SP\Domain\Notification\Models\Notification; use SP\Domain\Notification\Ports\NotificationServiceInterface; use SP\Html\Html; use SP\Http\JsonMessage; @@ -65,7 +65,7 @@ final class NotificationsController extends SimpleControllerBase { $notifications = array_map( static function ($notification) { - /** @@var $notification Notification */ + /** @@var $notification \SP\Domain\Notification\Models\Notification */ return sprintf( '(%s) - %s', $notification->getComponent(), diff --git a/app/modules/web/Controllers/Notification/NotificationViewBase.php b/app/modules/web/Controllers/Notification/NotificationViewBase.php index dab6499e..b33b6d3d 100644 --- a/app/modules/web/Controllers/Notification/NotificationViewBase.php +++ b/app/modules/web/Controllers/Notification/NotificationViewBase.php @@ -27,10 +27,10 @@ namespace SP\Modules\Web\Controllers\Notification; use SP\Core\Acl\Acl; use SP\Core\Application; -use SP\DataModel\Notification; use SP\Domain\Core\Acl\AclActionsInterface; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; +use SP\Domain\Notification\Models\Notification; use SP\Domain\Notification\Ports\NotificationServiceInterface; use SP\Domain\User\Ports\UserServiceInterface; use SP\Infrastructure\Common\Repositories\NoSuchItemException; diff --git a/app/modules/web/Forms/NotificationForm.php b/app/modules/web/Forms/NotificationForm.php index a6d288f1..f842a878 100644 --- a/app/modules/web/Forms/NotificationForm.php +++ b/app/modules/web/Forms/NotificationForm.php @@ -25,9 +25,9 @@ namespace SP\Modules\Web\Forms; use SP\Core\Messages\NotificationMessage; -use SP\DataModel\Notification; use SP\Domain\Core\Acl\AclActionsInterface; use SP\Domain\Core\Exceptions\ValidationException; +use SP\Domain\Notification\Models\Notification; /** * Class NotificationForm diff --git a/app/modules/web/themes/material-blue/views/notification/notification.inc b/app/modules/web/themes/material-blue/views/notification/notification.inc index 79196f40..23d8ada3 100644 --- a/app/modules/web/themes/material-blue/views/notification/notification.inc +++ b/app/modules/web/themes/material-blue/views/notification/notification.inc @@ -30,9 +30,9 @@ * @var TemplateInterface $this */ -use SP\DataModel\Notification; use SP\Domain\Config\Ports\ConfigDataInterface; use SP\Domain\Core\UI\ThemeIconsInterface; +use SP\Domain\Notification\Models\Notification; use SP\Mvc\View\Components\SelectItem; use SP\Mvc\View\TemplateInterface; use SP\Util\DateUtil; diff --git a/lib/SP/DataModel/Notification.php b/lib/SP/DataModel/Notification.php deleted file mode 100644 index 17e31abc..00000000 --- a/lib/SP/DataModel/Notification.php +++ /dev/null @@ -1,230 +0,0 @@ -. - */ - -namespace SP\DataModel; - -use SP\Domain\Common\Models\ItemWithIdAndNameModel; -use SP\Domain\Core\Messages\MessageInterface; - -/** - * Class NoticeData - * - * @package SP\DataModel - */ -class Notification implements ItemWithIdAndNameModel -{ - /** - * @var int - */ - public $id = 0; - /** - * @var string - */ - public $type; - /** - * @var string - */ - public $component; - /** - * @var string - */ - public $description; - /** - * @var int - */ - public $date = 0; - /** - * @var bool - */ - public $checked = 0; - /** - * @var int - */ - public $userId; - /** - * @var bool - */ - public $sticky = 0; - /** - * @var bool - */ - public $onlyAdmin = 0; - - /** - * @return int - */ - public function getId() - { - return (int)$this->id; - } - - /** - * @param int $id - */ - public function setId($id) - { - $this->id = (int)$id; - } - - /** - * @return string - */ - public function getType() - { - return $this->type; - } - - /** - * @param string $type - */ - public function setType($type) - { - $this->type = $type; - } - - /** - * @return string - */ - public function getComponent() - { - return $this->component; - } - - /** - * @param string $component - */ - public function setComponent($component) - { - $this->component = $component; - } - - /** - * @return string - */ - public function getDescription() - { - return $this->description; - } - - /** - * @param MessageInterface $message - * @param bool $useHtml - */ - public function setDescription(MessageInterface $message, bool $useHtml = false) - { - if ($useHtml) { - $this->description = $message->composeHtml(); - } else { - $this->description = $message->composeText(); - } - } - - /** - * @return int - */ - public function getDate() - { - return (int)$this->date; - } - - /** - * @param int $date - */ - public function setDate($date) - { - $this->date = (int)$date; - } - - /** - * @return int - */ - public function isChecked() - { - return (int)$this->checked; - } - - /** - * @param bool $checked - */ - public function setChecked($checked) - { - $this->checked = (int)$checked; - } - - /** - * @return int - */ - public function getUserId() - { - return (int)$this->userId; - } - - /** - * @param int $userId - */ - public function setUserId($userId) - { - $this->userId = (int)$userId; - } - - /** - * @return int - */ - public function isSticky() - { - return (int)$this->sticky; - } - - /** - * @param bool $sticky - */ - public function setSticky($sticky) - { - $this->sticky = (int)$sticky; - } - - /** - * @return int - */ - public function isOnlyAdmin() - { - return (int)$this->onlyAdmin; - } - - /** - * @param bool $onlyAdmin - */ - public function setOnlyAdmin($onlyAdmin) - { - $this->onlyAdmin = (int)$onlyAdmin; - } - - /** - * @return string - */ - public function getName() - { - return $this->component; - } -} diff --git a/lib/SP/Domain/Notification/Models/Notification.php b/lib/SP/Domain/Notification/Models/Notification.php new file mode 100644 index 00000000..ecb065e5 --- /dev/null +++ b/lib/SP/Domain/Notification/Models/Notification.php @@ -0,0 +1,94 @@ +. + */ + +namespace SP\Domain\Notification\Models; + +use SP\Domain\Common\Models\ItemWithIdAndNameModel; +use SP\Domain\Common\Models\Model; + +/** + * Class Notification + */ +class Notification extends Model implements ItemWithIdAndNameModel +{ + protected ?int $id = null; + protected ?string $type = null; + protected ?string $component = null; + protected ?string $description = null; + protected ?int $date = null; + protected ?bool $checked = false; + protected ?int $userId = null; + protected ?bool $sticky = false; + protected ?bool $onlyAdmin = false; + + public function getId(): ?int + { + return $this->id; + } + + public function getType(): ?string + { + return $this->type; + } + + public function getComponent(): ?string + { + return $this->component; + } + + public function getDescription(): ?string + { + return $this->description; + } + + public function getDate(): ?int + { + return $this->date; + } + + public function isChecked(): ?bool + { + return $this->checked; + } + + public function getUserId(): ?int + { + return $this->userId; + } + + public function isSticky(): ?bool + { + return $this->sticky; + } + + public function isOnlyAdmin(): ?bool + { + return $this->onlyAdmin; + } + + public function getName(): ?string + { + return $this->component; + } +} diff --git a/lib/SP/Domain/Notification/Ports/NotificationRepository.php b/lib/SP/Domain/Notification/Ports/NotificationRepository.php index 760e456b..f5996f37 100644 --- a/lib/SP/Domain/Notification/Ports/NotificationRepository.php +++ b/lib/SP/Domain/Notification/Ports/NotificationRepository.php @@ -28,65 +28,129 @@ use SP\DataModel\ItemSearchData; use SP\Domain\Common\Ports\Repository; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; +use SP\Domain\Notification\Models\Notification as NotificationModel; use SP\Infrastructure\Database\QueryResult; /** * Class NotificationRepository * - * @package SP\Infrastructure\Notification\Repositories + * @template T of NotificationModel */ interface NotificationRepository extends Repository { /** - * Deletes an item + * Creates an item * - * @param int $id + * @param NotificationModel $notification + * @return QueryResult + * @throws ConstraintException + * @throws QueryException + */ + public function create(NotificationModel $notification): QueryResult; + + /** + * Updates an item + * + * @param NotificationModel $notification * * @return int * @throws ConstraintException * @throws QueryException */ - public function deleteAdmin(int $id): int; + public function update(NotificationModel $notification): int; /** * Deletes an item * - * @param array $ids - * - * @return int - * @throws ConstraintException - * @throws QueryException - */ - public function deleteAdminBatch(array $ids): int; - - /** - * Searches for items by a given filter - * - * @param ItemSearchData $itemSearchData - * @param int $userId + * @param int $id * * @return QueryResult * @throws ConstraintException * @throws QueryException */ + public function delete(int $id): QueryResult; + + /** + * Returns the item for given id + * + * @param int $notificationId + * + * @return QueryResult + */ + public function getById(int $notificationId): QueryResult; + + /** + * Returns all the items + * + * @return QueryResult + */ + public function getAll(): QueryResult; + + /** + * Returns all the items for given ids + * + * @param array $notificationsId + * + * @return QueryResult + */ + public function getByIdBatch(array $notificationsId): QueryResult; + + /** + * Deletes all the items for given ids + * + * @param array $notificationsId + * @return QueryResult + * @throws ConstraintException + * @throws QueryException + */ + public function deleteByIdBatch(array $notificationsId): QueryResult; + + /** + * Deletes an item + * + * @param int $id + * + * @return QueryResult + * @throws ConstraintException + * @throws QueryException + */ + public function deleteAdmin(int $id): QueryResult; + + /** + * Deletes an item + * + * @param array $notificationsId + * + * @return QueryResult + * @throws ConstraintException + * @throws QueryException + */ + public function deleteAdminBatch(array $notificationsId): QueryResult; + + /** + * Searches for items by a given filter + * + * @param ItemSearchData $itemSearchData + * @param int $userId + * + * @return QueryResult + */ public function searchForUserId(ItemSearchData $itemSearchData, int $userId): QueryResult; /** * Searches for items by a given filter * - * @param ItemSearchData $itemSearchData - * @param int $userId + * @param ItemSearchData $itemSearchData + * @param int $userId * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException + * @return QueryResult */ public function searchForAdmin(ItemSearchData $itemSearchData, int $userId): QueryResult; /** * Marcar una notificación como leída * - * @param int $id + * @param int $id * * @return int * @throws ConstraintException @@ -97,39 +161,30 @@ interface NotificationRepository extends Repository /** * Devolver las notificaciones de un usuario para una fecha y componente determinados * - * @param string $component - * @param int $userId + * @param string $component + * @param int $userId * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException + * @return QueryResult */ public function getForUserIdByDate(string $component, int $userId): QueryResult; /** - * @param int $id + * @param int $userId * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException + * @return QueryResult */ - public function getAllForUserId(int $id): QueryResult; + public function getAllForUserId(int $userId): QueryResult; /** - * @param int $id - * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException + * @param int $userId + * @return QueryResult */ - public function getAllActiveForUserId(int $id): QueryResult; + public function getAllActiveForUserId(int $userId): QueryResult; /** - * @param int $id + * @param int $userId * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException + * @return QueryResult */ - public function getAllActiveForAdmin(int $id): QueryResult; + public function getAllActiveForAdmin(int $userId): QueryResult; } diff --git a/lib/SP/Domain/Notification/Ports/NotificationServiceInterface.php b/lib/SP/Domain/Notification/Ports/NotificationServiceInterface.php index 0bdf9510..d4dffdb5 100644 --- a/lib/SP/Domain/Notification/Ports/NotificationServiceInterface.php +++ b/lib/SP/Domain/Notification/Ports/NotificationServiceInterface.php @@ -25,10 +25,10 @@ namespace SP\Domain\Notification\Ports; use SP\DataModel\ItemSearchData; -use SP\DataModel\Notification; use SP\Domain\Common\Services\ServiceException; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; +use SP\Domain\Notification\Models\Notification; use SP\Infrastructure\Common\Repositories\NoSuchItemException; use SP\Infrastructure\Database\QueryResult; diff --git a/lib/SP/Domain/Notification/Services/NotificationService.php b/lib/SP/Domain/Notification/Services/NotificationService.php index 9216c5fd..d8a8429a 100644 --- a/lib/SP/Domain/Notification/Services/NotificationService.php +++ b/lib/SP/Domain/Notification/Services/NotificationService.php @@ -26,17 +26,16 @@ namespace SP\Domain\Notification\Services; use SP\Core\Application; use SP\DataModel\ItemSearchData; -use SP\DataModel\Notification; use SP\Domain\Common\Services\Service; use SP\Domain\Common\Services\ServiceException; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; use SP\Domain\Core\Exceptions\SPException; +use SP\Domain\Notification\Models\Notification; use SP\Domain\Notification\Ports\NotificationRepository; use SP\Domain\Notification\Ports\NotificationServiceInterface; use SP\Infrastructure\Common\Repositories\NoSuchItemException; use SP\Infrastructure\Database\QueryResult; -use SP\Infrastructure\Notification\Repositories\NotificationBaseRepository; /** * Class NotificationService @@ -45,13 +44,12 @@ use SP\Infrastructure\Notification\Repositories\NotificationBaseRepository; */ final class NotificationService extends Service implements NotificationServiceInterface { - protected NotificationBaseRepository $notificationRepository; - public function __construct(Application $application, NotificationRepository $notificationRepository) - { + public function __construct( + Application $application, + private readonly NotificationRepository $notificationRepository + ) { parent::__construct($application); - - $this->notificationRepository = $notificationRepository; } /** @@ -79,7 +77,7 @@ final class NotificationService extends Service implements NotificationServiceIn /** * Devolver los elementos con los ids especificados * - * @param int[] $ids + * @param int[] $ids * * @return Notification[] * @throws ConstraintException @@ -125,7 +123,7 @@ final class NotificationService extends Service implements NotificationServiceIn /** * Deletes an item * - * @param int[] $ids + * @param int[] $ids * * @throws ConstraintException * @throws QueryException @@ -148,7 +146,7 @@ final class NotificationService extends Service implements NotificationServiceIn /** * Deletes all the items for given ids * - * @param int[] $ids + * @param int[] $ids * * @throws ConstraintException * @throws QueryException @@ -225,7 +223,7 @@ final class NotificationService extends Service implements NotificationServiceIn } /** - * @return Notification[] + * @return \SP\Domain\Notification\Models\Notification[] * @throws ConstraintException * @throws QueryException */ @@ -235,7 +233,7 @@ final class NotificationService extends Service implements NotificationServiceIn } /** - * @return Notification[] + * @return \SP\Domain\Notification\Models\Notification[] * @throws ConstraintException * @throws QueryException */ diff --git a/lib/SP/Infrastructure/Notification/Repositories/Notification.php b/lib/SP/Infrastructure/Notification/Repositories/Notification.php new file mode 100644 index 00000000..b6156b42 --- /dev/null +++ b/lib/SP/Infrastructure/Notification/Repositories/Notification.php @@ -0,0 +1,414 @@ +. + */ + +namespace SP\Infrastructure\Notification\Repositories; + +use Aura\SqlQuery\Common\SelectInterface; +use SP\DataModel\ItemSearchData; +use SP\Domain\Core\Exceptions\ConstraintException; +use SP\Domain\Core\Exceptions\QueryException; +use SP\Domain\Notification\Models\Notification as NotificationModel; +use SP\Domain\Notification\Ports\NotificationRepository; +use SP\Infrastructure\Common\Repositories\BaseRepository; +use SP\Infrastructure\Common\Repositories\RepositoryItemTrait; +use SP\Infrastructure\Database\QueryData; +use SP\Infrastructure\Database\QueryResult; + +use function SP\__u; + +/** + * Class NotificationRepository + * + * @template T of NotificationModel + */ +final class Notification extends BaseRepository implements NotificationRepository +{ + use RepositoryItemTrait; + + public const TABLE = 'Notification'; + + /** + * Creates an item + * + * @param NotificationModel $notification + * @return QueryResult + * @throws ConstraintException + * @throws QueryException + */ + public function create(NotificationModel $notification): QueryResult + { + $query = $this->queryFactory + ->newInsert() + ->into(self::TABLE) + ->cols($notification->toArray(null, ['id', 'date'])) + ->set('date', 'UNIX_TIMESTAMP()'); + + $queryData = QueryData::build($query)->setOnErrorMessage(__u('Error while adding the notification')); + + return $this->db->doQuery($queryData); + } + + /** + * Updates an item + * + * @param NotificationModel $notification + * + * @return int + * @throws ConstraintException + * @throws QueryException + */ + public function update(NotificationModel $notification): int + { + $query = $this->queryFactory + ->newUpdate() + ->table(self::TABLE) + ->cols($notification->toArray(null, ['id'])) + ->set('date', 'UNIX_TIMESTAMP()') + ->where('id = :id', ['id' => $notification->getId()]) + ->limit(1); + + $queryData = QueryData::build($query)->setOnErrorMessage(__u('Error while updating the notification')); + + return $this->db->doQuery($queryData)->getAffectedNumRows(); + } + + /** + * Deletes an item + * + * @param int $id + * + * @return QueryResult + * @throws ConstraintException + * @throws QueryException + */ + public function delete(int $id): QueryResult + { + $query = $this->queryFactory + ->newDelete() + ->from(self::TABLE) + ->where('id = :id AND sticky = 0', ['id' => $id]) + ->limit(1); + + $queryData = QueryData::build($query)->setOnErrorMessage(__u('Error while deleting the notification')); + + return $this->db->doQuery($queryData); + } + + /** + * Deletes an item + * + * @param int $id + * + * @return QueryResult + * @throws ConstraintException + * @throws QueryException + */ + public function deleteAdmin(int $id): QueryResult + { + $query = $this->queryFactory + ->newDelete() + ->from(self::TABLE) + ->where('id = :id', ['id' => $id]) + ->limit(1); + + $queryData = QueryData::build($query)->setOnErrorMessage(__u('Error while deleting the notification')); + + return $this->db->doQuery($queryData); + } + + /** + * Deletes an item + * + * @param array $notificationsId + * + * @return QueryResult + * @throws ConstraintException + * @throws QueryException + */ + public function deleteAdminBatch(array $notificationsId): QueryResult + { + if (count($notificationsId) === 0) { + return new QueryResult(); + } + + $query = $this->queryFactory + ->newDelete() + ->from(self::TABLE) + ->where('id IN (:ids)', ['ids' => $notificationsId]); + + $queryData = QueryData::build($query)->setOnErrorMessage(__u('Error while deleting the notifications')); + + return $this->db->doQuery($queryData); + } + + /** + * Returns the item for given id + * + * @param int $notificationId + * + * @return QueryResult + */ + public function getById(int $notificationId): QueryResult + { + $query = $this->queryFactory + ->newSelect() + ->from(self::TABLE) + ->cols(NotificationModel::getCols()) + ->where('id = :id') + ->bindValues(['id' => $notificationId]) + ->limit(1); + + $queryData = QueryData::buildWithMapper($query, NotificationModel::class); + + return $this->db->doSelect($queryData); + } + + /** + * Returns all the items + * + * @return QueryResult + */ + public function getAll(): QueryResult + { + $query = $this->queryFactory + ->newSelect() + ->from(self::TABLE) + ->cols(NotificationModel::getCols()) + ->orderBy(['id']); + + return $this->db->doSelect(QueryData::buildWithMapper($query, NotificationModel::class)); + } + + /** + * Returns all the items for given ids + * + * @param array $notificationsId + * + * @return QueryResult + */ + public function getByIdBatch(array $notificationsId): QueryResult + { + $query = $this->queryFactory + ->newSelect() + ->from(self::TABLE) + ->cols(NotificationModel::getCols()) + ->where('id IN (:ids)', ['ids' => $notificationsId]); + + $queryData = QueryData::buildWithMapper($query, NotificationModel::class); + + return $this->db->doSelect($queryData); + } + + /** + * Deletes all the items for given ids + * + * @param array $notificationsId + * @return QueryResult + * @throws ConstraintException + * @throws QueryException + */ + public function deleteByIdBatch(array $notificationsId): QueryResult + { + if (count($notificationsId) === 0) { + return new QueryResult(); + } + + $query = $this->queryFactory + ->newDelete() + ->from(self::TABLE) + ->where('id IN (:ids) AND sticky = 0', ['ids' => $notificationsId]); + + $queryData = QueryData::build($query)->setOnErrorMessage(__u('Error while deleting the notifications')); + + return $this->db->doQuery($queryData); + } + + /** + * Searches for items by a given filter + * + * @param ItemSearchData $itemSearchData + * @param int $userId + * + * @return QueryResult + */ + public function searchForUserId(ItemSearchData $itemSearchData, int $userId): QueryResult + { + $query = $this->getBaseSearch($itemSearchData) + ->where( + '(userId = :userId OR (userId IS NULL AND onlyAdmin = 0) OR sticky = 1)', + ['userId' => $userId] + ); + + $queryData = QueryData::build($query)->setMapClassName(NotificationModel::class); + + return $this->db->doSelect($queryData, true); + } + + private function getBaseSearch(ItemSearchData $itemSearchData): SelectInterface + { + $query = $this->queryFactory + ->newSelect() + ->from(self::TABLE) + ->cols(NotificationModel::getCols()) + ->orderBy(['date DESC']) + ->limit($itemSearchData->getLimitCount()) + ->offset($itemSearchData->getLimitStart()); + + if (!empty($itemSearchData->getSeachString())) { + $query->where('(type LIKE :type OR component LIKE :component)'); + + $search = '%' . $itemSearchData->getSeachString() . '%'; + + $query->bindValues(['type' => $search, 'component' => $search]); + } + + return $query; + } + + /** + * Searches for items by a given filter + * + * @param ItemSearchData $itemSearchData + * @param int $userId + * + * @return QueryResult + */ + public function searchForAdmin(ItemSearchData $itemSearchData, int $userId): QueryResult + { + $query = $this->getBaseSearch($itemSearchData) + ->where('(userId = :userId OR onlyAdmin = 1 OR sticky = 1)', ['userId' => $userId]); + + $queryData = QueryData::build($query)->setMapClassName(NotificationModel::class); + + return $this->db->doSelect($queryData, true); + } + + /** + * Marcar una notificación como leída + * + * @param int $id + * + * @return int + * @throws ConstraintException + * @throws QueryException + */ + public function setCheckedById(int $id): int + { + $query = $this->queryFactory + ->newUpdate() + ->table(self::TABLE) + ->cols(['checked' => 1]) + ->where('id = :id', ['id' => $id]) + ->limit(1); + + $queryData = QueryData::build($query)->setOnErrorMessage(__u('Error while updating the notification')); + + return $this->db->doQuery($queryData)->getAffectedNumRows(); + } + + /** + * Devolver las notificaciones de un usuario para una fecha y componente determinados + * + * @param string $component + * @param int $userId + * + * @return QueryResult + */ + public function getForUserIdByDate(string $component, int $userId): QueryResult + { + $query = $this->queryFactory + ->newSelect() + ->from(self::TABLE) + ->cols(NotificationModel::getCols()) + ->where('userId = :userId AND component = :component AND (UNIX_TIMESTAMP() - date) <= 86400') + ->bindValues([ + 'userId' => $userId, + 'component' => $component + ]) + ->orderBy(['id']); + + $queryData = QueryData::buildWithMapper($query, NotificationModel::class); + + return $this->db->doSelect($queryData); + } + + /** + * @param int $userId + * + * @return QueryResult + */ + public function getAllForUserId(int $userId): QueryResult + { + $query = $this->queryFactory + ->newSelect() + ->from(self::TABLE) + ->cols(NotificationModel::getCols()) + ->where('(userId = :userId OR (userId IS NULL AND sticky = 1)) AND onlyAdmin = 0') + ->bindValues(['userId' => $userId]) + ->orderBy(['date DESC']); + + $queryData = QueryData::buildWithMapper($query, NotificationModel::class); + + return $this->db->doSelect($queryData); + } + + /** + * @param int $userId + * @return QueryResult + */ + public function getAllActiveForUserId(int $userId): QueryResult + { + $query = $this->queryFactory + ->newSelect() + ->from(self::TABLE) + ->cols(NotificationModel::getCols()) + ->where('(userId = :userId OR sticky = 1) AND onlyAdmin = 0 AND checked = 0') + ->bindValues(['userId' => $userId]) + ->orderBy(['date DESC']); + + $queryData = QueryData::buildWithMapper($query, NotificationModel::class); + + return $this->db->doSelect($queryData); + } + + /** + * @param int $userId + * + * @return QueryResult + */ + public function getAllActiveForAdmin(int $userId): QueryResult + { + $query = $this->queryFactory + ->newSelect() + ->from(self::TABLE) + ->cols(NotificationModel::getCols()) + ->where('(userId = :userId OR sticky = 1 OR userId IS NULL) AND checked = 0') + ->bindValues(['userId' => $userId]) + ->orderBy(['date DESC']); + + $queryData = QueryData::buildWithMapper($query, NotificationModel::class); + + return $this->db->doSelect($queryData); + } +} diff --git a/lib/SP/Infrastructure/Notification/Repositories/NotificationBaseRepository.php b/lib/SP/Infrastructure/Notification/Repositories/NotificationBaseRepository.php deleted file mode 100644 index a388e898..00000000 --- a/lib/SP/Infrastructure/Notification/Repositories/NotificationBaseRepository.php +++ /dev/null @@ -1,628 +0,0 @@ -. - */ - -namespace SP\Infrastructure\Notification\Repositories; - -use RuntimeException; -use SP\DataModel\ItemSearchData; -use SP\DataModel\Notification; -use SP\Domain\Core\Exceptions\ConstraintException; -use SP\Domain\Core\Exceptions\QueryException; -use SP\Domain\Notification\Ports\NotificationRepository; -use SP\Infrastructure\Common\Repositories\BaseRepository; -use SP\Infrastructure\Common\Repositories\RepositoryItemTrait; -use SP\Infrastructure\Database\QueryData; -use SP\Infrastructure\Database\QueryResult; -use SP\Mvc\Model\QueryCondition; - -/** - * Class NotificationRepository - * - * @package SP\Infrastructure\Notification\Repositories - */ -final class NotificationBaseRepository extends BaseRepository implements NotificationRepository -{ - use RepositoryItemTrait; - - /** - * Creates an item - * - * @param Notification $itemData - * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException - */ - public function create($itemData): QueryResult - { - $query = /** @lang SQL */ - 'INSERT INTO Notification - SET type = ?, - component = ?, - description = ?, - `date` = UNIX_TIMESTAMP(), - checked = 0, - userId = ?, - sticky = ?, - onlyAdmin = ?'; - - $queryData = new QueryData(); - $queryData->setQuery($query); - $queryData->setParams([ - $itemData->getType(), - $itemData->getComponent(), - $itemData->getDescription(), - $itemData->getUserId() ?: null, - $itemData->isSticky(), - $itemData->isOnlyAdmin(), - ]); - $queryData->setOnErrorMessage(__u('Error while adding the notification')); - - return $this->db->doQuery($queryData); - } - - /** - * Updates an item - * - * @param Notification $itemData - * - * @return int - * @throws ConstraintException - * @throws QueryException - */ - public function update($itemData): int - { - $query = /** @lang SQL */ - 'UPDATE Notification - SET type = ?, - component = ?, - description = ?, - `date` = UNIX_TIMESTAMP(), - checked = ?, - userId = ?, - sticky = ?, - onlyAdmin = ? - WHERE id = ? LIMIT 1'; - - $queryData = new QueryData(); - $queryData->setQuery($query); - $queryData->setParams([ - $itemData->getType(), - $itemData->getComponent(), - $itemData->getDescription(), - $itemData->isChecked(), - $itemData->getUserId() ?: null, - $itemData->isSticky(), - $itemData->isOnlyAdmin(), - $itemData->getId(), - ]); - $queryData->setOnErrorMessage(__u('Error while updating the notification')); - - return $this->db->doQuery($queryData)->getAffectedNumRows(); - } - - /** - * Deletes an item - * - * @param int $id - * - * @return int - * @throws ConstraintException - * @throws QueryException - */ - public function delete(int $id): int - { - $queryData = new QueryData(); - $queryData->setQuery('DELETE FROM Notification WHERE id = ? AND sticky = 0 LIMIT 1'); - $queryData->addParam($id); - $queryData->setOnErrorMessage(__u('Error while deleting the notification')); - - return $this->db->doQuery($queryData)->getAffectedNumRows(); - } - - /** - * Deletes an item - * - * @param int $id - * - * @return int - * @throws ConstraintException - * @throws QueryException - */ - public function deleteAdmin(int $id): int - { - $queryData = new QueryData(); - $queryData->setQuery('DELETE FROM Notification WHERE id = ? LIMIT 1'); - $queryData->addParam($id); - $queryData->setOnErrorMessage(__u('Error while deleting the notification')); - - return $this->db->doQuery($queryData)->getAffectedNumRows(); - } - - /** - * Deletes an item - * - * @param array $ids - * - * @return int - * @throws ConstraintException - * @throws QueryException - */ - public function deleteAdminBatch(array $ids): int - { - if (count($ids) === 0) { - return 0; - } - - $queryData = new QueryData(); - $queryData->setQuery('DELETE FROM Notification WHERE id IN ('.$this->buildParamsFromArray($ids).')'); - $queryData->setParams($ids); - $queryData->setOnErrorMessage(__u('Error while deleting the notifications')); - - return $this->db->doQuery($queryData)->getAffectedNumRows(); - } - - /** - * Returns the item for given id - * - * @param int $id - * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException - */ - public function getById(int $id): QueryResult - { - $query = /** @lang SQL */ - 'SELECT id, - type, - component, - description, - `date`, - userId, - checked, - sticky, - onlyAdmin - FROM Notification - WHERE id = ? LIMIT 1'; - - $queryData = new QueryData(); - $queryData->setMapClassName(Notification::class); - $queryData->setQuery($query); - $queryData->addParam($id); - $queryData->setOnErrorMessage(__u('Error while retrieving notification')); - - return $this->db->doSelect($queryData); - } - - /** - * Returns all the items - * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException - */ - public function getAll(): QueryResult - { - $query = /** @lang SQL */ - 'SELECT id, - type, - component, - description, - `date`, - userId, - checked, - sticky, - onlyAdmin - FROM Notification - ORDER BY id'; - - $queryData = new QueryData(); - $queryData->setMapClassName(Notification::class); - $queryData->setQuery($query); - $queryData->setOnErrorMessage(__u('Error while retrieving the notifications')); - - return $this->db->doSelect($queryData); - } - - /** - * Returns all the items for given ids - * - * @param array $ids - * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException - */ - public function getByIdBatch(array $ids): QueryResult - { - if (count($ids) === 0) { - return new QueryResult(); - } - - $query = /** @lang SQL */ - 'SELECT id, - type, - component, - description, - `date`, - userId, - checked, - sticky, - onlyAdmin - FROM Notification - WHERE id IN ('.$this->buildParamsFromArray($ids).') - ORDER BY id'; - - $queryData = new QueryData(); - $queryData->setMapClassName(Notification::class); - $queryData->setQuery($query); - $queryData->setParams($ids); - - return $this->db->doSelect($queryData); - } - - /** - * Deletes all the items for given ids - * - * @param array $ids - * - * @return int - * @throws ConstraintException - * @throws QueryException - */ - public function deleteByIdBatch(array $ids): int - { - if (count($ids) === 0) { - return 0; - } - - $queryData = new QueryData(); - $queryData->setQuery( - 'DELETE FROM Notification WHERE id IN ('.$this->buildParamsFromArray($ids).') AND sticky = 0' - ); - $queryData->setParams($ids); - $queryData->setOnErrorMessage(__u('Error while deleting the notifications')); - - return $this->db->doQuery($queryData)->getAffectedNumRows(); - } - - /** - * Checks whether the item is in use or not - * - * @param $id int - */ - public function checkInUse(int $id): bool - { - throw new RuntimeException('Not implemented'); - } - - /** - * Checks whether the item is duplicated on updating - * - * @param mixed $itemData - */ - public function checkDuplicatedOnUpdate($itemData): bool - { - throw new RuntimeException('Not implemented'); - } - - /** - * Checks whether the item is duplicated on adding - * - * @param mixed $itemData - */ - public function checkDuplicatedOnAdd($itemData): bool - { - throw new RuntimeException('Not implemented'); - } - - /** - * Searches for items by a given filter - * - * @param ItemSearchData $itemSearchData - * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException - */ - public function search(ItemSearchData $itemSearchData): QueryResult - { - $queryData = new QueryData(); - $queryData->setMapClassName(Notification::class); - $queryData->setSelect('id, type, component, description, `date`, checked, userId, sticky, onlyAdmin'); - $queryData->setFrom('Notification'); - $queryData->setOrder('`date` DESC'); - - if (!empty($itemSearchData->getSeachString())) { - $queryData->setWhere('type LIKE ? OR component LIKE ? OR description LIKE ?'); - - $search = '%'.$itemSearchData->getSeachString().'%'; - $queryData->addParam($search); - $queryData->addParam($search); - $queryData->addParam($search); - } - - $queryData->setLimit( - '?,?', - [$itemSearchData->getLimitStart(), $itemSearchData->getLimitCount()] - ); - - return $this->db->doSelect($queryData, true); - } - - /** - * Searches for items by a given filter - * - * @param ItemSearchData $itemSearchData - * @param int $userId - * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException - */ - public function searchForUserId( - ItemSearchData $itemSearchData, - int $userId - ): QueryResult { - $queryData = new QueryData(); - $queryData->setMapClassName(Notification::class); - $queryData->setSelect('id, type, component, description, `date`, checked, userId, sticky, onlyAdmin'); - $queryData->setFrom('Notification'); - $queryData->setOrder('`date` DESC'); - - $queryCondition = new QueryCondition(); - $queryCondition - ->addFilter('userId = ?', [$userId]) - ->addFilter('(userId IS NULL AND onlyAdmin = 0)') - ->addFilter('sticky = 1'); - - if (!empty($itemSearchData->getSeachString())) { - $queryData->setWhere( - '(type LIKE ? OR component LIKE ? OR description LIKE ?) AND ' - .$queryCondition->getFilters(QueryCondition::CONDITION_OR) - ); - - $search = '%'.$itemSearchData->getSeachString().'%'; - $queryData->setParams(array_merge([$search, $search, $search], $queryCondition->getParams())); - } else { - $queryData->setWhere($queryCondition->getFilters(QueryCondition::CONDITION_OR)); - $queryData->setParams($queryCondition->getParams()); - } - - $queryData->setLimit( - '?,?', - [$itemSearchData->getLimitStart(), $itemSearchData->getLimitCount()] - ); - - return $this->db->doSelect($queryData, true); - } - - /** - * Searches for items by a given filter - * - * @param ItemSearchData $itemSearchData - * @param int $userId - * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException - */ - public function searchForAdmin( - ItemSearchData $itemSearchData, - int $userId - ): QueryResult { - $queryData = new QueryData(); - $queryData->setMapClassName(Notification::class); - $queryData->setSelect('id, type, component, description, `date`, checked, userId, sticky, onlyAdmin'); - $queryData->setFrom('Notification'); - $queryData->setOrder('`date` DESC'); - - $queryCondition = new QueryCondition(); - $queryCondition - ->addFilter('userId = ?', [$userId]) - ->addFilter('onlyAdmin = 1') - ->addFilter('sticky = 1'); - - if (!empty($itemSearchData->getSeachString())) { - $queryData->setWhere( - '(type LIKE ? OR component LIKE ? OR description LIKE ?) AND ' - .$queryCondition->getFilters(QueryCondition::CONDITION_OR) - ); - - $search = '%'.$itemSearchData->getSeachString().'%'; - - $queryData->setParams(array_merge([$search, $search, $search], $queryCondition->getParams())); - } else { - $queryData->setWhere($queryCondition->getFilters(QueryCondition::CONDITION_OR)); - $queryData->setParams($queryCondition->getParams()); - } - - $queryData->setLimit( - '?,?', - [$itemSearchData->getLimitStart(), $itemSearchData->getLimitCount()] - ); - - return $this->db->doSelect($queryData, true); - } - - /** - * Marcar una notificación como leída - * - * @param int $id - * - * @return int - * @throws ConstraintException - * @throws QueryException - */ - public function setCheckedById(int $id): int - { - $query = /** @lang SQL */ - 'UPDATE Notification SET checked = 1 WHERE id = ? LIMIT 1'; - - $queryData = new QueryData(); - $queryData->setQuery($query); - $queryData->addParam($id); - $queryData->setOnErrorMessage(__u('Error while updating the notification')); - - return $this->db->doQuery($queryData)->getAffectedNumRows(); - } - - /** - * Devolver las notificaciones de un usuario para una fecha y componente determinados - * - * @param string $component - * @param int $userId - * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException - */ - public function getForUserIdByDate(string $component, int $userId): QueryResult - { - $query = /** @lang SQL */ - 'SELECT id, - type, - component, - description, - `date`, - userId, - checked, - sticky, - onlyAdmin - FROM Notification - WHERE component = ? - AND (UNIX_TIMESTAMP() - `date`) <= 86400 - AND userId = ? - ORDER BY id'; - - $queryData = new QueryData(); - $queryData->setMapClassName(Notification::class); - $queryData->setQuery($query); - $queryData->setParams([$component, $userId]); - $queryData->setOnErrorMessage(__u('Error while retrieving the notifications')); - - return $this->db->doSelect($queryData); - } - - /** - * @param int $id - * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException - */ - public function getAllForUserId(int $id): QueryResult - { - $query = /** @lang SQL */ - 'SELECT id, - type, - component, - description, - `date`, - userId, - checked, - sticky, - onlyAdmin - FROM Notification - WHERE (userId = ? OR (userId IS NULL AND sticky = 1)) - AND onlyAdmin = 0 - ORDER BY `date` DESC '; - - $queryData = new QueryData(); - $queryData->setMapClassName(Notification::class); - $queryData->setQuery($query); - $queryData->addParam($id); - $queryData->setOnErrorMessage(__u('Error while retrieving the notifications')); - - return $this->db->doSelect($queryData); - } - - /** - * @param int $id - * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException - */ - public function getAllActiveForUserId(int $id): QueryResult - { - $query = /** @lang SQL */ - 'SELECT id, - type, - component, - description, - `date`, - userId, - checked, - sticky, - onlyAdmin - FROM Notification - WHERE (userId = ? OR sticky = 1) - AND onlyAdmin = 0 - AND checked = 0 - ORDER BY `date` DESC '; - - $queryData = new QueryData(); - $queryData->setMapClassName(Notification::class); - $queryData->setQuery($query); - $queryData->addParam($id); - $queryData->setOnErrorMessage(__u('Error while retrieving the notifications')); - - return $this->db->doSelect($queryData); - } - - /** - * @param int $id - * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException - */ - public function getAllActiveForAdmin(int $id): QueryResult - { - $query = /** @lang SQL */ - 'SELECT id, - type, - component, - description, - `date`, - userId, - checked, - sticky, - onlyAdmin - FROM Notification - WHERE (userId = ? OR sticky = 1 OR userId IS NULL) - AND checked = 0 - ORDER BY `date` DESC '; - - $queryData = new QueryData(); - $queryData->setMapClassName(Notification::class); - $queryData->setQuery($query); - $queryData->addParam($id); - $queryData->setOnErrorMessage(__u('Error while retrieving the notifications')); - - return $this->db->doSelect($queryData); - } -} diff --git a/lib/SP/Providers/Notification/NotificationHandler.php b/lib/SP/Providers/Notification/NotificationHandler.php index 75763fb9..db93ad70 100644 --- a/lib/SP/Providers/Notification/NotificationHandler.php +++ b/lib/SP/Providers/Notification/NotificationHandler.php @@ -27,8 +27,8 @@ namespace SP\Providers\Notification; use Exception; use SP\Core\Application; use SP\Core\Events\Event; -use SP\DataModel\Notification; use SP\Domain\Core\Events\EventReceiver; +use SP\Domain\Notification\Models\Notification; use SP\Domain\Notification\Ports\NotificationServiceInterface; use SP\Providers\EventsTrait; use SP\Providers\Provider; @@ -96,6 +96,7 @@ final class NotificationHandler extends Provider implements EventReceiver $userIds = $eventMessage !== null ? $eventMessage->getExtra('userId') : []; foreach ($userIds as $userId) { + $description = $eventMessage->composeHtml(); $notificationData = new Notification(); $notificationData->setType(__('Request')); $notificationData->setComponent(__('Accounts')); @@ -128,6 +129,7 @@ final class NotificationHandler extends Provider implements EventReceiver if ($notify[0] === true) { $userId = $eventMessage->getExtra('userId')[0]; + $description = $eventMessage->composeHtml(); $notificationData = new Notification(); $notificationData->setType(__('Notification')); diff --git a/tests/SPT/Generators/NotificationDataGenerator.php b/tests/SPT/Generators/NotificationDataGenerator.php new file mode 100644 index 00000000..a5a06885 --- /dev/null +++ b/tests/SPT/Generators/NotificationDataGenerator.php @@ -0,0 +1,53 @@ +. + */ + +namespace SPT\Generators; + +use SP\Domain\Notification\Models\Notification; + +/** + * Class NotificationDataGenerator + */ +final class NotificationDataGenerator extends DataGenerator +{ + public function buildNotification(): Notification + { + return new Notification($this->notificationProperties()); + } + + private function notificationProperties(): array + { + return [ + 'id' => $this->faker->randomNumber(3), + 'type' => $this->faker->colorName(), + 'component' => $this->faker->colorName(), + 'description' => $this->faker->text(), + 'date' => $this->faker->unixTime(), + 'checked' => $this->faker->boolean(), + 'sticky' => $this->faker->boolean(), + 'onlyAdmin' => $this->faker->boolean(), + 'userId' => $this->faker->randomNumber(3) + ]; + } +} diff --git a/tests/SPT/Infrastructure/ItemPreset/Repositories/ItemPresetTest.php b/tests/SPT/Infrastructure/ItemPreset/Repositories/ItemPresetTest.php index b045c5bc..5923361d 100644 --- a/tests/SPT/Infrastructure/ItemPreset/Repositories/ItemPresetTest.php +++ b/tests/SPT/Infrastructure/ItemPreset/Repositories/ItemPresetTest.php @@ -82,6 +82,10 @@ class ItemPresetTest extends UnitaryTestCase $this->itemPreset->getByFilter('test', 100, 200, 300); } + /** + * @throws ConstraintException + * @throws QueryException + */ public function testDelete() { $id = self::$faker->randomNumber(); diff --git a/tests/SPT/Infrastructure/Notification/Repositories/NotificationTest.php b/tests/SPT/Infrastructure/Notification/Repositories/NotificationTest.php new file mode 100644 index 00000000..7c9142b9 --- /dev/null +++ b/tests/SPT/Infrastructure/Notification/Repositories/NotificationTest.php @@ -0,0 +1,504 @@ +. + */ + +namespace SPT\Infrastructure\Notification\Repositories; + +use Aura\SqlQuery\Common\DeleteInterface; +use Aura\SqlQuery\Common\InsertInterface; +use Aura\SqlQuery\Common\SelectInterface; +use Aura\SqlQuery\Common\UpdateInterface; +use Aura\SqlQuery\QueryFactory; +use PHPUnit\Framework\Constraint\Callback; +use SP\DataModel\ItemSearchData; +use SP\Domain\Common\Models\Simple; +use SP\Domain\Core\Exceptions\ConstraintException; +use SP\Domain\Core\Exceptions\QueryException; +use SP\Domain\Notification\Models\Notification as NotificationModel; +use SP\Infrastructure\Database\DatabaseInterface; +use SP\Infrastructure\Database\QueryData; +use SP\Infrastructure\Database\QueryResult; +use SP\Infrastructure\Notification\Repositories\Notification; +use SPT\Generators\NotificationDataGenerator; +use SPT\UnitaryTestCase; + +/** + * Class NotificationTest + * + * @group unitary + */ +class NotificationTest extends UnitaryTestCase +{ + + private Notification $notification; + + public function testGetByIdBatch() + { + $ids = [self::$faker->randomNumber(), self::$faker->randomNumber(), self::$faker->randomNumber()]; + + $callback = new Callback( + static function (QueryData $arg) use ($ids) { + $query = $arg->getQuery(); + $values = $query->getBindValues(); + + return count($values) === 3 + && array_shift($values) === array_shift($ids) + && array_shift($values) === array_shift($ids) + && array_shift($values) === array_shift($ids) + && $arg->getMapClassName() === NotificationModel::class + && is_a($query, SelectInterface::class) + && !empty($query->getStatement()); + } + ); + + $this->database + ->expects(self::once()) + ->method('doSelect') + ->with($callback); + + $this->notification->getByIdBatch($ids); + } + + public function testGetAllActiveForAdmin() + { + $callback = new Callback( + static function (QueryData $arg) { + $query = $arg->getQuery(); + $params = $query->getBindValues(); + + return count($params) === 1 + && $params['userId'] === 100 + && $arg->getMapClassName() === NotificationModel::class + && is_a($query, SelectInterface::class) + && !empty($query->getStatement()); + } + ); + + $this->database + ->expects(self::once()) + ->method('doSelect') + ->with($callback); + + $this->notification->getAllActiveForAdmin(100); + } + + public function testGetAllForUserId() + { + $callback = new Callback( + static function (QueryData $arg) { + $query = $arg->getQuery(); + $params = $query->getBindValues(); + + return count($params) === 1 + && $params['userId'] === 100 + && $arg->getMapClassName() === NotificationModel::class + && is_a($query, SelectInterface::class) + && !empty($query->getStatement()); + } + ); + + $this->database + ->expects(self::once()) + ->method('doSelect') + ->with($callback); + + $this->notification->getAllForUserId(100); + } + + /** + * @throws ConstraintException + * @throws QueryException + */ + public function testDelete() + { + $id = self::$faker->randomNumber(); + + $callback = new Callback( + static function (QueryData $arg) use ($id) { + $query = $arg->getQuery(); + + return $query->getBindValues()['id'] === $id + && is_a($query, DeleteInterface::class) + && !empty($query->getStatement()); + } + ); + + $this->database->expects(self::once())->method('doQuery')->with($callback); + + $this->notification->delete($id); + } + + /** + * @throws ConstraintException + * @throws QueryException + */ + public function testUpdate() + { + $notification = NotificationDataGenerator::factory()->buildNotification(); + + $callbackCreate = new Callback( + static function (QueryData $arg) use ($notification) { + $query = $arg->getQuery(); + $params = $query->getBindValues(); + + return count($params) === 9 + && $params['id'] === $notification->getId() + && $params['type'] === $notification->getType() + && $params['userId'] === $notification->getUserId() + && $params['component'] === $notification->getComponent() + && $params['description'] === $notification->getDescription() + && $params['date'] === $notification->getDate() + && $params['checked'] === $notification->isChecked() + && $params['sticky'] === $notification->isSticky() + && $params['onlyAdmin'] === $notification->isOnlyAdmin() + && is_a($query, UpdateInterface::class) + && !empty($query->getStatement()); + } + ); + + $queryResult = new QueryResult([]); + + $this->database + ->expects(self::exactly(1)) + ->method('doQuery') + ->with($callbackCreate) + ->willReturn($queryResult->setAffectedNumRows(1)); + + $out = $this->notification->update($notification); + + $this->assertEquals(1, $out); + } + + /** + * @throws ConstraintException + * @throws QueryException + */ + public function testSetCheckedById() + { + $callbackCreate = new Callback( + static function (QueryData $arg) { + $query = $arg->getQuery(); + $params = $query->getBindValues(); + + return count($params) === 2 + && $params['id'] === 100 + && $params['checked'] === 1 + && is_a($query, UpdateInterface::class) + && !empty($query->getStatement()); + } + ); + + $queryResult = new QueryResult([]); + + $this->database + ->expects(self::exactly(1)) + ->method('doQuery') + ->with($callbackCreate) + ->willReturn($queryResult->setAffectedNumRows(1)); + + $out = $this->notification->setCheckedById(100); + + $this->assertEquals(1, $out); + } + + public function testGetAllActiveForUserId() + { + $callback = new Callback( + static function (QueryData $arg) { + $query = $arg->getQuery(); + $params = $query->getBindValues(); + + return count($params) === 1 + && $params['userId'] === 100 + && $arg->getMapClassName() === NotificationModel::class + && is_a($query, SelectInterface::class) + && !empty($query->getStatement()); + } + ); + + $this->database + ->expects(self::once()) + ->method('doSelect') + ->with($callback); + + $this->notification->getAllForUserId(100); + } + + /** + * @throws ConstraintException + * @throws QueryException + */ + public function testDeleteAdminBatch() + { + $ids = [self::$faker->randomNumber(), self::$faker->randomNumber(), self::$faker->randomNumber()]; + + $callback = new Callback( + static function (QueryData $arg) use ($ids) { + $query = $arg->getQuery(); + $values = $query->getBindValues(); + + return count($values) === 3 + && array_shift($values) === array_shift($ids) + && array_shift($values) === array_shift($ids) + && array_shift($values) === array_shift($ids) + && $arg->getMapClassName() === Simple::class + && is_a($query, DeleteInterface::class) + && !empty($query->getStatement()); + } + ); + + $this->database + ->expects(self::once()) + ->method('doQuery') + ->with($callback); + + $this->notification->deleteAdminBatch($ids); + } + + /** + * @throws ConstraintException + * @throws QueryException + */ + public function testCreate() + { + $notification = NotificationDataGenerator::factory()->buildNotification(); + + $callbackCreate = new Callback( + static function (QueryData $arg) use ($notification) { + $query = $arg->getQuery(); + $params = $query->getBindValues(); + + return count($params) === 7 + && $params['type'] === $notification->getType() + && $params['userId'] === $notification->getUserId() + && $params['component'] === $notification->getComponent() + && $params['description'] === $notification->getDescription() + && $params['checked'] === $notification->isChecked() + && $params['sticky'] === $notification->isSticky() + && $params['onlyAdmin'] === $notification->isOnlyAdmin() + && is_a($query, InsertInterface::class) + && !empty($query->getStatement()); + } + ); + + $this->database + ->expects(self::exactly(1)) + ->method('doQuery') + ->with($callbackCreate) + ->willReturn(new QueryResult([])); + + $this->notification->create($notification); + } + + /** + * @throws ConstraintException + * @throws QueryException + */ + public function testDeleteAdmin() + { + $id = self::$faker->randomNumber(); + + $callback = new Callback( + static function (QueryData $arg) use ($id) { + $query = $arg->getQuery(); + + return $query->getBindValues()['id'] === $id + && is_a($query, DeleteInterface::class) + && !empty($query->getStatement()); + } + ); + + $this->database->expects(self::once())->method('doQuery')->with($callback); + + $this->notification->deleteAdmin($id); + } + + public function testGetById() + { + $callback = new Callback( + static function (QueryData $arg) { + $query = $arg->getQuery(); + $params = $query->getBindValues(); + + return count($params) === 1 + && $params['id'] === 100 + && $arg->getMapClassName() === NotificationModel::class + && is_a($query, SelectInterface::class) + && !empty($query->getStatement()); + } + ); + + $this->database + ->expects(self::once()) + ->method('doSelect') + ->with($callback); + + $this->notification->getById(100); + } + + /** + * @throws ConstraintException + * @throws QueryException + */ + public function testDeleteByIdBatch() + { + $ids = [self::$faker->randomNumber(), self::$faker->randomNumber(), self::$faker->randomNumber()]; + + $callback = new Callback( + static function (QueryData $arg) use ($ids) { + $query = $arg->getQuery(); + $values = $query->getBindValues(); + + return count($values) === 3 + && array_shift($values) === array_shift($ids) + && array_shift($values) === array_shift($ids) + && array_shift($values) === array_shift($ids) + && $arg->getMapClassName() === Simple::class + && is_a($query, DeleteInterface::class) + && !empty($query->getStatement()); + } + ); + + $this->database + ->expects(self::once()) + ->method('doQuery') + ->with($callback); + + $this->notification->deleteByIdBatch($ids); + } + + public function testSearchForUserId() + { + $item = new ItemSearchData(self::$faker->name); + + $callback = new Callback( + static function (QueryData $arg) use ($item) { + $query = $arg->getQuery(); + $params = $query->getBindValues(); + $searchStringLike = '%' . $item->getSeachString() . '%'; + + return count($params) === 3 + && $params['userId'] === 100 + && $params['type'] === $searchStringLike + && $params['component'] === $searchStringLike + && $arg->getMapClassName() === NotificationModel::class + && is_a($query, SelectInterface::class) + && !empty($query->getStatement()); + } + ); + + $this->database + ->expects(self::once()) + ->method('doSelect') + ->with($callback, true); + + $this->notification->searchForUserId($item, 100); + } + + public function testSearchForAdmin() + { + $item = new ItemSearchData(self::$faker->name); + + $callback = new Callback( + static function (QueryData $arg) use ($item) { + $query = $arg->getQuery(); + $params = $query->getBindValues(); + $searchStringLike = '%' . $item->getSeachString() . '%'; + + return count($params) === 3 + && $params['userId'] === 100 + && $params['type'] === $searchStringLike + && $params['component'] === $searchStringLike + && $arg->getMapClassName() === NotificationModel::class + && is_a($query, SelectInterface::class) + && !empty($query->getStatement()); + } + ); + + $this->database + ->expects(self::once()) + ->method('doSelect') + ->with($callback, true); + + $this->notification->searchForAdmin($item, 100); + } + + public function testGetAll() + { + $callback = new Callback( + static function (QueryData $arg) { + $query = $arg->getQuery(); + + return $arg->getMapClassName() === NotificationModel::class + && is_a($query, SelectInterface::class) + && !empty($query->getStatement()); + } + ); + + $this->database + ->expects(self::once()) + ->method('doSelect') + ->with($callback); + + $this->notification->getAll(); + } + + public function testGetForUserIdByDate() + { + $callback = new Callback( + static function (QueryData $arg) { + $query = $arg->getQuery(); + $params = $query->getBindValues(); + + return count($params) === 2 + && $params['userId'] === 100 + && $params['component'] === 'test' + && $arg->getMapClassName() === NotificationModel::class + && is_a($query, SelectInterface::class) + && !empty($query->getStatement()); + } + ); + + $this->database + ->expects(self::once()) + ->method('doSelect') + ->with($callback); + + $this->notification->getForUserIdByDate('test', 100); + } + + protected function setUp(): void + { + parent::setUp(); + + $this->database = $this->createMock(DatabaseInterface::class); + $queryFactory = new QueryFactory('mysql'); + + $this->notification = new Notification( + $this->database, + $this->context, + $this->application->getEventDispatcher(), + $queryFactory, + ); + } +}