diff --git a/application/Espo/Core/Entities/Person.php b/application/Espo/Core/Entities/Person.php index 5ff0dee7a2..7127a56e55 100644 --- a/application/Espo/Core/Entities/Person.php +++ b/application/Espo/Core/Entities/Person.php @@ -35,23 +35,17 @@ class Person extends \Espo\Core\ORM\Entity { $this->setValue('lastName', $value); - $firstName = $this->get('firstName'); - if (empty($firstName)) { - $this->setValue('name', $value); - } else { - $this->setValue('name', $firstName . ' ' . $value); - } + $name = $this->getEntityManager()->getHelper()->formatPersonName($this, 'name'); + + $this->setValue('name', $name); } public function _setFirstName($value) { $this->setValue('firstName', $value); - $lastName = $this->get('lastName'); - if (empty($lastName)) { - $this->setValue('name', $value); - } else { - $this->setValue('name', $value . ' ' . $lastName); - } + $name = $this->getEntityManager()->getHelper()->formatPersonName($this, 'name'); + + $this->setValue('name', $name); } } diff --git a/application/Espo/Core/Loaders/EntityManager.php b/application/Espo/Core/Loaders/EntityManager.php index e1dd23e57a..cedb1182d8 100644 --- a/application/Espo/Core/Loaders/EntityManager.php +++ b/application/Espo/Core/Loaders/EntityManager.php @@ -35,7 +35,7 @@ class EntityManager extends Base { $config = $this->getContainer()->get('config'); - $params = array( + $params = [ 'host' => $config->get('database.host'), 'port' => $config->get('database.port'), 'dbname' => $config->get('database.dbname'), @@ -50,15 +50,16 @@ class EntityManager extends Base 'sslCert' => $config->get('database.sslCert'), 'sslKey' => $config->get('database.sslKey'), 'sslCAPath' => $config->get('database.sslCAPath'), - 'sslCipher' => $config->get('database.sslCipher') - ); + 'sslCipher' => $config->get('database.sslCipher'), + ]; $entityManager = new \Espo\Core\ORM\EntityManager($params); + $entityManager->setEspoMetadata($this->getContainer()->get('metadata')); $entityManager->setHookManager($this->getContainer()->get('hookManager')); + $entityManager->setHelper($this->getContainer()->get('entityManagerHelper')); $entityManager->setContainer($this->getContainer()); return $entityManager; } } - diff --git a/application/Espo/Core/ORM/EntityManager.php b/application/Espo/Core/ORM/EntityManager.php index 29f58836bc..fa8ea2d97b 100644 --- a/application/Espo/Core/ORM/EntityManager.php +++ b/application/Espo/Core/ORM/EntityManager.php @@ -41,9 +41,11 @@ class EntityManager extends \Espo\ORM\EntityManager protected $container; - private $repositoryClassNameHash = array(); + private $repositoryClassNameHash = []; - private $entityClassNameHash = array(); + private $entityClassNameHash = []; + + private $helper; public function setContainer(\Espo\Core\Container $container) { @@ -108,5 +110,14 @@ class EntityManager extends \Espo\ORM\EntityManager } return $this->entityClassNameHash[$name]; } -} + public function setHelper(Helper $helper) + { + $this->helper = $helper; + } + + public function getHelper() + { + return $this->helper; + } +} diff --git a/application/Espo/Core/ORM/Helper.php b/application/Espo/Core/ORM/Helper.php new file mode 100644 index 0000000000..f5e25ba252 --- /dev/null +++ b/application/Espo/Core/ORM/Helper.php @@ -0,0 +1,80 @@ +config = $config; + } + + public function formatPersonName(Entity $entity, string $field) + { + $format = $this->config->get('personNameFormat'); + + $first = $entity->get('first' . ucfirst($field)); + $last = $entity->get('last' . ucfirst($field)); + + switch ($format) { + case 'lastFirst': + if (!$first && !$last) { + return null; + } + if (!$first) { + return $last; + } + if (!$last) { + return $first; + } + return $last . ' ' . $first; + + default: + if (!$first && !$last) { + return null; + } + if (!$first) { + return $last; + } + if (!$last) { + return $first; + } + return $first . ' ' . $last; + } + + return null; + } +} diff --git a/application/Espo/Core/Utils/Database/Orm/Base.php b/application/Espo/Core/Utils/Database/Orm/Base.php index 18e55df6e7..c24ac95eef 100644 --- a/application/Espo/Core/Utils/Database/Orm/Base.php +++ b/application/Espo/Core/Utils/Database/Orm/Base.php @@ -30,6 +30,7 @@ namespace Espo\Core\Utils\Database\Orm; use Espo\Core\Utils\Util; +use Espo\Core\Utils\Config; class Base { @@ -43,11 +44,14 @@ class Base private $entityDefs; - public function __construct(\Espo\Core\Utils\Metadata $metadata, array $ormEntityDefs, array $entityDefs) + protected $config; + + public function __construct(\Espo\Core\Utils\Metadata $metadata, array $ormEntityDefs, array $entityDefs, Config $config) { $this->metadata = $metadata; $this->ormEntityDefs = $ormEntityDefs; $this->entityDefs = $entityDefs; + $this->config = $config; } protected function getMetadata() @@ -216,20 +220,28 @@ class Base return $returns; } - /** - * Get Foreign field - * - * @param string $name - * @param string $entityName - * @return string - */ - protected function getForeignField($name, $entityName) + protected function getForeignField(string $name, string $entityType) { - $foreignField = $this->getMetadata()->get('entityDefs.'.$entityName.'.fields.'.$name); + $foreignField = $this->getMetadata()->get(['entityDefs', $entityType, 'fields', $name]); if ($foreignField['type'] != 'varchar') { if ($foreignField['type'] == 'personName') { - return array('first' . ucfirst($name), ' ', 'last' . ucfirst($name)); + $personNameFormat = $this->config->get('personNameFormat'); + + switch ($personNameFormat) { + case 'lastFirst': + return [ + 'last' . ucfirst($name), + ' ', + 'first' . ucfirst($name), + ]; + } + + return [ + 'first' . ucfirst($name), + ' ', + 'last' . ucfirst($name), + ]; } } @@ -238,9 +250,6 @@ class Base /** * Set a value for all elements of array. So, in result all elements will have the same values - * - * @param string $value - * @param array $array */ protected function setArrayValue($inputValue, array $array) { @@ -250,5 +259,4 @@ class Base return $array; } - } diff --git a/application/Espo/Core/Utils/Database/Orm/Converter.php b/application/Espo/Core/Utils/Database/Orm/Converter.php index b15e79faf6..0e887a0e90 100644 --- a/application/Espo/Core/Utils/Database/Orm/Converter.php +++ b/application/Espo/Core/Utils/Database/Orm/Converter.php @@ -116,7 +116,7 @@ class Converter $this->fileManager = $fileManager; //need to featue with ormHooks. Ex. isFollowed field $this->config = $config; - $this->relationManager = new RelationManager($this->metadata); + $this->relationManager = new RelationManager($this->metadata, $config); $this->metadataHelper = new \Espo\Core\Utils\Metadata\Helper($this->metadata); $this->databaseHelper = new \Espo\Core\Utils\Database\Helper($this->config); @@ -346,12 +346,8 @@ class Converter /** * Correct fields definitions based on \Espo\Custom\Core\Utils\Database\Orm\Fields - * - * @param array $ormMetadata - * - * @return array */ - protected function correctFields($entityName, array $ormMetadata) + protected function correctFields($entityName, array $ormMetadata) : array { $entityDefs = $this->getEntityDefs(); @@ -367,7 +363,7 @@ class Converter } if (class_exists($className) && method_exists($className, 'load')) { - $helperClass = new $className($this->metadata, $ormMetadata, $entityDefs); + $helperClass = new $className($this->metadata, $ormMetadata, $entityDefs, $this->config); $fieldResult = $helperClass->process($fieldName, $entityName); if (isset($fieldResult['unset'])) { $ormMetadata = Util::unsetInArray($ormMetadata, $fieldResult['unset']); diff --git a/application/Espo/Core/Utils/Database/Orm/Fields/Base.php b/application/Espo/Core/Utils/Database/Orm/Fields/Base.php index 279b53dd23..90fa336484 100644 --- a/application/Espo/Core/Utils/Database/Orm/Fields/Base.php +++ b/application/Espo/Core/Utils/Database/Orm/Fields/Base.php @@ -28,6 +28,7 @@ ************************************************************************/ namespace Espo\Core\Utils\Database\Orm\Fields; + class Base extends \Espo\Core\Utils\Database\Orm\Base { /** diff --git a/application/Espo/Core/Utils/Database/Orm/Fields/PersonName.php b/application/Espo/Core/Utils/Database/Orm/Fields/PersonName.php index 40a1eb3ab1..d1facca2d4 100644 --- a/application/Espo/Core/Utils/Database/Orm/Fields/PersonName.php +++ b/application/Espo/Core/Utils/Database/Orm/Fields/PersonName.php @@ -35,7 +35,16 @@ class PersonName extends Base { protected function load($fieldName, $entityName) { - $subList = ['first' . ucfirst($fieldName), ' ', 'last' . ucfirst($fieldName)]; + $format = $this->config->get('personNameFormat'); + + switch ($format) { + case 'lastFirst': + $subList = ['last' . ucfirst($fieldName), ' ', 'first' . ucfirst($fieldName)]; + break; + + default: + $subList = ['first' . ucfirst($fieldName), ' ', 'last' . ucfirst($fieldName)]; + } $tableName = Util::toUnderScore($entityName); diff --git a/application/Espo/Core/Utils/Database/Orm/RelationManager.php b/application/Espo/Core/Utils/Database/Orm/RelationManager.php index 2f07c6a08e..87ec02cf5e 100644 --- a/application/Espo/Core/Utils/Database/Orm/RelationManager.php +++ b/application/Espo/Core/Utils/Database/Orm/RelationManager.php @@ -30,14 +30,17 @@ namespace Espo\Core\Utils\Database\Orm; use Espo\Core\Utils\Util; +use Espo\Core\Utils\Metadata; +use Espo\Core\Utils\Config; class RelationManager { private $metadata; - public function __construct(\Espo\Core\Utils\Metadata $metadata) + public function __construct(Metadata $metadata, Config $config) { $this->metadata = $metadata; + $this->config = $config; } protected function getMetadata() @@ -132,7 +135,7 @@ class RelationManager } if (isset($className) && $className !== false) { - $helperClass = new $className($this->metadata, $ormMetadata, $entityDefs); + $helperClass = new $className($this->metadata, $ormMetadata, $entityDefs, $this->config); return $helperClass->process($linkName, $entityName, $foreignLink['name'], $foreignEntityName); } //END: relationDefs defined in separate file diff --git a/application/Espo/Core/defaults/config.php b/application/Espo/Core/defaults/config.php index 33f2d5bb43..cfd1c3d013 100644 --- a/application/Espo/Core/defaults/config.php +++ b/application/Espo/Core/defaults/config.php @@ -179,5 +179,6 @@ return [ 'emailForceUseExternalClient' => false, 'useWebSocket' => false, 'auth2FAMethodList' => ['Totp'], + 'personNameFormat' => 'firstLast', 'isInstalled' => false, ]; diff --git a/application/Espo/Resources/i18n/en_US/Settings.json b/application/Espo/Resources/i18n/en_US/Settings.json index 7fb4edfa74..d1385fcde2 100644 --- a/application/Espo/Resources/i18n/en_US/Settings.json +++ b/application/Espo/Resources/i18n/en_US/Settings.json @@ -83,6 +83,7 @@ "siteUrl": "Site URL", "addressPreview": "Address Preview", "addressFormat": "Address Format", + "personNameFormat": "Person Name Format", "notificationSoundsDisabled": "Disable Notification Sounds", "applicationName": "Application Name", "calendarEntityList": "Calendar Entity List", @@ -138,6 +139,10 @@ "1": "10 USD", "2": "$10" }, + "personNameFormat": { + "firstLast": "First Last", + "lastFirst": "Last First" + }, "streamEmailNotificationsTypeList": { "Post": "Posts", "Status": "Status updates", diff --git a/application/Espo/Resources/layouts/Settings/settings.json b/application/Espo/Resources/layouts/Settings/settings.json index d87b396c3d..9102e20dd6 100644 --- a/application/Espo/Resources/layouts/Settings/settings.json +++ b/application/Espo/Resources/layouts/Settings/settings.json @@ -27,7 +27,8 @@ [{"name": "language"}, {"name": "timeZone"}], [{"name": "dateFormat"}, {"name": "weekStart"}], [{"name": "timeFormat"}, {"name": "thousandSeparator"}], - [{"name": "fiscalYearShift"}, {"name": "decimalMark"}], + [{"name": "fiscalYearShift"}, {"name": "decimalMark"}], + [{"name": "personNameFormat"}, false], [{"name": "addressFormat"}, {"name": "addressPreview"}], [{"name": "addressCountryList"}, {"name": "addressCityList"}], [{"name": "addressStateList"}, false] diff --git a/application/Espo/Resources/metadata/app/containerServices.json b/application/Espo/Resources/metadata/app/containerServices.json index 7499f843c2..32079dd0cd 100644 --- a/application/Espo/Resources/metadata/app/containerServices.json +++ b/application/Espo/Resources/metadata/app/containerServices.json @@ -2,5 +2,9 @@ "clientManager": { "className": "\\Espo\\Core\\Utils\\ClientManager", "dependencyList": ["config", "themeManager", "metadata"] + }, + "entityManagerHelper": { + "className": "\\Espo\\Core\\ORM\\Helper", + "dependencyList": ["config"] } } \ No newline at end of file diff --git a/application/Espo/Resources/metadata/entityDefs/Settings.json b/application/Espo/Resources/metadata/entityDefs/Settings.json index af635db5f7..fda348bdac 100644 --- a/application/Espo/Resources/metadata/entityDefs/Settings.json +++ b/application/Espo/Resources/metadata/entityDefs/Settings.json @@ -453,6 +453,10 @@ "readOnly": true, "view": "views/settings/fields/address-preview" }, + "personNameFormat": { + "type": "enum", + "options": ["firstLast", "lastFirst"] + }, "currencyFormat": { "type": "enumInt", "options": [1, 2] diff --git a/application/Espo/Services/Settings.php b/application/Espo/Services/Settings.php index e3927c1e12..516ed48aca 100644 --- a/application/Espo/Services/Settings.php +++ b/application/Espo/Services/Settings.php @@ -197,8 +197,6 @@ class Settings extends \Espo\Core\Services\Base if ( (isset($data->useCache) && $data->useCache !== $this->getConfig()->get('useCache')) - || - (isset($data->aclStrictMode) && $data->aclStrictMode !== $this->getConfig()->get('aclStrictMode')) ) { $this->getContainer()->get('dataManager')->clearCache(); } @@ -211,6 +209,10 @@ class Settings extends \Espo\Core\Services\Base throw new Error('Cannot save settings'); } + if (isset($data->personNameFormat)) { + $this->getContainer()->get('dataManager')->clearCache(); + } + if (isset($data->defaultCurrency) || isset($data->baseCurrency) || isset($data->currencyRates)) { $this->getContainer()->get('dataManager')->rebuildDatabase([]); } diff --git a/client/res/templates/fields/person-name/detail.tpl b/client/res/templates/fields/person-name/detail.tpl index 702ccf1880..c7fc8bc67c 100644 --- a/client/res/templates/fields/person-name/detail.tpl +++ b/client/res/templates/fields/person-name/detail.tpl @@ -1,3 +1,5 @@ -{{#if isNotEmpty}}{{translateOption salutationValue field='salutationName' scope=scope}} {{firstValue}} {{lastValue}}{{else}} +{{#if isNotEmpty}}{{formattedValue}} +{{else}} {{#if valueIsSet}}{{{translate 'None'}}}{{else}}...{{/if}} -{{/if}} \ No newline at end of file +{{/if}} + diff --git a/client/res/templates/fields/person-name/edit-last-first.tpl b/client/res/templates/fields/person-name/edit-last-first.tpl new file mode 100644 index 0000000000..621e2d600c --- /dev/null +++ b/client/res/templates/fields/person-name/edit-last-first.tpl @@ -0,0 +1,13 @@ +