diff --git a/lib/SP/Domain/Account/In/AccountToUserRepositoryInterface.php b/lib/SP/Domain/Account/In/AccountToUserRepositoryInterface.php index 5197680c..71401b9c 100644 --- a/lib/SP/Domain/Account/In/AccountToUserRepositoryInterface.php +++ b/lib/SP/Domain/Account/In/AccountToUserRepositoryInterface.php @@ -26,7 +26,6 @@ namespace SP\Domain\Account\In; use SP\Core\Exceptions\ConstraintException; use SP\Core\Exceptions\QueryException; -use SP\Domain\Account\Services\AccountRequest; use SP\Domain\Common\In\RepositoryInterface; use SP\Infrastructure\Database\QueryResult; @@ -38,52 +37,40 @@ use SP\Infrastructure\Database\QueryResult; interface AccountToUserRepositoryInterface extends RepositoryInterface { /** - * Actualizar la asociación de grupos con cuentas. + * Eliminar la asociación de grupos con cuentas. * - * @param AccountRequest $accountRequest + * @param int $id con el Id de la cuenta + * @param bool $isEdit * + * @return void + * @throws ConstraintException + * @throws QueryException + */ + public function deleteTypeByAccountId(int $id, bool $isEdit): void; + + /** + * Crear asociación de usuarios con cuentas. + * + * @param int $accountId + * @param array $items * @param bool $isEdit * * @return void * @throws \SP\Core\Exceptions\ConstraintException * @throws \SP\Core\Exceptions\QueryException */ - public function updateByType(AccountRequest $accountRequest, bool $isEdit): void; - - /** - * Eliminar la asociación de grupos con cuentas. - * - * @param int $id con el Id de la cuenta - * @param bool $isEdit - * - * @return int - * @throws ConstraintException - * @throws QueryException - */ - public function deleteTypeByAccountId(int $id, bool $isEdit): int; - - /** - * Crear asociación de usuarios con cuentas. - * - * @param AccountRequest $accountRequest - * @param bool $isEdit - * - * @return int - * @throws \SP\Core\Exceptions\ConstraintException - * @throws \SP\Core\Exceptions\QueryException - */ - public function addByType(AccountRequest $accountRequest, bool $isEdit): int; + public function addByType(int $accountId, array $items, bool $isEdit): void; /** * Eliminar la asociación de grupos con cuentas. * * @param int $id con el Id de la cuenta * - * @return int + * @return bool * @throws ConstraintException * @throws QueryException */ - public function deleteByAccountId(int $id): int; + public function deleteByAccountId(int $id): bool; /** * Obtiene el listado de usuarios de una cuenta. diff --git a/lib/SP/Domain/Account/Services/AccountService.php b/lib/SP/Domain/Account/Services/AccountService.php index 07394847..7ad1921b 100644 --- a/lib/SP/Domain/Account/Services/AccountService.php +++ b/lib/SP/Domain/Account/Services/AccountService.php @@ -485,15 +485,14 @@ final class AccountService extends Service implements AccountServiceInterface if ($accountRequest->changePermissions) { if ($accountRequest->userGroupsView !== null) { if (count($accountRequest->userGroupsView) > 0) { - $this->accountToUserGroupRepository - ->transactionAware( - function () use ($accountRequest) { - $this->accountToUserGroupRepository - ->deleteTypeByAccountId($accountRequest->id, false); - $this->accountToUserGroupRepository - ->addByType($accountRequest->id, $accountRequest->userGroupsView, false); - } - ); + $this->accountToUserGroupRepository->transactionAware( + function () use ($accountRequest) { + $this->accountToUserGroupRepository + ->deleteTypeByAccountId($accountRequest->id, false); + $this->accountToUserGroupRepository + ->addByType($accountRequest->id, $accountRequest->userGroupsView, false); + } + ); } else { $this->accountToUserGroupRepository->deleteTypeByAccountId($accountRequest->id, false); } @@ -501,15 +500,14 @@ final class AccountService extends Service implements AccountServiceInterface if ($accountRequest->userGroupsEdit !== null) { if (count($accountRequest->userGroupsEdit) > 0) { - $this->accountToUserGroupRepository - ->transactionAware( - function () use ($accountRequest) { - $this->accountToUserGroupRepository - ->deleteTypeByAccountId($accountRequest->id, true); - $this->accountToUserGroupRepository - ->addByType($accountRequest->id, $accountRequest->userGroupsEdit, true); - } - ); + $this->accountToUserGroupRepository->transactionAware( + function () use ($accountRequest) { + $this->accountToUserGroupRepository + ->deleteTypeByAccountId($accountRequest->id, true); + $this->accountToUserGroupRepository + ->addByType($accountRequest->id, $accountRequest->userGroupsEdit, true); + } + ); } else { $this->accountToUserGroupRepository->deleteTypeByAccountId($accountRequest->id, true); } @@ -517,7 +515,14 @@ final class AccountService extends Service implements AccountServiceInterface if ($accountRequest->usersView !== null) { if (count($accountRequest->usersView) > 0) { - $this->accountToUserRepository->updateByType($accountRequest, false); + $this->accountToUserRepository->transactionAware( + function () use ($accountRequest) { + $this->accountToUserRepository + ->deleteTypeByAccountId($accountRequest->id, false); + $this->accountToUserRepository + ->addByType($accountRequest->id, $accountRequest->usersView, false); + } + ); } else { $this->accountToUserRepository->deleteTypeByAccountId($accountRequest->id, false); } @@ -525,7 +530,14 @@ final class AccountService extends Service implements AccountServiceInterface if ($accountRequest->usersEdit !== null) { if (count($accountRequest->usersEdit) > 0) { - $this->accountToUserRepository->updateByType($accountRequest, true); + $this->accountToUserRepository->transactionAware( + function () use ($accountRequest) { + $this->accountToUserRepository + ->deleteTypeByAccountId($accountRequest->id, true); + $this->accountToUserRepository + ->addByType($accountRequest->id, $accountRequest->usersEdit, true); + } + ); } else { $this->accountToUserRepository->deleteTypeByAccountId($accountRequest->id, true); } diff --git a/lib/SP/Infrastructure/Account/Repositories/AccountToUserRepository.php b/lib/SP/Infrastructure/Account/Repositories/AccountToUserRepository.php index 612836f3..ffa35c8a 100644 --- a/lib/SP/Infrastructure/Account/Repositories/AccountToUserRepository.php +++ b/lib/SP/Infrastructure/Account/Repositories/AccountToUserRepository.php @@ -28,11 +28,12 @@ use SP\Core\Exceptions\ConstraintException; use SP\Core\Exceptions\QueryException; use SP\DataModel\ItemData; use SP\Domain\Account\In\AccountToUserRepositoryInterface; -use SP\Domain\Account\Services\AccountRequest; +use SP\Domain\Common\In\Query; use SP\Infrastructure\Common\Repositories\Repository; use SP\Infrastructure\Common\Repositories\RepositoryItemTrait; use SP\Infrastructure\Database\QueryData; use SP\Infrastructure\Database\QueryResult; +use function SP\__u; /** * Class AccountToUserRepository @@ -44,76 +45,61 @@ final class AccountToUserRepository extends Repository implements AccountToUserR use RepositoryItemTrait; /** - * Actualizar la asociación de grupos con cuentas. + * Eliminar la asociación de grupos con cuentas. * - * @param AccountRequest $accountRequest + * @param int $id con el Id de la cuenta * @param bool $isEdit * * @return void * @throws \SP\Core\Exceptions\ConstraintException * @throws \SP\Core\Exceptions\QueryException */ - public function updateByType(AccountRequest $accountRequest, bool $isEdit): void + public function deleteTypeByAccountId(int $id, bool $isEdit): void { - $this->deleteTypeByAccountId($accountRequest->id, $isEdit); - $this->addByType($accountRequest, $isEdit); - } + $query = $this->queryFactory + ->newDelete() + ->from('AccountToUser') + ->where('accountId = :accountId') + ->where('isEdit = :isEdit') + ->bindValues([ + 'accountId' => $id, + 'isEdit' => (int)$isEdit, + ]); - /** - * Eliminar la asociación de grupos con cuentas. - * - * @param int $id con el Id de la cuenta - * @param bool $isEdit - * - * @return int - * @throws ConstraintException - * @throws QueryException - */ - public function deleteTypeByAccountId(int $id, bool $isEdit): int - { - $queryData = new QueryData(); - $queryData->setQuery('DELETE FROM AccountToUser WHERE accountId = ? AND isEdit = ?'); - $queryData->setParams([$id, (int)$isEdit]); - $queryData->setOnErrorMessage(__u('Error while deleting the account users')); + $queryData = QueryData::build($query)->setOnErrorMessage(__u('Error while deleting the account\'s groups')); - return $this->db->doQuery($queryData)->getAffectedNumRows(); + $this->db->doQuery($queryData); } /** * Crear asociación de usuarios con cuentas. * - * @param AccountRequest $accountRequest + * @param int $accountId + * @param array $items * @param bool $isEdit * - * @return int + * @return void * @throws \SP\Core\Exceptions\ConstraintException * @throws \SP\Core\Exceptions\QueryException */ - public function addByType(AccountRequest $accountRequest, bool $isEdit): int + public function addByType(int $accountId, array $items, bool $isEdit): void { - $items = $isEdit ? $accountRequest->usersEdit : $accountRequest->usersView; - $values = $this->buildParamsFromArray($items, '(?,?,?)'); + $values = array_map(static function ($item) use ($accountId, $isEdit) { + return [$accountId, (int)$item, (int)$isEdit]; + }, $items); + + $parameters = $this->buildParamsFromArray($values, '(?,?,?)'); $query = /** @lang SQL */ 'INSERT INTO AccountToUser (accountId, userId, isEdit) - VALUES '.$values.' - ON DUPLICATE KEY UPDATE isEdit = '.(int)$isEdit; + VALUES '.$parameters.' + ON DUPLICATE KEY UPDATE isEdit = ?'; - $queryData = new QueryData(); - $queryData->setQuery($query); - $queryData->setOnErrorMessage(__u('Error while updating the account users')); + $queryData = QueryData::build( + Query::buildForMySQL($query, array_merge_recursive($values)) + )->setOnErrorMessage(__u('Error while updating the account users')); - $params = []; - - foreach ($items as $user) { - $params[] = $accountRequest->id; - $params[] = $user; - $params[] = (int)$isEdit; - } - - $queryData->setParams($params); - - return $this->db->doQuery($queryData)->getAffectedNumRows(); + $this->db->doQuery($queryData); } /** @@ -121,18 +107,23 @@ final class AccountToUserRepository extends Repository implements AccountToUserR * * @param int $id con el Id de la cuenta * - * @return int + * @return bool * @throws ConstraintException * @throws QueryException */ - public function deleteByAccountId(int $id): int + public function deleteByAccountId(int $id): bool { - $queryData = new QueryData(); - $queryData->setQuery('DELETE FROM AccountToUser WHERE accountId = ?'); - $queryData->addParam($id); - $queryData->setOnErrorMessage(__u('Error while deleting the account users')); + $query = $this->queryFactory + ->newDelete() + ->from('AccountToUser') + ->where('accountId = :accountId') + ->bindValues([ + 'accountId' => $id, + ]); - return $this->db->doQuery($queryData)->getAffectedNumRows(); + $queryData = QueryData::build($query)->setOnErrorMessage(__u('Error while deleting the account users')); + + return $this->db->doQuery($queryData)->getAffectedNumRows() === 1; } /** @@ -141,23 +132,23 @@ final class AccountToUserRepository extends Repository implements AccountToUserR * @param int $id con el id de la cuenta * * @return QueryResult - * @throws ConstraintException - * @throws QueryException */ public function getUsersByAccountId(int $id): QueryResult { - $query = /** @lang SQL */ - 'SELECT `User`.id, `User`.name, `User`.login, AccountToUser.isEdit - FROM AccountToUser - INNER JOIN `User` ON AccountToUser.userId = `User`.id - WHERE AccountToUser.accountId = ? - ORDER BY `User`.name'; + $query = $this->queryFactory + ->newSelect() + ->cols([ + 'User.id', + 'User.name', + 'User.login', + 'AccountToUser.isEdit', + ]) + ->from('AccountToUser') + ->join('INNER', 'User', 'User.id == AccountToUser.userId') + ->where('AccountToUser.accountId = :accountId') + ->bindValues(['accountId' => $id]) + ->orderBy(['User.name ASC']); - $queryData = new QueryData(); - $queryData->setQuery($query); - $queryData->addParam($id); - $queryData->setMapClassName(ItemData::class); - - return $this->db->doSelect($queryData); + return $this->db->doSelect(QueryData::build($query)->setMapClassName(ItemData::class)); } -} \ No newline at end of file +} diff --git a/tests/SP/Infrastructure/Account/Repositories/AccountToUserRepositoryTest.php b/tests/SP/Infrastructure/Account/Repositories/AccountToUserRepositoryTest.php new file mode 100644 index 00000000..f069887c --- /dev/null +++ b/tests/SP/Infrastructure/Account/Repositories/AccountToUserRepositoryTest.php @@ -0,0 +1,197 @@ +. + */ + +namespace SP\Tests\Infrastructure\Account\Repositories; + +use Aura\SqlQuery\QueryFactory; +use PHPUnit\Framework\Constraint\Callback; +use PHPUnit\Framework\MockObject\MockObject; +use SP\DataModel\ItemData; +use SP\Infrastructure\Account\Repositories\AccountToUserRepository; +use SP\Infrastructure\Database\DatabaseInterface; +use SP\Infrastructure\Database\QueryData; +use SP\Infrastructure\Database\QueryResult; +use SP\Tests\UnitaryTestCase; + +/** + * Class AccountToUserRepositoryTest + */ +class AccountToUserRepositoryTest extends UnitaryTestCase +{ + private MockObject|DatabaseInterface $database; + private AccountToUserRepository $accountToUserRepository; + + /** + * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Core\Exceptions\ConstraintException + */ + public function testDeleteTypeByAccountId(): void + { + $accountId = self::$faker->randomNumber(); + + $expected = new QueryResult(); + $expected->setAffectedNumRows(1); + + $callback = new Callback( + static function (QueryData $arg) use ($accountId) { + $query = $arg->getQuery(); + $params = $query->getBindValues(); + + return $params['accountId'] === $accountId + && !empty($query->getStatement()); + } + ); + + $this->database + ->expects(self::once()) + ->method('doQuery') + ->with($callback) + ->willReturn($expected); + + $this->assertTrue($this->accountToUserRepository->deleteByAccountId($accountId)); + } + + public function testGetUserGroupsByAccountId(): void + { + $id = self::$faker->randomNumber(); + + $callback = new Callback( + static function (QueryData $arg) use ($id) { + $query = $arg->getQuery(); + + return $query->getBindValues()['accountId'] === $id + && $arg->getMapClassName() === ItemData::class + && !empty($query->getStatement()); + } + ); + + $this->database + ->expects(self::once()) + ->method('doSelect') + ->with($callback) + ->willReturn(new QueryResult()); + + $this->accountToUserRepository->getUsersByAccountId($id); + } + + /** + * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Core\Exceptions\ConstraintException + */ + public function testDeleteByUserGroupId(): void + { + + $accountId = self::$faker->randomNumber(); + + $expected = new QueryResult(); + $expected->setAffectedNumRows(1); + + $callback = new Callback( + static function (QueryData $arg) use ($accountId) { + $query = $arg->getQuery(); + $params = $query->getBindValues(); + + return $params['accountId'] === $accountId + && !empty($query->getStatement()); + } + ); + + $this->database + ->expects(self::once()) + ->method('doQuery') + ->with($callback) + ->willReturn($expected); + + $this->assertTrue($this->accountToUserRepository->deleteByAccountId($accountId)); + } + + /** + * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Core\Exceptions\ConstraintException + */ + public function testAddByType(): void + { + $userGroups = self::getRandomNumbers(10); + + $callback = new Callback( + static fn(QueryData $arg) => !empty($arg->getQuery()->getStatement()) + ); + + $this->database + ->expects(self::once()) + ->method('doQuery') + ->with($callback); + + $this->accountToUserRepository->addByType( + self::$faker->randomNumber(), + $userGroups, + self::$faker->boolean + ); + } + + /** + * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Core\Exceptions\ConstraintException + */ + public function testDeleteByAccountId(): void + { + $accountId = self::$faker->randomNumber(); + + $expected = new QueryResult(); + $expected->setAffectedNumRows(1); + + $callback = new Callback( + static function (QueryData $arg) use ($accountId) { + $query = $arg->getQuery(); + $params = $query->getBindValues(); + + return $params['accountId'] === $accountId + && !empty($query->getStatement()); + } + ); + + $this->database + ->expects(self::once()) + ->method('doQuery') + ->with($callback) + ->willReturn($expected); + + $this->assertTrue($this->accountToUserRepository->deleteByAccountId($accountId)); + } + + protected function setUp(): void + { + parent::setUp(); + + $this->database = $this->createMock(DatabaseInterface::class); + $queryFactory = new QueryFactory('mysql'); + + $this->accountToUserRepository = new AccountToUserRepository( + $this->database, + $this->context, + $this->application->getEventDispatcher(), + $queryFactory, + ); + } +}