Przeglądaj źródła

clean up and add FindInSetFilter

Olivier Massot 3 lat temu
rodzic
commit
cfe71fd526

+ 1 - 0
composer.json

@@ -12,6 +12,7 @@
         "ext-ctype": "*",
         "ext-iconv": "*",
         "api-platform/core": "^2.6",
+        "beberlei/doctrineextensions": "^1.3",
         "blackfire/php-sdk": "^1.23",
         "composer/package-versions-deprecated": "^1.11",
         "damienharper/auditor-bundle": "^5.0",

+ 4 - 0
config/packages/doctrine.yaml

@@ -42,7 +42,11 @@ doctrine:
                         dir: '%kernel.project_dir%/src/Entity'
                         prefix: 'App\Entity'
                         alias: App
+                dql:
+                    string_functions:
+                        find_in_set: DoctrineExtensions\Query\Mysql\FindInSet
             audit:
                 connection: audit
             adminassos:
                 connection: adminassos
+

+ 1 - 1
sql/schema-extensions/001-view_public_events.sql

@@ -7,7 +7,7 @@ AS
         TRIM(BOTH ' ' FROM CONCAT( if(ap.streetAddress is null,'',ap.streetAddress), ' ', if(ap.streetAddressSecond is null,'',ap.streetAddressSecond), ' ', if(ap.streetAddressThird is null,'',ap.streetAddressThird))) AS streetAddress,
         ap.longitude, ap.latitude,
         r.name AS roomName, r.description AS roomDescription, r.localisation AS roomLocalisation, r.capacity AS roomCapacity, r.floorSize AS roomFloorSize, b.image_id AS imageId,
