mirror of
https://github.com/espocrm/espocrm.git
synced 2026-06-28 06:56:05 +00:00
refactoring
This commit is contained in:
@@ -376,64 +376,27 @@ class Manager
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge file content and save it to a file.
|
||||
*
|
||||
* @param string | array $path
|
||||
* @param string $content JSON string
|
||||
* @param bool $isReturnJson
|
||||
* @param string | array $removeOptions List of unset keys from content.
|
||||
* @param bool $isPhp Is merge php files.
|
||||
*
|
||||
* @return bool | array
|
||||
* Merge JSON file contents with existing and override the file.
|
||||
*/
|
||||
public function mergeContents($path, $content, $isReturnJson = false, $removeOptions = null, $isPhp = false)
|
||||
public function mergeJsonContents(string $path, array $data): bool
|
||||
{
|
||||
if ($isPhp) {
|
||||
$fileContent = $this->getPhpContents($path);
|
||||
}
|
||||
else {
|
||||
$fileContent = $this->getContents($path);
|
||||
$currentContents = $this->getContents($path);
|
||||
|
||||
if ($this->isFile($path) && $currentContents === false) {
|
||||
throw new Error("FileManager: Failed to read file '{$path}'.");
|
||||
}
|
||||
|
||||
$fullPath = $this->concatPaths($path);
|
||||
$currentData = $this->isFile($path) ?
|
||||
Json::decode($currentContents, true):
|
||||
[];
|
||||
|
||||
if (file_exists($fullPath) && ($fileContent === false || empty($fileContent))) {
|
||||
throw new Error('FileManager: Failed to read file [' . $fullPath .'].');
|
||||
}
|
||||
$mergedData = Util::merge($currentData, $data);
|
||||
|
||||
$savedDataArray = Json::decode($fileContent, true);
|
||||
$jsonOptions = JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES;
|
||||
|
||||
$newDataArray = Json::decode($content, true);
|
||||
$stringData = Json::encode($mergedData, $jsonOptions);
|
||||
|
||||
if (isset($removeOptions)) {
|
||||
$savedDataArray = Util::unsetInArray($savedDataArray, $removeOptions);
|
||||
$newDataArray = Util::unsetInArray($newDataArray, $removeOptions);
|
||||
}
|
||||
|
||||
$data = Util::merge($savedDataArray, $newDataArray);
|
||||
|
||||
if ($isReturnJson) {
|
||||
$data = Json::encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
}
|
||||
|
||||
if ($isPhp) {
|
||||
return $this->putPhpContents($path, $data);
|
||||
}
|
||||
|
||||
return $this->putContents($path, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge PHP content and save it to a file.
|
||||
*
|
||||
* @param string | array $path
|
||||
* @param string $content JSON string
|
||||
* @param string | array $removeOptions - List of unset keys from content
|
||||
* @return bool
|
||||
*/
|
||||
public function mergePhpContents($path, $content, $removeOptions = null)
|
||||
{
|
||||
return $this->mergeContents($path, $content, false, $removeOptions, true);
|
||||
return (bool) $this->putContents($path, $stringData);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -450,39 +413,33 @@ class Manager
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset some element of content data.
|
||||
*
|
||||
* @param string | array $path
|
||||
* @param array | string $unsets
|
||||
* @return bool
|
||||
* Unset specific items in a JSON file and override the file.
|
||||
* Items are specified as an array of JSON paths.
|
||||
*/
|
||||
public function unsetContents($path, $unsets, $isJSON = true)
|
||||
public function unsetJsonContents(string $path, array $unsets): bool
|
||||
{
|
||||
$currentData = $this->getContents($path);
|
||||
|
||||
if (!isset($currentData) || !$currentData) {
|
||||
if (!file_exists($path)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$currentDataArray = Json::decode($currentData, true);
|
||||
$currentContents = $this->getContents($path);
|
||||
|
||||
$unsettedData = Util::unsetInArray($currentDataArray, $unsets, true);
|
||||
|
||||
if (is_null($unsettedData) || (is_array($unsettedData) && empty($unsettedData))) {
|
||||
$fullPath = $this->concatPaths($path);
|
||||
|
||||
if (!file_exists($fullPath)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->unlink($fullPath);
|
||||
if (!isset($currentContents) || !$currentContents) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($isJSON) {
|
||||
return $this->putContentsJson($path, $unsettedData);
|
||||
$currentData = Json::decode($currentContents, true);
|
||||
|
||||
$unsettedData = Util::unsetInArray($currentData, $unsets, true);
|
||||
|
||||
if (
|
||||
is_null($unsettedData) ||
|
||||
(is_array($unsettedData) && empty($unsettedData))
|
||||
) {
|
||||
return $this->unlink($path);
|
||||
}
|
||||
|
||||
return $this->putContents($path, $unsettedData);
|
||||
return (bool) $this->putContentsJson($path, $unsettedData);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -29,9 +29,12 @@
|
||||
|
||||
namespace Espo\Core\Utils\File;
|
||||
|
||||
use Espo\Core\Utils;
|
||||
use Espo\Core\Utils\Util;
|
||||
|
||||
use Espo\Core\Exceptions\Error;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class Permission
|
||||
{
|
||||
private $fileManager;
|
||||
@@ -89,12 +92,6 @@ class Permission
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function getFileManager()
|
||||
{
|
||||
return $this->fileManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default settings.
|
||||
*
|
||||
@@ -179,7 +176,7 @@ class Permission
|
||||
/**
|
||||
* Change permissions.
|
||||
*
|
||||
* @param string $filename
|
||||
* @param string $path
|
||||
* @param int|array $octal ex. 0755, array(0644, 0755), array('file'=>0644, 'dir'=>0755).
|
||||
* @param bool $recurse
|
||||
*
|
||||
@@ -245,7 +242,7 @@ class Permission
|
||||
/**
|
||||
* Change permissions recursive.
|
||||
*
|
||||
* @param string $filename
|
||||
* @param string $path
|
||||
* @param int $fileOctal - ex. 0644
|
||||
* @param int $dirOctal - ex. 0755
|
||||
*
|
||||
@@ -263,9 +260,10 @@ class Permission
|
||||
|
||||
$result = $this->chmodReal($path, $dirOctal);
|
||||
|
||||
$allFiles = $this->getFileManager()->getFileList($path);
|
||||
$allFiles = $this->fileManager->getFileList($path);
|
||||
|
||||
foreach ($allFiles as $item) {
|
||||
$result &= $this->chmodRecurse($path . Utils\Util::getSeparator() . $item, $fileOctal, $dirOctal);
|
||||
$result &= $this->chmodRecurse($path . Util::getSeparator() . $item, $fileOctal, $dirOctal);
|
||||
}
|
||||
|
||||
return (bool) $result;
|
||||
@@ -319,9 +317,9 @@ class Permission
|
||||
|
||||
$result = $this->chownReal($path, $user);
|
||||
|
||||
$allFiles = $this->getFileManager()->getFileList($path);
|
||||
$allFiles = $this->fileManager->getFileList($path);
|
||||
foreach ($allFiles as $item) {
|
||||
$result &= $this->chownRecurse($path . Utils\Util::getSeparator() . $item, $user);
|
||||
$result &= $this->chownRecurse($path . Util::getSeparator() . $item, $user);
|
||||
}
|
||||
|
||||
return (bool) $result;
|
||||
@@ -376,9 +374,9 @@ class Permission
|
||||
|
||||
$result = $this->chgrpReal($path, $group);
|
||||
|
||||
$allFiles = $this->getFileManager()->getFileList($path);
|
||||
$allFiles = $this->fileManager->getFileList($path);
|
||||
foreach ($allFiles as $item) {
|
||||
$result &= $this->chgrpRecurse($path . Utils\Util::getSeparator() . $item, $group);
|
||||
$result &= $this->chgrpRecurse($path . Util::getSeparator() . $item, $group);
|
||||
}
|
||||
|
||||
return (bool) $result;
|
||||
@@ -500,7 +498,7 @@ class Permission
|
||||
try {
|
||||
$this->chmod($path, $this->writablePermissions, $options['recursive']);
|
||||
}
|
||||
catch (\Throwable $e) {}
|
||||
catch (Throwable $e) {}
|
||||
|
||||
/** check is writable */
|
||||
$res = is_writable($path);
|
||||
@@ -508,10 +506,12 @@ class Permission
|
||||
if (is_dir($path)) {
|
||||
try {
|
||||
$name = uniqid();
|
||||
$res &= $this->getFileManager()->putContents([$path, $name], 'test');
|
||||
$res &= $this->getFileManager()->removeFile($name, $path);
|
||||
|
||||
$res &= $this->fileManager->putContents($path . '/' . $name, 'test');
|
||||
|
||||
$res &= $this->fileManager->removeFile($name, $path);
|
||||
}
|
||||
catch (\Throwable $e) {
|
||||
catch (Throwable $e) {
|
||||
$res = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ class Language
|
||||
];
|
||||
|
||||
public function __construct(
|
||||
?string $language = null,
|
||||
?string $language,
|
||||
FileManager $fileManager,
|
||||
Metadata $metadata,
|
||||
DataCache $dataCache = null,
|
||||
@@ -81,7 +81,8 @@ class Language
|
||||
) {
|
||||
if ($language) {
|
||||
$this->currentLanguage = $language;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
$this->currentLanguage = $this->defaultLanguage;
|
||||
}
|
||||
|
||||
@@ -99,16 +100,6 @@ class Language
|
||||
$this->unifier = new FileUnifier($this->fileManager, $this->metadata);
|
||||
}
|
||||
|
||||
protected function getFileManager()
|
||||
{
|
||||
return $this->fileManager;
|
||||
}
|
||||
|
||||
protected function getMetadata()
|
||||
{
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
protected function getUnifier()
|
||||
{
|
||||
return $this->unifier;
|
||||
@@ -247,17 +238,22 @@ class Language
|
||||
|
||||
if (!empty($this->changedData)) {
|
||||
foreach ($this->changedData as $scope => $data) {
|
||||
if (!empty($data)) {
|
||||
$result &= $this->getFileManager()->mergeContents([$path, $scope.'.json'], $data, true);
|
||||
if (empty($data)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$result &= $this->fileManager->mergeJsonContents($path . "/{$scope}.json", $data);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($this->deletedData)) {
|
||||
foreach ($this->deletedData as $scope => $unsetData) {
|
||||
if (!empty($unsetData)) {
|
||||
$result &= $this->getFileManager()->unsetContents([$path, $scope.'.json'], $unsetData, true);
|
||||
if (empty($unsetData)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$result &= $this->fileManager->unsetJsonContents($path . "/{$scope}.json", $unsetData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,11 +318,11 @@ class Language
|
||||
/**
|
||||
* Remove a label.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $category
|
||||
* @param string $scope
|
||||
* @param string $scope
|
||||
* @param string $category
|
||||
* @param string|array $name
|
||||
*/
|
||||
public function delete($scope, $category, $name)
|
||||
public function delete(string $scope, string $category, $name): void
|
||||
{
|
||||
if (is_array($name)) {
|
||||
foreach ($name as $rowLabel) {
|
||||
|
||||
@@ -38,6 +38,8 @@ use Espo\Core\{
|
||||
Utils\DataCache,
|
||||
};
|
||||
|
||||
use StdClass;
|
||||
|
||||
class Metadata
|
||||
{
|
||||
protected $data = null;
|
||||
@@ -46,8 +48,6 @@ class Metadata
|
||||
|
||||
protected $useCache;
|
||||
|
||||
private $unifier;
|
||||
|
||||
private $objUnifier;
|
||||
|
||||
private $module;
|
||||
@@ -75,6 +75,7 @@ class Metadata
|
||||
private $changedData = [];
|
||||
|
||||
private $fileManager;
|
||||
|
||||
private $dataCache;
|
||||
|
||||
public function __construct(FileManager $fileManager, DataCache $dataCache, bool $useCache = false)
|
||||
@@ -352,14 +353,15 @@ class Metadata
|
||||
/**
|
||||
* Get metadata definition in custom directory.
|
||||
*
|
||||
* @param string|array $key
|
||||
* @param mixed $default
|
||||
* @param string|array $key
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return object|mixed
|
||||
* @return object
|
||||
*/
|
||||
public function getCustom($key1, $key2, $default = null)
|
||||
{
|
||||
$filePath = array($this->paths['customPath'], $key1, $key2.'.json');
|
||||
$filePath = $this->paths['customPath'] . "/{$key1}/{$key2}.json";
|
||||
|
||||
$fileContent = $this->fileManager->getContents($filePath);
|
||||
|
||||
if ($fileContent) {
|
||||
@@ -373,43 +375,33 @@ class Metadata
|
||||
* Set and save metadata in custom directory.
|
||||
* The data is not merging with existing data. Use getCustom() to get existing data.
|
||||
*
|
||||
* @param string $key1
|
||||
* @param string $key2
|
||||
* @param array $data
|
||||
*
|
||||
* @return boolean
|
||||
* @param string $key1
|
||||
* @param string $key2
|
||||
* @param array|object $data
|
||||
*/
|
||||
public function saveCustom($key1, $key2, $data)
|
||||
public function saveCustom(string $key1, string $key2, $data): void
|
||||
{
|
||||
if (is_object($data)) {
|
||||
foreach ($data as $key => $item) {
|
||||
if ($item == new \stdClass()) {
|
||||
if ($item == new StdClass()) {
|
||||
unset($data->$key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$filePath = array($this->paths['customPath'], $key1, $key2.'.json');
|
||||
$filePath = $this->paths['customPath'] . "/{$key1}/{$key2}.json";
|
||||
|
||||
$changedData = Json::encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
|
||||
$result = $this->fileManager->putContents($filePath, $changedData);
|
||||
$this->fileManager->putContents($filePath, $changedData);
|
||||
|
||||
$this->init(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Metadata data.
|
||||
* Ex. $key1 = menu, $key2 = Account then will be created a file metadataFolder/menu/Account.json
|
||||
*
|
||||
* @param string $key1
|
||||
* @param string $key2
|
||||
* @param JSON string $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function set($key1, $key2, $data)
|
||||
* Set Metadata data.
|
||||
*/
|
||||
public function set(string $key1, string $key2, $data): void
|
||||
{
|
||||
if (is_array($data)) {
|
||||
foreach ($data as $key => $item) {
|
||||
@@ -419,11 +411,11 @@ class Metadata
|
||||
}
|
||||
}
|
||||
|
||||
$newData = array(
|
||||
$key1 => array(
|
||||
$newData = [
|
||||
$key1 => [
|
||||
$key2 => $data,
|
||||
),
|
||||
);
|
||||
],
|
||||
];
|
||||
|
||||
$this->changedData = Util::merge($this->changedData, $newData);
|
||||
$this->data = Util::merge($this->getData(), $newData);
|
||||
@@ -434,13 +426,11 @@ class Metadata
|
||||
/**
|
||||
* Unset some fields and other stuff in metadata.
|
||||
*
|
||||
* @param string $key1
|
||||
* @param string $key2
|
||||
* @param array | string $unsets Ex. 'fields.name'
|
||||
* @param array|string $unsets Ex. `fields.name`.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete($key1, $key2, $unsets = null)
|
||||
public function delete(string $key1, string $key2, $unsets = null)
|
||||
{
|
||||
if (!is_array($unsets)) {
|
||||
$unsets = (array) $unsets;
|
||||
@@ -459,7 +449,9 @@ class Metadata
|
||||
$fieldPath = [$key1, $key2, 'fields', $fieldName];
|
||||
|
||||
$additionalFields = $this->getMetadataHelper()->getAdditionalFieldList(
|
||||
$fieldName, $this->get($fieldPath, []), $fieldDefinitionList
|
||||
$fieldName,
|
||||
$this->get($fieldPath, []),
|
||||
$fieldDefinitionList
|
||||
);
|
||||
|
||||
if (is_array($additionalFields)) {
|
||||
@@ -524,7 +516,7 @@ class Metadata
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function save()
|
||||
public function save(): bool
|
||||
{
|
||||
$path = $this->paths['customPath'];
|
||||
|
||||
@@ -533,9 +525,13 @@ class Metadata
|
||||
if (!empty($this->changedData)) {
|
||||
foreach ($this->changedData as $key1 => $keyData) {
|
||||
foreach ($keyData as $key2 => $data) {
|
||||
if (!empty($data)) {
|
||||
$result &= $this->fileManager->mergeContents([$path, $key1, $key2.'.json'], $data, true);
|
||||
if (empty($data)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$filePath = $path . "/{$key1}/{$key2}.json";
|
||||
|
||||
$result &= $this->fileManager->mergeJsonContents($filePath, $data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -543,25 +539,27 @@ class Metadata
|
||||
if (!empty($this->deletedData)) {
|
||||
foreach ($this->deletedData as $key1 => $keyData) {
|
||||
foreach ($keyData as $key2 => $unsetData) {
|
||||
if (!empty($unsetData)) {
|
||||
$rowResult = $this->fileManager->unsetContents(
|
||||
[$path, $key1, $key2.'.json'], $unsetData, true
|
||||
);
|
||||
|
||||
if ($rowResult == false) {
|
||||
$GLOBALS['log']->warning(
|
||||
'Metadata items ['.$key1.'.'.$key2.'] can be deleted for custom code only.'
|
||||
);
|
||||
}
|
||||
|
||||
$result &= $rowResult;
|
||||
if (empty($unsetData)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$filePath = $path . "/{$key1}/{$key2}.json";
|
||||
|
||||
$rowResult = $this->fileManager->unsetJsonContents($filePath, $unsetData);
|
||||
|
||||
if (!$rowResult) {
|
||||
$GLOBALS['log']->warning(
|
||||
'Metadata items ['.$key1.'.'.$key2.'] can be deleted for custom code only.'
|
||||
);
|
||||
}
|
||||
|
||||
$result &= $rowResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($result == false) {
|
||||
throw new Error("Error saving metadata. See log file for details.");
|
||||
if (!$result) {
|
||||
throw new Error("Error while saving metadata. See log file for details.");
|
||||
}
|
||||
|
||||
$this->clearChanges();
|
||||
|
||||
@@ -263,12 +263,12 @@ class EntityManager
|
||||
}
|
||||
|
||||
if ($this->checkControllerExists($name)) {
|
||||
throw new Conflict('Entity name \''.$name.'\' is not allowed.');
|
||||
throw new Conflict('Entity name \''.$name.'\' is not allowed. Controller already exists.');
|
||||
}
|
||||
|
||||
$serviceFactory = $this->getServiceFactory();
|
||||
|
||||
if ($serviceFactory && $serviceFactory->checKExists($name)) {
|
||||
if ($serviceFactory && $serviceFactory->checkExists($name)) {
|
||||
throw new Conflict('Entity name \''.$name.'\' is not allowed.');
|
||||
}
|
||||
|
||||
@@ -486,6 +486,7 @@ class EntityManager
|
||||
$this->getBaseLanguage()->save();
|
||||
|
||||
$layoutsPath = $templatePath . "/Layouts/{$type}";
|
||||
|
||||
if ($this->getFileManager()->isDir($layoutsPath)) {
|
||||
$this->getFileManager()->copy($layoutsPath, 'custom/Espo/Custom/Resources/layouts/' . $name);
|
||||
}
|
||||
|
||||
@@ -550,7 +550,9 @@ class FieldManager
|
||||
}
|
||||
}
|
||||
|
||||
return $this->getMetadata()->saveCustom('entityDefs', $scope, $customDefs);
|
||||
$this->getMetadata()->saveCustom('entityDefs', $scope, $customDefs);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function getLinkDefs($scope, $name)
|
||||
|
||||
@@ -119,7 +119,9 @@ class LayoutManager
|
||||
|
||||
$data = Json::encode($layoutData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||||
|
||||
$result &= $this->fileManager->putContents([$layoutPath, $layoutName.'.json'], $data);
|
||||
$path = $layoutPath . '/' . $layoutName . '.json';
|
||||
|
||||
$result &= $this->fileManager->putContents($path, $data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -186,10 +186,11 @@ class ManagerTest extends \PHPUnit\Framework\TestCase
|
||||
$initData = '{"fields":{"someName":{"type":"varchar","maxLength":40},"someName2":{"type":"varchar","maxLength":36}}}';
|
||||
$this->object->putContents($testPath, $initData);
|
||||
|
||||
$unsets = 'fields.someName2';
|
||||
$this->assertTrue($this->object->unsetContents($testPath, $unsets));
|
||||
$unsets = ['fields.someName2'];
|
||||
$this->assertTrue($this->object->unsetJsonContents($testPath, $unsets));
|
||||
|
||||
$result = '{"fields":{"someName":{"type":"varchar","maxLength":40}}}';
|
||||
|
||||
$this->assertJsonStringEqualsJsonFile($testPath, $result);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user