diff --git a/app/modules/api/Controllers/Tag/CreateController.php b/app/modules/api/Controllers/Tag/CreateController.php index e17adf9b..52923797 100644 --- a/app/modules/api/Controllers/Tag/CreateController.php +++ b/app/modules/api/Controllers/Tag/CreateController.php @@ -28,10 +28,10 @@ namespace SP\Modules\Api\Controllers\Tag; use Exception; use SP\Core\Events\Event; use SP\Core\Events\EventMessage; -use SP\DataModel\TagData; use SP\Domain\Api\Dtos\ApiResponse; use SP\Domain\Common\Services\ServiceException; use SP\Domain\Core\Acl\AclActionsInterface; +use SP\Domain\Tag\Models\Tag; /** * Class CreateController @@ -72,12 +72,12 @@ final class CreateController extends TagBase } /** - * @return TagData + * @return Tag * @throws ServiceException */ - private function buildTagData(): TagData + private function buildTagData(): Tag { - $tagData = new TagData(); + $tagData = new Tag(); $tagData->setName($this->apiService->getParamString('name', true)); return $tagData; diff --git a/app/modules/api/Controllers/Tag/EditController.php b/app/modules/api/Controllers/Tag/EditController.php index 9d2052c0..946c6960 100644 --- a/app/modules/api/Controllers/Tag/EditController.php +++ b/app/modules/api/Controllers/Tag/EditController.php @@ -28,10 +28,10 @@ namespace SP\Modules\Api\Controllers\Tag; use Exception; use SP\Core\Events\Event; use SP\Core\Events\EventMessage; -use SP\DataModel\TagData; use SP\Domain\Api\Dtos\ApiResponse; use SP\Domain\Common\Services\ServiceException; use SP\Domain\Core\Acl\AclActionsInterface; +use SP\Domain\Tag\Models\Tag; /** * Class EditController @@ -70,12 +70,12 @@ final class EditController extends TagBase } /** - * @return TagData + * @return Tag * @throws ServiceException */ - private function buildTagData(): TagData + private function buildTagData(): Tag { - $tagData = new TagData(); + $tagData = new Tag(); $tagData->setId($this->apiService->getParamInt('id', true)); $tagData->setName($this->apiService->getParamString('name', true)); diff --git a/app/modules/web/Controllers/Tag/TagViewBase.php b/app/modules/web/Controllers/Tag/TagViewBase.php index 265c3c9a..49d13b0f 100644 --- a/app/modules/web/Controllers/Tag/TagViewBase.php +++ b/app/modules/web/Controllers/Tag/TagViewBase.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -27,10 +27,10 @@ namespace SP\Modules\Web\Controllers\Tag; use SP\Core\Acl\Acl; use SP\Core\Application; -use SP\DataModel\TagData; use SP\Domain\Core\Acl\AclActionsInterface; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; +use SP\Domain\Tag\Models\Tag; use SP\Domain\Tag\Ports\TagServiceInterface; use SP\Infrastructure\Common\Repositories\NoSuchItemException; use SP\Modules\Web\Controllers\ControllerBase; @@ -70,7 +70,7 @@ abstract class TagViewBase extends ControllerBase $tag = $tagId ? $this->tagService->getById($tagId) - : new TagData(); + : new Tag(); $this->view->assign('tag', $tag); diff --git a/app/modules/web/Forms/TagForm.php b/app/modules/web/Forms/TagForm.php index e0a8262e..91b1fcf2 100644 --- a/app/modules/web/Forms/TagForm.php +++ b/app/modules/web/Forms/TagForm.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -24,9 +24,9 @@ namespace SP\Modules\Web\Forms; -use SP\DataModel\TagData; use SP\Domain\Core\Acl\AclActionsInterface; use SP\Domain\Core\Exceptions\ValidationException; +use SP\Domain\Tag\Models\Tag; /** * Class TagForm @@ -35,7 +35,7 @@ use SP\Domain\Core\Exceptions\ValidationException; */ final class TagForm extends FormBase implements FormInterface { - protected ?TagData $tagData = null; + protected ?Tag $tagData = null; /** * Validar el formulario @@ -70,7 +70,7 @@ final class TagForm extends FormBase implements FormInterface */ protected function analyzeRequestData(): void { - $this->tagData = new TagData(); + $this->tagData = new Tag(); $this->tagData->setId($this->itemId); $this->tagData->setName($this->request->analyzeString('name')); } @@ -85,7 +85,7 @@ final class TagForm extends FormBase implements FormInterface } } - public function getItemData(): ?TagData + public function getItemData(): ?Tag { return $this->tagData; } diff --git a/app/modules/web/themes/material-blue/views/itemshow/tag.inc b/app/modules/web/themes/material-blue/views/itemshow/tag.inc index b34110a5..6212984c 100644 --- a/app/modules/web/themes/material-blue/views/itemshow/tag.inc +++ b/app/modules/web/themes/material-blue/views/itemshow/tag.inc @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -23,16 +23,16 @@ */ /** - * @var TagData $tag + * @var \SP\Domain\Tag\Models\Tag $tag * @var ThemeIconsInterface $icons * @var ConfigDataInterface $configData * @var callable $_getvar * @var TemplateInterface $this */ -use SP\DataModel\TagData; use SP\Domain\Config\Ports\ConfigDataInterface; use SP\Domain\Core\UI\ThemeIconsInterface; +use SP\Domain\Tag\Models\Tag; use SP\Mvc\View\TemplateInterface; $tag = $_getvar('tag'); diff --git a/lib/SP/DataModel/TagData.php b/lib/SP/DataModel/TagData.php deleted file mode 100644 index 861bec84..00000000 --- a/lib/SP/DataModel/TagData.php +++ /dev/null @@ -1,108 +0,0 @@ -. - */ - -namespace SP\DataModel; - -use SP\Domain\Common\Adapters\DataModelInterface; -use SP\Domain\Common\Models\Model; - -defined('APP_ROOT') || die(); - -/** - * Class TagData - * - * @package SP\Mgmt\Tags - */ -class TagData extends Model implements DataModelInterface -{ - /** - * @var int - */ - public $id = 0; - /** - * @var string - */ - public $name = ''; - /** - * @var string - */ - public $hash = ''; - - /** - * @return int - */ - public function getId() - { - return (int)$this->id; - } - - /** - * @param int $id - */ - public function setId($id) - { - $this->id = (int)$id; - } - - /** - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * @param string $name - */ - public function setName($name) - { - $this->name = $name; - $this->createTagHash(); - } - - /** - * Formatear el nombre de la etiqueta y devolver un hash - */ - protected function createTagHash() - { - $this->hash = sha1(strtolower(preg_replace('#[\.\s_,\-;\'":()|/"]+#', '', $this->name))); - } - - /** - * @return string - */ - public function getHash() - { - return $this->hash; - } - - /** - * @param string $hash - */ - public function setHash($hash) - { - $this->hash = $hash; - } -} diff --git a/lib/SP/Domain/Export/Services/XmlTagExport.php b/lib/SP/Domain/Export/Services/XmlTagExport.php index 0973a7e4..c2051a7a 100644 --- a/lib/SP/Domain/Export/Services/XmlTagExport.php +++ b/lib/SP/Domain/Export/Services/XmlTagExport.php @@ -22,7 +22,7 @@ * along with sysPass. If not, see . */ -namespace SP\Domain\Export\Ports; +namespace SP\Domain\Export\Services; use DOMDocument; use DOMElement; @@ -32,7 +32,8 @@ use SP\Core\Events\Event; use SP\Core\Events\EventMessage; use SP\Domain\Common\Services\Service; use SP\Domain\Common\Services\ServiceException; -use SP\Domain\Tag\Services\TagService; +use SP\Domain\Export\Ports\XmlTagExportService; +use SP\Domain\Tag\Ports\TagServiceInterface; use function SP\__u; @@ -42,8 +43,8 @@ use function SP\__u; final class XmlTagExport extends Service implements XmlTagExportService { public function __construct( - Application $application, - private readonly TagService $tagService, + Application $application, + private readonly TagServiceInterface $tagService, ) { parent::__construct($application); diff --git a/lib/SP/Domain/Import/Services/ImportTrait.php b/lib/SP/Domain/Import/Services/ImportTrait.php index daae1213..ad4dd467 100644 --- a/lib/SP/Domain/Import/Services/ImportTrait.php +++ b/lib/SP/Domain/Import/Services/ImportTrait.php @@ -26,7 +26,6 @@ namespace SP\Domain\Import\Services; use Defuse\Crypto\Exception\CryptoException; use SP\Core\Crypt\Crypt; -use SP\DataModel\TagData; use SP\Domain\Account\Dtos\AccountRequest; use SP\Domain\Account\Ports\AccountService; use SP\Domain\Category\Models\Category; @@ -37,6 +36,7 @@ use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\NoSuchPropertyException; use SP\Domain\Core\Exceptions\QueryException; use SP\Domain\Core\Exceptions\SPException; +use SP\Domain\Tag\Models\Tag; use SP\Domain\Tag\Ports\TagServiceInterface; use SP\Infrastructure\Common\Repositories\DuplicatedItemException; @@ -202,12 +202,12 @@ trait ImportTrait /** * Añadir una etiqueta y devolver el Id * - * @param TagData $tagData + * @param Tag $tagData * * @return int * @throws SPException */ - protected function addTag(TagData $tagData): int + protected function addTag(Tag $tagData): int { try { $tagId = $this->getWorkingItem('tag', $tagData->getName()); diff --git a/lib/SP/Domain/Import/Services/SyspassImport.php b/lib/SP/Domain/Import/Services/SyspassImport.php index 7167c11e..4736b869 100644 --- a/lib/SP/Domain/Import/Services/SyspassImport.php +++ b/lib/SP/Domain/Import/Services/SyspassImport.php @@ -34,12 +34,12 @@ use SP\Core\Crypt\Crypt; use SP\Core\Crypt\Hash; use SP\Core\Events\Event; use SP\Core\Events\EventMessage; -use SP\DataModel\TagData; use SP\Domain\Account\Dtos\AccountRequest; use SP\Domain\Category\Models\Category; use SP\Domain\Client\Models\Client; use SP\Domain\Core\Exceptions\SPException; use SP\Domain\Export\Services\XmlVerifyService; +use SP\Domain\Tag\Models\Tag; use SP\Util\VersionUtil; defined('APP_ROOT') || die(); @@ -379,7 +379,7 @@ final class SyspassImport extends XmlImportBase implements ImportInterface 'Tags', 'Tag', function (DOMElement $tag) { - $tagData = new TagData(); + $tagData = new Tag(); foreach ($tag->childNodes as $node) { if (isset($node->tagName) && $node->tagName === 'name') { diff --git a/lib/SP/Domain/Tag/Models/Tag.php b/lib/SP/Domain/Tag/Models/Tag.php new file mode 100644 index 00000000..1e87b570 --- /dev/null +++ b/lib/SP/Domain/Tag/Models/Tag.php @@ -0,0 +1,58 @@ +. + */ + +namespace SP\Domain\Tag\Models; + +use SP\Domain\Common\Adapters\DataModelInterface; +use SP\Domain\Common\Models\Model; + +/** + * Class Tag + */ +class Tag extends Model implements DataModelInterface +{ + protected ?int $id = null; + protected ?string $name = null; + protected ?string $hash = null; + + public function getId(): ?int + { + return (int)$this->id; + } + + public function getName(): ?string + { + return $this->name; + } + + public function withHash(): Tag + { + return $this->mutate(['hash' => sha1(strtolower(preg_replace('#[.\s_,\-;\'":()|/]+#', '', $this->name)))]); + } + + public function getHash(): ?string + { + return $this->hash; + } +} diff --git a/lib/SP/Domain/Tag/Ports/TagServiceInterface.php b/lib/SP/Domain/Tag/Ports/TagServiceInterface.php index 44d94922..0e91acda 100644 --- a/lib/SP/Domain/Tag/Ports/TagServiceInterface.php +++ b/lib/SP/Domain/Tag/Ports/TagServiceInterface.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -25,10 +25,10 @@ namespace SP\Domain\Tag\Ports; use SP\DataModel\ItemSearchData; -use SP\DataModel\TagData; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; use SP\Domain\Core\Exceptions\SPException; +use SP\Domain\Tag\Models\Tag; use SP\Infrastructure\Common\Repositories\DuplicatedItemException; use SP\Infrastructure\Common\Repositories\NoSuchItemException; use SP\Infrastructure\Database\QueryResult; @@ -51,14 +51,14 @@ interface TagServiceInterface * @throws QueryException * @throws NoSuchItemException */ - public function getById(int $id): TagData; + public function getById(int $id): Tag; /** * @throws NoSuchItemException * @throws ConstraintException * @throws QueryException */ - public function getByName(string $name): ?TagData; + public function getByName(string $name): ?Tag; /** * @throws ConstraintException @@ -79,19 +79,19 @@ interface TagServiceInterface * @throws QueryException * @throws DuplicatedItemException */ - public function create(TagData $itemData): int; + public function create(Tag $itemData): int; /** * @throws SPException * @throws ConstraintException * @throws QueryException */ - public function update(TagData $itemData): int; + public function update(Tag $itemData): int; /** * Get all items from the service's repository * - * @return TagData[] + * @return \SP\Domain\Tag\Models\Tag[] * @throws ConstraintException * @throws QueryException */ diff --git a/lib/SP/Domain/Tag/Services/TagService.php b/lib/SP/Domain/Tag/Services/TagService.php index 13b49391..63b53031 100644 --- a/lib/SP/Domain/Tag/Services/TagService.php +++ b/lib/SP/Domain/Tag/Services/TagService.php @@ -26,13 +26,13 @@ namespace SP\Domain\Tag\Services; use SP\Core\Application; use SP\DataModel\ItemSearchData; -use SP\DataModel\TagData; use SP\Domain\Common\Services\Service; use SP\Domain\Common\Services\ServiceException; use SP\Domain\Common\Services\ServiceItemTrait; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; use SP\Domain\Core\Exceptions\SPException; +use SP\Domain\Tag\Models\Tag; use SP\Domain\Tag\Ports\TagRepository; use SP\Domain\Tag\Ports\TagServiceInterface; use SP\Infrastructure\Common\Repositories\DuplicatedItemException; @@ -72,7 +72,7 @@ final class TagService extends Service implements TagServiceInterface * @throws QueryException * @throws NoSuchItemException */ - public function getById(int $id): TagData + public function getById(int $id): Tag { $result = $this->tagRepository->getById($id); @@ -88,7 +88,7 @@ final class TagService extends Service implements TagServiceInterface * @throws ConstraintException * @throws QueryException */ - public function getByName(string $name): ?TagData + public function getByName(string $name): ?Tag { $result = $this->tagRepository->getByName($name); @@ -132,7 +132,7 @@ final class TagService extends Service implements TagServiceInterface * @throws QueryException * @throws DuplicatedItemException */ - public function create(TagData $itemData): int + public function create(Tag $itemData): int { return $this->tagRepository->create($itemData); } @@ -142,7 +142,7 @@ final class TagService extends Service implements TagServiceInterface * @throws ConstraintException * @throws QueryException */ - public function update(TagData $itemData): int + public function update(Tag $itemData): int { return $this->tagRepository->update($itemData); } @@ -150,7 +150,7 @@ final class TagService extends Service implements TagServiceInterface /** * Get all items from the service's repository * - * @return TagData[] + * @return Tag[] * @throws ConstraintException * @throws QueryException */ diff --git a/lib/SP/Infrastructure/Tag/Repositories/TagBaseRepository.php b/lib/SP/Infrastructure/Tag/Repositories/TagBaseRepository.php index b48f3aeb..b0a2a14e 100644 --- a/lib/SP/Infrastructure/Tag/Repositories/TagBaseRepository.php +++ b/lib/SP/Infrastructure/Tag/Repositories/TagBaseRepository.php @@ -25,9 +25,9 @@ namespace SP\Infrastructure\Tag\Repositories; use SP\DataModel\ItemSearchData; -use SP\DataModel\TagData; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; +use SP\Domain\Tag\Models\Tag; use SP\Domain\Tag\Ports\TagRepository; use SP\Infrastructure\Common\Repositories\BaseRepository; use SP\Infrastructure\Common\Repositories\DuplicatedItemException; @@ -47,7 +47,7 @@ final class TagBaseRepository extends BaseRepository implements TagRepository /** * Creates an item * - * @param TagData $itemData + * @param Tag $itemData * * @return int * @throws ConstraintException @@ -74,7 +74,7 @@ final class TagBaseRepository extends BaseRepository implements TagRepository /** * Checks whether the item is duplicated on adding * - * @param TagData $itemData + * @param Tag $itemData * * @return bool * @throws ConstraintException @@ -95,7 +95,7 @@ final class TagBaseRepository extends BaseRepository implements TagRepository /** * Updates an item * - * @param TagData $itemData + * @param Tag $itemData * * @return int * @throws ConstraintException @@ -123,7 +123,7 @@ final class TagBaseRepository extends BaseRepository implements TagRepository /** * Checks whether the item is duplicated on updating * - * @param TagData $itemData + * @param Tag $itemData * * @return bool * @throws ConstraintException @@ -154,7 +154,7 @@ final class TagBaseRepository extends BaseRepository implements TagRepository public function getById(int $id): QueryResult { $queryData = new QueryData(); - $queryData->setMapClassName(TagData::class); + $queryData->setMapClassName(Tag::class); $queryData->setQuery('SELECT id, `name` FROM Tag WHERE id = ? ORDER BY `name` LIMIT 1'); $queryData->addParam($id); @@ -173,7 +173,7 @@ final class TagBaseRepository extends BaseRepository implements TagRepository public function getByName(string $name): QueryResult { $queryData = new QueryData(); - $queryData->setMapClassName(TagData::class); + $queryData->setMapClassName(Tag::class); $queryData->setQuery('SELECT id, `name` FROM Tag WHERE `hash` = ? OR `name` = ? ORDER BY `name` LIMIT 1'); $queryData->setParams([$this->makeItemHash($name), $name]); @@ -183,14 +183,14 @@ final class TagBaseRepository extends BaseRepository implements TagRepository /** * Returns all the items * - * @return TagData[] + * @return Tag[] * @throws ConstraintException * @throws QueryException */ public function getAll(): array { $queryData = new QueryData(); - $queryData->setMapClassName(TagData::class); + $queryData->setMapClassName(Tag::class); $queryData->setQuery('SELECT id, `name`, `hash` FROM Tag ORDER BY `name`'); return $this->db->doSelect($queryData)->getDataAsArray(); @@ -215,7 +215,7 @@ final class TagBaseRepository extends BaseRepository implements TagRepository 'SELECT id, `name` FROM Tag WHERE id IN ('.$this->buildParamsFromArray($ids).')'; $queryData = new QueryData(); - $queryData->setMapClassName(TagData::class); + $queryData->setMapClassName(Tag::class); $queryData->setQuery($query); $queryData->setParams($ids); diff --git a/tests/SPT/Domain/Export/Services/XmlTagExportTest.php b/tests/SPT/Domain/Export/Services/XmlTagExportTest.php new file mode 100644 index 00000000..a9ce4f44 --- /dev/null +++ b/tests/SPT/Domain/Export/Services/XmlTagExportTest.php @@ -0,0 +1,135 @@ +. + */ + +namespace SPT\Domain\Export\Services; + +use DOMDocument; +use DOMNodeList; +use PHPUnit\Framework\MockObject\Exception; +use PHPUnit\Framework\MockObject\MockObject; +use RuntimeException; +use SP\Domain\Common\Services\ServiceException; +use SP\Domain\Export\Services\XmlTagExport; +use SP\Domain\Tag\Ports\TagServiceInterface; +use SPT\Generators\TagGenerator; +use SPT\UnitaryTestCase; + +/** + * Class XmlTagExportTest + * + * @group unitary + */ +class XmlTagExportTest extends UnitaryTestCase +{ + + private TagServiceInterface|MockObject $tagService; + private XmlTagExport $xmlTagExport; + + /** + * @throws Exception + * @throws ServiceException + */ + public function testExport() + { + $tag = TagGenerator::factory()->buildTag(); + + $document = new DOMDocument(); + + $this->tagService + ->expects(self::once()) + ->method('getAll') + ->willReturn([$tag]); + + $out = $this->xmlTagExport->export($document); + + $this->assertEquals('Tags', $out->nodeName); + $this->assertEquals('Tag', $out->firstChild->nodeName); + $this->assertEquals($tag->getId(), $out->firstChild->attributes->getNamedItem('id')->nodeValue); + $this->assertEquals(1, $out->firstChild->childNodes->count()); + + $nodes = ['name' => $tag->getName()]; + + $this->checkNodes($out->firstChild->childNodes, $nodes); + } + + private function checkNodes(DOMNodeList $nodeList, array $nodes): void + { + $names = array_keys($nodes); + $values = array_values($nodes); + + foreach ($names as $key => $nodeName) { + $this->assertEquals($nodeName, $nodeList->item($key)->nodeName); + $this->assertEquals($values[$key], $nodeList->item($key)->nodeValue); + } + } + + /** + * @throws Exception + * @throws ServiceException + */ + public function testExportWithoutCategories() + { + $document = new DOMDocument(); + + $this->tagService + ->expects(self::once()) + ->method('getAll') + ->willReturn([]); + + $out = $this->xmlTagExport->export($document); + + $this->assertEquals('Tags', $out->nodeName); + $this->assertEquals(0, $out->childNodes->count()); + } + + /** + * @throws Exception + * @throws ServiceException + */ + public function testExportWithException() + { + $document = new DOMDocument(); + + $this->tagService + ->expects(self::once()) + ->method('getAll') + ->willThrowException(new RuntimeException('test')); + + $this->expectException(ServiceException::class); + $this->expectExceptionMessage('test'); + $this->xmlTagExport->export($document); + } + + protected function setUp(): void + { + parent::setUp(); + + $this->tagService = $this->createMock(TagServiceInterface::class); + + $this->xmlTagExport = new XmlTagExport( + $this->application, + $this->tagService + ); + } +} diff --git a/tests/SPT/Generators/TagGenerator.php b/tests/SPT/Generators/TagGenerator.php new file mode 100644 index 00000000..9326261d --- /dev/null +++ b/tests/SPT/Generators/TagGenerator.php @@ -0,0 +1,48 @@ +. + */ + +namespace SPT\Generators; + +use SP\Domain\Tag\Models\Tag; + +/** + * Class TagGenerator + */ +final class TagGenerator extends DataGenerator +{ + + public function buildTag(): Tag + { + return new Tag($this->tagProperties()); + } + + private function tagProperties(): array + { + return [ + 'id' => $this->faker->randomNumber(3), + 'name' => $this->faker->colorName(), + 'hash' => $this->faker->sha1() + ]; + } +}