فهرست منبع

add FederationStructure resource, builder and provider

Olivier Massot 3 سال پیش
والد
کامیت
169726dabb

+ 305 - 1
src/ApiResources/Public/FederationStructure.php

@@ -1,6 +1,310 @@
 <?php
+namespace App\ApiResources\Public;
 
-class FederationStructure
+use ApiPlatform\Core\Annotation\ApiProperty;
+use ApiPlatform\Core\Annotation\ApiResource;
+use App\ApiResources\ApiResourcesInterface;
+
+/**
+ * Structure telle qu'elle est représentée sur l'iframe de recherche des structures d'une fédération
+ */
+#[ApiResource(
+    collectionOperations:[
+        'get' => [
+            'method' => 'GET',
+            'path' => '/api/public/federation_structures/get?parent-id=${parentId}',
+        ]
+    ],
+    itemOperations: [
+        'get' => [
+            'method' => 'GET',
+            'path' => '/api/public/federation_structures/get?organization-id=${organizationId}',
+        ]
+    ]
+)]
+class FederationStructure implements ApiResourcesInterface
 {
+// n1.parent_id as n1Id, net1.name as n1Name, n2.parent_id as n2Id, n3.parent_id as n3Id, n4.parent_id as n4Id, n5.parent_id as n5Id,
+
+    #[ApiProperty(identifier: true)]
+    private int $id;
+
+    private string $name;
+
+    private int $logoId;
+
+    private string $principalType;
+
+    private string $website;
+
+    private string $addresses;
+
+    private string $practices;
+
+    private int $parentId;
+
+    private int $n1Id;
+
+    private int $n2Id;
+
+    private int $n3Id;
+
+    private int $n4Id;
+
+    private int $n5Id;
+
+    private string $parents;
+
+    /**
+     * @return int
+     */
+    public function getId(): int
+    {
+        return $this->id;
+    }
+
+    /**
+     * @param int $id
+     * @return FederationStructure
+     */
+    public function setId(int $id): self
+    {
+        $this->id = $id;
+
+        return $this;
+    }
+
+    /**
+     * @return string
+     */
+    public function getName(): string
+    {
+        return $this->name;
+    }
+
+    /**
+     * @param string $name
+     */
+    public function setName(string $name): self
+    {
+        $this->name = $name;
+
+        return $this;
+    }
+
+    /**
+     * @return int
+     */
+    public function getLogoId(): int
+    {
+        return $this->logoId;
+    }
+
+    /**
+     * @param int $logoId
+     */
+    public function setLogoId(int $logoId): self
+    {
+        $this->logoId = $logoId;
+
+        return $this;
+    }
+
+    /**
+     * @return string
+     */
+    public function getPrincipalType(): string
+    {
+        return $this->principalType;
+    }
+
+    /**
+     * @param string $principalType
+     */
+    public function setPrincipalType(string $principalType): self
+    {
+        $this->principalType = $principalType;
+
+        return $this;
+    }
+
+    /**
+     * @return string
+     */
+    public function getWebsite(): string
+    {
+        return $this->website;
+    }
+
+    /**
+     * @param string $website
+     */
+    public function setWebsite(string $website): self
+    {
+        $this->website = $website;
+
+        return $this;
+    }
+
+    /**
+     * @return string
+     */
+    public function getAddresses(): string
+    {
+        return $this->addresses;
+    }
+
+    /**
+     * @param string $addresses
+     */
+    public function setAddresses(string $addresses): self
+    {
+        $this->addresses = $addresses;
+
+        return $this;
+    }
+
+    /**
+     * @return string
+     */
+    public function getPractices(): string
+    {
+        return $this->practices;
+    }
+
+    /**
+     * @param string $practices
+     */
+    public function setPractices(string $practices): self
+    {
+        $this->practices = $practices;
+
+        return $this;
+    }
+
+    /**
+     * @return int
+     */
+    public function getParentId(): int
+    {
+        return $this->parentId;
+    }
+
+    /**
+     * @param int $parentId
+     */
+    public function setParentId(int $parentId): self
+    {
+        $this->parentId = $parentId;
+
+        return $this;
+    }
+
+    /**
+     * @return int
+     */
+    public function getN1Id(): int
+    {
+        return $this->n1Id;
+    }
+
+    /**
+     * @param int $n1Id
+     */
+    public function setN1Id(int $n1Id): self
+    {
+        $this->n1Id = $n1Id;
+
+        return $this;
+    }
+
+    /**
+     * @return int
+     */
+    public function getN2Id(): int
+    {
+        return $this->n2Id;
+    }
+
+    /**
+     * @param int $n2Id
+     */
+    public function setN2Id(int $n2Id): self
+    {
+        $this->n2Id = $n2Id;
+
+        return $this;
+    }
+
+    /**
+     * @return int
+     */
+    public function getN3Id(): int
+    {
+        return $this->n3Id;
+    }
+
+    /**
+     * @param int $n3Id
+     */
+    public function setN3Id(int $n3Id): self
+    {
+        $this->n3Id = $n3Id;
+
+        return $this;
+    }
+
+    /**
+     * @return int
+     */
+    public function getN4Id(): int
+    {
+        return $this->n4Id;
+    }
+
+    /**
+     * @param int $n4Id
+     */
+    public function setN4Id(int $n4Id): self
+    {
+        $this->n4Id = $n4Id;
+
+        return $this;
+    }
+
+    /**
+     * @return int
+     */
+    public function getN5Id(): int
+    {
+        return $this->n5Id;
+    }
+
+    /**
+     * @param int $n5Id
+     */
+    public function setN5Id(int $n5Id): self
+    {
+        $this->n5Id = $n5Id;
+
+        return $this;
+    }
+
+    /**
+     * @return string
+     */
+    public function getParents(): string
+    {
+        return $this->parents;
+    }
+
+    /**
+     * @param string $parents
+     */
+    public function setParents(string $parents): self
+    {
+        $this->parents = $parents;
 
+        return $this;
+    }
 }

