From aa5bcf97d20e812e4a70e38dbacee0e3cedfc5a7 Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Fri, 18 Jun 2021 15:17:21 +0300 Subject: [PATCH] resource finder --- application/Espo/Core/Utils/Language.php | 48 ++++---- application/Espo/Core/Utils/Metadata.php | 32 +++-- .../Espo/Core/Utils/Resource/Reader.php | 88 ++++++++++++++ .../Espo/Core/Utils/Resource/ReaderParams.php | 68 +++++++++++ .../Espo/Tools/LabelManager/LabelManager.php | 32 +++-- tests/unit/Espo/Core/Utils/LanguageTest.php | 23 +++- tests/unit/Espo/Core/Utils/MetadataTest.php | 60 ++++----- .../Espo/Core/Utils/Resource/ReaderTest.php | 114 ++++++++++++++++++ 8 files changed, 375 insertions(+), 90 deletions(-) create mode 100644 application/Espo/Core/Utils/Resource/Reader.php create mode 100644 application/Espo/Core/Utils/Resource/ReaderParams.php create mode 100644 tests/unit/Espo/Core/Utils/Resource/ReaderTest.php diff --git a/application/Espo/Core/Utils/Language.php b/application/Espo/Core/Utils/Language.php index 619a7ec5bb..86dabb3ee8 100644 --- a/application/Espo/Core/Utils/Language.php +++ b/application/Espo/Core/Utils/Language.php @@ -34,9 +34,10 @@ use Espo\Core\{ Utils\Util, Utils\File\Manager as FileManager, Utils\Metadata, - Utils\File\Unifier, Utils\Config, Utils\DataCache, + Utils\Resource\Reader as ResourceReader, + Utils\Resource\ReaderParams as ResourceReaderParams, }; use Espo\{ @@ -45,12 +46,6 @@ use Espo\{ class Language { - private $fileManager; - - private $metadata; - - private $unifier; - private $data = []; private $deletedData = []; @@ -65,17 +60,23 @@ class Language protected $noCustom = false; - protected $paths = [ - 'corePath' => 'application/Espo/Resources/i18n/{language}', - 'modulePath' => 'application/Espo/Modules/{*}/Resources/i18n/{language}', - 'customPath' => 'custom/Espo/Custom/Resources/i18n/{language}', - ]; + private $customPath = 'custom/Espo/Custom/Resources/i18n/{language}'; + + private $resourcePath = 'i18n/{language}'; + + private $fileManager; + + private $metadata; + + private $resourceReader; + + private $dataCache; public function __construct( ?string $language, FileManager $fileManager, Metadata $metadata, - Unifier $unifier, + ResourceReader $resourceReader, DataCache $dataCache, bool $useCache = false, bool $noCustom = false @@ -84,7 +85,7 @@ class Language $this->fileManager = $fileManager; $this->metadata = $metadata; - $this->unifier = $unifier; + $this->resourceReader = $resourceReader; $this->dataCache = $dataCache; $this->useCache = $useCache; @@ -220,10 +221,7 @@ class Language */ public function save(): bool { - $language = $this->currentLanguage; - - $path = $this->paths['customPath']; - $path = str_replace('{language}', $language, $path); + $path = str_replace('{language}', $this->currentLanguage, $this->customPath); $result = true; @@ -370,7 +368,7 @@ class Language $cacheKey = $this->getCacheKey($language); if (!$this->useCache || !$this->dataCache->has($cacheKey) || $reload) { - $paths = $this->paths; + /*$paths = $this->paths; foreach ($paths as $k => &$path) { $path = str_replace('{language}', $language, $path); @@ -378,9 +376,17 @@ class Language if ($this->noCustom) { unset($paths['customPath']); - } + }*/ - $data = $this->unifier->unify($paths, true); + $readerParams = ResourceReaderParams::create() + ->withAsArray() + ->withNoCustom($this->noCustom); + + $path = str_replace('{language}', $language, $this->resourcePath); + + $data = $this->resourceReader->read($path, $readerParams); + + //$data = $this->unifier->unify($paths, true); if (is_array($data)) { $this->sanitizeData($data); diff --git a/application/Espo/Core/Utils/Metadata.php b/application/Espo/Core/Utils/Metadata.php index a2a9ee4127..a2136af8e5 100644 --- a/application/Espo/Core/Utils/Metadata.php +++ b/application/Espo/Core/Utils/Metadata.php @@ -32,10 +32,11 @@ namespace Espo\Core\Utils; use Espo\Core\{ Exceptions\Error, Utils\File\Manager as FileManager, - Utils\File\UnifierObj, Utils\Module, Utils\Metadata\Helper, Utils\DataCache, + Utils\Resource\Reader as ResourceReader, + Utils\Resource\ReaderParams as ResourceReaderParams, }; use StdClass; @@ -48,19 +49,11 @@ class Metadata private $useCache; - private $module; - - private $metadataHelper; - private $cacheKey = 'metadata'; private $objCacheKey = 'objMetadata'; - private $paths = [ - 'corePath' => 'application/Espo/Resources/metadata', - 'modulePath' => 'application/Espo/Modules/{*}/Resources/metadata', - 'customPath' => 'custom/Espo/Custom/Resources/metadata', - ]; + private $customPath = 'custom/Espo/Custom/Resources/metadata'; private $moduleList = null; @@ -68,21 +61,25 @@ class Metadata private $changedData = []; + private $metadataHelper; + + private $module; + private $fileManager; private $dataCache; - private $unifier; + private $resourceReader; public function __construct( FileManager $fileManager, DataCache $dataCache, - UnifierObj $unifier, + ResourceReader $resourceReader, bool $useCache = false ){ $this->fileManager = $fileManager; $this->dataCache = $dataCache; - $this->unifier = $unifier; + $this->resourceReader = $resourceReader; $this->useCache = $useCache; @@ -186,7 +183,8 @@ class Metadata return; } - $this->objData = $this->unifier->unify($this->paths, true); + $this->objData = $this->resourceReader->read('metadata', ResourceReaderParams::create()); + $this->objData = $this->addAdditionalFieldsObj($this->objData); if ($this->useCache) { @@ -359,7 +357,7 @@ class Metadata */ public function getCustom($key1, $key2, $default = null) { - $filePath = $this->paths['customPath'] . "/{$key1}/{$key2}.json"; + $filePath = $this->customPath . "/{$key1}/{$key2}.json"; $fileContent = $this->fileManager->getContents($filePath); @@ -388,7 +386,7 @@ class Metadata } } - $filePath = $this->paths['customPath'] . "/{$key1}/{$key2}.json"; + $filePath = $this->customPath . "/{$key1}/{$key2}.json"; $changedData = Json::encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); @@ -513,7 +511,7 @@ class Metadata */ public function save(): bool { - $path = $this->paths['customPath']; + $path = $this->customPath; $result = true; diff --git a/application/Espo/Core/Utils/Resource/Reader.php b/application/Espo/Core/Utils/Resource/Reader.php new file mode 100644 index 0000000000..2cccb00303 --- /dev/null +++ b/application/Espo/Core/Utils/Resource/Reader.php @@ -0,0 +1,88 @@ + 'application/Espo/Resources/', + 'modulePath' => 'application/Espo/Modules/{*}/Resources/', + 'customPath' => 'custom/Espo/Custom/Resources/', + ]; + + private $unifier; + + private $unifierObj; + + public function __construct(Unifier $unifier, UnifierObj $unifierObj) + { + $this->unifier = $unifier; + $this->unifierObj = $unifierObj; + } + + /** + * Read resource data. + * + * @return stdClass|array + */ + public function read(string $path, ReaderParams $params) + { + $paths = $this->buildPaths($path, $params); + + if ($params->asArray()) { + return $this->unifier->unify($paths); + } + + return $this->unifierObj->unify($paths); + } + + private function buildPaths(string $path, ReaderParams $params): array + { + $paths = []; + + foreach ($this->paths as $key => $dir) { + $paths[$key] = $dir . $path; + } + + if ($params->noCustom()) { + unset($paths['customPath']); + } + + return $paths; + } +} diff --git a/application/Espo/Core/Utils/Resource/ReaderParams.php b/application/Espo/Core/Utils/Resource/ReaderParams.php new file mode 100644 index 0000000000..02fedee5b2 --- /dev/null +++ b/application/Espo/Core/Utils/Resource/ReaderParams.php @@ -0,0 +1,68 @@ +noCustom = $noCustom; + + return $obj; + } + + public function withAsArray(bool $asArray = true): self + { + $obj = clone $this; + $obj->asArray = $asArray; + + return $obj; + } + + public function noCustom(): bool + { + return $this->noCustom; + } + + public function asArray(): bool + { + return $this->asArray; + } +} diff --git a/application/Espo/Tools/LabelManager/LabelManager.php b/application/Espo/Tools/LabelManager/LabelManager.php index 9c4469586c..2325a54ca4 100644 --- a/application/Espo/Tools/LabelManager/LabelManager.php +++ b/application/Espo/Tools/LabelManager/LabelManager.php @@ -30,14 +30,16 @@ namespace Espo\Tools\LabelManager; use Espo\Core\{ - Exceptions\NotFound, - Exceptions\Error, - Utils\Util, Di, Utils\Language, + InjectableFactory, }; -class LabelManager implements Di\DefaultLanguageAware, Di\MetadataAware, Di\FileManagerAware, Di\DataCacheAware +class LabelManager implements + Di\DefaultLanguageAware, + Di\MetadataAware, + Di\FileManagerAware, + Di\DataCacheAware { use Di\DefaultLanguageSetter; use Di\MetadataSetter; @@ -48,6 +50,13 @@ class LabelManager implements Di\DefaultLanguageAware, Di\MetadataAware, Di\File 'Global.sets', ]; + private $injectableFactory; + + public function __construct(InjectableFactory $injectableFactory) + { + $this->injectableFactory = $injectableFactory; + } + public function getScopeList() { $scopeList = []; @@ -55,6 +64,7 @@ class LabelManager implements Di\DefaultLanguageAware, Di\MetadataAware, Di\File $languageObj = $this->defaultLanguage; $data = $languageObj->getAll(); + foreach (array_keys($data) as $scope) { if (!in_array($scope, $scopeList)) { $scopeList[] = $scope; @@ -72,7 +82,9 @@ class LabelManager implements Di\DefaultLanguageAware, Di\MetadataAware, Di\File public function getScopeData($language, $scope) { - $languageObj = new Language($language, $this->fileManager, $this->metadata, $this->dataCache); + $languageObj = $this->injectableFactory->createWith(Language::class, [ + 'language' => $language, + ]); $data = $languageObj->get($scope); @@ -180,8 +192,14 @@ class LabelManager implements Di\DefaultLanguageAware, Di\MetadataAware, Di\File public function saveLabels($language, $scope, $labels) { - $languageObj = new Language($language, $this->fileManager, $this->metadata, $this->dataCache); - $languageOriginalObj = new Language($language, $this->fileManager, $this->metadata, $this->dataCache, false, true); + $languageObj = $this->injectableFactory->createWith(Language::class, [ + 'language' => $language, + ]); + + $languageOriginalObj = $this->injectableFactory->createWith(Language::class, [ + 'language' => $language, + 'noCustom' => true, + ]); $returnDataHash = []; diff --git a/tests/unit/Espo/Core/Utils/LanguageTest.php b/tests/unit/Espo/Core/Utils/LanguageTest.php index dbc102d9d1..f90c512edc 100644 --- a/tests/unit/Espo/Core/Utils/LanguageTest.php +++ b/tests/unit/Espo/Core/Utils/LanguageTest.php @@ -36,7 +36,9 @@ use Espo\Core\Utils\Language; use Espo\Core\Utils\DataCache; use Espo\Core\Utils\File\Manager as FileManager; use Espo\Core\Utils\File\Unifier; +use Espo\Core\Utils\File\UnifierObj; use Espo\Core\Utils\Module; +use Espo\Core\Utils\Resource\Reader; class LanguageTest extends \PHPUnit\Framework\TestCase { @@ -45,9 +47,9 @@ class LanguageTest extends \PHPUnit\Framework\TestCase protected $reflection; protected $paths = [ - 'corePath' => 'tests/unit/testData/Utils/I18n/Espo/Resources/i18n/{language}', - 'modulePath' => 'tests/unit/testData/Utils/I18n/Espo/Modules/{*}/Resources/i18n/{language}', - 'customPath' => 'tests/unit/testData/Utils/I18n/Espo/Custom/Resources/i18n/{language}', + 'corePath' => 'tests/unit/testData/Utils/I18n/Espo/Resources/', + 'modulePath' => 'tests/unit/testData/Utils/I18n/Espo/Modules/{*}/Resources/', + 'customPath' => 'tests/unit/testData/Utils/I18n/Espo/Custom/Resources/', ]; protected function setUp(): void @@ -68,20 +70,29 @@ class LanguageTest extends \PHPUnit\Framework\TestCase $module = new Module($this->fileManager); - $this->unifier = new Unifier($this->fileManager, $module); + $unifierObj = new UnifierObj($this->fileManager, $module); + $unifier = new Unifier($this->fileManager, $module); + + $reader = new Reader($unifier, $unifierObj); + + $this->readerReflection = new ReflectionHelper($reader); + + $this->readerReflection->setProperty('paths', $this->paths); $this->object = new Language( null, $this->fileManager, $this->metadata, - $this->unifier, + $reader, $this->dataCache, false ); $this->reflection = new ReflectionHelper($this->object); - $this->reflection->setProperty('paths', $this->paths); + $this->customPath = 'tests/unit/testData/Utils/I18n/Espo/Custom/Resources/i18n/{language}'; + + $this->reflection->setProperty('customPath', $this->customPath); $this->reflection->setProperty('currentLanguage', 'en_US'); } diff --git a/tests/unit/Espo/Core/Utils/MetadataTest.php b/tests/unit/Espo/Core/Utils/MetadataTest.php index e455c85f0c..5a25d600b8 100644 --- a/tests/unit/Espo/Core/Utils/MetadataTest.php +++ b/tests/unit/Espo/Core/Utils/MetadataTest.php @@ -36,7 +36,9 @@ use Espo\Core\Utils\File\Manager as FileManager; use Espo\Core\Utils\Log; use Espo\Core\Utils\DataCache; use Espo\Core\Utils\File\UnifierObj; +use Espo\Core\Utils\File\Unifier; use Espo\Core\Utils\Module; +use Espo\Core\Utils\Resource\Reader; class MetadataTest extends \PHPUnit\Framework\TestCase { @@ -56,11 +58,18 @@ class MetadataTest extends \PHPUnit\Framework\TestCase $module = new Module($this->fileManager); - $unifier = new UnifierObj($this->fileManager, $module); + $unifierObj = new UnifierObj($this->fileManager, $module); + $unifier = new Unifier($this->fileManager, $module); - $this->object = new Metadata($this->fileManager, $this->dataCache, $unifier, true); + $reader = new Reader($unifier, $unifierObj); + + $this->object = new Metadata($this->fileManager, $this->dataCache, $reader, true); $this->reflection = new ReflectionHelper($this->object); + + $this->customPath = 'tests/unit/testData/cache/metadata/custom'; + + $this->reflection->setProperty('customPath', $this->customPath); } protected function tearDown() : void @@ -71,11 +80,9 @@ class MetadataTest extends \PHPUnit\Framework\TestCase public function testGet() { - $result = 'System'; - $this->assertEquals($result, $this->object->get('app.adminPanel.system.label')); + $this->assertEquals('System', $this->object->get('app.adminPanel.system.label')); - $result = 'fields'; - $this->assertArrayHasKey($result, $this->object->get('entityDefs.User')); + $this->assertArrayHasKey('fields', $this->object->get('entityDefs.User')); } public function testSet() @@ -238,13 +245,6 @@ class MetadataTest extends \PHPUnit\Framework\TestCase public function testGetCustom() { - $customPath = 'tests/unit/testData/cache/metadata/custom'; - - $paths = $this->reflection->getProperty('paths'); - $paths['customPath'] = $customPath; - - $this->reflection->setProperty('paths', $paths); - $this->assertNull($this->object->getCustom('entityDefs', 'Lead')); $customData = $this->object->getCustom('entityDefs', 'Lead', (object) []); @@ -264,19 +264,11 @@ class MetadataTest extends \PHPUnit\Framework\TestCase $this->assertEquals($data, $this->object->getCustom('entityDefs', 'Lead')); - unlink($customPath . '/entityDefs/Lead.json'); + unlink($this->customPath . '/entityDefs/Lead.json'); } - public function testSaveCustom() + public function testSaveCustom1() { - $initStatusOptions = $this->object->get('entityDefs.Lead.fields.status.options'); - - $customPath = 'tests/unit/testData/cache/metadata/custom'; - - $paths = $this->reflection->getProperty('paths'); - $paths['customPath'] = $customPath; - $this->reflection->setProperty('paths', $paths); - $data = (object) [ 'fields' => (object) [ 'status' => (object) [ @@ -288,28 +280,18 @@ class MetadataTest extends \PHPUnit\Framework\TestCase $this->object->saveCustom('entityDefs', 'Lead', $data); - $savedFile = $customPath . '/entityDefs/Lead.json'; + $savedFile = $this->customPath . '/entityDefs/Lead.json'; $fileContent = $this->fileManager->getContents($savedFile); $savedData = \Espo\Core\Utils\Json::decode($fileContent); $this->assertEquals($data, $savedData); - $initStatusOptions[] = 'Test1'; - $initStatusOptions[] = 'Test2'; - $this->assertEquals($initStatusOptions, $this->object->get('entityDefs.Lead.fields.status.options')); - unlink($savedFile); } public function testSaveCustom2() { - $customPath = 'tests/unit/testData/cache/metadata/custom'; - - $paths = $this->reflection->getProperty('paths'); - $paths['customPath'] = $customPath; - $this->reflection->setProperty('paths', $paths); - $initData = (object) [ 'fields' => (object) [ 'status' => (object) [ @@ -327,8 +309,10 @@ class MetadataTest extends \PHPUnit\Framework\TestCase $customData->fields->status->options = ["__APPEND__", "Test1"]; $this->object->saveCustom('entityDefs', 'Lead', $customData); - $savedFile = $customPath . '/entityDefs/Lead.json'; + $savedFile = $this->customPath . '/entityDefs/Lead.json'; + $fileContent = $this->fileManager->getContents($savedFile); + $savedData = \Espo\Core\Utils\Json::decode($fileContent); $expectedData = (object) [ @@ -346,11 +330,9 @@ class MetadataTest extends \PHPUnit\Framework\TestCase public function testGetObjects() { - $result = 'System'; - $this->assertEquals($result, $this->object->getObjects('app.adminPanel.system.label')); + $this->assertEquals('System', $this->object->getObjects('app.adminPanel.system.label')); - $result = 'fields'; - $this->assertObjectHasAttribute($result, $this->object->getObjects('entityDefs.User')); + $this->assertObjectHasAttribute('fields', $this->object->getObjects('entityDefs.User')); $this->assertObjectHasAttribute('type', $this->object->getObjects('entityDefs.User.fields.name')); } diff --git a/tests/unit/Espo/Core/Utils/Resource/ReaderTest.php b/tests/unit/Espo/Core/Utils/Resource/ReaderTest.php new file mode 100644 index 0000000000..fc4510b724 --- /dev/null +++ b/tests/unit/Espo/Core/Utils/Resource/ReaderTest.php @@ -0,0 +1,114 @@ +unifier = $this->createMock(Unifier::class); + $this->unifierObj = $this->createMock(UnifierObj::class); + + $this->reader = new Reader($this->unifier, $this->unifierObj); + } + + public function testRead1(): void + { + $params = ReaderParams::create(); + + $this->unifierObj + ->expects($this->once()) + ->method('unify') + ->with([ + 'corePath' => 'application/Espo/Resources/test/hello', + 'modulePath' => 'application/Espo/Modules/{*}/Resources/test/hello', + 'customPath' => 'custom/Espo/Custom/Resources/test/hello', + ]) + ->willReturn((object) []); + + $this->reader->read('test/hello', $params); + } + + public function testRead2(): void + { + $params = ReaderParams::create() + ->withAsArray(); + + $this->unifier + ->expects($this->once()) + ->method('unify') + ->with([ + 'corePath' => 'application/Espo/Resources/test/hello', + 'modulePath' => 'application/Espo/Modules/{*}/Resources/test/hello', + 'customPath' => 'custom/Espo/Custom/Resources/test/hello', + ]) + ->willReturn([]); + + $this->reader->read('test/hello', $params); + } + + public function testRead3(): void + { + $params = ReaderParams::create() + ->withAsArray() + ->withNoCustom(); + + $this->unifier + ->expects($this->once()) + ->method('unify') + ->with([ + 'corePath' => 'application/Espo/Resources/test/hello', + 'modulePath' => 'application/Espo/Modules/{*}/Resources/test/hello', + ]) + ->willReturn([]); + + $this->reader->read('test/hello', $params); + } +}