diff --git a/api/.gitignore b/api/.gitignore index ae93018f235cd62b0e8536d2cce6dab6f898b1be..c930ddc07af540284ffa34249f9b1830b8f6d331 100644 --- a/api/.gitignore +++ b/api/.gitignore @@ -22,4 +22,3 @@ ### Migration ### /migrations/* -``` diff --git a/api/composer.json b/api/composer.json index 8eed869be14c53e2a433996bbb16a0336ecb970f..016958969d33ecfe1ecd5728b265871ff6a605ed 100644 --- a/api/composer.json +++ b/api/composer.json @@ -6,6 +6,7 @@ "ext-ctype": "*", "ext-iconv": "*", "api-platform/core": "^3.2", + "beberlei/doctrineextensions": "^1.3", "doctrine/doctrine-bundle": "^2.7", "doctrine/doctrine-migrations-bundle": "^3.2", "doctrine/orm": "^2.12", diff --git a/api/composer.lock b/api/composer.lock index 4fc11b5129d1df4ae3ce5933160fabb7833a9887..ec310a17f1f047e8eb9d94015a41587ff2711718 100644 --- a/api/composer.lock +++ b/api/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "934976d853cfcd0af63e3e1658634266", + "content-hash": "4a4de0353136f892d2f58fbbeba4ab1d", "packages": [ { "name": "api-platform/core", - "version": "v3.2.7", + "version": "v3.2.9", "source": { "type": "git", "url": "https://github.com/api-platform/core.git", - "reference": "f297d2192652a3acd2a644707740de8cb5069221" + "reference": "fe07a7f8196bfbefd2f8d02d0f7cacb6b1fbf527" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/api-platform/core/zipball/f297d2192652a3acd2a644707740de8cb5069221", - "reference": "f297d2192652a3acd2a644707740de8cb5069221", + "url": "https://api.github.com/repos/api-platform/core/zipball/fe07a7f8196bfbefd2f8d02d0f7cacb6b1fbf527", + "reference": "fe07a7f8196bfbefd2f8d02d0f7cacb6b1fbf527", "shasum": "" }, "require": { @@ -69,9 +69,11 @@ "phpstan/phpstan-doctrine": "^1.0", "phpstan/phpstan-phpunit": "^1.0", "phpstan/phpstan-symfony": "^1.0", + "phpunit/phpunit": "^9.5", "psr/log": "^1.0 || ^2.0 || ^3.0", "ramsey/uuid": "^3.9.7 || ^4.0", "ramsey/uuid-doctrine": "^1.4 || ^2.0", + "sebastian/comparator": "<5.0", "soyuka/contexts": "v3.3.9", "soyuka/stubs-mongodb": "^1.0", "symfony/asset": "^6.1 || ^7.0", @@ -165,9 +167,66 @@ ], "support": { "issues": "https://github.com/api-platform/core/issues", - "source": "https://github.com/api-platform/core/tree/v3.2.7" + "source": "https://github.com/api-platform/core/tree/v3.2.9" + }, + "time": "2023-12-20T17:01:35+00:00" + }, + { + "name": "beberlei/doctrineextensions", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/beberlei/DoctrineExtensions.git", + "reference": "008f162f191584a6c37c03a803f718802ba9dd9a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/beberlei/DoctrineExtensions/zipball/008f162f191584a6c37c03a803f718802ba9dd9a", + "reference": "008f162f191584a6c37c03a803f718802ba9dd9a", + "shasum": "" + }, + "require": { + "doctrine/orm": "^2.7", + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.14", + "nesbot/carbon": "*", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "symfony/yaml": "^4.2 || ^5.0", + "zf1/zend-date": "^1.12", + "zf1/zend-registry": "^1.12" + }, + "type": "library", + "autoload": { + "psr-4": { + "DoctrineExtensions\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Steve Lacey", + "email": "steve@steve.ly" + } + ], + "description": "A set of extensions to Doctrine 2 that add support for additional query functions available in MySQL, Oracle, PostgreSQL and SQLite.", + "keywords": [ + "database", + "doctrine", + "orm" + ], + "support": { + "source": "https://github.com/beberlei/DoctrineExtensions/tree/v1.3.0" }, - "time": "2023-11-30T13:51:25+00:00" + "time": "2020-11-29T07:37:23+00:00" }, { "name": "doctrine/cache", diff --git a/api/config/packages/doctrine.yaml b/api/config/packages/doctrine.yaml index 559641f79e97fe65de4b01d1ed46ced14fde2d35..53270fd1a5b123fb3091af70951d8ea1805a2ee7 100644 --- a/api/config/packages/doctrine.yaml +++ b/api/config/packages/doctrine.yaml @@ -21,6 +21,10 @@ doctrine: dir: '%kernel.project_dir%/src/Entity' prefix: 'App\Entity' alias: App + dql: + string_functions: + MONTH: DoctrineExtensions\Query\Postgresql\Month + YEAR: DoctrineExtensions\Query\Postgresql\Year when@test: doctrine: diff --git a/api/src/Controller/SaleController.php b/api/src/Controller/SaleController.php new file mode 100644 index 0000000000000000000000000000000000000000..cad37dcdee8370f85b3b741bdba45f41e6ceb508 --- /dev/null +++ b/api/src/Controller/SaleController.php @@ -0,0 +1,28 @@ +saleService = $saleService; + } + + public function __invoke(): JsonResponse + { + $result = $this->saleService->getMonthlyAveragePriceEvolution(); + + return $this->json($result); + } +} diff --git a/api/src/Dto/MonthlyAveragePriceEvolutionDto.php b/api/src/Dto/MonthlyAveragePriceEvolutionDto.php new file mode 100644 index 0000000000000000000000000000000000000000..fc489793a1899d0e949a3b794bc596300a54455c --- /dev/null +++ b/api/src/Dto/MonthlyAveragePriceEvolutionDto.php @@ -0,0 +1,17 @@ +month = $month; + $this->year = $year; + $this->averagePrice = $averagePrice; + } +} diff --git a/api/src/Entity/Sale.php b/api/src/Entity/Sale.php index 9ceb2c1394e677d4aaf043dbebfadd1bdbbd695a..712002d51c080cd0375f7c89bc1dd89e072b369b 100644 --- a/api/src/Entity/Sale.php +++ b/api/src/Entity/Sale.php @@ -3,9 +3,21 @@ namespace App\Entity; use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\GetCollection; +use App\Controller\SaleController; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; +#[ApiResource( + operations: [ + new GetCollection( + uriTemplate: '/sales/monthly_average_price_evolution', + controller: SaleController::class, + name: 'monthly_average_price_evolution' + ) + ] +)] + /** A sale. */ #[ORM\Entity] #[ApiResource] diff --git a/api/src/Service/SaleService.php b/api/src/Service/SaleService.php new file mode 100644 index 0000000000000000000000000000000000000000..6f2a07be684b1f9c3cae940052fa09ca794c205a --- /dev/null +++ b/api/src/Service/SaleService.php @@ -0,0 +1,41 @@ +entityManager = $entityManager; + } + + public function getMonthlyAveragePriceEvolution(): array + { + $queryBuilder = $this->entityManager->createQueryBuilder(); + + $result = $queryBuilder + ->select('MONTH(s.date) as month', 'YEAR(s.date) as year', 'AVG(CASE WHEN s.surface <> 0 THEN s.amount / s.surface ELSE 0 END) as average_price') + ->from(Sale::class, 's') + ->groupBy('year, month') + ->orderBy('year, month') + ->getQuery() + ->getResult(); + + $monthlyAveragePriceEvolutions = []; + foreach ($result as $row) { + $monthlyAveragePriceEvolutions[] = new MonthlyAveragePriceEvolutionDto( + (int)$row['month'], + (int)$row['year'], + (float)$row['average_price'] + ); + } + + return $monthlyAveragePriceEvolutions; + } +} diff --git a/insertions/script-2.mjs b/insertions/script-2.mjs index abf296dde3c46983aa254bf1cfa00b45a4b736d8..d3c2ba5c614c1698a5f8e697ca31a4d4567b9cc3 100644 --- a/insertions/script-2.mjs +++ b/insertions/script-2.mjs @@ -134,6 +134,6 @@ rl.on('line', (line) => { }); rl.on('close', () => { - const str = `INSERT INTO vente(date, value, region, surface) VALUES\n${lines.join(",\n")};`; + const str = `INSERT INTO sale(date, amount, region, surface) VALUES\n${lines.join(",\n")};`; console.log(str); });