+ 28 - 1
src/DataProvider/Public/FederationStructureDataProvider.php

@@ -2,10 +2,37 @@
 
 namespace App\DataProvider\Public;
 
+use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface;
 use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
 use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
+use App\ApiResources\Public\FederationStructure;
+use App\Service\ApiResourceBuilder\Public\FederationStructureBuilder;
+use Symfony\Component\HttpFoundation\RequestStack;
 
-class FederationStructure implements ItemDataProviderInterface, RestrictedDataProviderInterface
+
+class FederationStructureDataProvider implements ItemDataProviderInterface, CollectionDataProviderInterface, RestrictedDataProviderInterface
 {
+    public function __construct(
+        private FederationStructureBuilder $builder,
+        private RequestStack $requestStack
+    ) {}
+
+    public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
+    {
+        return FederationStructure::class === $resourceClass;
+    }
+
+    public function getItem(string $resourceClass, $id, string $operationName = null, array $context = []): ?FederationStructure
+    {
+        return $this->builder->getFederationStructureByOrganizationId($id);
+    }
 
+    public function getCollection(string $resourceClass, string $operationName = null): array
+    {
+        $request = $this->requestStack->getCurrentRequest();
+        if ($request === null) {
+            throw new \RuntimeException('Undefined request');
+        }
+        return $this->builder->getDataByFederationId($request->get('parent-id'));
+    }
 }

+ 123 - 0
src/Service/ApiResourceBuilder/Public/FederationStructureBuilder.php

@@ -1,6 +1,129 @@
 <?php
 
