From 91a654ec507a3032d591dcb3da8e7293c6da5880 Mon Sep 17 00:00:00 2001 From: Austin Flores Date: Mon, 10 Mar 2025 12:34:24 +0100 Subject: [PATCH 1/4] Add themes from database to endpoints --- src/Controller/Api/ThemesController.php | 33 +++++------------- src/Repository/ThemeRepository.php | 15 +++++++-- tests/Api/ThemesTest.php | 45 +++++++++++++++++++++---- tests/Themes/ThemeRepositoryTest.php | 38 +++++++++++++++++++++ 4 files changed, 98 insertions(+), 33 deletions(-) diff --git a/src/Controller/Api/ThemesController.php b/src/Controller/Api/ThemesController.php index 996ee36..74a858f 100644 --- a/src/Controller/Api/ThemesController.php +++ b/src/Controller/Api/ThemesController.php @@ -5,35 +5,20 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\Routing\Attribute\Route; - +use App\Repository\ThemeRepository; #[Route('/api')] final class ThemesController extends AbstractController { + private $themeRepository; + + public function __construct(ThemeRepository $themeRepository) + { + $this->themeRepository = $themeRepository; + } + #[Route('/themes', name: 'app_themes', methods: ['GET'])] public function index(): JsonResponse { - return $this->json([ - 'themes' => [ - [ - 'code' => 'environment', - 'id' => 1234, - 'parentId' => null, - 'children' => [ - [ - 'code' => 'some_sub_theme', - 'id' => 1024, - 'parentId' => 1234, - 'children' => [ - [ - 'code' => 'yet_another_sub_theme', - 'id' => 2048, - 'parentId' => 1024, - ], - ], - ], - ], - ], - ], - ]); + return $this->json($this->themeRepository->findAllHierarchical()); } } diff --git a/src/Repository/ThemeRepository.php b/src/Repository/ThemeRepository.php index 8d8d09c..9f2bed5 100644 --- a/src/Repository/ThemeRepository.php +++ b/src/Repository/ThemeRepository.php @@ -8,10 +8,21 @@ class ThemeRepository extends ServiceEntityRepository { - private $entityManager; - public function __construct(ManagerRegistry $registry) { parent::__construct($registry, Theme::class); } + + public function findAllHierarchical(): array + { + $themes = $this->findAll(); + $themesByParentId = []; + array_map(function (Theme $theme) use (&$themesByParentId) { + $children = $themesByParentId[$theme->getParentId()] ?? []; + $children[] = ['id' => $theme->getId(), 'name' => $theme->getName(), 'parentId' => $theme->getParentId(), 'externalId' => $theme->getExternalId()]; + $themesByParentId[$theme->getParentId() ?? 'base'] = $children; + }, $themes); + + return $themesByParentId; + } } diff --git a/tests/Api/ThemesTest.php b/tests/Api/ThemesTest.php index db7ad09..bc8d31a 100644 --- a/tests/Api/ThemesTest.php +++ b/tests/Api/ThemesTest.php @@ -3,20 +3,51 @@ namespace App\Tests; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; - +use App\Entity\Theme; class ThemesTest extends WebTestCase { - // Ideally this should be replaced with a more comprehensive test - // once we have our data model in place + + private $client; + private $themeRepository; + private $entityManager; + + protected function setUp(): void + { + parent::setUp(); + $this->client = static::createClient(); + + + $container = static::getContainer(); + $this->entityManager = $container->get('doctrine.orm.entity_manager'); + $this->themeRepository = $this->entityManager->getRepository(Theme::class); + + $parent = new Theme(); + $parent->setName('Environment'); + $parent->setIsSection(true); + $parent->setParentId(null); + $parent->setExternalId('external_id1'); + $this->entityManager->persist($parent); + $this->entityManager->flush(); + } + + protected function tearDown(): void + { + $themes = $this->themeRepository->findAll(); + foreach ($themes as $theme) { + $this->entityManager->remove($theme); + } + $this->entityManager->flush(); + parent::tearDown(); + } + public function testApiResponse(): void { - $client = static::createClient(); - $client->request('GET', '/api/themes'); + $this->client->request('GET', '/api/themes'); $this->assertResponseIsSuccessful(); - $content = $client->getResponse()->getContent(); + $content = $this->client->getResponse()->getContent(); $results = json_decode($content, true); - $this->assertEquals('environment', $results['themes'][0]['code']); + $this->assertEquals('Environment', $results['base'][0]['name']); } } diff --git a/tests/Themes/ThemeRepositoryTest.php b/tests/Themes/ThemeRepositoryTest.php index 9b84cde..93159ad 100644 --- a/tests/Themes/ThemeRepositoryTest.php +++ b/tests/Themes/ThemeRepositoryTest.php @@ -53,4 +53,42 @@ public function testAddChildTheme(): void $this->entityManager->flush(); $this->assertNotNull($child->getId()); } + + public function testFindAllHierarchical(): void + { + $themes = $this->themeRepository->findAllHierarchical(); + $this->assertEquals(0, count($themes)); + + $parent = new Theme(); + $parent->setName('Environment'); + $parent->setIsSection(true); + $parent->setParentId(null); + $parent->setExternalId('external_id1'); + $this->entityManager->persist($parent); + $this->entityManager->flush(); + + $child = new Theme(); + $child->setName('Climate Change'); + $child->setIsSection(true); + $child->setParentId($parent->getId()); + $child->setExternalId('external_id2'); + $this->entityManager->persist($child); + $this->entityManager->flush(); + + $grandchild = new Theme(); + $grandchild->setName('Sea Level Rise'); + $grandchild->setIsSection(true); + $grandchild->setParentId($child->getId()); + $grandchild->setExternalId('external_id3'); + $this->entityManager->persist($grandchild); + $this->entityManager->flush(); + + $themes = $this->themeRepository->findAllHierarchical(); + $this->assertEquals(3, count($themes)); + $this->assertEquals('Environment', $themes["base"][0]['name']); + $topParentId = $themes['base'][0]['id']; + $this->assertEquals('Climate Change', $themes[$topParentId][0]['name']); + $midParentId = $themes[$topParentId][0]['id']; + $this->assertEquals('Sea Level Rise', $themes[$midParentId][0]['name']); + } } From b4b656fa7e23bf7e1de9ed2e689db57b7c407603 Mon Sep 17 00:00:00 2001 From: Austin Flores Date: Mon, 10 Mar 2025 16:10:26 +0100 Subject: [PATCH 2/4] Make a Makefile for the common tasks --- Makefile | 31 +++++++++++++++++++++++++++++++ README.md | 8 ++++---- composer.json | 6 +----- 3 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..284f7fd --- /dev/null +++ b/Makefile @@ -0,0 +1,31 @@ +help: ## Show this help message + @echo 'Usage:' + @echo ' make ' + @echo '' + @echo 'Targets:' + @awk 'BEGIN {FS = ":.*##"} /^[a-zA-Z_\/-]+:.*?##/ { printf " %-20s %s\n", $$1, $$2 }' $(MAKEFILE_LIST) + +dev/start-server: ## Start the Symfony server + symfony server:start + +dev/install-deps: ## Install the dependencies + composer install + +db/generate-migration: ## Generate a new migration + php bin/console make:migration + +db/create: ## Create the database + php bin/console doctrine:database:create + +db/migrate: ## Run the migrations + php bin/console doctrine:migrations:migrate --no-interaction --all-or-nothing + +test: ## Run the tests + php bin/phpunit + +lint: ## Run the linter + vendor/bin/php-cs-fixer fix + +imports/import-themes: ## Import the themes + php bin/console ExtractService extractthemes + diff --git a/README.md b/README.md index 7eb0da5..914b8be 100644 --- a/README.md +++ b/README.md @@ -19,18 +19,18 @@ This project is a web-based visualization tool for exploring and analyzing open 3. Install Composer (PHP dependency manager): - Follow installation steps at: https://getcomposer.org/download/ - - Run `composer install` to install dependencies + - Run `make dev/install-deps` to install dependencies 4. Run migrations: ``` - composer db:create - composer db:migrate + make db/create + make db/migrate ``` 5. Set up local development server: - Install Symfony CLI from: https://symfony.com/download - Build database schema: `symfony console doctrine:schema:update --force` - - Start the server: `symfony server:start` + - Start the server: `make dev/start-server` 6. Access the application: - Open your browser and navigate to: http://localhost:8000/ diff --git a/composer.json b/composer.json index 86eb592..903105b 100644 --- a/composer.json +++ b/composer.json @@ -64,11 +64,7 @@ ], "post-update-cmd": [ "@auto-scripts" - ], - "fix-style": "php-cs-fixer fix", - "db:migrate": "php bin/console doctrine:migrations:migrate --no-interaction --all-or-nothing", - "db:create": "php bin/console doctrine:database:create", - "migration:create": "php bin/console make:migration" + ] }, "conflict": { "symfony/symfony": "*" From 19f6e6bafcb695374373071bab4a63b65d4f2024 Mon Sep 17 00:00:00 2001 From: Austin Flores Date: Mon, 10 Mar 2025 16:11:10 +0100 Subject: [PATCH 3/4] Update some lint info --- src/Controller/Api/ThemesController.php | 3 ++- tests/Api/ThemesTest.php | 5 ++--- tests/Themes/ThemeRepositoryTest.php | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Controller/Api/ThemesController.php b/src/Controller/Api/ThemesController.php index 74a858f..c76bc71 100644 --- a/src/Controller/Api/ThemesController.php +++ b/src/Controller/Api/ThemesController.php @@ -2,10 +2,11 @@ namespace App\Controller\Api; +use App\Repository\ThemeRepository; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\Routing\Attribute\Route; -use App\Repository\ThemeRepository; + #[Route('/api')] final class ThemesController extends AbstractController { diff --git a/tests/Api/ThemesTest.php b/tests/Api/ThemesTest.php index bc8d31a..5f15c92 100644 --- a/tests/Api/ThemesTest.php +++ b/tests/Api/ThemesTest.php @@ -2,11 +2,11 @@ namespace App\Tests; -use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use App\Entity\Theme; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; + class ThemesTest extends WebTestCase { - private $client; private $themeRepository; private $entityManager; @@ -16,7 +16,6 @@ protected function setUp(): void parent::setUp(); $this->client = static::createClient(); - $container = static::getContainer(); $this->entityManager = $container->get('doctrine.orm.entity_manager'); $this->themeRepository = $this->entityManager->getRepository(Theme::class); diff --git a/tests/Themes/ThemeRepositoryTest.php b/tests/Themes/ThemeRepositoryTest.php index 93159ad..89dd892 100644 --- a/tests/Themes/ThemeRepositoryTest.php +++ b/tests/Themes/ThemeRepositoryTest.php @@ -85,7 +85,7 @@ public function testFindAllHierarchical(): void $themes = $this->themeRepository->findAllHierarchical(); $this->assertEquals(3, count($themes)); - $this->assertEquals('Environment', $themes["base"][0]['name']); + $this->assertEquals('Environment', $themes['base'][0]['name']); $topParentId = $themes['base'][0]['id']; $this->assertEquals('Climate Change', $themes[$topParentId][0]['name']); $midParentId = $themes[$topParentId][0]['id']; From d8cd7c115017a446867069addbca19d668c5188e Mon Sep 17 00:00:00 2001 From: Austin Flores Date: Mon, 10 Mar 2025 16:12:57 +0100 Subject: [PATCH 4/4] Give the base response a key --- README.md | 2 +- src/Controller/Api/ThemesController.php | 2 +- tests/Api/ThemesTest.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 914b8be..b582f62 100644 --- a/README.md +++ b/README.md @@ -38,4 +38,4 @@ This project is a web-based visualization tool for exploring and analyzing open ## Running tests - Build database schema: `symfony console doctrine:schema:update --force --env=test` -- Run tests: `php bin/phpunit` +- Run tests: `make test` diff --git a/src/Controller/Api/ThemesController.php b/src/Controller/Api/ThemesController.php index c76bc71..1992fab 100644 --- a/src/Controller/Api/ThemesController.php +++ b/src/Controller/Api/ThemesController.php @@ -20,6 +20,6 @@ public function __construct(ThemeRepository $themeRepository) #[Route('/themes', name: 'app_themes', methods: ['GET'])] public function index(): JsonResponse { - return $this->json($this->themeRepository->findAllHierarchical()); + return $this->json(['themes' => $this->themeRepository->findAllHierarchical()]); } } diff --git a/tests/Api/ThemesTest.php b/tests/Api/ThemesTest.php index 5f15c92..0d4b82c 100644 --- a/tests/Api/ThemesTest.php +++ b/tests/Api/ThemesTest.php @@ -47,6 +47,6 @@ public function testApiResponse(): void $content = $this->client->getResponse()->getContent(); $results = json_decode($content, true); - $this->assertEquals('Environment', $results['base'][0]['name']); + $this->assertEquals('Environment', $results['themes']['base'][0]['name']); } }