diff --git a/package.json b/package.json index 0bd3a81e5..590976cfa 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "@fullcalendar/timegrid": "^6.1.4", "@fullcalendar/vue3": "^6.1.4", "@popperjs/core": "^2.9.2", + "@types/leaflet": "^1.9.3", "dropzone": "^5.7.6", "es6-promise": "^4.2.8", "leaflet": "^1.7.1", diff --git a/src/Bundle/ChillMainBundle/Controller/AddressToReferenceMatcherController.php b/src/Bundle/ChillMainBundle/Controller/AddressToReferenceMatcherController.php new file mode 100644 index 000000000..5cdefceb5 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Controller/AddressToReferenceMatcherController.php @@ -0,0 +1,111 @@ +security = $security; + $this->entityManager = $entityManager; + $this->serializer = $serializer; + } + + /** + * @Route("/api/1.0/main/address/reference-match/{id}/set/reviewed", methods={"POST"}) + */ + public function markAddressAsReviewed(Address $address): JsonResponse + { + if (!$this->security->isGranted('ROLE_USER')) { + throw new AccessDeniedHttpException(); + } + + $address->setRefStatus(Address::ADDR_REFERENCE_STATUS_REVIEWED); + + $this->entityManager->flush(); + + return new JsonResponse( + $this->serializer->serialize($address, 'json', [AbstractNormalizer::GROUPS => ['read']]), + JsonResponse::HTTP_OK, + [], + true + ); + } + + /** + * Set an address back to "to review". Only if the address is in "reviewed" state. + * + * @Route("/api/1.0/main/address/reference-match/{id}/set/to_review", methods={"POST"}) + */ + public function markAddressAsToReview(Address $address): JsonResponse + { + if (!$this->security->isGranted('ROLE_USER')) { + throw new AccessDeniedHttpException(); + } + + if (Address::ADDR_REFERENCE_STATUS_REVIEWED !== $address->getRefStatus()) { + throw new AccessDeniedHttpException("forbidden to mark a matching address to 'to review'"); + } + + $address->setRefStatus(Address::ADDR_REFERENCE_STATUS_TO_REVIEW); + + $this->entityManager->flush(); + + return new JsonResponse( + $this->serializer->serialize($address, 'json', [AbstractNormalizer::GROUPS => ['read']]), + JsonResponse::HTTP_OK, + [], + true + ); + } + + /** + * @Route("/api/1.0/main/address/reference-match/{id}/sync-with-reference", methods={"POST"}) + */ + public function syncAddressWithReference(Address $address): JsonResponse + { + if (null === $address->getAddressReference()) { + throw new BadRequestHttpException('this address does not have any address reference'); + } + + $address->syncWithReference($address->getAddressReference()); + + $this->entityManager->flush(); + + return new JsonResponse( + $this->serializer->serialize($address, 'json', [AbstractNormalizer::GROUPS => ['read']]), + JsonResponse::HTTP_OK, + [], + true + ); + } + +} diff --git a/src/Bundle/ChillMainBundle/Controller/GeographicalUnitByAddressApiController.php b/src/Bundle/ChillMainBundle/Controller/GeographicalUnitByAddressApiController.php new file mode 100644 index 000000000..988439de5 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Controller/GeographicalUnitByAddressApiController.php @@ -0,0 +1,75 @@ +paginatorFactory = $paginatorFactory; + $this->geographicalUnitRepository = $geographicalUnitRepository; + $this->security = $security; + $this->serializer = $serializer; + } + + /** + * @Route("/api/1.0/main/geographical-unit/by-address/{id}.{_format}", requirements={"_format": "json"}) + */ + public function getGeographicalUnitCoveringAddress(Address $address): JsonResponse + { + if (!$this->security->isGranted('ROLE_USER')) { + throw new AccessDeniedHttpException(); + } + + $count = $this->geographicalUnitRepository->countGeographicalUnitContainingAddress($address); + $pagination = $this->paginatorFactory->create($count); + $units = $this->geographicalUnitRepository->findGeographicalUnitContainingAddress($address, $pagination->getCurrentPageFirstItemNumber(), $pagination->getItemsPerPage()); + + $collection = new Collection($units, $pagination); + + return new JsonResponse( + $this->serializer->serialize($collection, 'json', [AbstractNormalizer::GROUPS => ['read']]), + JsonResponse::HTTP_OK, + [], + true + ); + } +} diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php index 69546016a..c86a69be2 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php @@ -46,6 +46,7 @@ use Chill\MainBundle\Doctrine\Type\NativeDateIntervalType; use Chill\MainBundle\Doctrine\Type\PointType; use Chill\MainBundle\Entity\Civility; use Chill\MainBundle\Entity\Country; +use Chill\MainBundle\Entity\GeographicalUnitLayer; use Chill\MainBundle\Entity\Language; use Chill\MainBundle\Entity\Location; use Chill\MainBundle\Entity\LocationType; @@ -732,6 +733,20 @@ class ChillMainExtension extends Extension implements ], ], ], + [ + 'class' => GeographicalUnitLayer::class, + 'name' => 'geographical-unit-layer', + 'base_path' => '/api/1.0/main/geographical-unit-layer', + 'base_role' => 'ROLE_USER', + 'actions' => [ + '_index' => [ + 'methods' => [ + Request::METHOD_GET => true, + Request::METHOD_HEAD => true, + ], + ], + ], + ] ], ]); } diff --git a/src/Bundle/ChillMainBundle/Entity/Address.php b/src/Bundle/ChillMainBundle/Entity/Address.php index 9a0f8b7b3..8e5299579 100644 --- a/src/Bundle/ChillMainBundle/Entity/Address.php +++ b/src/Bundle/ChillMainBundle/Entity/Address.php @@ -12,6 +12,10 @@ declare(strict_types=1); namespace Chill\MainBundle\Entity; use Chill\MainBundle\Doctrine\Model\Point; +use Chill\MainBundle\Doctrine\Model\TrackCreationInterface; +use Chill\MainBundle\Doctrine\Model\TrackCreationTrait; +use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface; +use Chill\MainBundle\Doctrine\Model\TrackUpdateTrait; use Chill\ThirdPartyBundle\Entity\ThirdParty; use DateTime; use DateTimeInterface; @@ -28,8 +32,28 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface; * @ORM\Table(name="chill_main_address") * @ORM\HasLifecycleCallbacks */ -class Address +class Address implements TrackCreationInterface, TrackUpdateInterface { + use TrackCreationTrait; + use TrackUpdateTrait; + + /** + * When an Address does match with the AddressReference + */ + public const ADDR_REFERENCE_STATUS_MATCH = 'match'; + + /** + * When an Address does not match with the AddressReference, and + * is pending for a review + */ + public const ADDR_REFERENCE_STATUS_TO_REVIEW = 'to_review'; + + /** + * When an Address does not match with the AddressReference, but + * is reviewed + */ + public const ADDR_REFERENCE_STATUS_REVIEWED = 'reviewed'; + /** * @ORM\ManyToOne(targetEntity=AddressReference::class) * @Groups({"write"}) @@ -37,67 +61,48 @@ class Address private ?AddressReference $addressReference = null; /** - * @var string|null - * - * @ORM\Column(type="string", length=255, nullable=true) + * @ORM\Column(type="text", nullable=false, options={"default": ""}) * @Groups({"write"}) */ - private $buildingName; + private string $buildingName = ''; /** - * @ORM\Column(type="boolean") + * @ORM\Column(type="boolean", options={"default": false}) * @Groups({"write"}) */ private bool $confidential = false; /** - * @var string|null - * - * @ORM\Column(type="string", length=255, nullable=true) + * @ORM\Column(type="text", nullable=false, options={"default": ""}) * @Groups({"write"}) */ - private $corridor; + private string $corridor = ''; /** - * A list of metadata, added by customizable fields. - * - * @var array - */ - private $customs = []; - - /** - * @var string|null - * * used for the CEDEX information * - * @ORM\Column(type="string", length=255, nullable=true) + * @ORM\Column(type="text", nullable=false, options={"default": ""}) * @Groups({"write"}) */ - private $distribution; + private string $distribution = ''; /** - * @var string|null - * - * @ORM\Column(type="string", length=255, nullable=true) + * @ORM\Column(type="text", nullable=false, options={"default": ""}) * @Groups({"write"}) */ - private $extra; + private string $extra = ''; /** - * @var string|null - * - * @ORM\Column(type="string", length=255, nullable=true) + * @ORM\Column(type="text", nullable=false, options={"default": ""}) * @Groups({"write"}) */ - private $flat; + private string $flat = ''; /** - * @var string|null - * - * @ORM\Column(type="string", length=255, nullable=true) + * @ORM\Column(type="text", nullable=false, options={"default": ""}) * @Groups({"write"}) */ - private $floor; + private string $floor = ''; /** * List of geographical units and addresses. @@ -131,11 +136,9 @@ class Address * True if the address is a "no address", aka homeless person, ... * * @Groups({"write"}) - * @ORM\Column(type="boolean") - * - * @var bool + * @ORM\Column(type="boolean", options={"default": false}) */ - private $isNoAddress = false; + private bool $isNoAddress = false; /** * A ThirdParty reference for person's addresses that are linked to a third party. @@ -146,7 +149,7 @@ class Address * @Groups({"write"}) * @ORM\JoinColumn(nullable=true, onDelete="SET NULL") */ - private $linkedToThirdParty; + private ?ThirdParty $linkedToThirdParty; /** * A geospatial field storing the coordinates of the Address. @@ -156,7 +159,7 @@ class Address * @ORM\Column(type="point", nullable=true) * @Groups({"write"}) */ - private $point; + private ?Point $point = null; /** * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\PostalCode") @@ -166,28 +169,36 @@ class Address private ?PostalCode $postcode = null; /** - * @var string|null - * - * @ORM\Column(type="string", length=255, nullable=true) - * @Groups({"write"}) + * @var self::ADDR_REFERENCE_STATUS_* + * @ORM\Column(type="text", nullable=false, options={"default": self::ADDR_REFERENCE_STATUS_MATCH}) */ - private $steps; + private string $refStatus = self::ADDR_REFERENCE_STATUS_MATCH; /** - * @var string - * - * @ORM\Column(type="string", length=255) - * @Groups({"write"}) + * @ORM\Column(type="datetime_immutable", nullable=false, options={"default": "CURRENT_TIMESTAMP"}) */ - private $street = ''; + private \DateTimeImmutable $refStatusLastUpdate; /** - * @var string * - * @ORM\Column(type="string", length=255) + * @ORM\Column(type="text", nullable=false, options={"default": ""}) * @Groups({"write"}) */ - private $streetNumber = ''; + private string $steps = ''; + + /** + * + * @ORM\Column(type="text", nullable=false, options={"default": ""}) + * @Groups({"write"}) + */ + private string $street = ''; + + /** + * + * @ORM\Column(type="text", nullable=false, options={"default": ""}) + * @Groups({"write"}) + */ + private string $streetNumber = ''; /** * Indicates when the address starts validation. Used to build an history @@ -210,6 +221,7 @@ class Address public function __construct() { $this->validFrom = new DateTime(); + $this->refStatusLastUpdate = new \DateTimeImmutable('now'); $this->geographicalUnits = new ArrayCollection(); } @@ -220,7 +232,6 @@ class Address ->setBuildingName($original->getBuildingName()) ->setConfidential($original->getConfidential()) ->setCorridor($original->getCorridor()) - ->setCustoms($original->getCustoms()) ->setDistribution($original->getDistribution()) ->setExtra($original->getExtra()) ->setFlat($original->getFlat()) @@ -239,11 +250,20 @@ class Address public static function createFromAddressReference(AddressReference $original): Address { return (new Address()) - ->setPoint($original->getPoint()) - ->setPostcode($original->getPostcode()) - ->setStreet($original->getStreet()) - ->setStreetNumber($original->getStreetNumber()) - ->setAddressReference($original); + ->syncWithReference($original); + } + + public function syncWithReference(AddressReference $addressReference): Address + { + $this + ->setPoint($addressReference->getPoint()) + ->setPostcode($addressReference->getPostcode()) + ->setStreet($addressReference->getStreet()) + ->setStreetNumber($addressReference->getStreetNumber()) + ->setRefStatus(self::ADDR_REFERENCE_STATUS_MATCH) + ->setAddressReference($addressReference); + + return $this; } public function getAddressReference(): ?AddressReference @@ -251,7 +271,7 @@ class Address return $this->addressReference; } - public function getBuildingName(): ?string + public function getBuildingName(): string { return $this->buildingName; } @@ -261,35 +281,27 @@ class Address return $this->confidential; } - public function getCorridor(): ?string + public function getCorridor(): string { return $this->corridor; } - /** - * Get customs informations in the address. - */ - public function getCustoms(): array - { - return $this->customs; - } - - public function getDistribution(): ?string + public function getDistribution(): string { return $this->distribution; } - public function getExtra(): ?string + public function getExtra(): string { return $this->extra; } - public function getFlat(): ?string + public function getFlat(): string { return $this->flat; } - public function getFloor(): ?string + public function getFloor(): string { return $this->floor; } @@ -340,12 +352,22 @@ class Address return $this->postcode; } - public function getSteps(): ?string + public function getRefStatus(): string + { + return $this->refStatus; + } + + public function getRefStatusLastUpdate(): \DateTimeImmutable + { + return $this->refStatusLastUpdate; + } + + public function getSteps(): string { return $this->steps; } - public function getStreet(): ?string + public function getStreet(): string { return $this->street; } @@ -354,6 +376,7 @@ class Address * Get streetAddress1 (legacy function). * * @return string + * @deprecated */ public function getStreetAddress1() { @@ -364,13 +387,14 @@ class Address * Get streetAddress2 (legacy function). * * @return string + * @deprecated */ public function getStreetAddress2() { return $this->streetNumber; } - public function getStreetNumber(): ?string + public function getStreetNumber(): string { return $this->streetNumber; } @@ -378,7 +402,7 @@ class Address /** * @return DateTime */ - public function getValidFrom() + public function getValidFrom(): DateTime { return $this->validFrom; } @@ -407,7 +431,7 @@ class Address public function setBuildingName(?string $buildingName): self { - $this->buildingName = $buildingName; + $this->buildingName = (string) $buildingName; return $this; } @@ -421,47 +445,35 @@ class Address public function setCorridor(?string $corridor): self { - $this->corridor = $corridor; - - return $this; - } - - /** - * Store custom informations in the address. - * - * @return $this - */ - public function setCustoms(array $customs): self - { - $this->customs = $customs; + $this->corridor = (string) $corridor; return $this; } public function setDistribution(?string $distribution): self { - $this->distribution = $distribution; + $this->distribution = (string) $distribution; return $this; } public function setExtra(?string $extra): self { - $this->extra = $extra; + $this->extra = (string) $extra; return $this; } public function setFlat(?string $flat): self { - $this->flat = $flat; + $this->flat = (string) $flat; return $this; } public function setFloor(?string $floor): self { - $this->floor = $floor; + $this->floor = (string) $floor; return $this; } @@ -508,19 +520,44 @@ class Address return $this; } + /** + * Update the ref status + * + * <<<<<<< HEAD + * @param Address::ADDR_REFERENCE_STATUS_* $refStatus + * @param bool|null $updateLastUpdate Also update the "refStatusLastUpdate" + * ======= + * The refstatuslast update is also updated + * >>>>>>> 31152616d (Feature: Provide api endpoint for reviewing addresses) + */ + public function setRefStatus(string $refStatus, ?bool $updateLastUpdate = true): self + { + $this->refStatus = $refStatus; + + if ($updateLastUpdate) { + $this->setRefStatusLastUpdate(new \DateTimeImmutable('now')); + } + + return $this; + } + + public function setRefStatusLastUpdate(\DateTimeImmutable $refStatusLastUpdate): self + { + $this->refStatusLastUpdate = $refStatusLastUpdate; + + return $this; + } + public function setSteps(?string $steps): self { - $this->steps = $steps; + $this->steps = (string) $steps; return $this; } public function setStreet(?string $street): self { - if (null === $street) { - $street = ''; - } - $this->street = $street; + $this->street = (string) $street; return $this; } @@ -531,6 +568,7 @@ class Address * @param string $streetAddress1 * * @return Address + * @deprecated */ public function setStreetAddress1($streetAddress1) { @@ -543,7 +581,7 @@ class Address * Set streetAddress2 (legacy function). * * @param string $streetAddress2 - * + * @deprecated * @return Address */ public function setStreetAddress2($streetAddress2) @@ -555,10 +593,7 @@ class Address public function setStreetNumber(?string $streetNumber): self { - if (null === $streetNumber) { - $streetNumber = ''; - } - $this->streetNumber = $streetNumber; + $this->streetNumber = (string) $streetNumber; return $this; } @@ -605,7 +640,7 @@ class Address return; } - if (empty($this->getStreetAddress1())) { + if ('' === $this->getStreet()) { $context ->buildViolation('address.street1-should-be-set') ->atPath('streetAddress1') diff --git a/src/Bundle/ChillMainBundle/Entity/AddressReference.php b/src/Bundle/ChillMainBundle/Entity/AddressReference.php index 68cc32186..57421749f 100644 --- a/src/Bundle/ChillMainBundle/Entity/AddressReference.php +++ b/src/Bundle/ChillMainBundle/Entity/AddressReference.php @@ -55,13 +55,13 @@ class AddressReference * @ORM\Column(type="integer") * @groups({"read"}) */ - private $id; + private ?int $id; /** - * @ORM\Column(type="string", length=255, nullable=true) + * @ORM\Column(type="text", nullable=false, options={"default": ""}) * @groups({"read"}) */ - private $municipalityCode; + private string $municipalityCode = ''; /** * A geospatial field storing the coordinates of the Address. @@ -71,7 +71,7 @@ class AddressReference * @ORM\Column(type="point") * @groups({"read"}) */ - private $point; + private ?Point $point = null; /** * @var PostalCode @@ -79,31 +79,31 @@ class AddressReference * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\PostalCode") * @groups({"read"}) */ - private $postcode; + private ?PostalCode $postcode; /** - * @ORM\Column(type="string", length=255) + * @ORM\Column(type="text", nullable=false, options={"default": ""}) * @groups({"read"}) */ - private $refId; + private string $refId = ''; /** - * @ORM\Column(type="string", length=255, nullable=true) + * @ORM\Column(type="text", nullable=false, options={"default": ""}) * @groups({"read"}) */ - private $source; + private string $source = ''; /** - * @ORM\Column(type="string", length=255, nullable=true) + * @ORM\Column(type="text", nullable=false, options={"default": ""}) * @groups({"read"}) */ - private $street; + private string $street = ''; /** - * @ORM\Column(type="string", length=255, nullable=true) + * @ORM\Column(type="text", nullable=false, options={"default": ""}) * @groups({"read"}) */ - private $streetNumber; + private string $streetNumber = ''; /** * @ORM\Column(type="datetime_immutable", nullable=true) @@ -126,7 +126,7 @@ class AddressReference return $this->id; } - public function getMunicipalityCode(): ?string + public function getMunicipalityCode(): string { return $this->municipalityCode; } @@ -141,27 +141,27 @@ class AddressReference * * @return PostalCode */ - public function getPostcode() + public function getPostcode(): ?PostalCode { return $this->postcode; } - public function getRefId(): ?string + public function getRefId(): string { return $this->refId; } - public function getSource(): ?string + public function getSource(): string { return $this->source; } - public function getStreet(): ?string + public function getStreet(): string { return $this->street; } - public function getStreetNumber(): ?string + public function getStreetNumber(): string { return $this->streetNumber; } @@ -192,7 +192,7 @@ class AddressReference public function setMunicipalityCode(?string $municipalityCode): self { - $this->municipalityCode = $municipalityCode; + $this->municipalityCode = (string) $municipalityCode; return $this; } @@ -227,21 +227,21 @@ class AddressReference public function setSource(?string $source): self { - $this->source = $source; + $this->source = (string) $source; return $this; } public function setStreet(?string $street): self { - $this->street = $street; + $this->street = (string) $street; return $this; } public function setStreetNumber(?string $streetNumber): self { - $this->streetNumber = $streetNumber; + $this->streetNumber = (string) $streetNumber; return $this; } diff --git a/src/Bundle/ChillMainBundle/Entity/GeographicalUnit/SimpleGeographicalUnitDTO.php b/src/Bundle/ChillMainBundle/Entity/GeographicalUnit/SimpleGeographicalUnitDTO.php index 34f16a0fb..7add53066 100644 --- a/src/Bundle/ChillMainBundle/Entity/GeographicalUnit/SimpleGeographicalUnitDTO.php +++ b/src/Bundle/ChillMainBundle/Entity/GeographicalUnit/SimpleGeographicalUnitDTO.php @@ -11,6 +11,8 @@ declare(strict_types=1); namespace Chill\MainBundle\Entity\GeographicalUnit; +use Symfony\Component\Serializer\Annotation as Serializer; + /** * Simple GeographialUnit Data Transfer Object. * @@ -21,24 +23,28 @@ class SimpleGeographicalUnitDTO /** * @readonly * @psalm-readonly + * @Serializer\Groups({"read"}) */ public int $id; /** * @readonly * @psalm-readonly + * @Serializer\Groups({"read"}) */ public int $layerId; /** * @readonly * @psalm-readonly + * @Serializer\Groups({"read"}) */ public string $unitName; /** * @readonly * @psalm-readonly + * @Serializer\Groups({"read"}) */ public string $unitRefId; diff --git a/src/Bundle/ChillMainBundle/Entity/GeographicalUnitLayer.php b/src/Bundle/ChillMainBundle/Entity/GeographicalUnitLayer.php index bdea40563..b856c7a21 100644 --- a/src/Bundle/ChillMainBundle/Entity/GeographicalUnitLayer.php +++ b/src/Bundle/ChillMainBundle/Entity/GeographicalUnitLayer.php @@ -14,6 +14,7 @@ namespace Chill\MainBundle\Entity; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; +use Symfony\Component\Serializer\Annotation as Serializer; /** * @ORM\Table(name="chill_main_geographical_unit_layer", uniqueConstraints={ @@ -27,16 +28,19 @@ class GeographicalUnitLayer * @ORM\Id * @ORM\GeneratedValue * @ORM\Column(type="integer") + * @Serializer\Groups({"read"}) */ private ?int $id = null; /** * @ORM\Column(type="json", nullable=false, options={"default": "[]"}) + * @Serializer\Groups({"read"}) */ private array $name = []; /** * @ORM\Column(type="text", nullable=false, options={"default": ""}) + * @Serializer\Groups({"read"}) */ private string $refId = ''; diff --git a/src/Bundle/ChillMainBundle/Form/DataMapper/AddressDataMapper.php b/src/Bundle/ChillMainBundle/Form/DataMapper/AddressDataMapper.php index 8961627d4..ca9c8452e 100644 --- a/src/Bundle/ChillMainBundle/Form/DataMapper/AddressDataMapper.php +++ b/src/Bundle/ChillMainBundle/Form/DataMapper/AddressDataMapper.php @@ -43,11 +43,13 @@ class AddressDataMapper implements DataMapperInterface /** @var FormInterface $form */ switch ($key) { case 'streetAddress1': + /** @phpstan-ignore-next-line */ $form->setData($address->getStreetAddress1()); break; case 'streetAddress2': + /** @phpstan-ignore-next-line */ $form->setData($address->getStreetAddress2()); break; @@ -110,11 +112,13 @@ class AddressDataMapper implements DataMapperInterface return; } + /** @phpstan-ignore-next-line */ $address->setStreetAddress1($form->getData()); break; case 'streetAddress2': + /** @phpstan-ignore-next-line */ $address->setStreetAddress2($form->getData()); break; diff --git a/src/Bundle/ChillMainBundle/Form/DataMapper/RollingDateDataMapper.php b/src/Bundle/ChillMainBundle/Form/DataMapper/RollingDateDataMapper.php index 21d0c3fde..909b671b8 100644 --- a/src/Bundle/ChillMainBundle/Form/DataMapper/RollingDateDataMapper.php +++ b/src/Bundle/ChillMainBundle/Form/DataMapper/RollingDateDataMapper.php @@ -38,7 +38,7 @@ class RollingDateDataMapper implements DataMapperInterface $forms = iterator_to_array($forms); $viewData = new RollingDate( - $forms['roll']->getData(), + ($forms['roll']->getData() ?? RollingDate::T_TODAY), $forms['fixedDate']->getData() ); } diff --git a/src/Bundle/ChillMainBundle/Repository/GeographicalUnitRepository.php b/src/Bundle/ChillMainBundle/Repository/GeographicalUnitRepository.php index b422b8649..f5e646dba 100644 --- a/src/Bundle/ChillMainBundle/Repository/GeographicalUnitRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/GeographicalUnitRepository.php @@ -11,20 +11,58 @@ declare(strict_types=1); namespace Chill\MainBundle\Repository; +use Chill\MainBundle\Entity\Address; use Chill\MainBundle\Entity\GeographicalUnit; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; +use Doctrine\ORM\Query\Expr\Join; +use Doctrine\ORM\QueryBuilder; -class GeographicalUnitRepository implements GeographicalUnitRepositoryInterface +final class GeographicalUnitRepository implements GeographicalUnitRepositoryInterface { - private EntityManagerInterface $em; - private EntityRepository $repository; public function __construct(EntityManagerInterface $em) { $this->repository = $em->getRepository($this->getClassName()); - $this->em = $em; + } + + + public function countGeographicalUnitContainingAddress(Address $address): int + { + $qb = $this->buildQueryGeographicalUnitContainingAddress($address); + + return $qb + ->select('COUNT(gu)') + ->getQuery() + ->getSingleScalarResult(); + } + + public function findGeographicalUnitContainingAddress(Address $address, int $offset = 0, int $limit = 50): array + { + $qb = $this->buildQueryGeographicalUnitContainingAddress($address); + + return $qb + ->select(sprintf('NEW %s(gu.id, gu.unitName, gu.unitRefId, IDENTITY(gu.layer))', GeographicalUnit\SimpleGeographicalUnitDTO::class)) + ->addOrderBy('IDENTITY(gu.layer)') + ->addOrderBy(('gu.unitName')) + ->getQuery() + ->setFirstResult($offset) + ->setMaxResults($limit) + ->getResult(); + } + + private function buildQueryGeographicalUnitContainingAddress(Address $address): QueryBuilder + { + $qb = $this->repository + ->createQueryBuilder('gu') + ; + return $qb + ->select(sprintf('NEW %s(gu.id, gu.unitName, gu.unitRefId, IDENTITY(gu.layer))', GeographicalUnit\SimpleGeographicalUnitDTO::class)) + ->innerJoin(Address::class, 'address', Join::WITH, 'ST_CONTAINS(gu.geom, address.point) = TRUE') + ->where($qb->expr()->eq('address', ':address')) + ->setParameter('address', $address) + ; } public function find($id): ?GeographicalUnit diff --git a/src/Bundle/ChillMainBundle/Repository/GeographicalUnitRepositoryInterface.php b/src/Bundle/ChillMainBundle/Repository/GeographicalUnitRepositoryInterface.php index cdfb057e2..f2c102407 100644 --- a/src/Bundle/ChillMainBundle/Repository/GeographicalUnitRepositoryInterface.php +++ b/src/Bundle/ChillMainBundle/Repository/GeographicalUnitRepositoryInterface.php @@ -11,8 +11,23 @@ declare(strict_types=1); namespace Chill\MainBundle\Repository; +use Chill\MainBundle\Entity\Address; +use Chill\MainBundle\Entity\GeographicalUnit\SimpleGeographicalUnitDTO; use Doctrine\Persistence\ObjectRepository; interface GeographicalUnitRepositoryInterface extends ObjectRepository { + /** + * Return the geographical units as @link{SimpleGeographicalUnitDTO} whithin the address is contained. + * + * This query is executed in real time (without the refresh of the materialized view which load the addresses). + * + * @param Address $address + * @param int $offset + * @param int $limit + * @return SimpleGeographicalUnitDTO[] + */ + public function findGeographicalUnitContainingAddress(Address $address, int $offset = 0, int $limit = 50): array; + + public function countGeographicalUnitContainingAddress(Address $address): int; } diff --git a/src/Bundle/ChillMainBundle/Resources/public/lib/api/address.ts b/src/Bundle/ChillMainBundle/Resources/public/lib/api/address.ts new file mode 100644 index 000000000..1499f4a6a --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/public/lib/api/address.ts @@ -0,0 +1,35 @@ +import {Address, GeographicalUnitLayer, SimpleGeographicalUnit} from "../../types"; +import {fetchResults, makeFetch} from "./apiMethods"; + +export const getAddressById = async (address_id: number): Promise
=> +{ + const url = `/api/1.0/main/address/${address_id}.json`; + + const response = await fetch(url); + + if (response.ok) { + return response.json(); + } + + throw Error('Error with request resource response'); +}; + +export const getGeographicalUnitsByAddress = async (address: Address): PromiseVoir sur Google Maps OSM
+ + + + + diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/AddressDetails/Parts/AddressDetailsRefMatching.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/AddressDetails/Parts/AddressDetailsRefMatching.vue new file mode 100644 index 000000000..cbeb9e9e9 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/AddressDetails/Parts/AddressDetailsRefMatching.vue @@ -0,0 +1,96 @@ + + +L'adresse de référence a été modifiée.
+L'adresse est conservée, mais diffère de l'adresse de référence.
+ + + +{{ l }}
+{{ address.text }}
-{{ address.postcode.code }} {{ address.postcode.name }}
-{{ address.country.name.fr }}
@@ -35,11 +36,12 @@{{ l }}
+
- {{ address.text }}
+ {{ address.text }}
-
++
+