diff --git a/migrations/Version20251001132155.php b/migrations/Version20251001132155.php new file mode 100644 index 0000000..30726b1 --- /dev/null +++ b/migrations/Version20251001132155.php @@ -0,0 +1,82 @@ +addSql(<<<'SQL' + CREATE TABLE category ( + id VARCHAR(255) NOT NULL, + PRIMARY KEY(id) + ) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB + SQL); + $this->addSql(<<<'SQL' + CREATE TABLE project_category ( + project_id INT NOT NULL, + category_id VARCHAR(255) NOT NULL, + INDEX IDX_3B02921A166D1F9C (project_id), + INDEX IDX_3B02921A12469DE2 (category_id), + PRIMARY KEY(project_id, category_id) + ) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB + SQL); + $this->addSql(<<<'SQL' + ALTER TABLE + project_category + ADD + CONSTRAINT FK_3B02921A166D1F9C FOREIGN KEY (project_id) REFERENCES project (id) ON DELETE CASCADE + SQL); + $this->addSql(<<<'SQL' + ALTER TABLE + project_category + ADD + CONSTRAINT FK_3B02921A12469DE2 FOREIGN KEY (category_id) REFERENCES category (id) ON DELETE CASCADE + SQL); + $this->addSql(<<<'SQL' + ALTER TABLE project DROP category + SQL); + + $this->addSql(<<<'SQL' + INSERT INTO category (id) VALUES ('education'); + INSERT INTO category (id) VALUES ('culture'); + INSERT INTO category (id) VALUES ('journalism'); + INSERT INTO category (id) VALUES ('democracy'); + INSERT INTO category (id) VALUES ('rural-development'); + INSERT INTO category (id) VALUES ('health-and-cares'); + INSERT INTO category (id) VALUES ('science-and-technology'); + INSERT INTO category (id) VALUES ('sustainability'); + INSERT INTO category (id) VALUES ('social-economy'); + SQL); + } + + public function down(Schema $schema): void + { + $this->addSql(<<<'SQL' + ALTER TABLE project_category DROP FOREIGN KEY FK_3B02921A166D1F9C + SQL); + $this->addSql(<<<'SQL' + ALTER TABLE project_category DROP FOREIGN KEY FK_3B02921A12469DE2 + SQL); + $this->addSql(<<<'SQL' + DROP TABLE category + SQL); + $this->addSql(<<<'SQL' + DROP TABLE project_category + SQL); + $this->addSql(<<<'SQL' + ALTER TABLE project ADD category VARCHAR(255) NOT NULL + SQL); + } +} diff --git a/src/ApiResource/Project/ProjectApiResource.php b/src/ApiResource/Project/ProjectApiResource.php index af64ffb..bf0b121 100644 --- a/src/ApiResource/Project/ProjectApiResource.php +++ b/src/ApiResource/Project/ProjectApiResource.php @@ -13,7 +13,6 @@ use App\Dto\ProjectCreationDto; use App\Dto\ProjectUpdationDto; use App\Entity\Project\Project; use App\Entity\Project\ProjectCalendar; -use App\Entity\Project\ProjectCategory; use App\Entity\Project\ProjectDeadline; use App\Entity\Project\ProjectStatus; use App\Entity\Project\ProjectVideo; @@ -109,11 +108,11 @@ class ProjectApiResource public ProjectCalendar $calendar; /** - * One of the available categories. + * A list of the available categories most relevant to this Project. */ #[Assert\NotBlank()] #[API\ApiFilter(filterClass: SearchFilter::class, strategy: 'exact')] - public ProjectCategory $category; + public array $categories; /** * ISO 3166 data about the Project's territory of interest. diff --git a/src/Entity/Category.php b/src/Entity/Category.php new file mode 100644 index 0000000..7227ca8 --- /dev/null +++ b/src/Entity/Category.php @@ -0,0 +1,19 @@ +id; + } +} diff --git a/src/Entity/Project/Project.php b/src/Entity/Project/Project.php index a34b5dc..8d73307 100644 --- a/src/Entity/Project/Project.php +++ b/src/Entity/Project/Project.php @@ -3,6 +3,7 @@ namespace App\Entity\Project; use App\Entity\Accounting\Accounting; +use App\Entity\Category; use App\Entity\Interface\AccountingOwnerInterface; use App\Entity\Interface\LocalizedEntityInterface; use App\Entity\Interface\UserOwnedInterface; @@ -64,8 +65,11 @@ class Project implements UserOwnedInterface, AccountingOwnerInterface, Localized #[ORM\Embedded(class: ProjectCalendar::class)] private ?ProjectCalendar $calendar = null; - #[ORM\Column(enumType: ProjectCategory::class)] - private ?ProjectCategory $category = null; + /** + * @var Collection + */ + #[ORM\ManyToMany(targetEntity: Category::class)] + private Collection $categories; /** * Project's territory of interest. @@ -145,6 +149,7 @@ class Project implements UserOwnedInterface, AccountingOwnerInterface, Localized $this->budgetItems = new ArrayCollection(); $this->updates = new ArrayCollection(); $this->supports = new ArrayCollection(); + $this->categories = new ArrayCollection(); } public function getId(): ?int @@ -219,14 +224,26 @@ class Project implements UserOwnedInterface, AccountingOwnerInterface, Localized return $this; } - public function getCategory(): ?ProjectCategory + /** + * @return Collection + */ + public function getCategories(): Collection { - return $this->category; + return $this->categories; } - public function setCategory(ProjectCategory $category): static + public function addCategory(Category $category): static { - $this->category = $category; + if (!$this->categories->contains($category)) { + $this->categories->add($category); + } + + return $this; + } + + public function removeCategory(Category $category): static + { + $this->categories->removeElement($category); return $this; } diff --git a/src/Repository/CategoryRepository.php b/src/Repository/CategoryRepository.php new file mode 100644 index 0000000..2ea6ad9 --- /dev/null +++ b/src/Repository/CategoryRepository.php @@ -0,0 +1,43 @@ + + */ +class CategoryRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Category::class); + } + + // /** + // * @return Category[] Returns an array of Category objects + // */ + // public function findByExampleField($value): array + // { + // return $this->createQueryBuilder('c') + // ->andWhere('c.exampleField = :val') + // ->setParameter('val', $value) + // ->orderBy('c.id', 'ASC') + // ->setMaxResults(10) + // ->getQuery() + // ->getResult() + // ; + // } + + // public function findOneBySomeField($value): ?Category + // { + // return $this->createQueryBuilder('c') + // ->andWhere('c.exampleField = :val') + // ->setParameter('val', $value) + // ->getQuery() + // ->getOneOrNullResult() + // ; + // } +}