-        (SELECT CONCAT('[',GROUP_CONCAT(CONCAT(f.code)),']')
+        (SELECT GROUP_CONCAT(CONCAT(f.code))
          FROM event_categories AS ec
             LEFT JOIN Categories AS cs ON(cs.id = ec.categories_id)
             LEFT JOIN Familly AS f ON(f.id = cs.familly_id)

+ 5 - 6
sql/schema-extensions/002-view_federation_structures.sql

@@ -1,17 +1,16 @@
 CREATE OR REPLACE VIEW view_federation_structures
 AS
-    SELECT o.id, o.name, o.logo_id as logoId, o.description, o.image_id as imageId, o.principalType, p.otherWebsite as website, a.latitude, a.longitude,
+    SELECT o.id, o.name, o.logo_id as logoId, o.description, o.image_id as imageId, o.principalType as type, p.otherWebsite as website,
            CONCAT('[', 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,
            cp.telphone as phone, cp.mobilPhone as mobilePhone, 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
+           (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, n2.parent_id as n2Id, n3.parent_id as n3Id, n4.parent_id as n4Id, n5.parent_id as n5Id,
+                     WHERE otp.organization_id = o.id)
+               AS practices,
+           oar.articles, n1.parent_id as parentId, net1.name as parentName,
            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

+ 0 - 94
src/Commands/TestCommand.php

@@ -1,94 +0,0 @@
-<?php
-
-namespace App\Commands;
-
-use App\Service\Dolibarr\DolibarrSyncService;
-use Symfony\Component\Console\Attribute\AsCommand;
-use Symfony\Component\Console\Command\Command;
-use Symfony\Component\Console\Command\LockableTrait;
-use Symfony\Component\Console\Helper\ProgressBar;
-use Symfony\Component\Console\Input\InputInterface;
-use Symfony\Component\Console\Input\InputOption;
-use Symfony\Component\Console\Output\OutputInterface;
-
-#[AsCommand(
-    name: 'ot:dolibarr-sync',
-    description: 'Push the latest data from the Opentalent DB to dolibarr'
-)]
-class DolibarrSyncCommand extends Command
-{
-    use LockableTrait;
-
-    /**
-     * How many operations are shown each time the preview choice is made
-     */
-    const PREVIEW_CHUNK = 20;
-
-    public function __construct(
-        private DolibarrSyncService $dolibarrSyncService
-    ) {
-        parent::__construct();
-    }
-
-    protected function configure()
-    {
-        $this->addOption(
-            'preview',
-            'p',
-            InputOption::VALUE_NONE,
-            'Only preview the sync operations instead of executing it'
-        );
-    }
-
-    protected function execute(InputInterface $input, OutputInterface $output): int
-    {
-        if (!$this->lock()) {
-            $output->writeln('The command is already running in another process.');
-            return Command::SUCCESS;
-        }
-
-        $output->writeln("Start the synchronization");
-        $t0 = microtime(true);
-        $output->writeln("Scanning...");
-
-        $progressBar = new ProgressBar($output, 0);
-        $progressCallback = function($i, $total) use ($progressBar) {
-            if (!$progressBar->getMaxSteps() !== $total) {
-                $progressBar->setMaxSteps($total);
-            }
-            $progressBar->setProgress($i);
-        };
-
-        $operations = $this->dolibarrSyncService->scan($progressCallback);
-
-        $t1 = microtime(true);
-        $output->writeln("Scan lasted " . ($t1 - $t0) . " sec.");
-
-        $output->writeln(count($operations) . " operations to be executed");
-
-        if ($input->getOption('preview')) {
-            $output->writeln("-- Preview --");
-            foreach ($operations as $i => $iValue) {
-                $output->writeln($i . '. ' . $iValue->getLabel());
-                foreach ($iValue->getChangeLog() as $message) {
-                    $output->writeln('   ' . $message);
-                }
-            }
-        } else {
-            $t0 = microtime(true);
-            $output->writeln("Executing...");
-
-            $operations = $this->dolibarrSyncService->execute($operations, $progressCallback);
-
-            $successes = count(array_filter($operations, function ($o) { return $o->getStatus() === $o::STATUS_DONE; } ));
-            $errors = count(array_filter($operations, function ($o) { return $o->getStatus() === $o::STATUS_ERROR; } ));
-            $output->writeln($successes . " operations successfully executed");
-            $output->writeln($errors . " errors");
-
-            $t1 = microtime(true);
-            $output->writeln("Execution lasted " . ($t1 - $t0) . " sec.");
-        }
-
-        return Command::SUCCESS;
-    }
-}

+ 25 - 150
src/Entity/Public/FederationStructure.php

@@ -3,7 +3,11 @@ declare(strict_types=1);
 
 namespace App\Entity\Public;
 
+use ApiPlatform\Core\Annotation\ApiFilter;
 use ApiPlatform\Core\Annotation\ApiResource;
+use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\NumericFilter;
+use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
+use App\Filter\Utils\FindInSetFilter;
 use App\Repository\Public\FederationStructureRepository;
 use Doctrine\ORM\Mapping as ORM;
 use Symfony\Component\Serializer\Annotation\Groups;
@@ -32,6 +36,9 @@ use Symfony\Component\Serializer\Annotation\Groups;
         ]
     ]
 )]
