Skip to content

Commit

Permalink
add place collection provider
Browse files Browse the repository at this point in the history
  • Loading branch information
bailletced committed Feb 4, 2025
1 parent 9dc4921 commit 7171ba8
Show file tree
Hide file tree
Showing 10 changed files with 257 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace App\Field\Infrastructure\ApiPlatform\Filter;

use ApiPlatform\Metadata\FilterInterface;
use App\Field\Domain\Enum\FieldCommunity;
use Symfony\Component\PropertyInfo\Type;

final class FieldParentCommunityIdFilter implements FilterInterface
{
public function getDescription(string $resourceClass): array
{
return [
'parentCommunityId' => [
'property' => FieldCommunity::PARENT_COMMUNITY_ID->value,
'type' => Type::BUILTIN_TYPE_STRING,
'required' => false,
],
];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace App\Field\Infrastructure\ApiPlatform\Filter;

use ApiPlatform\Metadata\FilterInterface;
use App\Field\Domain\Enum\FieldCommunity;
use Symfony\Component\PropertyInfo\Type;

final class FieldParentWikidataIdFilter implements FilterInterface
{
public function getDescription(string $resourceClass): array
{
return [
'parentWikidataId' => [
'property' => FieldCommunity::PARENT_WIKIDATA_ID->value,
'type' => Type::BUILTIN_TYPE_INT,
'required' => false,
],
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use ApiPlatform\Metadata\Put;
use App\Field\Domain\Model\Field;
use App\Field\Infrastructure\ApiPlatform\Filter\FieldNameFilter;
use App\Field\Infrastructure\ApiPlatform\Filter\FieldParentWikidataIdFilter;
use App\Field\Infrastructure\ApiPlatform\Filter\FieldTypeFilter;
use App\Field\Infrastructure\ApiPlatform\Filter\FieldWikidataIdFilter;
use App\FieldHolder\Community\Domain\Model\Community;
Expand Down Expand Up @@ -57,6 +58,7 @@
filters: [
FieldTypeFilter::class,
FieldWikidataIdFilter::class,
FieldParentWikidataIdFilter::class,
FieldNameFilter::class,
],
provider: CommunityCollectionProvider::class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public function provide(Operation $operation, array $uriVariables = [], array $c
/** @var string|null $type */
$type = $context['filters'][FieldCommunity::TYPE->value] ?? null;
$wikidataId = $context['filters'][FieldCommunity::WIKIDATA_ID->value] ?? null;
$parentWikidataId = $context['filters'][FieldCommunity::PARENT_WIKIDATA_ID->value] ?? null;

$name = $context['filters'][FieldCommunity::NAME->value] ?? null;
$page = $itemsPerPage = null;
Expand All @@ -61,11 +62,16 @@ public function provide(Operation $operation, array $uriVariables = [], array $c
return [];
}
}

if ($parentWikidataId) {
$parentCommunity = $this->communityRepo->withWikidataId(intval($parentWikidataId))->asCollection()->first();
}

$models = $this->communityRepo
->ofIds(array_map(fn (string $entityId) => Uuid::fromString($entityId), $entityIds ?? []))
->withType($type)
->withWikidataId(intval($wikidataId))
->withParentCommunityId($parentCommunity->id ?? null)
->withPagination($page, $itemsPerPage);

$resources = [];
Expand Down
1 change: 1 addition & 0 deletions src/FieldHolder/Place/Domain/Model/Place.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class Place extends FieldHolder
* @var Collection<int, Field>
*/
#[ORM\OneToMany(targetEntity: Field::class, mappedBy: 'place')]
#[Groups(['places'])]
public Collection $fields;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,6 @@ public function withWikidataId(?int $value): static;
* @param array<int> $wikidataIds
*/
public function withWikidataIds(array $wikidataIds): static;

public function withParentCommunityId(Uuid $parentId): static;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\Put;
use App\Field\Domain\Model\Field;
use App\Field\Infrastructure\ApiPlatform\Filter\FieldParentCommunityIdFilter;
use App\FieldHolder\Place\Domain\Model\Place;
use App\FieldHolder\Place\Infrastructure\ApiPlatform\Input\PlaceWikidataInput;
use App\FieldHolder\Place\Infrastructure\ApiPlatform\State\Processor\CreatePlaceProcessor;
use App\FieldHolder\Place\Infrastructure\ApiPlatform\State\Processor\UpdatePlaceProcessor;
use App\FieldHolder\Place\Infrastructure\ApiPlatform\State\Processor\UpsertPlaceProcessor;
use App\FieldHolder\Place\Infrastructure\ApiPlatform\State\Provider\PlaceCollectionProvider;
use App\FieldHolder\Place\Infrastructure\ApiPlatform\State\Provider\PlaceItemProvider;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Uid\Uuid;
Expand Down Expand Up @@ -53,6 +56,14 @@
processor: UpsertPlaceProcessor::class,
input: PlaceWikidataInput::class,
),
new GetCollection(
uriTemplate: '/places',
filters: [
FieldParentCommunityIdFilter::class,
],
provider: PlaceCollectionProvider::class,
normalizationContext: ['groups' => ['places']],
),
],
)]
final class PlaceResource
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

declare(strict_types=1);

namespace App\FieldHolder\Place\Infrastructure\ApiPlatform\State\Provider;

use ApiPlatform\Metadata\Exception\InvalidArgumentException;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\Pagination\Pagination;
use ApiPlatform\State\ProviderInterface;
use App\Field\Domain\Enum\FieldCommunity;
use App\FieldHolder\Place\Domain\Repository\PlaceRepositoryInterface;
use App\FieldHolder\Place\Infrastructure\ApiPlatform\Resource\PlaceResource;
use App\Shared\Infrastructure\ApiPlatform\State\Paginator;
use Symfony\Component\Uid\Uuid;

/**
* @implements ProviderInterface<PlaceResource>
*/
final class PlaceCollectionProvider implements ProviderInterface
{
public function __construct(
private Pagination $pagination,
private PlaceRepositoryInterface $placeRepo,
) {
}

/**
* @return Paginator<PlaceResource>|list<PlaceResource>
*/
public function provide(Operation $operation, array $uriVariables = [], array $context = []): Paginator|array
{
$parentCommunityId = $context['filters'][FieldCommunity::PARENT_COMMUNITY_ID->value] ?? null;
if ($parentCommunityId && !Uuid::isValid($parentCommunityId)) {
throw new InvalidArgumentException(sprintf('provided parentCommunityId %s is not a valid uuid', $parentCommunityId));
}

$page = $itemsPerPage = null;

if ($this->pagination->isEnabled($operation, $context)) {
$page = $this->pagination->getPage($context);
$itemsPerPage = $this->pagination->getLimit($operation, $context);
}

$models = $this->placeRepo
->withParentCommunityId(Uuid::fromString($parentCommunityId))
->withPagination($page, $itemsPerPage);

$resources = [];
foreach ($models as $model) {
$resources[] = PlaceResource::fromModel($model);
}

if (null !== $paginator = $models->paginator()) {
$resources = new Paginator(
new \ArrayIterator($resources),
(float) $paginator->getCurrentPage(),
(float) $paginator->getItemsPerPage(),
(float) $paginator->getLastPage(),
(float) $paginator->getTotalItems(),
);
}

return $resources;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,25 @@ public function withWikidataIds(?array $wikidataIds): static
->setParameter('valueWikidataIds', $wikidataIds);
});
}

