Browse Source

make use of the new federation structure api route to display all
structures on the map

Olivier Massot 4 years ago
parent
commit
dcbfb1b5a5

+ 319 - 0
ot_core/Classes/Domain/Model/FederationStructure.php

@@ -0,0 +1,319 @@
+<?php
+namespace Opentalent\OtCore\Domain\Model;
+
+use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
+
+/**
+ * FederationStructure
+ *
+ * Similar to the Organization object, this entity is created from the federation_structures api route,
+ * which is designed to return the structures belonging to a federation
+ */
+class FederationStructure extends AbstractEntity
+{
+    /**
+     * id
+     *
+     * @var int
+     */
+    protected $id;
+
+    /**
+     * name
+     *
+     * @var string
+     */
+    protected $name;
+
+    /**
+     * principalType
+     *
+     * @var string
+     */
+    protected $principalType;
+
+    /**
+     * addressCity
+     *
+     * @var string
+     */
+    protected $addressCity;
+
+    /**
+     * postalCode
+     *
+     * @var string
+     */
+    protected $postalCode;
+
+    /**
+     * streetAdress
+     *
+     * @var string
+     */
+    protected $streetAddress;
+
+    /**
+     * latitude
+     *
+     * @var float
+     */
+    protected $latitude;
+
+    /**
+     * longitude
+     *
+     * @var float
+     */
+    protected $longitude;
+
+    /**
+     * country
+     *
+     * @var string
+     */
+    protected $country;
+
+    /**
+     * logo
+     *
+     * @var string
+     */
+    protected $logo_id;
+
+    /**
+     * parents
+     *
+     * @var string
+     */
+    protected $parents;
+
+    /**
+     * Returns the id
+     *
+     * @return int $id
+     */
+    public function getId(): int
+    {
+        return $this->id;
+    }
+
+    /**
+     * Sets the id
+     *
+     * @param int $id
+     * @return void
+     */
+    public function setId(int $id)
+    {
+        $this->id = $id;
+    }
+
+    /**
+     * Returns the name
+     *
+     * @return string $name
+     */
+    public function getName(): ?string
+    {
+        return $this->name;
+    }
+
+    /**
+     * Sets the name
+     *
+     * @param string|null $name
+     * @return void
+     */
+    public function setName(?string $name)
+    {
+        $this->name = $name;
+    }
+
+    /**
+     * Returns the principalType
+     *
+     * @return string $principalType
+     */
+    public function getPrincipalType(): ?string
+    {
+        return $this->principalType;
+    }
+
+    /**
+     * Sets the principalType
+     *
+     * @param string|null $principalType
+     * @return void
+     */
+    public function setPrincipalType(?string $principalType)
+    {
+        $this->principalType = $principalType;
+    }
+
+    /**
+     * Returns the addressCity
+     *
+     * @return string $addressCity
+     */
+    public function getAddressCity(): ?string
+    {
+        return $this->addressCity;
+    }
+
+    /**
+     * Sets the addressCity
+     *
+     * @param string|null $addressCity
+     * @return void
+     */
+    public function setAddressCity(?string $addressCity)
+    {
+        $this->addressCity = $addressCity;
+    }
+
+    /**
+     * Returns the postalCode
+     *
+     * @return string $postalCode
+     */
+    public function getPostalCode(): ?string
+    {
+        return $this->postalCode;
+    }
+
+    /**
+     * Sets the postalCode
+     *
+     * @param string|null $postalCode
+     * @return void
+     */
+    public function setPostalCode(?string $postalCode)
+    {
+        $this->postalCode = $postalCode;
+    }
+
+    /**
+     * Returns the streetAddress
+     *
+     * @return string $streetAddress
+     */
+    public function getStreetAddress(): ?string
+    {
+        return $this->streetAddress;
+    }
+
+    /**
+     * Sets the streetAdress
+     *
+     * @param string|null $streetAddress
+     * @return void
+     */
+    public function setStreetAddress(?string $streetAddress)
+    {
+        $this->streetAddress = $streetAddress;
+    }
+
+    /**
+     * Returns the latitude
+     *
+     * @return float $latitude
+     */
+    public function getLatitude(): ?float
+    {
+        return $this->latitude;
+    }
+
+    /**
+     * Sets the latitude
+     *
+     * @param float|null $latitude
+     */
+    public function setLatitude(?float $latitude)
+    {
+        $this->latitude = $latitude;
+    }
+
+    /**
+     * Returns the longitude
+     *
+     * @return float $longitude
+     */
+    public function getLongitude(): ?float
+    {
+        return $this->longitude;
+    }
+
+    /**
+     * Sets the longitude
+     *
+     * @param float|null $longitude
+     */
+    public function setLongitude(?float $longitude)
+    {
+        $this->longitude = $longitude;
+    }
+
+    /**
+     * Returns the country
+     *
+     * @return string $country
+     */
+    public function getCountry(): ?string
+    {
+        return $this->country;
+    }
+
+    /**
+     * Sets the country
+     *
+     * @param string|null $country
+     * @return void
+     */
+    public function setCountry(?string $country)
+    {
+        $this->country = $country;
+    }
+
+    /**
+     * Returns the logo
+     *
+     * @return string $logo_id
+     */
+    public function getLogoId(): ?string
+    {
+        return $this->logo_id;
+    }
+
+    /**
+     * Sets the logo
+     *
+     * @param string|null $logo_id
+     * @return void
+     */
+    public function setLogoId(?string $logo_id)
+    {
+        $this->logo_id = $logo_id;
+    }
+
+    /**
+     * Returns the parents
+     *
+     * @return string $parents
+     */
+    public function getParents(): ?string
+    {
+        return $this->parents;
+    }
+
+    /**
+     * Sets the parents
+     *
+     * @param string|null $parents
+     * @return void
+     */
+    public function setParents(?string $parents)
+    {
+        $this->parents = $parents;
+    }
+}