+#[ApiFilter(SearchFilter::class, properties: ['name' => 'partial', 'city' => 'exact'])]
+#[ApiFilter(NumericFilter::class, properties: ['id', 'parentId'])]
+#[ApiFilter(FindInSetFilter::class, properties: ['parents'])]
 class FederationStructure
 {
     #[ORM\Id]
@@ -57,7 +64,7 @@ class FederationStructure
 
     #[ORM\Column]
     #[Groups(["federation_structure_item_get", "federation_structure_collection_get"])]
-    private ?string $principalType;
+    private ?string $type;
 
     #[ORM\Column]
     #[Groups(["federation_structure_item_get", "federation_structure_collection_get"])]
@@ -103,37 +110,13 @@ class FederationStructure
     #[Groups(["federation_structure_item_get", "federation_structure_collection_get"])]
     private ?array $practices;
 
-    #[ORM\Column(type: 'float')]
-    #[Groups(["federation_structure_item_get", "federation_structure_collection_get"])]
-    private ?float $latitude;
-
-    #[ORM\Column(type: 'float')]
-    #[Groups(["federation_structure_item_get", "federation_structure_collection_get"])]
-    private ?float $longitude;
-
     #[ORM\Column(type: 'integer')]
     #[Groups(["federation_structure_item_get"])]
-    private ?int $n1Id;
+    private ?int $parentId;
 
     #[ORM\Column(type: 'integer')]
     #[Groups(["federation_structure_item_get"])]
-    private ?string $n1Name;
-
-    #[ORM\Column(type: 'integer')]
-    #[Groups(["federation_structure_collection_get"])]
-    private ?int $n2Id;
-
-    #[ORM\Column(type: 'integer')]
-    #[Groups(["federation_structure_collection_get"])]
-    private ?int $n3Id;
-
-    #[ORM\Column(type: 'integer')]
-    #[Groups(["federation_structure_collection_get"])]
-    private ?int $n4Id;
-
-    #[ORM\Column(type: 'integer')]
-    #[Groups(["federation_structure_collection_get"])]
-    private ?int $n5Id;
+    private ?string $parentName;
 
     #[ORM\Column(type: 'simple_array')]
     #[Groups(["federation_structure_item_get", "federation_structure_collection_get"])]
@@ -235,18 +218,18 @@ class FederationStructure
     /**
      * @return string|null
      */
-    public function getPrincipalType(): ?string
+    public function getType(): ?string
     {
-        return $this->principalType;
+        return $this->type;
     }
 
     /**
-     * @param string|null $principalType
+     * @param string|null $type
      * @return FederationStructure
      */
-    public function setPrincipalType(?string $principalType): self
+    public function setType(?string $type): self
     {
-        $this->principalType = $principalType;
+        $this->type = $type;
         return $this;
     }
 
@@ -449,147 +432,39 @@ class FederationStructure
         return $this;
     }
 
-    /**
-     * @return float|null
-     */
-    public function getLatitude(): ?float
-    {
-        return $this->latitude;
-    }
-
-    /**
-     * @param float|null $latitude
-     * @return FederationStructure
-     */
-    public function setLatitude(?float $latitude): self
-    {
-        $this->latitude = $latitude;
-        return $this;
-    }
-
-    /**
-     * @return float|null
-     */
-    public function getLongitude(): ?float
-    {
-        return $this->longitude;
-    }
-
-    /**
-     * @param float|null $longitude
-     * @return FederationStructure
-     */
-    public function setLongitude(?float $longitude): self
-    {
-        $this->longitude = $longitude;
-        return $this;
-    }
-
     /**
      * @return int|null
      */
-    public function getN1Id(): ?int
+    public function getParentId(): ?int
     {
-        return $this->n1Id;
+        return $this->parentId;
     }
 
     /**
-     * @param int|null $n1Id
+     * @param int|null $parentId
      * @return FederationStructure
      */
-    public function setN1Id(?int $n1Id): self
+    public function setParentId(?int $parentId): self
     {
-        $this->n1Id = $n1Id;
+        $this->parentId = $parentId;
         return $this;
     }
 
     /**
      * @return string|null
      */