public function withParentCommunityId(?Uuid $parentId): static
{
if (!$parentId) {
return $this;
}

return
$this->filter(static function (QueryBuilder $qb) use ($parentId): void {
$qb->andWhere("
EXISTS (
SELECT 1 FROM App\Field\Domain\Model\Field f_community_parent_id
JOIN f_community_parent_id.communitiesVal communities
WHERE f_community_parent_id.place = place AND
f_community_parent_id.name = 'parentCommunities' AND
communities.id = :valueParentCommunity
)
")
->setParameter('valueParentCommunity', $parentId->toBinary());
});
}
}
102 changes: 102 additions & 0 deletions tests/FieldHolder/Place/Acceptance/GetPlacesTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?php

namespace App\Tests\FieldHolder\Place\Acceptance;

use App\Field\Domain\Enum\FieldCommunity;
use App\Field\Domain\Enum\FieldPlace;
use App\Field\Domain\Model\Field;
use App\FieldHolder\Community\Domain\Enum\CommunityType;
use App\Tests\Field\DummyFactory\DummyFieldFactory;
use App\Tests\FieldHolder\Community\DummyFactory\DummyCommunityFactory;
use App\Tests\FieldHolder\Place\DummyFactory\DummyPlaceFactory;
use App\Tests\Helper\AcceptanceTestHelper;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\HttpFoundation\Response as HttpFoundationResponse;
use Zenstruck\Foundry\Test\Factories;