+ 3 - 0
ot_core/Classes/Domain/Repository/ApiPagedCollection.php

@@ -66,6 +66,9 @@ class ApiPagedCollection
      * @return int
      */
     public function getLastPage() {
+        if (!$this->getItemsPerPage() > 0) {
+            return 1;
+        }
         $nb = intdiv($this->getTotalItems(), $this->getItemsPerPage());
         if ($this->getTotalItems() % $this->getItemsPerPage() != 0) {
             $nb += 1;

+ 67 - 0
ot_core/Classes/Domain/Repository/FederationStructureRepository.php

@@ -0,0 +1,67 @@
+<?php
+
+namespace Opentalent\OtCore\Domain\Repository;
+
+use GuzzleHttp\Exception\GuzzleException;
+use Opentalent\OtCore\Domain\Model\FederationStructure;
+use Opentalent\OtCore\Domain\Model\Organization;
+use Opentalent\OtCore\Exception\ApiRequestException;
+
+/**
+ * Class FederationStructureRepository
+ * @package Opentalent\OtCore\Domain\Repository
+ *
+ */
+class FederationStructureRepository extends BaseApiRepository
+{
+    const URI_TRAILING_PART = '/api/public/federation_structures';
+    const HYDRA_TYPE = 'PortailFederationStructure';
+
+    /**
+     * Get the organization's child structures by id
+     *
+     * @param int $id The id of the organization
+     * @param array $searchParams An array of parameters which will be passed to the Api request as URI parameters
+     * @param int $page
+     * @return ApiPagedCollection
+     * @throws ApiRequestException
+     */
+    public function findChildrenById(int $id, $searchParams = [], $page = 1): ApiPagedCollection
+    {
+        $params = [];
+        $params['parent'] = $id;
+        $params['page'] = $page;
+
+        $params = array_merge($params, $searchParams);
+
+        return $this->getApiRecords($params);
+    }
+
+    /**
+     * Returns an Organization object from an Api record
+     *
+     * @param array $record
+     * @return FederationStructure|null
+     */
+    protected function memberToObject(array $record) {
+        if ($record['@type'] != $this::HYDRA_TYPE) {
+            return null;
+        }
+
+        $federationStructure = new FederationStructure();
+        $a = explode('/', $record['@id']);
+        $federationStructure->setId(end($a));
+        $federationStructure->setName($record['name']);
+        $federationStructure->setPrincipalType($record['principalType']);
+        $federationStructure->setAddressCity($record['addressCity']);
+        $federationStructure->setPostalCode($record['postalCode']);
+        $federationStructure->setStreetAddress($record['streetAddress']);
+        $federationStructure->setLatitude($record['latitude']);
+        $federationStructure->setLongitude($record['longitude']);
+        $federationStructure->setCountry($record['country']);
+        $federationStructure->setLogoId($record['logo_id']);
+        $federationStructure->setParents($record['parents']);
+        return $federationStructure;
+    }
+
+}

+ 80 - 0
ot_templating/Classes/ViewHelpers/Organizations/AsGeoMarkersArrayViewHelper.php

@@ -0,0 +1,80 @@
+<?php
+
+namespace Opentalent\OtTemplating\ViewHelpers\Organizations;
+
+use FluidTYPO3\Vhs\Traits\TemplateVariableViewHelperTrait;
+use Opentalent\OtCore\ViewHelpers\OtAbstractViewHelper;
+use Opentalent\OtCore\Domain\Model\Organization;
+use Opentalent\OtCore\Domain\Repository\OrganizationRepository;
+use Opentalent\OtCore\Exception\ApiRequestException;
+
+/**
+ *   This viewhelper formats an array of Organization / FederationStructures objects into an json-array
+ *   containing the data needed by the leaflet markers: [{id: 0, long: 0, lat: 0, label: ''}, ...]
+ *
+ *     {namespace ot=Opentalent\OtTemplating\ViewHelpers}
+ *
+ *     <ot:organizations.asGeoMarkersArray structures="structures">
+ *          <f:debug>{organization}</f:debug>
+ *     </ot:organizations.asGeoMarkersArray>
+ *
+ * @package Opentalent\OtTemplating\ViewHelpers
+ */
+class AsGeoMarkersArrayViewHelper extends OtAbstractViewHelper {
+
+    use TemplateVariableViewHelperTrait;
+
+    /**
+     * >> Required to prevent typo3 to escape the html output
+     * @var boolean
+     */
+    protected $escapeOutput = true;
+
+    /**
+     * -- This method is expected by Fluid --
+     * Declares the viewhelper's parameters
+     */
+    public function initializeArguments()
+    {
+        $this->registerArgument(
+            'structures',
+            'array',
+            'Array of Organization or FederationStructure objects',
+            true
+        );
+    }
+
+    /**
+     * -- This method is expected by Fluid --
+     * Renders the content as html
+     *
+     * @return string
+     * @throws ApiRequestException
+     */
+    public function render()
+    {
+        $structures = $this->arguments['structures'];
+
+        $markers = [];
+        foreach ($structures as $structure)  {
+            if ($structure->getLongitude() && $structure->getLatitude()) {
+                $markers[] = [
+                    'id' => $structure->getId(),
+                    'long' => $structure->getLongitude(),
+                    'lat' => $structure->getLatitude(),
+                    'label' => $structure->getName() ?? ""
+                ];
+            }
+        }
+
+        return json_encode($markers);
+    }
+
+    /**
+     * @param OrganizationRepository $organizationRepository
+     */
+    public function injectOrganizationRepository(OrganizationRepository $organizationRepository)
+    {
+        $this->organizationRepository = $organizationRepository;
+    }
+}

+ 99 - 0
ot_templating/Classes/ViewHelpers/Organizations/GetFederationStructuresViewHelper.php

@@ -0,0 +1,99 @@
+<?php
+
+namespace Opentalent\OtTemplating\ViewHelpers\Organizations;
+
+use FluidTYPO3\Vhs\Traits\TemplateVariableViewHelperTrait;
+use Opentalent\OtCore\Domain\Repository\FederationStructureRepository;
+use Opentalent\OtCore\ViewHelpers\OtAbstractViewHelper;
+
+/**
+ *   This view helper returns all of the organization children structures as an ApiPagedCollection, without pagination
+ *
+ *     {namespace ot=Opentalent\OtTemplating\ViewHelpers}
+ *
+ *     <ot:organizations.getFederationStructures as="organization"
+ *                               organizationId="1">
+ *          <f:debug>{organization}</f:debug>
+ *     </ot:organizations.getFederationStructures>
+ *
+ * @package Opentalent\OtTemplating\ViewHelpers
+ */
+class GetFederationStructuresViewHelper extends OtAbstractViewHelper {
+
+    use TemplateVariableViewHelperTrait;
+
+    /**
+     * >> Required to prevent typo3 to escape the html output
+     * @var boolean
+     */
+    protected $escapeOutput = false;
+
+    /**
+     * @var FederationStructureRepository
+     *
+     */
+    protected $federationRepository;
+
+    /**
+     * -- This method is expected by Fluid --
+     * Declares the viewhelper's parameters
+     */
+    public function initializeArguments()
+    {
+        $this->registerArgument(
+            'as',
+            'string',
+            'Name of the returned array',
+            true
+        );
+        $this->registerArgument(
+            'parentId',
+            'integer',
+            'Id of the parent organization',
+            true
+        );
+        $this->registerArgument(
+            'itemsPerPage',
+            'string',
+            'Number of items per page',
+            false,
+            10
+        );
+    }
+
+    /**
+     * -- This method is expected by Fluid --
+     * Renders the content as html
+     *
+     * @return string
+     */
+    public function render()
+    {
+        $as = $this->arguments['as'];
+        $parentId = $this->arguments['parentId'];
+        $itemsPerPage = $this->arguments['itemsPerPage'];
+        $page = $_REQUEST['page'] ?? 1;
+
+        if ($itemsPerPage == 'all') {
+            $itemsPerPage = 99999; // the 'all' keyword raise an error during the api call
+            $page = 1;
+        }
+
+        $searchParams = ['itemsPerPage' => $itemsPerPage];
+
+        $organizations = $this->federationRepository->findChildrenById($parentId, $searchParams, $page);
+
+        $variables = [
+            $as => $organizations
+        ];
+        return $this->renderChildrenWithVariables($variables);
+    }
+
+    /**
+     * @param FederationStructureRepository $federationRepository
+     */
+    public function injectFederationRepository(FederationStructureRepository $federationRepository)
+    {
+        $this->federationRepository = $federationRepository;
+    }
+}

+ 26 - 27
ot_templating/Resources/Private/Layouts/Classic/Structures.html

@@ -13,25 +13,22 @@
         <f:comment><!-- All members --></f:comment>
         <div class="ot-structures map-view">
 
-            <ot:organizations.getChildren as="structuresCollection"
-                                          organizationId="{settings.organizationId}">
+            <ot:organizations.getFederationStructures as="structuresCollection"
+                                                      parentId="{settings.organizationId}">
 
                 <div class="structure-col structure-col-map">
-                    <div id="structure-map-wrapper">
-                        <div id="structure-map">
-                            <f:for each="{structuresCollection.members}" as="structure" iteration="it">
-                                <f:if condition="{structure.longitude}">
-                                    <i class="item-geodata"
-                                       style="display: none;"
-                                       data-id="{structure.id}"
-                                       data-long="{structure.longitude}"
-                                       data-lat="{structure.latitude}"
-                                       data-label="<b>{structure.name}</b><br/>{structure.streetAdress}<br/>{structure.postalCode} {structure.addressCity}">
-                                    </i>
-                                </f:if>
-                            </f:for>
+                    <ot:organizations.getFederationStructures as="allStructuresCollection"
+                                                              parentId="{settings.organizationId}"
+                                                              itemsPerPage="all">
+                        <div id="structure-map-wrapper">
+                            <div id="structure-map"
+                                 data-all-structures="{ot:organizations.asGeoMarkersArray(structures:allStructuresCollection.members)}"
+                                 data-selected-structures="{ot:organizations.asGeoMarkersArray(structures:structuresCollection.members)}"
+                            >
+                            </div>
                         </div>
-                    </div>
+                    </ot:organizations.getFederationStructures>
+
                     <div id="structure-map-bar">
                         <div class="btn">{f:translate(key: 'click-on-land-to-go-there')}</div>
                         <ul id="overseas-provinces-list">
@@ -99,13 +96,14 @@
                             <span><f:translate key="no-result"/></span>
                         </f:if>
 
-                        <f:for each="{structuresCollection.members}" as="structure">
+                        <f:for each="{structuresCollection.members}" as="structure" iteration="it">
+
                             <div class="structure-card" data-id="{structure.id}">
 
                                 <div class="structure-poster">
-                                    <f:if condition="{structure.logo}">
+                                    <f:if condition="{structure.logoId}">
                                         <f:then>
-                                            <img src='{structure.logo}' alt="poster" />
+                                            <img src='{structure.logoId}' alt="poster" />
                                         </f:then>
                                         <f:else>
                                             <f:image src="EXT:ot_templating/Resources/Public/media/event-default.jpg" alt="poster" />
@@ -114,13 +112,14 @@
                                 </div>
 
                                 <div class="structure-details">
-                                    <div class="structure-categories">
-                                        <f:for each="{structure.categories}" as="category">
-                                            <span class="structure-category">
-                                                <f:translate key="{category}"/>
-                                            </span>
-                                        </f:for>
-                                    </div>
+                                    <f:comment>
+                                        <!--                                    <div class="structure-categories">-->
+<!--                                        <f:for each="{structure.categories}" as="category">-->
+<!--                                            <span class="structure-category">-->
+<!--                                                <f:translate key="{category}"/>-->
+<!--                                            </span>-->
+<!--                                        </f:for>-->
+<!--                                    </div>--></f:comment>
 
                                     <div class="structure-name">
                                         {structure.name}
@@ -155,7 +154,7 @@
 
                     </div>
                 </div>
-            </ot:organizations.getChildren>
+            </ot:organizations.getFederationStructures>
 
         </div>
     </div>

+ 30 - 4
ot_templating/Resources/Public/assets/Classic/script/main.js

@@ -183,7 +183,7 @@ $(document).ready(function(){
         }
 
         // Collect the data from th map children <i>
-        var items = [];
+        let items = [];
         mapDiv.children('.item-geodata').each(function () {
             let item = {
                 id: $(this).data('id'),
@@ -209,7 +209,8 @@ $(document).ready(function(){
         }).addTo(map);
 
         // Collect the event geodata to create the markers
-        let markers = []
+        let markers = [];
+
         items.forEach(function (item) {
             let marker = L.marker([item.lat, item.long]).addTo(map);
             marker.bindPopup(item.label);
@@ -233,7 +234,6 @@ $(document).ready(function(){
         }
     }
 
-
     // Display map on events index page
     if ($('.ot-all-events #event-map').length) {
         showMap($('#event-map').first());
@@ -246,7 +246,33 @@ $(document).ready(function(){
 
     // Display map on network structures page
     if ($('.ot-structures #structure-map').length) {
-        showMap($('#structure-map').first(), false);
+
+        let mapDiv = $('#structure-map').first();
+        showMap(mapDiv, false);
+
+        let greySquareIcon = L.divIcon({
+            html: '<svg style="width:5px;height:5px;fill:#808080" width="512px" height="512px" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><title>ionicons-v5-q</title><path d="M416,464H96a48.05,48.05,0,0,1-48-48V96A48.05,48.05,0,0,1,96,48H416a48.05,48.05,0,0,1,48,48V416A48.05,48.05,0,0,1,416,464Z"/></svg>',
+            className: "",
+            iconSize: [5, 5],
+            iconAnchor: [0, 10],
+        });
+
+        let allStructures = mapDiv.data('all-structures') ?? [];
+        allStructures.forEach(function (item) {
+            L.marker([item.lat, item.long], { icon: greySquareIcon, zIndexOffset: -1 }).addTo(map);
+        });
+
+        let orangeSquareIcon = L.divIcon({
+            html: '<svg style="width:8px;height:8px;fill:#e4611b" width="512px" height="512px" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><title>ionicons-v5-q</title><path d="M416,464H96a48.05,48.05,0,0,1-48-48V96A48.05,48.05,0,0,1,96,48H416a48.05,48.05,0,0,1,48,48V416A48.05,48.05,0,0,1,416,464Z"/></svg>',
+            className: "",
+            iconSize: [8, 8],
+            iconAnchor: [0, 16],
+        });
+
+        let selectedStructures = mapDiv.data('selected-structures') ?? [];
+        selectedStructures.forEach(function (item) {
+            L.marker([item.lat, item.long], { icon: orangeSquareIcon }).addTo(map);
+        });
     }
 
     // Goto commands