-    public function getN1Name(): ?string
-    {
-        return $this->n1Name;
-    }
-
-    /**
-     * @param string|null $n1Name
-     * @return FederationStructure
-     */
-    public function setN1Name(?string $n1Name): self
-    {
-        $this->n1Name = $n1Name;
-        return $this;
-    }
-
-    /**
-     * @return int|null
-     */
-    public function getN2Id(): ?int
-    {
-        return $this->n2Id;
-    }
-
-    /**
-     * @param int|null $n2Id
-     * @return FederationStructure
-     */
-    public function setN2Id(?int $n2Id): self
-    {
-        $this->n2Id = $n2Id;
-        return $this;
-    }
-
-    /**
-     * @return int|null
-     */
-    public function getN3Id(): ?int
-    {
-        return $this->n3Id;
-    }
-
-    /**
-     * @param int|null $n3Id
-     * @return FederationStructure
-     */
-    public function setN3Id(?int $n3Id): self
-    {
-        $this->n3Id = $n3Id;
-        return $this;
-    }
-
-    /**
-     * @return int|null
-     */
-    public function getN4Id(): ?int
-    {
-        return $this->n4Id;
-    }
-
-    /**
-     * @param int|null $n4Id
-     * @return FederationStructure
-     */
-    public function setN4Id(?int $n4Id): self
-    {
-        $this->n4Id = $n4Id;
-        return $this;
-    }
-
-    /**
-     * @return int|null
-     */
-    public function getN5Id(): ?int
+    public function getParentName(): ?string
     {
-        return $this->n5Id;
+        return $this->parentName;
     }
 
     /**
-     * @param int|null $n5Id
+     * @param string|null $parentName
      * @return FederationStructure
      */
-    public function setN5Id(?int $n5Id): self
+    public function setParentName(?string $parentName): self
     {
-        $this->n5Id = $n5Id;
+        $this->parentName = $parentName;
         return $this;
     }
 

+ 6 - 6
src/Entity/Public/PublicEvent.php

@@ -92,8 +92,8 @@ class PublicEvent
     #[ORM\Column(type: 'integer')]
     private ?int $imageId;
 
-    #[ORM\Column]
-    private ?string $categories;
+    #[ORM\Column(type: 'simple_array')]
+    private ?array $categories;
 
     #[ORM\Column]
     private string $origin = 'opentalent';
@@ -426,18 +426,18 @@ class PublicEvent
     }
 
     /**
-     * @return string|null
+     * @return array|null
      */
-    public function getCategories(): ?string
+    public function getCategories(): ?array
     {
         return $this->categories;
     }
 
     /**
-     * @param string|null $categories
+     * @param array|null $categories
      * @return PublicEvent
      */
