diff --git a/application/Espo/Core/Utils/Metadata.php b/application/Espo/Core/Utils/Metadata.php index cacffd0598..b997afcd86 100644 --- a/application/Espo/Core/Utils/Metadata.php +++ b/application/Espo/Core/Utils/Metadata.php @@ -165,11 +165,11 @@ class Metadata /** * Get all metadata. * - * @param bool $isJSON - * @param bool $reload - * @return array|string + * @/param bool $isJSON + * @/param bool $reload + * @/return array|string */ - public function getAll(bool $isJSON = false, bool $reload = false) + /*public function getAll(bool $isJSON = false, bool $reload = false) { if ($reload) { $this->init($reload); @@ -182,7 +182,7 @@ class Metadata } return $this->data; - } + }*/ private function objInit(bool $reload = false): void { @@ -236,75 +236,9 @@ class Metadata return Util::getValueByKey($objData, $key, $default); } - /** - * This method modified loaded metadata object. - * Only to be used in short living request processes. - */ - public function getAllForFrontend(): stdClass + public function getAll(): stdClass { - $data = $this->getObjData(); - - $frontendHiddenPathList = $this->get(['app', 'metadata', 'frontendHiddenPathList'], []); - - foreach ($frontendHiddenPathList as $row) { - $this->removeDataByPath($row, $data); - } - - return $data; - } - - /** - * - * @param string[] $row - * @param stdClass $data - */ - private function removeDataByPath($row, &$data): void - { - $p = &$data; - $path = [&$p]; - - foreach ($row as $i => $item) { - if (is_array($item)) { - break; - } - - if ($item === self::ANY_KEY) { - foreach (get_object_vars($p) as &$v) { - $this->removeDataByPath( - array_slice($row, $i + 1), - $v - ); - } - - return; - } - - if (!property_exists($p, $item)) { - break; - } - - if ($i == count($row) - 1) { - unset($p->$item); - - $o = &$p; - - for ($j = $i - 1; $j > 0; $j--) { - if (is_object($o) && !count(get_object_vars($o))) { - $o = &$path[$j]; - $k = $row[$j]; - - unset($o->$k); - } - else { - break; - } - } - } - else { - $p = &$p->$item; - $path[] = &$p; - } - } + return $this->getObjData(); } /** diff --git a/application/Espo/Resources/metadata/app/metadata.json b/application/Espo/Resources/metadata/app/metadata.json index 8f5c73bbfa..cdbeba5043 100644 --- a/application/Espo/Resources/metadata/app/metadata.json +++ b/application/Espo/Resources/metadata/app/metadata.json @@ -35,10 +35,12 @@ ["app", "recordId"], ["app", "currencyConversion"], ["selectDefs"], - ["recordDefs"], ["pdfDefs"], ["aclDefs"], ["notificationDefs"], ["authenticationMethods", "__ANY__", "implementationClassName"] + ], + "frontendNonAdminHiddenPathList": [ + ["recordDefs"] ] } diff --git a/application/Espo/Tools/App/MetadataService.php b/application/Espo/Tools/App/MetadataService.php index adc4450ec4..89dfabf272 100644 --- a/application/Espo/Tools/App/MetadataService.php +++ b/application/Espo/Tools/App/MetadataService.php @@ -38,6 +38,8 @@ use stdClass; class MetadataService { + private const ANY_KEY = '__ANY__'; + public function __construct( private Acl $acl, private MetadataUtil $metadata, @@ -47,12 +49,24 @@ class MetadataService public function getDataForFrontend(): stdClass { - $data = $this->metadata->getAllForFrontend(); + $data = $this->metadata->getAll(); + + $hiddenPathList = $this->metadata->get(['app', 'metadata', 'frontendHiddenPathList'], []); + + foreach ($hiddenPathList as $row) { + $this->removeDataByPath($row, $data); + } if ($this->user->isAdmin()) { return $data; } + $hiddenPathList = $this->metadata->get(['app', 'metadata', 'frontendNonAdminHiddenPathList'], []); + + foreach ($hiddenPathList as $row) { + $this->removeDataByPath($row, $data); + } + /** @var string[] $scopeList */ $scopeList = array_keys($this->metadata->get(['entityDefs'], [])); @@ -196,4 +210,58 @@ class MetadataService return $data; } + + /** + * + * @param string[] $row + * @param stdClass $data + */ + private function removeDataByPath($row, &$data): void + { + $p = &$data; + $path = [&$p]; + + foreach ($row as $i => $item) { + if (is_array($item)) { + break; + } + + if ($item === self::ANY_KEY) { + foreach (get_object_vars($p) as &$v) { + $this->removeDataByPath( + array_slice($row, $i + 1), + $v + ); + } + + return; + } + + if (!property_exists($p, $item)) { + break; + } + + if ($i == count($row) - 1) { + unset($p->$item); + + $o = &$p; + + for ($j = $i - 1; $j > 0; $j--) { + if (is_object($o) && !count(get_object_vars($o))) { + $o = &$path[$j]; + $k = $row[$j]; + + unset($o->$k); + } + else { + break; + } + } + } + else { + $p = &$p->$item; + $path[] = &$p; + } + } + } } diff --git a/schema/metadata/app/metadata.json b/schema/metadata/app/metadata.json index fb2b8e0da2..2440b3aa09 100644 --- a/schema/metadata/app/metadata.json +++ b/schema/metadata/app/metadata.json @@ -20,6 +20,21 @@ ] } }, + "frontendNonAdminHiddenPathList": { + "type": "array", + "description": "Sections of metadata (defined as paths) to be hidden from the front-end for non-admin users.", + "items": { + "anyOf": [ + {"const": "__APPEND__"}, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, "aclDependencies": { "type": "object", "description": "Rules making a metadata sections available for a user when they don't have access to a scope.",