+namespace App\Service\ApiResourceBuilder\Public;
+
+use App\ApiResources\Public\FederationStructure;
+use Doctrine\ORM\EntityManagerInterface;
+
 class FederationStructureBuilder
 {
+    public function __construct(
+        private EntityManagerInterface $em
+    ) {}
+
+    private static function buildFederationStructure(array $data) {
+        return (new FederationStructure())
+            ->setId((int)$data['id'])
+            ->setName((string)$data['name'])
+            ->setLogoId((int)$data['logoId'])
+            ->setPrincipalType((string)$data['principalType'])
+            ->setWebsite((string)$data['website'])
+            ->setAddresses((string)$data['addresses'])
+            ->setPractices((string)$data['practices'])
+            ->setParentId((int)$data['parentId'])
+            ->setN1Id((int)$data['n1Id'])
+            ->setN2Id((int)$data['n2id'])
+            ->setN3Id((int)$data['n3Id'])
+            ->setN4Id((int)$data['n4Id'])
+            ->setN5Id((int)$data['n5Id'])
+            ->setParents((string)$data['parents']);
+    }
+
+    /**
+     * Route optimisée pour retourner les données de réseau d'une structure membre de fédération, au format json
+     *
+     * Cette route est utilisée par l'iframe de recherche des structures
+     * @see https://gitlab.2iopenservice.com/opentalent/frames
+     *
+     * @param int $organizationId
+     * @return FederationStructure
+     * @throws \Doctrine\DBAL\DBALException
+     * @throws \Doctrine\DBAL\Driver\Exception
+     * @throws \Doctrine\DBAL\Exception
+     */
+    public function getFederationStructureByOrganizationId(int $organizationId): FederationStructure
+    {
+
+        $sql = "SELECT o.id, o.name, o.logo_id as logoId, o.description, o.image_id as imageId, p.otherWebsite as website, a.latitude, a.longitude,
+                       GROUP_CONCAT(COLUMN_JSON(COLUMN_CREATE(
+                             'type', oa.type, 'latitude', a.latitude, 'longitude', a.longitude, 
+                             'streetAddress', TRIM(BOTH '\n' FROM CONCAT_WS('\n', a.addressOwner, a.streetAddress, a.streetAddressSecond, a.streetAddressThird)),
+                             'postalCode', a.postalCode, 'addressCity', a.addressCity, 'country', c.name))) as addresses,
+                       cp.telphone, cp.mobilPhone, cp.email, o.facebook, o.twitter, o.instagram, o.youtube,
+                       (SELECT CONCAT(GROUP_CONCAT(DISTINCT CONCAT(tp.name)))
+                        FROM organization_type_of_practices AS otp
+                        LEFT JOIN TypeOfPractice AS tp ON(tp.id = otp.typeofpractice_id)
+                        WHERE otp.organization_id = o.id) AS practices,
+                       oar.articles,
+                       n1.parent_id as n1Id, net1.name as n1Name
+                    FROM opentalent.Organization o
+                        INNER JOIN opentalent.Parameters p on o.parameters_id = p.id
+                        LEFT JOIN opentalent.OrganizationAddressPostal oa on oa.organization_id = o.id
+                        LEFT JOIN opentalent.AddressPostal a on oa.addressPostal_id = a.id
+                        LEFT JOIN opentalent.Country c ON c.id = a.addressCountry_id
+                        INNER JOIN (SELECT * FROM NetworkOrganization WHERE parent_id NOT IN (32366, 13) AND (endDate IS NULL OR endDate = '0000-00-00')) n1 on n1.organization_id = o.id
+                        INNER JOIN Organization net1 ON net1.id = n1.parent_id
+                        LEFT JOIN opentalent.organization_contactpoint ocp ON ocp.organization_id = o.id
+                        INNER JOIN (SELECT * FROM opentalent.ContactPoint WHERE `contactType`='PRINCIPAL') cp ON cp.id = ocp.contactPoint_id
+                        LEFT JOIN (
+                            SELECT oar_.organization_id, GROUP_CONCAT(COLUMN_JSON(COLUMN_CREATE('id', oar_.id, 'title', oar_.title, 'date', DATE_FORMAT(oar_.date, '%Y-%m-%dT%TZ'), 'link', oar_.link))) as articles
+                            FROM (SELECT * FROM OrganizationArticle WHERE link is not null and link != '' ORDER BY date DESC) as oar_
+                            group by organization_id
+                        ) oar ON oar.organization_id = o.id
+                    WHERE o.id = :organizationId;";
+
+        $stmt = $this->em->getConnection()->prepare($sql);
+        $data = $stmt->executeQuery(['organizationId' => $organizationId])->fetchAssociative();
+        return self::buildFederationStructure($data);
+    }
+
+    /**
+     * Route optimisée pour retourner l'ensemble des structures d'une fédération au format json
+     *
+     * Cette route est utilisée par l'iframe de recherche des structures
+     * @see https://gitlab.2iopenservice.com/opentalent/frames
+     *
+     * @param int $parentId
+     * @return array
+     * @throws \Doctrine\DBAL\DBALException
+     * @throws \Doctrine\DBAL\Driver\Exception
+     * @throws \Doctrine\DBAL\Exception
+     */
+    public function getDataByFederationId(int $parentId): array
+    {
+        // NOTE: Cette route est utilisée pour l'affichage et la recherche des structures adhérentes à une fédération
+        // Pour éviter une requête récursive et conserver des performances correctes, on a mis en place ces JOIN chainés.
+        // Au moment du développement de cette route (juin 2021), aucune structure n'a plus de 4 fédération parentes,
+        // les 5 niveaux de JOIN devraient donc suffire.
+        $sql = "SELECT o.id, o.name, o.logo_id as logoId, o.principalType, p.otherWebsite as website,    
+                        GROUP_CONCAT(COLUMN_JSON(COLUMN_CREATE(
+                             'type', oa.type, 'latitude', a.latitude, 'longitude', a.longitude, 
+                             'streetAddress', TRIM(BOTH '\n' FROM CONCAT_WS('\n', a.streetAddress, a.streetAddressSecond, a.streetAddressThird)),
+                             'postalCode', a.postalCode, 'addressCity', a.addressCity, 'country', c.name))) as addresses,
+                        (SELECT CONCAT(GROUP_CONCAT(DISTINCT CONCAT(tp.name)))
+                        FROM organization_type_of_practices AS otp
+                        LEFT JOIN TypeOfPractice AS tp ON(tp.id = otp.typeofpractice_id)
+                        WHERE otp.organization_id = o.id) AS practices,
+                       n1.parent_id as n1Id, net1.name as n1Name, n2.parent_id as n2Id, n3.parent_id as n3Id, n4.parent_id as n4Id, n5.parent_id as n5Id,
+                       CONCAT_WS(',', n1.parent_id, n2.parent_id, n3.parent_id, n4.parent_id, n5.parent_id) as parents
+                    FROM opentalent.Organization o
+                        INNER JOIN opentalent.Parameters p on o.parameters_id = p.id
+                        LEFT JOIN opentalent.OrganizationAddressPostal oa on oa.organization_id = o.id
+                        LEFT JOIN opentalent.AddressPostal a on oa.addressPostal_id = a.id
+                        LEFT JOIN opentalent.Country c ON (c.id = a.addressCountry_id)
+                        INNER JOIN (SELECT DISTINCT organization_id, parent_id FROM NetworkOrganization WHERE parent_id NOT IN (32366, 13) AND (endDate IS NULL OR endDate = '0000-00-00')) n1 on n1.organization_id = o.id
+                        INNER JOIN Organization net1 ON net1.id = n1.parent_id
+                        LEFT JOIN (SELECT DISTINCT organization_id, parent_id FROM NetworkOrganization WHERE parent_id NOT IN (32366, 13) AND (endDate IS NULL OR endDate = '0000-00-00')) n2 on n2.organization_id = n1.parent_id
+                        LEFT JOIN (SELECT DISTINCT organization_id, parent_id FROM NetworkOrganization WHERE parent_id NOT IN (32366, 13) AND (endDate IS NULL OR endDate = '0000-00-00')) n3 on n3.organization_id = n2.parent_id
+                        LEFT JOIN (SELECT DISTINCT organization_id, parent_id FROM NetworkOrganization WHERE parent_id NOT IN (32366, 13) AND (endDate IS NULL OR endDate = '0000-00-00')) n4 on n4.organization_id = n3.parent_id
+                        LEFT JOIN (SELECT DISTINCT organization_id, parent_id FROM NetworkOrganization WHERE parent_id NOT IN (32366, 13) AND (endDate IS NULL OR endDate = '0000-00-00')) n5 on n5.organization_id = n4.parent_id
+                        WHERE :parentId IN (n1.parent_id, n2.parent_id, n3.parent_id, n4.parent_id, n5.parent_id)
+                        GROUP BY o.id
+        ;";
+
+        $stmt = $this->em->getConnection()->prepare($sql);
+        $rows = $stmt->executeQuery(['parentId' => $parentId])->fetchAllAssociative();
 
+        return array_map('self::buildFederationStructure', $rows);
+    }
 }