-    public function setCategories(?string $categories): self
+    public function setCategories(?array $categories): self
     {
         $this->categories = $categories;
         return $this;

+ 54 - 0
src/Filter/Utils/FindInSetFilter.php

@@ -0,0 +1,54 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Filter\Utils;
+
+use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\AbstractContextAwareFilter;
+use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
+use Doctrine\ORM\QueryBuilder;
+use Symfony\Component\PropertyInfo\Type;
+
+final class FindInSetFilter extends AbstractContextAwareFilter {
+    protected function filterProperty(string $property, $value, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null)
+    {
+        // otherwise filter is applied to order and page as well
+        if (!$this->isPropertyEnabled($property, $resourceClass) || !$this->isPropertyMapped($property, $resourceClass)
+        ) {
+            return;
+        }
+
+        $alias = $queryBuilder->getRootAliases()[0];
+        $parameterName = $queryNameGenerator->generateParameterName($property); // Generate a unique parameter name to avoid collisions with other filters
+        $queryBuilder
+            ->andWhere(sprintf('find_in_set(:%s, %s.%s) <> 0', $parameterName, $alias, $property))
+            ->setParameter($parameterName, explode(',', $value));
+    }
+
+    /**
+     * API docs
+     * @param string $resourceClass
+     * @return array[]
+     */
+    public function getDescription(string $resourceClass): array
+    {
+        if (!$this->properties) {
+            return [];
+        }
+
+        $description = [];
+        foreach ($this->properties as $property => $strategy) {
+            $description["$property"] = [
+                'property' => $property,
+                'type' => Type::BUILTIN_TYPE_STRING,
+                'required' => false,
+                'swagger' => [
+                    'description' => "Filtre de type find_in_set(), vérifie que la valeur est dans le set d'un champs de type CSV",
+                    'name' => 'FindInSet Filter',
+                    'type' => 'Utils Filter',
+                ],
+            ];
+        }
+
+        return $description;
+    }
+}

+ 4 - 1
src/Filter/Utils/InFilter.php

@@ -8,6 +8,9 @@ use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
 use Doctrine\ORM\QueryBuilder;
 use Symfony\Component\PropertyInfo\Type;
 
+/**
+ * Is property included in the given CSV array
+ */
 final class InFilter extends AbstractContextAwareFilter {
     protected function filterProperty(string $property, $value, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null)
     {
@@ -53,4 +56,4 @@ final class InFilter extends AbstractContextAwareFilter {
 
         return $description;
     }
-}
+}

+ 1 - 137
src/Repository/Organization/OrganizationRepository.php

@@ -3,9 +3,7 @@ declare(strict_types=1);
 
 namespace App\Repository\Organization;
 
-use App\ApiResources\Public\FederationStructure;
 use App\Entity\Organization\Organization;
-use App\Service\Utils\ArrayUtils;
 use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
 use Doctrine\ORM\EntityManagerInterface;
 use Doctrine\Persistence\ManagerRegistry;
@@ -18,142 +16,8 @@ use Doctrine\Persistence\ManagerRegistry;
  */
 class OrganizationRepository extends ServiceEntityRepository
 {
-    public function __construct(ManagerRegistry $registry, private EntityManagerInterface $em)
+    public function __construct(ManagerRegistry $registry)
     {
         parent::__construct($registry, Organization::class);
     }
-
-    /**
-     * Route optimisée pour retourner les données de réseau d'une structure membre de fédération, sous forme d'Api resources
-     * de type FederationStructure.
-     *
-     * 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 sous forme d'Api resources
-     * de type FederationStructure
-     *
-     * 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 getChildrenStructuresByFederationId(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);
-    }
-
-    /**
-     * Build a FederationStructure with the data provided by getFederationStructureByOrganizationId() and
-     * getChildrenStructuresByFederationId().
-     */
-    private static function buildFederationStructure(array $data) {
-        return (new FederationStructure())
-            ->setId((int)$data['id'])
-            ->setName($data['name'])
-            ->setLogoId(ArrayUtils::getAndCast($data, 'logoId', 'int'))
-            ->setDescription($data['description'] ?? null)
-            ->setImageId(ArrayUtils::getAndCast($data, 'imageId', 'int'))
-            ->setPrincipalType($data['principalType'] ?? null)
-            ->setWebsite($data['website'])
-            ->setAddresses($data['addresses'])
-            ->setTelphone($data['telphone'] ?? null)
-            ->setMobilPhone($data['mobilPhone'] ?? null)
-            ->setEmail($data['email'] ?? null)
-            ->setFacebook($data['facebook'] ?? null)
-            ->setTwitter($data['twitter'] ?? null)
-            ->setInstagram($data['instagram'] ?? null)
-            ->setYoutube($data['youtube'] ?? null)
-            ->setArticles($data['articles'] ?? null)
-            ->setPractices($data['practices'])
-            ->setLatitude($data['latitude'] ?? null)
-            ->setLongitude($data['longitude'] ?? null)
-            ->setN1Id(ArrayUtils::getAndCast($data, 'n1Id', 'int'))
-            ->setN1Name($data['n1Name'] ?? null)
-            ->setN2Id(ArrayUtils::getAndCast($data, 'n2id', 'int'))
-            ->setN3Id(ArrayUtils::getAndCast($data, 'n3Id', 'int'))
-            ->setN4Id(ArrayUtils::getAndCast($data, 'n4Id', 'int'))
-            ->setN5Id(ArrayUtils::getAndCast($data, 'n5Id', 'int'))
-            ->setParents($data['parents'] ?? null);
-    }
 }