class GetPlacesTest extends AcceptanceTestHelper
{
use Factories;

protected function setUp(): void
{
parent::setUp();
}

public function testFilterByParentCommunityId(): void
{
[$community1, $community2] = DummyCommunityFactory::createMany(2,
[
'fields' => [
DummyFieldFactory::createOne([
'name' => FieldCommunity::TYPE->value,
Field::getPropertyName(FieldCommunity::TYPE) => CommunityType::PARISH->value,
]),
],
]
);

$church1 = DummyPlaceFactory::createOne([
'fields' => [
DummyFieldFactory::createOne([
'name' => FieldPlace::PARENT_COMMUNITIES->value,
Field::getPropertyName(FieldPlace::PARENT_COMMUNITIES) => new ArrayCollection([$community1->_real()]),
]),
],
]);

$church2 = DummyPlaceFactory::createOne([
'fields' => [
DummyFieldFactory::createOne([
'name' => FieldPlace::PARENT_COMMUNITIES->value,
Field::getPropertyName(FieldPlace::PARENT_COMMUNITIES) => new ArrayCollection([$community1->_real()]),
]),
],
]);

$church3 = DummyPlaceFactory::createOne([
'fields' => [
DummyFieldFactory::createOne([
'name' => FieldPlace::PARENT_COMMUNITIES->value,
Field::getPropertyName(FieldPlace::PARENT_COMMUNITIES) => new ArrayCollection([$community2->_real()]),
]),
],
]);

$church4 = DummyPlaceFactory::createOne([
'fields' => [
DummyFieldFactory::createOne([
'name' => FieldPlace::PARENT_COMMUNITIES->value,
Field::getPropertyName(FieldPlace::PARENT_COMMUNITIES) => new ArrayCollection([$community2->_real()]),
]),
],
]);

$response = self::assertResponse($this->get('/places', querystring: [
FieldCommunity::PARENT_COMMUNITY_ID->value => $community1->id->toString(),
]), HttpFoundationResponse::HTTP_OK);
$churchIds = array_map(fn (array $church) => $church['id'], $response);
self::assertCount(2, $churchIds);
self::assertContains($church1->id->toString(), $churchIds);
self::assertContains($church2->id->toString(), $churchIds);

$response = self::assertResponse($this->get('/places', querystring: [
FieldCommunity::PARENT_COMMUNITY_ID->value => $community2->id->toString(),
]), HttpFoundationResponse::HTTP_OK);
$churchIds = array_map(fn (array $church) => $church['id'], $response);
self::assertCount(2, $churchIds);
self::assertContains($church3->id->toString(), $churchIds);
self::assertContains($church4->id->toString(), $churchIds);
}

public function testShouldErrorIfParentCommunityIdNotAUuid(): void
{
$response = self::assertErrorResponse(
$this->get('/places', querystring: [
FieldCommunity::PARENT_COMMUNITY_ID->value => 123,
]),
HttpFoundationResponse::HTTP_BAD_REQUEST,
sprintf('provided parentCommunityId %s is not a valid uuid', 123)
);
}
}

0 comments on commit 7171ba8

Please sign in to comment.