From c21d33f8aabf4c014c236998657d29ae20314875 Mon Sep 17 00:00:00 2001 From: Riccardo Beltrami Date: Tue, 30 Jan 2024 16:49:55 +0100 Subject: [PATCH] embedded relations loading, embedded projects loading when the main project is cached --- lizmap/modules/lizmap/lib/Project/Project.php | 30 ++++++++++++++----- .../lizmap/lib/Project/QgisProject.php | 30 +++++++++++++++---- 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/lizmap/modules/lizmap/lib/Project/Project.php b/lizmap/modules/lizmap/lib/Project/Project.php index 2908c3c526..f8b299d04c 100644 --- a/lizmap/modules/lizmap/lib/Project/Project.php +++ b/lizmap/modules/lizmap/lib/Project/Project.php @@ -164,6 +164,8 @@ public function __construct($key, Repository $rep, App\AppContextInterface $appC } } $rewriteCache = false; + // embedded layers + $embeddedProjects = array(); foreach ($data['qgis']['layers'] as $index => $layer) { if (array_key_exists('embedded', $layer) && $layer['embedded'] == '1' @@ -172,16 +174,30 @@ public function __construct($key, Repository $rep, App\AppContextInterface $appC || $layer['qgsmtime'] < filemtime($layer['file']) ) ) { - $qgsProj = new QgisProject($layer['file'], $services, $this->appContext); - $newLayer = $qgsProj->getLayerDefinition($layer['id']); - $newLayer['qgsmtime'] = filemtime($layer['file']); - $newLayer['file'] = $layer['file']; - $newLayer['embedded'] = 1; - $newLayer['projectPath'] = $layer['projectPath']; - $data['qgis']['layers'][$index] = $newLayer; + if (!array_key_exists($layer['file'], $embeddedProjects)) { + $embeddedProjects[$layer['file']] = array(); + } + // populate array of embedded layers + $embeddedProjects[$layer['file']][$index] = $layer; $rewriteCache = true; } } + + // loop through the embedded projects if any, to get the embedded layers definition + foreach ($embeddedProjects as $projectPath => $embeddedLayers) { + if (is_array($embeddedLayers)) { + $embeddedProject = new QgisProject($projectPath, $this->services, $this->appContext); + foreach ($embeddedLayers as $index => $embeddedLayer) { + $newLayer = $embeddedProject->getLayerDefinition($embeddedLayer['id']); + $newLayer['qgsmtime'] = filemtime($embeddedLayer['file']); + $newLayer['file'] = $embeddedLayer['file']; + $newLayer['embedded'] = 1; + $newLayer['projectPath'] = $embeddedLayer['projectPath']; + $data['qgis']['layers'][$index] = $newLayer; + } + } + } + if ($rewriteCache) { $this->cacheHandler->storeProjectData($data); } diff --git a/lizmap/modules/lizmap/lib/Project/QgisProject.php b/lizmap/modules/lizmap/lib/Project/QgisProject.php index 71c9048b01..be07547133 100644 --- a/lizmap/modules/lizmap/lib/Project/QgisProject.php +++ b/lizmap/modules/lizmap/lib/Project/QgisProject.php @@ -581,15 +581,28 @@ public function xpathQuery($query) * * @deprecated * - * @param mixed $layerId + * @param mixed $layerId + * @param null|array $embeddedRelationsProjects reference to associative array path(key) - QgisProject instance (value) * * @return \SimpleXMLElement[] */ - public function getXmlLayer($layerId) + public function getXmlLayer($layerId, &$embeddedRelationsProjects = null) { $layer = $this->getLayerDefinition($layerId); if ($layer && array_key_exists('embedded', $layer) && $layer['embedded'] == 1) { - $qgsProj = new QgisProject(realpath(dirname($this->path).DIRECTORY_SEPARATOR.$layer['projectPath']), $this->services, $this->appContext); + // avoid reloading the same qgis project multiple times while reading relations by checking embeddedRelationsProjects param + // If this array is null or does not contains the corresponding qgis project, then the function if forced to load a new qgis project + if ($embeddedRelationsProjects && array_key_exists($layer['projectPath'], $embeddedRelationsProjects)) { + // use QgisProject instance already created + $qgsProj = $embeddedRelationsProjects[$layer['projectPath']]; + } else { + // create new QgisProject instance + $qgsProj = new QgisProject(realpath(dirname($this->path).DIRECTORY_SEPARATOR.$layer['projectPath']), $this->services, $this->appContext); + // update the array, if exists + if ($embeddedRelationsProjects) { + $embeddedRelationsProjects[$layer['projectPath']] = $qgsProj; + } + } return $qgsProj->getXml()->xpath("//maplayer[id='{$layerId}']"); } @@ -1336,11 +1349,15 @@ protected function readRelations($xml) $pivotGather = array(); $pivot = array(); if ($xmlRelations) { + // Store qgisProjects references in a key=>value array and pass it by reference along the methods that loads and validates relations. + // This avoid to reload the same QgisProject instance multiple times, if there are many "embedded relations" referencing the same (embedded) qgis project + $embeddedRelationsProjects = array(); + /** @var \SimpleXMLElement $relation */ foreach ($xmlRelations[0] as $relation) { $relationObj = $relation->attributes(); - $relationField = $this->readRelationField($relation); + $relationField = $this->readRelationField($relation, $embeddedRelationsProjects); if ($relationField === null) { // no corresponding layer continue; @@ -1384,12 +1401,13 @@ protected function readRelations($xml) /** * @param \SimpleXMLElement $relationXml + * @param null|array $embeddedRelationsProjects */ - protected function readRelationField($relationXml) + protected function readRelationField($relationXml, &$embeddedRelationsProjects = null) { $referencedLayerId = $relationXml->attributes()->referencedLayer; - $_referencedLayerXml = $this->getXmlLayer($referencedLayerId); + $_referencedLayerXml = $this->getXmlLayer($referencedLayerId, $embeddedRelationsProjects); if (count($_referencedLayerXml) == 0) { return null; }