diff --git a/config/api_platform/Partition.yaml b/config/api_platform/Partition.yaml new file mode 100644 index 0000000..1d270e7 --- /dev/null +++ b/config/api_platform/Partition.yaml @@ -0,0 +1,30 @@ +resources: + App\Entity\Partition: + processor: App\State\Processor\PartitionProcessor + input: App\Dto\Input\PartitionInput + output: App\Dto\Output\PartitionOutput + normalization_context: + groups: ['default', 'partition:read'] + denormalization_context: + groups: ['partition:write'] + operations: + ApiPlatform\Metadata\GetCollection: + provider: App\State\Provider\PartitionProvider + filters: + - 'api_platform.filter.partition.order' + - 'api_platform.filter.partition.search' + ApiPlatform\Metadata\Get: + provider: App\State\Provider\PartitionProvider + ApiPlatform\Metadata\Put: + provider: App\State\Provider\PartitionProvider + ApiPlatform\Metadata\Patch: + provider: App\State\Provider\PartitionProvider + ApiPlatform\Metadata\Post: ~ + ApiPlatform\Metadata\Delete: ~ + +properties: + App\Entity\Partition: + id: + identifier: false + uuid: + identifier: true \ No newline at end of file diff --git a/config/services.yaml b/config/services.yaml index 3e2e835..8b4eaac 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -56,6 +56,11 @@ services: $itemProvider: '@api_platform.doctrine.orm.state.item_provider' App\State\Provider\MenuProvider: + bind: + $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider' + $itemProvider: '@api_platform.doctrine.orm.state.item_provider' + + App\State\Provider\PartitionProvider: bind: $collectionProvider: '@api_platform.doctrine.orm.state.collection_provider' $itemProvider: '@api_platform.doctrine.orm.state.item_provider' \ No newline at end of file diff --git a/config/services/api_platform.yaml b/config/services/api_platform.yaml index 1541e80..fd54ddb 100644 --- a/config/services/api_platform.yaml +++ b/config/services/api_platform.yaml @@ -1,17 +1,74 @@ services: + api_platform.filter.client.order: + parent: 'api_platform.doctrine.orm.order_filter' + arguments: + $properties: { 'id': ~, 'name': ~, 'serialNumber': ~ } + $orderParameterName: 'order' + tags: + - [ 'api_platform.filter' ] + + api_platform.filter.client.search: + parent: 'api_platform.doctrine.orm.search_filter' + arguments: [ { 'id': 'exact', 'name': 'partial', 'serialNumber': 'exact' } ] + tags: + - [ 'api_platform.filter' ] + + api_platform.filter.hardware.order: + parent: 'api_platform.doctrine.orm.order_filter' + arguments: + $properties: { 'id': ~, 'name': ~ } + $orderParameterName: 'order' + tags: + - [ 'api_platform.filter' ] + + api_platform.filter.hardware.search: + parent: 'api_platform.doctrine.orm.search_filter' + arguments: [ { 'id': 'exact', 'name': 'partial' } ] + tags: + - [ 'api_platform.filter' ] + + api_platform.filter.menu.order: + parent: 'api_platform.doctrine.orm.order_filter' + arguments: + $properties: { 'id': ~, 'name': ~, 'title': ~ } + $orderParameterName: 'order' + tags: + - [ 'api_platform.filter' ] + + api_platform.filter.menu.search: + parent: 'api_platform.doctrine.orm.search_filter' + arguments: [ { 'id': 'exact', 'name': 'exact', 'title': 'exact' } ] + tags: + - [ 'api_platform.filter' ] + + + api_platform.filter.partition.order: + parent: 'api_platform.doctrine.orm.order_filter' + arguments: + $properties: { 'id': ~, 'usage': ~ } + $orderParameterName: 'order' + tags: + - [ 'api_platform.filter' ] + + api_platform.filter.partition.search: + parent: 'api_platform.doctrine.orm.search_filter' + arguments: [ { 'id': 'exact', 'usage': 'exact', 'diskNumber': 'exact' } ] + tags: + - [ 'api_platform.filter' ] + api_platform.filter.user.order: parent: 'api_platform.doctrine.orm.order_filter' arguments: - $properties: { 'id' : ~, 'username': ~ } + $properties: { 'id': ~, 'username': ~ } $orderParameterName: 'order' tags: - - ['api_platform.filter' ] + - [ 'api_platform.filter' ] api_platform.filter.user.search: parent: 'api_platform.doctrine.orm.search_filter' - arguments: [ { 'id': 'exact', 'username': 'partial' }] + arguments: [ { 'id': 'exact', 'username': 'partial' } ] tags: - - ['api_platform.filter' ] + - [ 'api_platform.filter' ] api_platform.filter.user.boolean: parent: 'api_platform.doctrine.orm.boolean_filter' @@ -39,16 +96,4 @@ services: tags: - [ 'api_platform.filter' ] - api_platform.filter.hardware.order: - parent: 'api_platform.doctrine.orm.order_filter' - arguments: - $properties: { 'id': ~, 'name': ~ } - $orderParameterName: 'order' - tags: - - [ 'api_platform.filter' ] - api_platform.filter.hardware.search: - parent: 'api_platform.doctrine.orm.search_filter' - arguments: [ { 'id': 'exact', 'name': 'partial' } ] - tags: - - [ 'api_platform.filter' ] diff --git a/migrations/Version20240614082024.php b/migrations/Version20240614082024.php new file mode 100644 index 0000000..9794d3b --- /dev/null +++ b/migrations/Version20240614082024.php @@ -0,0 +1,33 @@ +addSql('CREATE TABLE `partition` (id INT AUTO_INCREMENT NOT NULL, client_id INT DEFAULT NULL, uuid CHAR(36) NOT NULL COMMENT \'(DC2Type:uuid)\', migration_id VARCHAR(255) DEFAULT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, created_by VARCHAR(255) DEFAULT NULL, updated_by VARCHAR(255) DEFAULT NULL, disk_number INT DEFAULT NULL, partition_number INT DEFAULT NULL, partition_code VARCHAR(255) DEFAULT NULL, size INT NOT NULL, cache_content VARCHAR(255) DEFAULT NULL, filesystem VARCHAR(255) DEFAULT NULL, os_name VARCHAR(255) NOT NULL, memory_usage INT NOT NULL, UNIQUE INDEX UNIQ_9EB910E4D17F50A6 (uuid), INDEX IDX_9EB910E419EB6921 (client_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('ALTER TABLE `partition` ADD CONSTRAINT FK_9EB910E419EB6921 FOREIGN KEY (client_id) REFERENCES client (id)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE `partition` DROP FOREIGN KEY FK_9EB910E419EB6921'); + $this->addSql('DROP TABLE `partition`'); + } +} diff --git a/migrations/Version20240614082735.php b/migrations/Version20240614082735.php new file mode 100644 index 0000000..5243e2c --- /dev/null +++ b/migrations/Version20240614082735.php @@ -0,0 +1,35 @@ +addSql('ALTER TABLE client DROP FOREIGN KEY FK_C7440455CCD7E912'); + $this->addSql('DROP INDEX IDX_C7440455CCD7E912 ON client'); + $this->addSql('ALTER TABLE client ADD menu VARCHAR(255) DEFAULT NULL, DROP menu_id'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE client ADD menu_id INT DEFAULT NULL, DROP menu'); + $this->addSql('ALTER TABLE client ADD CONSTRAINT FK_C7440455CCD7E912 FOREIGN KEY (menu_id) REFERENCES menu (id)'); + $this->addSql('CREATE INDEX IDX_C7440455CCD7E912 ON client (menu_id)'); + } +} diff --git a/src/Dto/Input/ClientInput.php b/src/Dto/Input/ClientInput.php index 366aa43..6a90ee0 100644 --- a/src/Dto/Input/ClientInput.php +++ b/src/Dto/Input/ClientInput.php @@ -51,7 +51,6 @@ final class ClientInput #[ApiProperty(description: 'The hardware profile of the client')] public ?HardwareProfileOutput $hardwareProfile = null; - #[Assert\NotNull] #[Groups(['client:write'])] #[ApiProperty(description: 'The menu of the client')] public ?MenuOutput $menu = null; @@ -85,7 +84,11 @@ final class ClientInput $client->setNetiface($this->netiface); $client->setOrganizationalUnit($this->organizationalUnit->getEntity()); $client->setHardwareProfile($this->hardwareProfile->getEntity()); - $client->setMenu($this->menu->getEntity()); + + if ($this->menu) { + $client->setMenu($this->menu->getEntity()); + } + $client->setNetDriver($this->netDriver); $client->setMac($this->mac); $client->setIp($this->ip); diff --git a/src/Dto/Input/MenuInput.php b/src/Dto/Input/MenuInput.php index 03631ee..d09d78e 100644 --- a/src/Dto/Input/MenuInput.php +++ b/src/Dto/Input/MenuInput.php @@ -16,6 +16,7 @@ final class MenuInput #[ApiProperty(description: 'The name of the menu', example: "Menu 1")] public ?string $name = null; + #[Assert\NotNull()] #[Groups(['menu:write'])] #[ApiProperty(description: 'The title of the menu', example: "Menu 1 title")] public ?string $title = null; diff --git a/src/Dto/Input/PartitionInput.php b/src/Dto/Input/PartitionInput.php new file mode 100644 index 0000000..b4da4ed --- /dev/null +++ b/src/Dto/Input/PartitionInput.php @@ -0,0 +1,91 @@ +diskNumber = $partition->getDiskNumber(); + $this->partitionNumber = $partition->getPartitionNumber(); + $this->partitionCode = $partition->getPartitionCode(); + $this->size = $partition->getSize(); + $this->cacheContent = $partition->getCacheContent(); + $this->filesystem = $partition->getFilesystem(); + $this->osName = $partition->getOsName(); + $this->client = new ClientOutput($partition->getClient()); + $this->memoryUsage = $partition->getMemoryUsage(); + } + + public function createOrUpdateEntity(?Partition $partition = null): Partition + { + if (!$partition) { + $partition = new Partition(); + } + + $partition->setDiskNumber($this->diskNumber); + $partition->setPartitionNumber($this->partitionNumber); + $partition->setPartitionCode($this->partitionCode); + $partition->setSize($this->size * 100); + $partition->setCacheContent($this->cacheContent); + $partition->setFilesystem($this->filesystem); + $partition->setOsName($this->osName); + $partition->setClient($this->client->getEntity()); + $partition->setMemoryUsage($this->memoryUsage * 100); + + return $partition; + } +} \ No newline at end of file diff --git a/src/Dto/Output/ClientOutput.php b/src/Dto/Output/ClientOutput.php index 34c5b3c..d95e0ca 100644 --- a/src/Dto/Output/ClientOutput.php +++ b/src/Dto/Output/ClientOutput.php @@ -4,6 +4,7 @@ namespace App\Dto\Output; use ApiPlatform\Metadata\Get; use App\Entity\Client; +use App\Entity\Partition; use Symfony\Component\Serializer\Annotation\Groups; #[Get(shortName: 'Client')] @@ -27,6 +28,12 @@ final class ClientOutput extends AbstractOutput #[Groups(['client:read'])] public ?MenuOutput $menu = null; + /** + * @var Partition[] + */ + #[Groups(['client:read'])] + public array $partitions = []; + #[Groups(['client:read'])] public \DateTime $createdAt; @@ -49,6 +56,11 @@ final class ClientOutput extends AbstractOutput if($client->getMenu()) { $this->menu = new MenuOutput($client->getMenu()); } + + foreach ($client->getPartitions() as $partition) { + $this->partitions[] = new PartitionOutput($partition); + } + $this->createdAt = $client->getCreatedAt(); $this->createdBy = $client->getCreatedBy(); } diff --git a/src/Dto/Output/PartitionOutput.php b/src/Dto/Output/PartitionOutput.php new file mode 100644 index 0000000..273c4b8 --- /dev/null +++ b/src/Dto/Output/PartitionOutput.php @@ -0,0 +1,52 @@ +diskNumber = $partition->getDiskNumber(); + $this->partitionNumber = $partition->getPartitionNumber(); + $this->partitionCode = $partition->getPartitionCode(); + $this->size = $partition->getSize() / 100; + $this->cacheContent = $partition->getCacheContent(); + $this->filesystem = $partition->getFilesystem(); + $this->osName = $partition->getOsName(); + $this->client = new ClientOutput($partition->getClient()); + $this->memoryUsage = $partition->getMemoryUsage() / 100; + } + +} \ No newline at end of file diff --git a/src/Entity/Client.php b/src/Entity/Client.php index f632a8f..0fc4f47 100644 --- a/src/Entity/Client.php +++ b/src/Entity/Client.php @@ -3,6 +3,8 @@ namespace App\Entity; use App\Repository\ClientRepository; +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity(repositoryClass: ClientRepository::class)] @@ -35,8 +37,21 @@ class Client extends AbstractEntity private ?HardwareProfile $hardwareProfile = null; #[ORM\ManyToOne(inversedBy: 'clients')] + #[ORM\Column(nullable: true)] private ?Menu $menu = null; + /** + * @var Collection + */ + #[ORM\OneToMany(mappedBy: 'client', targetEntity: Partition::class)] + private Collection $partitions; + + public function __construct() + { + parent::__construct(); + $this->partitions = new ArrayCollection(); + } + public function getSerialNumber(): ?string { return $this->serialNumber; @@ -144,4 +159,34 @@ class Client extends AbstractEntity return $this; } + + /** + * @return Collection + */ + public function getPartitions(): Collection + { + return $this->partitions; + } + + public function addPartition(Partition $partition): static + { + if (!$this->partitions->contains($partition)) { + $this->partitions->add($partition); + $partition->setClient($this); + } + + return $this; + } + + public function removePartition(Partition $partition): static + { + if ($this->partitions->removeElement($partition)) { + // set the owning side to null (unless already changed) + if ($partition->getClient() === $this) { + $partition->setClient(null); + } + } + + return $this; + } } diff --git a/src/Entity/Partition.php b/src/Entity/Partition.php new file mode 100644 index 0000000..316eb28 --- /dev/null +++ b/src/Entity/Partition.php @@ -0,0 +1,146 @@ +diskNumber; + } + + public function setDiskNumber(?int $diskNumber): static + { + $this->diskNumber = $diskNumber; + + return $this; + } + + public function getPartitionNumber(): ?int + { + return $this->partitionNumber; + } + + public function setPartitionNumber(?int $partitionNumber): static + { + $this->partitionNumber = $partitionNumber; + + return $this; + } + + public function getPartitionCode(): ?string + { + return $this->partitionCode; + } + + public function setPartitionCode(?string $partitionCode): static + { + $this->partitionCode = $partitionCode; + + return $this; + } + + public function getSize(): ?int + { + return $this->size; + } + + public function setSize(int $size): static + { + $this->size = $size; + + return $this; + } + + public function getCacheContent(): ?string + { + return $this->cacheContent; + } + + public function setCacheContent(?string $cacheContent): static + { + $this->cacheContent = $cacheContent; + + return $this; + } + + public function getFilesystem(): ?string + { + return $this->filesystem; + } + + public function setFilesystem(?string $filesystem): static + { + $this->filesystem = $filesystem; + + return $this; + } + + public function getOsName(): ?string + { + return $this->osName; + } + + public function setOsName(string $osName): static + { + $this->osName = $osName; + + return $this; + } + + public function getClient(): ?Client + { + return $this->client; + } + + public function setClient(?Client $client): static + { + $this->client = $client; + + return $this; + } + + public function getMemoryUsage(): ?int + { + return $this->memoryUsage; + } + + public function setMemoryUsage(int $memoryUsage): static + { + $this->memoryUsage = $memoryUsage; + + return $this; + } +} diff --git a/src/Repository/PartitionRepository.php b/src/Repository/PartitionRepository.php new file mode 100644 index 0000000..e4964b3 --- /dev/null +++ b/src/Repository/PartitionRepository.php @@ -0,0 +1,18 @@ + + */ +class PartitionRepository extends AbstractRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Partition::class); + } +} diff --git a/src/State/Processor/HardwareProcessor.php b/src/State/Processor/HardwareProcessor.php index 25781a8..971fb3d 100644 --- a/src/State/Processor/HardwareProcessor.php +++ b/src/State/Processor/HardwareProcessor.php @@ -52,11 +52,11 @@ class HardwareProcessor implements ProcessorInterface $entity = $this->hardwareRepository->findOneByUuid($uriVariables['uuid']); } - $userGroup = $data->createOrUpdateEntity($entity); - $this->validator->validate($userGroup); - $this->hardwareRepository->save($userGroup); + $hardware = $data->createOrUpdateEntity($entity); + $this->validator->validate($hardware); + $this->hardwareRepository->save($hardware); - return new HardwareOutput($userGroup); + return new HardwareOutput($hardware); } private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null diff --git a/src/State/Processor/HardwareProfileProcessor.php b/src/State/Processor/HardwareProfileProcessor.php index aaf2bdd..ed6ccf8 100644 --- a/src/State/Processor/HardwareProfileProcessor.php +++ b/src/State/Processor/HardwareProfileProcessor.php @@ -17,8 +17,8 @@ use App\Repository\HardwareProfileRepository; readonly class HardwareProfileProcessor implements ProcessorInterface { public function __construct( - private HardwareProfileRepository $hardwareProfileRepository, - private ValidatorInterface $validator + private HardwareProfileRepository $hardwareProfileRepository, + private ValidatorInterface $validator ) { } @@ -44,7 +44,7 @@ readonly class HardwareProfileProcessor implements ProcessorInterface private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): HardwareProfileOutput { if (!($data instanceof HardwareProfileInput)) { - throw new \Exception(sprintf('data is not instance of %s', HardwareInput::class)); + throw new \Exception(sprintf('data is not instance of %s', HardwareProfileInput::class)); } $entity = null; @@ -52,11 +52,11 @@ readonly class HardwareProfileProcessor implements ProcessorInterface $entity = $this->hardwareProfileRepository->findOneByUuid($uriVariables['uuid']); } - $userGroup = $data->createOrUpdateEntity($entity); - $this->validator->validate($userGroup); - $this->hardwareProfileRepository->save($userGroup); + $hardwareProfile = $data->createOrUpdateEntity($entity); + $this->validator->validate($hardwareProfile); + $this->hardwareProfileRepository->save($hardwareProfile); - return new HardwareProfileOutput($userGroup); + return new HardwareProfileOutput($hardwareProfile); } private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null diff --git a/src/State/Processor/MenuProcessor.php b/src/State/Processor/MenuProcessor.php index bc4a911..16bda49 100644 --- a/src/State/Processor/MenuProcessor.php +++ b/src/State/Processor/MenuProcessor.php @@ -16,11 +16,11 @@ use App\Dto\Output\UserGroupOutput; use App\Repository\MenuRepository; use App\Repository\UserGroupRepository; -class MenuProcessor implements ProcessorInterface +readonly class MenuProcessor implements ProcessorInterface { public function __construct( - private readonly MenuRepository $menuRepository, - private readonly ValidatorInterface $validator + private MenuRepository $menuRepository, + private ValidatorInterface $validator ) { } @@ -46,7 +46,7 @@ class MenuProcessor implements ProcessorInterface private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): MenuOutput { if (!($data instanceof MenuInput)) { - throw new \Exception(sprintf('data is not instance of %s', UserGroupInput::class)); + throw new \Exception(sprintf('data is not instance of %s', MenuInput::class)); } $entity = null; @@ -54,11 +54,11 @@ class MenuProcessor implements ProcessorInterface $entity = $this->menuRepository->findOneByUuid($uriVariables['uuid']); } - $userGroup = $data->createOrUpdateEntity($entity); - $this->validator->validate($userGroup); - $this->menuRepository->save($userGroup); + $menu = $data->createOrUpdateEntity($entity); + $this->validator->validate($menu); + $this->menuRepository->save($menu); - return new MenuOutput($userGroup); + return new MenuOutput($menu); } private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null diff --git a/src/State/Processor/PartitionProcessor.php b/src/State/Processor/PartitionProcessor.php new file mode 100644 index 0000000..f17affc --- /dev/null +++ b/src/State/Processor/PartitionProcessor.php @@ -0,0 +1,74 @@ +processCreateOrUpdate($data, $operation, $uriVariables, $context); + case $operation instanceof Delete: + return $this->processDelete($data, $operation, $uriVariables, $context); + } + } + + /** + * @throws \Exception + */ + private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): PartitionOutput + { + if (!($data instanceof PartitionInput)) { + throw new \Exception(sprintf('data is not instance of %s', PartitionInput::class)); + } + + $entity = null; + if (isset($uriVariables['uuid'])) { + $entity = $this->partitionRepository->findOneByUuid($uriVariables['uuid']); + } + + $partition = $data->createOrUpdateEntity($entity); + $this->validator->validate($partition); + $this->partitionRepository->save($partition); + + return new PartitionOutput($partition); + } + + private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null + { + $user = $this->partitionRepository->findOneByUuid($uriVariables['uuid']); + $this->partitionRepository->delete($user); + + return null; + } +} diff --git a/src/State/Provider/PartitionProvider.php b/src/State/Provider/PartitionProvider.php new file mode 100644 index 0000000..ae6abe8 --- /dev/null +++ b/src/State/Provider/PartitionProvider.php @@ -0,0 +1,77 @@ +provideCollection($operation, $uriVariables, $context); + case $operation instanceof Patch: + case $operation instanceof Put: + return $this->provideInput($operation, $uriVariables, $context); + case $operation instanceof Get: + return $this->provideItem($operation, $uriVariables, $context); + } + } + + private function provideCollection(Operation $operation, array $uriVariables = [], array $context = []): object + { + $paginator = $this->collectionProvider->provide($operation, $uriVariables, $context); + + $items = new \ArrayObject(); + foreach ($paginator->getIterator() as $item){ + $items[] = new PartitionOutput($item); + } + + return new TraversablePaginator($items, $paginator->getCurrentPage(), $paginator->getItemsPerPage(), $paginator->getTotalItems()); + } + + public function provideItem(Operation $operation, array $uriVariables = [], array $context = []): object|array|null + { + $item = $this->itemProvider->provide($operation, $uriVariables, $context); + + if (!$item) { + throw new NotFoundHttpException('Partition not found'); + } + + return new PartitionOutput($item); + } + + public function provideInput(Operation $operation, array $uriVariables = [], array $context = []): object|array|null + { + if (isset($uriVariables['uuid'])) { + $item = $this->itemProvider->provide($operation, $uriVariables, $context); + + return $item !== null ? new PartitionInput($item) : null; + } + + return new PartitionInput(); + } +}