Skip to content

Commit f254351

Browse files
committed
Index cities in elastic + add endpoint to retrieve them
1 parent 07bff1c commit f254351

16 files changed

Lines changed: 418 additions & 3 deletions

File tree

.env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ CORS_ALLOW_ORIGIN='^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$'
1111
REDIS_URL=redis://redis:6379
1212
LOCK_DSN=flock
1313
SENTRY_DSN=
14+
CITIES_DOWNLOAD_URL="https://datanova.laposte.fr/data-fair/api/v1/datasets/laposte-hexasmal/raw"

compose.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ services:
9898
ELASTIC_PASSWORD:
9999
SYNCHRO_SECRET_KEY:
100100
REDIS_URL:
101+
CITIES_DOWNLOAD_URL:
101102
depends_on:
102103
- db
103104
- redis

config/packages/api_platform.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ api_platform:
1414
- "%kernel.project_dir%/src/FieldHolder/Community/Domain/Exception/"
1515
- "%kernel.project_dir%/src/Field/Domain/Exception/"
1616
- "%kernel.project_dir%/src/System/Infrastructure/ApiPlatform/Resource/"
17+
- "%kernel.project_dir%/src/City/Infrastructure/ApiPlatform/Resource/"
1718
formats:
1819
json: ["application/json"]
1920
jsonld: ["application/ld+json"]

config/services.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ services:
1111
_defaults:
1212
autowire: true # Automatically injects dependencies in your services.
1313
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
14+
bind:
15+
$citiesDownloadUrl: "%env(CITIES_DOWNLOAD_URL)%"
16+
$targetPath: "%kernel.project_dir%/var/data/cities.csv"
1417

1518
# makes classes in src/ available to be used as services
1619
# this creates a service per class whose id is the fully-qualified class name
@@ -54,6 +57,8 @@ services:
5457
$elasticsearchHost: "%env(ELASTICSEARCH_IRI)%"
5558
App\Core\Domain\Service\Search\SearchServiceInterface:
5659
class: App\Core\Infrastructure\Service\OfficialElasticSearchService
60+
App\Core\Domain\Service\Search\CitiesDownloaderInterface:
61+
class: App\Core\Infrastructure\Symfony\Service\LaposteCitiesDownloader
5762

5863
App\Core\Infrastructure\ElasticSearch\Helper\OfficialElasticSearchHelper:
5964
arguments:

etc/cron.d/backend

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ HOME=/var/www/html
2222
#
2323
# m h dom mon dow command
2424

25-
30 18 * * * www-data /usr/bin/php $HOME/bin/console app:write:indexes > /proc/1/fd/1 2>/proc/1/fd/2
25+
30 18 * * * www-data /usr/bin/php $HOME/bin/console app:index:communities > /proc/1/fd/1 2>/proc/1/fd/2
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\City\Infrastructure\ApiPlatform\Filter;
6+
7+
use ApiPlatform\Metadata\FilterInterface;
8+
use Symfony\Component\PropertyInfo\Type;
9+
10+
final class NameFilter implements FilterInterface
11+
{
12+
public function getDescription(string $resourceClass): array
13+
{
14+
return [
15+
'name' => [
16+
'property' => 'name',
17+
'type' => Type::BUILTIN_TYPE_STRING,
18+
'required' => false,
19+
],
20+
];
21+
}
22+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\City\Infrastructure\ApiPlatform\Resource;
6+
7+
use ApiPlatform\Metadata\ApiResource;
8+
use ApiPlatform\Metadata\GetCollection;
9+
use App\City\Infrastructure\ApiPlatform\State\Provider\CityCollectionProvider;
10+
use App\City\Infrastructure\ApiPlatform\Filter\NameFilter;
11+
use App\Field\Domain\Model\Field;
12+
13+
#[ApiResource(
14+
shortName: 'City',
15+
cacheHeaders: [
16+
'public' => true,
17+
'max_age' => 3600,
18+
],
19+
uriTemplate: '/cities',
20+
operations: [
21+
new GetCollection(
22+
filters: [
23+
NameFilter::class,
24+
],
25+
provider: CityCollectionProvider::class,
26+
),
27+
],
28+
)]
29+
final class CityResource
30+
{
31+
/**
32+
* @param Field[] $fields
33+
*/
34+
public function __construct(
35+
public string $name,
36+
37+
public string $postCode,
38+
) {
39+
}
40+
41+
public static function fromModel(array $city): self
42+
{
43+
return new self(
44+
$city['cityName'],
45+
$city['postCode'],
46+
);
47+
}
48+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\City\Infrastructure\ApiPlatform\State\Provider;
6+
7+
use ApiPlatform\Metadata\Operation;
8+
use ApiPlatform\State\Pagination\Pagination;
9+
use ApiPlatform\State\ProviderInterface;
10+
use App\City\Infrastructure\ApiPlatform\Resource\CityResource;
11+
use App\Core\Domain\Search\Service\SearchServiceInterface;
12+
use App\Shared\Infrastructure\ApiPlatform\State\Paginator;
13+
14+
/**
15+
* @implements ProviderInterface<CityResource>
16+
*/
17+
final class CityCollectionProvider implements ProviderInterface
18+
{
19+
public function __construct(
20+
private Pagination $pagination,
21+
private SearchServiceInterface $searchService,
22+
) {
23+
}
24+
25+
/**
26+
* @return Paginator<CityResource>|list<CityResource>
27+
*/
28+
public function provide(Operation $operation, array $uriVariables = [], array $context = []): Paginator|array
29+
{
30+
$name = $context['filters']['name'] ?? null;
31+
$page = $itemsPerPage = null;
32+
$cities = [];
33+
34+
if ($this->pagination->isEnabled($operation, $context)) {
35+
$page = $this->pagination->getPage($context);
36+
$itemsPerPage = $this->pagination->getLimit($operation, $context);
37+
}
38+
39+
if ($name !== null) {
40+
$cities = $this->searchService->searchCities($name, $itemsPerPage, $page - 1);
41+
};
42+
43+
$resources = [];
44+
foreach ($cities as $city) {
45+
$resources[] = CityResource::fromModel($city);
46+
}
47+
48+
return $resources;
49+
}
50+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Core\Domain\Search\Service;
6+
7+
interface CitiesDownloaderInterface
8+
{
9+
/**
10+
* @return array<{cityName: string, postCode: int}>
11+
*/
12+
public function getCities(): array;
13+
}

src/Core/Domain/Search/Service/SearchServiceInterface.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ public function searchDioceseIds(string $text, int $limit, int $offset): array;
2222

2323
public function findDiocese(string $text): ?Community;
2424

25+
public function searchCities(string $text, int $limit, int $offset): array;
26+
2527
/**
2628
* @return string[]
2729
*/

0 commit comments

Comments
 (0)