mirror of
https://github.com/espocrm/espocrm.git
synced 2026-03-03 02:27:01 +00:00
full name additional attribute list
This commit is contained in:
@@ -33,6 +33,13 @@ use Espo\ORM\Defs\Params\FieldParam;
|
||||
|
||||
class FieldUtil
|
||||
{
|
||||
private const PARAM_ACTUAL = 'actual';
|
||||
private const PARAM_NOT_ACTUAL = 'notActual';
|
||||
private const PARAM_NAMING = 'naming';
|
||||
|
||||
private const NAMING_PREFIX = 'prefix';
|
||||
private const NAMING_SUFFIX = 'suffix';
|
||||
|
||||
/** @var array<string, array<string, string[]>> */
|
||||
private $fieldByTypeListCache = [];
|
||||
|
||||
@@ -59,7 +66,7 @@ class FieldUtil
|
||||
return [];
|
||||
}
|
||||
|
||||
$defs = $this->metadata->get('fields.' . $fieldType);
|
||||
$defs = $this->metadata->get("fields.$fieldType");
|
||||
|
||||
if (!$defs) {
|
||||
return [];
|
||||
@@ -69,37 +76,39 @@ class FieldUtil
|
||||
$defs = get_object_vars($defs);
|
||||
}
|
||||
|
||||
$fieldList = [];
|
||||
$output = [];
|
||||
|
||||
if (isset($defs[$type . 'Fields'])) {
|
||||
$list = $defs[$type . 'Fields'];
|
||||
|
||||
$naming = 'suffix';
|
||||
|
||||
if (isset($defs['naming'])) {
|
||||
$naming = $defs['naming'];
|
||||
if (!isset($defs[$type . 'Fields'])) {
|
||||
if ($type === self::PARAM_ACTUAL) {
|
||||
$output[] = $name;
|
||||
}
|
||||
|
||||
if ($naming == 'prefix') {
|
||||
foreach ($list as $f) {
|
||||
if ($f === '') {
|
||||
$fieldList[] = $name;
|
||||
} else {
|
||||
$fieldList[] = $f . ucfirst($name);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach ($list as $f) {
|
||||
$fieldList[] = $name . ucfirst($f);
|
||||
return $output;
|
||||
}
|
||||
|
||||
$list = $defs[$type . 'Fields'];
|
||||
|
||||
$naming = self::NAMING_SUFFIX;
|
||||
|
||||
if (isset($defs[self::PARAM_NAMING])) {
|
||||
$naming = $defs[self::PARAM_NAMING];
|
||||
}
|
||||
|
||||
if ($naming === self::NAMING_PREFIX) {
|
||||
foreach ($list as $it) {
|
||||
if ($it === '') {
|
||||
$output[] = $name;
|
||||
} else {
|
||||
$output[] = $it . ucfirst($name);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($type == 'actual') {
|
||||
$fieldList[] = $name;
|
||||
foreach ($list as $it) {
|
||||
$output[] = $name . ucfirst($it);
|
||||
}
|
||||
}
|
||||
|
||||
return $fieldList;
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,11 +116,9 @@ class FieldUtil
|
||||
*/
|
||||
public function getAdditionalActualAttributeList(string $entityType, string $name): array
|
||||
{
|
||||
$attributeList = [];
|
||||
|
||||
$list = $this->metadata->get(['entityDefs', $entityType, 'fields', $name, 'additionalAttributeList']);
|
||||
|
||||
if (empty($list)) {
|
||||
if (!$list) {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -121,19 +128,21 @@ class FieldUtil
|
||||
return [];
|
||||
}
|
||||
|
||||
$naming = $this->metadata->get(['fields', $type, 'naming'], 'suffix');
|
||||
$naming = $this->metadata->get("fields.$type.naming") ?? self::NAMING_SUFFIX;
|
||||
|
||||
if ($naming == 'prefix') {
|
||||
foreach ($list as $f) {
|
||||
$attributeList[] = $f . ucfirst($name);
|
||||
$output = [];
|
||||
|
||||
if ($naming === self::NAMING_PREFIX) {
|
||||
foreach ($list as $it) {
|
||||
$output[] = $it . ucfirst($name);
|
||||
}
|
||||
} else {
|
||||
foreach ($list as $f) {
|
||||
$attributeList[] = $name . ucfirst($f);
|
||||
foreach ($list as $it) {
|
||||
$output[] = $name . ucfirst($it);
|
||||
}
|
||||
}
|
||||
|
||||
return $attributeList;
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,8 +153,9 @@ class FieldUtil
|
||||
public function getActualAttributeList(string $entityType, string $field): array
|
||||
{
|
||||
return array_merge(
|
||||
$this->getAttributeListByType($entityType, $field, 'actual'),
|
||||
$this->getAdditionalActualAttributeList($entityType, $field)
|
||||
$this->getAttributeListByType($entityType, $field, self::PARAM_ACTUAL),
|
||||
$this->getAdditionalActualAttributeList($entityType, $field),
|
||||
$this->getFullNameAdditionalActualAttributeList($entityType, $field),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -156,7 +166,7 @@ class FieldUtil
|
||||
*/
|
||||
public function getNotActualAttributeList(string $entityType, string $field): array
|
||||
{
|
||||
return $this->getAttributeListByType($entityType, $field, 'notActual');
|
||||
return $this->getAttributeListByType($entityType, $field, self::PARAM_NOT_ACTUAL);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,39 +216,42 @@ class FieldUtil
|
||||
*/
|
||||
private function getFieldTypeAttributeListByType(string $fieldType, string $name, string $type): array
|
||||
{
|
||||
/** @var ?array<string, mixed> $defs */
|
||||
$defs = $this->metadata->get(['fields', $fieldType]);
|
||||
|
||||
if (!$defs) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$attributeList = [];
|
||||
$output = [];
|
||||
|
||||
if (isset($defs[$type . 'Fields'])) {
|
||||
$list = $defs[$type . 'Fields'];
|
||||
|
||||
$naming = 'suffix';
|
||||
|
||||
if (isset($defs['naming'])) {
|
||||
$naming = $defs['naming'];
|
||||
if (!isset($defs[$type . 'Fields'])) {
|
||||
if ($type === self::PARAM_ACTUAL) {
|
||||
$output[] = $name;
|
||||
}
|
||||
|
||||
if ($naming == 'prefix') {
|
||||
foreach ($list as $f) {
|
||||
$attributeList[] = $f . ucfirst($name);
|
||||
}
|
||||
} else {
|
||||
foreach ($list as $f) {
|
||||
$attributeList[] = $name . ucfirst($f);
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
$list = $defs[$type . 'Fields'];
|
||||
|
||||
$naming = self::NAMING_SUFFIX;
|
||||
|
||||
if (isset($defs['naming'])) {
|
||||
$naming = $defs['naming'];
|
||||
}
|
||||
|
||||
if ($naming === self::NAMING_PREFIX) {
|
||||
foreach ($list as $f) {
|
||||
$output[] = $f . ucfirst($name);
|
||||
}
|
||||
} else {
|
||||
if ($type == 'actual') {
|
||||
$attributeList[] = $name;
|
||||
foreach ($list as $f) {
|
||||
$output[] = $name . ucfirst($f);
|
||||
}
|
||||
}
|
||||
|
||||
return $attributeList;
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -249,8 +262,8 @@ class FieldUtil
|
||||
public function getFieldTypeAttributeList(string $fieldType, string $name): array
|
||||
{
|
||||
return array_merge(
|
||||
$this->getFieldTypeAttributeListByType($fieldType, $name, 'actual'),
|
||||
$this->getFieldTypeAttributeListByType($fieldType, $name, 'notActual')
|
||||
$this->getFieldTypeAttributeListByType($fieldType, $name, self::PARAM_ACTUAL),
|
||||
$this->getFieldTypeAttributeListByType($fieldType, $name, self::PARAM_NOT_ACTUAL)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -305,4 +318,13 @@ class FieldUtil
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function getFullNameAdditionalActualAttributeList(string $entityType, string $field): array
|
||||
{
|
||||
/** @var string[] */
|
||||
return $this->metadata->get("entityDefs.$entityType.fields.$field.fullNameAdditionalAttributeList") ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,35 +157,31 @@ class FieldManager {
|
||||
* @returns {string[]}
|
||||
*/
|
||||
getActualAttributeList(fieldType, fieldName) {
|
||||
const fieldNames = [];
|
||||
const output = [];
|
||||
|
||||
if (fieldType in this.defs) {
|
||||
if ('actualFields' in this.defs[fieldType]) {
|
||||
const actualFields = this.defs[fieldType].actualFields;
|
||||
|
||||
let naming = 'suffix';
|
||||
|
||||
if ('naming' in this.defs[fieldType]) {
|
||||
naming = this.defs[fieldType].naming;
|
||||
}
|
||||
|
||||
if (naming === 'prefix') {
|
||||
actualFields.forEach(f => {
|
||||
fieldNames.push(f + Espo.Utils.upperCaseFirst(fieldName));
|
||||
});
|
||||
}
|
||||
else {
|
||||
actualFields.forEach(f => {
|
||||
fieldNames.push(fieldName + Espo.Utils.upperCaseFirst(f));
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
fieldNames.push(fieldName);
|
||||
}
|
||||
if (!(fieldType in this.defs)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return fieldNames;
|
||||
if ('actualFields' in this.defs[fieldType]) {
|
||||
const actualFields = this.defs[fieldType].actualFields;
|
||||
|
||||
let naming = 'suffix';
|
||||
|
||||
if ('naming' in this.defs[fieldType]) {
|
||||
naming = this.defs[fieldType].naming;
|
||||
}
|
||||
|
||||
if (naming === 'prefix') {
|
||||
actualFields.forEach(it => output.push(it + Espo.Utils.upperCaseFirst(fieldName)));
|
||||
} else {
|
||||
actualFields.forEach(it => output.push(fieldName + Espo.Utils.upperCaseFirst(it)));
|
||||
}
|
||||
} else {
|
||||
output.push(fieldName);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -198,37 +194,37 @@ class FieldManager {
|
||||
* @returns {string[]}
|
||||
*/
|
||||
getNotActualAttributeList(fieldType, fieldName) {
|
||||
const fieldNames = [];
|
||||
|
||||
if (fieldType in this.defs) {
|
||||
if ('notActualFields' in this.defs[fieldType]) {
|
||||
const notActualFields = this.defs[fieldType].notActualFields;
|
||||
|
||||
let naming = 'suffix';
|
||||
|
||||
if ('naming' in this.defs[fieldType]) {
|
||||
naming = this.defs[fieldType].naming;
|
||||
}
|
||||
|
||||
if (naming === 'prefix') {
|
||||
notActualFields.forEach(f => {
|
||||
if (f === '') {
|
||||
fieldNames.push(fieldName);
|
||||
}
|
||||
else {
|
||||
fieldNames.push(f + Espo.Utils.upperCaseFirst(fieldName));
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
notActualFields.forEach(f => {
|
||||
fieldNames.push(fieldName + Espo.Utils.upperCaseFirst(f));
|
||||
});
|
||||
}
|
||||
}
|
||||
if (!(fieldType in this.defs)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return fieldNames;
|
||||
if (!('notActualFields' in this.defs[fieldType])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const notActualFields = this.defs[fieldType].notActualFields;
|
||||
|
||||
let naming = 'suffix';
|
||||
|
||||
if ('naming' in this.defs[fieldType]) {
|
||||
naming = this.defs[fieldType].naming;
|
||||
}
|
||||
|
||||
const output = [];
|
||||
|
||||
if (naming === 'prefix') {
|
||||
notActualFields.forEach(it => {
|
||||
if (it === '') {
|
||||
output.push(fieldName);
|
||||
} else {
|
||||
output.push(it + Espo.Utils.upperCaseFirst(fieldName));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
notActualFields.forEach(it => output.push(fieldName + Espo.Utils.upperCaseFirst(it)));
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -247,7 +243,8 @@ class FieldManager {
|
||||
|
||||
return _.union(
|
||||
this.getAttributeList(type, field),
|
||||
this._getEntityTypeFieldAdditionalAttributeList(entityType, field)
|
||||
this._getEntityTypeFieldAdditionalAttributeList(entityType, field),
|
||||
this._getEntityTypeFieldFullNameAdditionalAttributeList(entityType, field),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -267,7 +264,8 @@ class FieldManager {
|
||||
|
||||
return _.union(
|
||||
this.getActualAttributeList(type, field),
|
||||
this._getEntityTypeFieldAdditionalAttributeList(entityType, field)
|
||||
this._getEntityTypeFieldAdditionalAttributeList(entityType, field),
|
||||
this._getEntityTypeFieldFullNameAdditionalAttributeList(entityType, field),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -386,14 +384,6 @@ class FieldManager {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Since v5.7.
|
||||
* @todo Remove.
|
||||
*/
|
||||
getScopeFieldList(entityType) {
|
||||
return this.getEntityTypeFieldList(entityType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a field parameter value.
|
||||
*
|
||||
@@ -424,7 +414,7 @@ class FieldManager {
|
||||
|
||||
/**
|
||||
* @deprecated Use `getParamList`.
|
||||
* @todo Remove.
|
||||
* @todo Remove in v10.0.
|
||||
*/
|
||||
getParams(fieldType) {
|
||||
return this.getParamList(fieldType);
|
||||
@@ -432,7 +422,7 @@ class FieldManager {
|
||||
|
||||
/**
|
||||
* @deprecated Use `getAttributeList`.
|
||||
* @todo Remove.
|
||||
* @todo Remove in v10.0.
|
||||
*/
|
||||
getAttributes(fieldType, fieldName) {
|
||||
return this.getAttributeList(fieldType, fieldName);
|
||||
@@ -440,7 +430,7 @@ class FieldManager {
|
||||
|
||||
/**
|
||||
* @deprecated Use `getActualAttributeList`.
|
||||
* @todo Remove.
|
||||
* @todo Remove in v10.0.
|
||||
*/
|
||||
getActualAttributes(fieldType, fieldName) {
|
||||
return this.getActualAttributeList(fieldType, fieldName);
|
||||
@@ -448,6 +438,7 @@ class FieldManager {
|
||||
|
||||
/**
|
||||
* @deprecated Use `getNotActualAttributeList`.
|
||||
* @todo Remove in v10.0.
|
||||
*/
|
||||
getNotActualAttributes(fieldType, fieldName) {
|
||||
return this.getNotActualAttributeList(fieldType, fieldName);
|
||||
@@ -487,11 +478,21 @@ class FieldManager {
|
||||
|
||||
/**
|
||||
* @deprecated Use `isEntityTypeFieldAvailable`.
|
||||
* @todo Remove.
|
||||
* @todo Remove in v10.0.
|
||||
*/
|
||||
isScopeFieldAvailable(entityType, field) {
|
||||
return this.isEntityTypeFieldAvailable(entityType, field);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} entityType
|
||||
* @param {string} field
|
||||
* @return {string[]}
|
||||
* @private
|
||||
*/
|
||||
_getEntityTypeFieldFullNameAdditionalAttributeList(entityType, field) {
|
||||
return this.metadata.get(`entityDefs.${entityType}.fields.${field}.fullNameAdditionalAttributeList`) ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
export default FieldManager;
|
||||
|
||||
@@ -1082,7 +1082,14 @@
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Additional attributes for a field. Attribute name will be derived by concatenation with the field name."
|
||||
"description": "Additional attributes for a field. Attribute names will be derived by concatenating specified names with the field name."
|
||||
},
|
||||
"fullNameAdditionalAttributeList": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Additional attributes for a field. As of v9.2."
|
||||
},
|
||||
"dependeeAttributeList": {
|
||||
"type": "array",
|
||||
|
||||
132
tests/unit/Espo/Core/Utils/FieldUtilTest.php
Normal file
132
tests/unit/Espo/Core/Utils/FieldUtilTest.php
Normal file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace tests\unit\Espo\Core\Utils;
|
||||
|
||||
use Espo\Core\Utils\FieldUtil;
|
||||
use Espo\Core\Utils\Metadata;
|
||||
use Espo\Core\Utils\Util;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class FieldUtilTest extends TestCase
|
||||
{
|
||||
private ?Metadata $metadata = null;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->metadata = $this->createMock(Metadata::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $data
|
||||
*/
|
||||
private function initMetadata(array $data): void
|
||||
{
|
||||
$this->metadata
|
||||
->expects($this->any())
|
||||
->method('get')
|
||||
->willReturnCallback(function ($key, $default) use ($data) {
|
||||
return Util::getValueByKey($data, $key, $default);
|
||||
});
|
||||
}
|
||||
|
||||
public function testGetActualAttributeListSuffix(): void
|
||||
{
|
||||
$this->initMetadata([
|
||||
'fields' => [
|
||||
'testType' => [
|
||||
'naming' => 'suffix',
|
||||
'actualFields' => [
|
||||
'',
|
||||
'helloOne',
|
||||
],
|
||||
],
|
||||
],
|
||||
'entityDefs' => [
|
||||
'Test' => [
|
||||
'fields' => [
|
||||
'test' => [
|
||||
'type' => 'testType',
|
||||
'additionalAttributeList' => ['helloTwo'],
|
||||
'fullNameAdditionalAttributeList' => ['helloThree'],
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$fieldUtil = new FieldUtil($this->metadata);
|
||||
|
||||
$actual = $fieldUtil->getActualAttributeList('Test', 'test');
|
||||
|
||||
$this->assertEquals([
|
||||
'test',
|
||||
'testHelloOne',
|
||||
'testHelloTwo',
|
||||
'helloThree',
|
||||
], $actual);
|
||||
}
|
||||
|
||||
public function testGetActualAttributeListPrefix(): void
|
||||
{
|
||||
$this->initMetadata([
|
||||
'fields' => [
|
||||
'testType' => [
|
||||
'naming' => 'prefix',
|
||||
'actualFields' => [
|
||||
'',
|
||||
'helloOne',
|
||||
],
|
||||
],
|
||||
],
|
||||
'entityDefs' => [
|
||||
'Test' => [
|
||||
'fields' => [
|
||||
'test' => [
|
||||
'type' => 'testType',
|
||||
'additionalAttributeList' => ['helloTwo'],
|
||||
'fullNameAdditionalAttributeList' => ['helloThree'],
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$fieldUtil = new FieldUtil($this->metadata);
|
||||
|
||||
$actual = $fieldUtil->getActualAttributeList('Test', 'test');
|
||||
|
||||
$this->assertEquals([
|
||||
'test',
|
||||
'helloOneTest',
|
||||
'helloTwoTest',
|
||||
'helloThree',
|
||||
], $actual);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user