mirror of
https://github.com/espocrm/espocrm.git
synced 2026-06-28 06:56:05 +00:00
link manager: parent
This commit is contained in:
@@ -60,7 +60,7 @@ class EntityManager extends \Espo\Core\Controllers\Base
|
||||
$name = filter_var($name, \FILTER_SANITIZE_STRING);
|
||||
$type = filter_var($type, \FILTER_SANITIZE_STRING);
|
||||
|
||||
$params = array();
|
||||
$params = [];
|
||||
|
||||
if (!empty($data['labelSingular'])) {
|
||||
$params['labelSingular'] = $data['labelSingular'];
|
||||
@@ -187,19 +187,19 @@ class EntityManager extends \Espo\Core\Controllers\Base
|
||||
|
||||
$paramList = [
|
||||
'entity',
|
||||
'entityForeign',
|
||||
'link',
|
||||
'linkForeign',
|
||||
'label',
|
||||
'labelForeign',
|
||||
'linkType'
|
||||
'linkType',
|
||||
];
|
||||
|
||||
$additionalParamList = [
|
||||
'entityForeign',
|
||||
'relationName',
|
||||
'labelForeign',
|
||||
];
|
||||
|
||||
$params = array();
|
||||
$params = [];
|
||||
|
||||
foreach ($paramList as $item) {
|
||||
if (empty($data[$item])) {
|
||||
@@ -209,9 +209,11 @@ class EntityManager extends \Espo\Core\Controllers\Base
|
||||
}
|
||||
|
||||
foreach ($additionalParamList as $item) {
|
||||
$params[$item] = filter_var($data[$item], \FILTER_SANITIZE_STRING);
|
||||
$params[$item] = filter_var($data[$item] ?? null, \FILTER_SANITIZE_STRING);
|
||||
}
|
||||
|
||||
$params['labelForeign'] = $params['labelForeign'] ?? $params['linkForeign'];
|
||||
|
||||
if (array_key_exists('linkMultipleField', $data)) {
|
||||
$params['linkMultipleField'] = $data['linkMultipleField'];
|
||||
}
|
||||
@@ -225,6 +227,12 @@ class EntityManager extends \Espo\Core\Controllers\Base
|
||||
if (array_key_exists('auditedForeign', $data)) {
|
||||
$params['auditedForeign'] = $data['auditedForeign'];
|
||||
}
|
||||
if (array_key_exists('parentEntityTypeList', $data)) {
|
||||
$params['parentEntityTypeList'] = $data['parentEntityTypeList'];
|
||||
}
|
||||
if (array_key_exists('foreignLinkEntityTypeList', $data)) {
|
||||
$params['foreignLinkEntityTypeList'] = $data['foreignLinkEntityTypeList'];
|
||||
}
|
||||
|
||||
$result = $this->getContainer()->get('entityManagerUtil')->createLink($params);
|
||||
|
||||
@@ -251,12 +259,12 @@ class EntityManager extends \Espo\Core\Controllers\Base
|
||||
'link',
|
||||
'linkForeign',
|
||||
'label',
|
||||
'labelForeign'
|
||||
'labelForeign',
|
||||
];
|
||||
|
||||
$additionalParamList = [];
|
||||
|
||||
$params = array();
|
||||
$params = [];
|
||||
foreach ($paramList as $item) {
|
||||
if (array_key_exists($item, $data)) {
|
||||
$params[$item] = filter_var($data[$item], \FILTER_SANITIZE_STRING);
|
||||
@@ -280,6 +288,12 @@ class EntityManager extends \Espo\Core\Controllers\Base
|
||||
if (array_key_exists('auditedForeign', $data)) {
|
||||
$params['auditedForeign'] = $data['auditedForeign'];
|
||||
}
|
||||
if (array_key_exists('parentEntityTypeList', $data)) {
|
||||
$params['parentEntityTypeList'] = $data['parentEntityTypeList'];
|
||||
}
|
||||
if (array_key_exists('foreignLinkEntityTypeList', $data)) {
|
||||
$params['foreignLinkEntityTypeList'] = $data['foreignLinkEntityTypeList'];
|
||||
}
|
||||
|
||||
$result = $this->getContainer()->get('entityManagerUtil')->updateLink($params);
|
||||
|
||||
|
||||
@@ -672,18 +672,23 @@ class EntityManager
|
||||
if (empty($linkType)) {
|
||||
throw new Error();
|
||||
}
|
||||
if (empty($entity) || empty($entityForeign)) {
|
||||
throw new Error();
|
||||
}
|
||||
if (empty($entityForeign) || empty($linkForeign)) {
|
||||
if (empty($entity)) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
if ($linkType !== 'childrenToParent') {
|
||||
if (empty($entityForeign)) {
|
||||
throw new Error();
|
||||
}
|
||||
}
|
||||
if ($this->getMetadata()->get('entityDefs.' . $entity . '.links.' . $link)) {
|
||||
throw new Conflict('Link ['.$entity.'::'.$link.'] already exists.');
|
||||
}
|
||||
if ($this->getMetadata()->get('entityDefs.' . $entityForeign . '.links.' . $linkForeign)) {
|
||||
throw new Conflict('Link ['.$entityForeign.'::'.$linkForeign.'] already exists.');
|
||||
|
||||
if ($entityForeign) {
|
||||
if ($this->getMetadata()->get('entityDefs.' . $entityForeign . '.links.' . $linkForeign)) {
|
||||
throw new Conflict('Link ['.$entityForeign.'::'.$linkForeign.'] already exists.');
|
||||
}
|
||||
}
|
||||
|
||||
if ($entity === $entityForeign) {
|
||||
@@ -926,28 +931,60 @@ class EntityManager
|
||||
$dataRight['links'][$linkForeign]['midKeys'] = ['rightId', 'leftId'];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'childrenToParent':
|
||||
$dataLeft = [
|
||||
'fields' => [
|
||||
$link => [
|
||||
'type' => 'linkParent',
|
||||
'entityList' => $params['parentEntityTypeList'] ?? [],
|
||||
],
|
||||
],
|
||||
'links' => [
|
||||
$link => [
|
||||
'type' => 'belongsToParent',
|
||||
'foreign' => $linkForeign,
|
||||
'isCustom' => true,
|
||||
],
|
||||
],
|
||||
];
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$this->getMetadata()->set('entityDefs', $entity, $dataLeft);
|
||||
$this->getMetadata()->set('entityDefs', $entityForeign, $dataRight);
|
||||
if ($entityForeign) {
|
||||
$this->getMetadata()->set('entityDefs', $entityForeign, $dataRight);
|
||||
}
|
||||
$this->getMetadata()->save();
|
||||
|
||||
$this->getLanguage()->set($entity, 'fields', $link, $label);
|
||||
$this->getLanguage()->set($entity, 'links', $link, $label);
|
||||
$this->getLanguage()->set($entityForeign, 'fields', $linkForeign, $labelForeign);
|
||||
$this->getLanguage()->set($entityForeign, 'links', $linkForeign, $labelForeign);
|
||||
if ($entityForeign) {
|
||||
$this->getLanguage()->set($entityForeign, 'fields', $linkForeign, $labelForeign);
|
||||
$this->getLanguage()->set($entityForeign, 'links', $linkForeign, $labelForeign);
|
||||
}
|
||||
$this->getLanguage()->save();
|
||||
|
||||
if ($this->getLanguage()->getLanguage() !== $this->getBaseLanguage()->getLanguage()) {
|
||||
$this->getBaseLanguage()->set($entity, 'fields', $link, $label);
|
||||
$this->getBaseLanguage()->set($entity, 'links', $link, $label);
|
||||
$this->getBaseLanguage()->set($entityForeign, 'fields', $linkForeign, $labelForeign);
|
||||
$this->getBaseLanguage()->set($entityForeign, 'links', $linkForeign, $labelForeign);
|
||||
if ($entityForeign) {
|
||||
$this->getBaseLanguage()->set($entityForeign, 'fields', $linkForeign, $labelForeign);
|
||||
$this->getBaseLanguage()->set($entityForeign, 'links', $linkForeign, $labelForeign);
|
||||
}
|
||||
$this->getBaseLanguage()->save();
|
||||
}
|
||||
|
||||
if ($linkType === 'childrenToParent') {
|
||||
$foreignLinkEntityTypeList = $params['foreignLinkEntityTypeList'] ?? null;
|
||||
if ($foreignLinkEntityTypeList && is_array($foreignLinkEntityTypeList)) {
|
||||
$this->updateParentForeignLinks($entity, $link, $linkForeign, $foreignLinkEntityTypeList);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -955,18 +992,22 @@ class EntityManager
|
||||
{
|
||||
$entity = $params['entity'];
|
||||
$link = $params['link'];
|
||||
$entityForeign = $params['entityForeign'];
|
||||
$entityForeign = $params['entityForeign'] ?? null;
|
||||
$linkForeign = $params['linkForeign'];
|
||||
|
||||
if (empty($entity) || empty($entityForeign)) {
|
||||
throw new Error();
|
||||
}
|
||||
if (empty($entityForeign) || empty($linkForeign)) {
|
||||
throw new Error();
|
||||
}
|
||||
if (empty($link)) throw new BadRequest();
|
||||
if (empty($entity)) throw new BadRequest();
|
||||
|
||||
$linkType = $this->getMetadata()->get("entityDefs.{$entity}.links.{$link}.type");
|
||||
$isCustom = $this->getMetadata()->get("entityDefs.{$entity}.links.{$link}.isCustom");
|
||||
|
||||
if ($linkType === 'belongsToParent') {
|
||||
|
||||
} else {
|
||||
if (empty($entityForeign)) throw new BadRequest();
|
||||
if (empty($linkForeign)) throw new BadRequest();
|
||||
}
|
||||
|
||||
if (
|
||||
$this->getMetadata()->get("entityDefs.{$entity}.links.{$link}.type") == 'hasMany'
|
||||
&&
|
||||
@@ -1033,6 +1074,7 @@ class EntityManager
|
||||
}
|
||||
|
||||
if (
|
||||
$linkForeign &&
|
||||
in_array($this->getMetadata()->get("entityDefs.{$entityForeign}.links.{$linkForeign}.type"), ['hasMany', 'hasChildren'])
|
||||
) {
|
||||
if (array_key_exists('auditedForeign', $params)) {
|
||||
@@ -1049,23 +1091,44 @@ class EntityManager
|
||||
}
|
||||
}
|
||||
|
||||
if ($linkType === 'belongsToParent') {
|
||||
$parentEntityTypeList = $params['parentEntityTypeList'] ?? null;
|
||||
if ($parentEntityTypeList && is_array($parentEntityTypeList)) {
|
||||
$data = [
|
||||
'fields' => [
|
||||
$link => [
|
||||
'entityList' => $parentEntityTypeList,
|
||||
],
|
||||
],
|
||||
];
|
||||
$this->getMetadata()->set('entityDefs', $entity, $data);
|
||||
$this->getMetadata()->save();
|
||||
}
|
||||
|
||||
$foreignLinkEntityTypeList = $params['foreignLinkEntityTypeList'] ?? null;
|
||||
if ($foreignLinkEntityTypeList && is_array($foreignLinkEntityTypeList)) {
|
||||
$this->updateParentForeignLinks($entity, $link, $linkForeign, $foreignLinkEntityTypeList);
|
||||
}
|
||||
}
|
||||
|
||||
$label = null;
|
||||
if (isset($params['label'])) {
|
||||
$label = $params['label'];
|
||||
}
|
||||
$labelForeign = null;
|
||||
if (isset($params['labelForeign'])) {
|
||||
$labelForeign = $params['labelForeign'];
|
||||
}
|
||||
|
||||
if ($label) {
|
||||
$this->getLanguage()->set($entity, 'fields', $link, $label);
|
||||
$this->getLanguage()->set($entity, 'links', $link, $label);
|
||||
}
|
||||
|
||||
if ($labelForeign) {
|
||||
$this->getLanguage()->set($entityForeign, 'fields', $linkForeign, $labelForeign);
|
||||
$this->getLanguage()->set($entityForeign, 'links', $linkForeign, $labelForeign);
|
||||
if ($linkType !== 'belongsToParent') {
|
||||
$labelForeign = null;
|
||||
if (isset($params['labelForeign'])) {
|
||||
$labelForeign = $params['labelForeign'];
|
||||
}
|
||||
if ($labelForeign) {
|
||||
$this->getLanguage()->set($entityForeign, 'fields', $linkForeign, $labelForeign);
|
||||
$this->getLanguage()->set($entityForeign, 'links', $linkForeign, $labelForeign);
|
||||
}
|
||||
}
|
||||
|
||||
$this->getLanguage()->save();
|
||||
@@ -1076,7 +1139,7 @@ class EntityManager
|
||||
$this->getBaseLanguage()->set($entity, 'fields', $link, $label);
|
||||
$this->getBaseLanguage()->set($entity, 'links', $link, $label);
|
||||
}
|
||||
if ($labelForeign) {
|
||||
if ($labelForeign && $linkType !== 'belongsToParent') {
|
||||
$this->getBaseLanguage()->set($entityForeign, 'fields', $linkForeign, $labelForeign);
|
||||
$this->getBaseLanguage()->set($entityForeign, 'links', $linkForeign, $labelForeign);
|
||||
}
|
||||
@@ -1096,14 +1159,38 @@ class EntityManager
|
||||
throw new Error("Could not delete link {$entity}.{$link}. Not isCustom.");
|
||||
}
|
||||
|
||||
if (empty($entity) || empty($link)) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$entityForeign = $this->getMetadata()->get("entityDefs.{$entity}.links.{$link}.entity");
|
||||
$linkForeign = $this->getMetadata()->get("entityDefs.{$entity}.links.{$link}.foreign");
|
||||
$linkType = $this->getMetadata()->get("entityDefs.{$entity}.links.{$link}.type");
|
||||
|
||||
if (empty($entity) || empty($entityForeign)) {
|
||||
throw new Error();
|
||||
if (!$this->getMetadata()->get('entityDefs', $entity, 'links', $link, 'isCustom')) {
|
||||
throw new Error("Can't remove not custom link.");
|
||||
}
|
||||
|
||||
if ($linkType === 'hasChildren') {
|
||||
$this->getMetadata()->delete('entityDefs', $entity, [
|
||||
'links.' . $link,
|
||||
]);
|
||||
$this->getMetadata()->save();
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($linkType === 'belongsToParent') {
|
||||
$this->getMetadata()->delete('entityDefs', $entity, [
|
||||
'fields.' . $link,
|
||||
'links.' . $link,
|
||||
]);
|
||||
$this->getMetadata()->save();
|
||||
$this->updateParentForeignLinks($entity, $link, $linkForeign, []);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (empty($entityForeign) || empty($linkForeign)) {
|
||||
throw new Error();
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$this->getMetadata()->delete('entityDefs', $entity, array(
|
||||
@@ -1148,8 +1235,6 @@ class EntityManager
|
||||
$className = '\\Espo\\Modules\\'.$normalizedTemplateModuleName.'\\Core\\Utils\\EntityManager\\Hooks\\' . $type . 'Type';
|
||||
}
|
||||
|
||||
|
||||
|
||||
$className = $this->getMetadata()->get(['app', 'entityTemplates', $type, 'hookClassName'], $className);
|
||||
|
||||
if (class_exists($className)) {
|
||||
@@ -1192,4 +1277,89 @@ class EntityManager
|
||||
$this->getLanguage()->delete('Global', 'scopeNamesPlural', $scope);
|
||||
$this->getLanguage()->save();
|
||||
}
|
||||
|
||||
protected function updateParentForeignLinks(
|
||||
string $entityType, string $link, string $linkForeign, array $foreignLinkEntityTypeList
|
||||
)
|
||||
{
|
||||
$toCreateList = [];
|
||||
|
||||
foreach ($foreignLinkEntityTypeList as $foreignEntityType) {
|
||||
$linkDefs = $this->getMetadata()->get(['entityDefs', $foreignEntityType, 'links']) ?? [];
|
||||
|
||||
foreach ($linkDefs as $kLink => $defs) {
|
||||
$kForeign = $defs['foreign'] ?? null;
|
||||
$kIsCustom = $defs['isCustom'] ?? false;
|
||||
$kEntity = $defs['entity'] ?? null;
|
||||
|
||||
if (
|
||||
$kForeign === $link && !$kIsCustom && $kEntity == $entityType
|
||||
) continue 2;
|
||||
|
||||
if ($kLink == $linkForeign) {
|
||||
if ($defs['type'] !== 'hasChildren') continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
$toCreateList[] = $foreignEntityType;
|
||||
}
|
||||
|
||||
$entityTypeList = array_keys($this->getMetadata()->get('entityDefs') ?? []);
|
||||
|
||||
foreach ($entityTypeList as $itemEntityType) {
|
||||
$linkDefs = $this->getMetadata()->get(['entityDefs', $itemEntityType, 'links']) ?? [];
|
||||
|
||||
foreach ($linkDefs as $kLink => $defs) {
|
||||
$kForeign = $defs['foreign'] ?? null;
|
||||
$kIsCustom = $defs['isCustom'] ?? false;
|
||||
$kEntity = $defs['entity'] ?? null;
|
||||
|
||||
if (
|
||||
$kForeign === $link && $kIsCustom && $kEntity == $entityType && $defs['type'] == 'hasChildren' &&
|
||||
$kLink === $linkForeign
|
||||
) {
|
||||
if (!in_array($itemEntityType, $toCreateList)) {
|
||||
$this->getMetadata()->delete('entityDefs', $itemEntityType, [
|
||||
'links.' . $linkForeign,
|
||||
]);
|
||||
|
||||
$this->getLanguage()->delete($itemEntityType, 'links', $linkForeign);
|
||||
|
||||
if ($this->getLanguage()->getLanguage() !== $this->getBaseLanguage()->getLanguage()) {
|
||||
$this->getBaseLanguage()->delete($itemEntityType, 'links', $linkForeign);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($toCreateList as $itemEntityType) {
|
||||
$this->getMetadata()->set('entityDefs', $itemEntityType, [
|
||||
'links' => [
|
||||
$linkForeign => [
|
||||
'type' => 'hasChildren',
|
||||
'foreign' => $link,
|
||||
'entity' => $entityType,
|
||||
'isCustom' => true,
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$label = $this->getLanguage()->translate($entityType, 'scopeNamesPlural');
|
||||
|
||||
$this->getLanguage()->set($itemEntityType, 'links', $linkForeign, $label);
|
||||
if ($this->getLanguage()->getLanguage() !== $this->getBaseLanguage()->getLanguage()) {
|
||||
$this->getBaseLanguage()->set($itemEntityType, 'links', $linkForeign, $label);
|
||||
}
|
||||
}
|
||||
|
||||
$this->getMetadata()->save();
|
||||
|
||||
$this->getLanguage()->save();
|
||||
|
||||
if ($this->getLanguage()->getLanguage() !== $this->getBaseLanguage()->getLanguage()) {
|
||||
$this->getBaseLanguage()->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,9 @@
|
||||
"kanbanStatusIgnoreList": "Ignored groups in Kanban view",
|
||||
"iconClass": "Icon",
|
||||
"countDisabled": "Disable record count",
|
||||
"fullTextSearch": "Full-Text Search"
|
||||
"fullTextSearch": "Full-Text Search",
|
||||
"parentEntityTypeList": "Parent Entity Types",
|
||||
"foreignLinkEntityTypeList": "Foreign Links"
|
||||
},
|
||||
"options": {
|
||||
"type": {
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
</a>
|
||||
</td>
|
||||
<td align="right" width="10%">
|
||||
{{#if isCustom}}
|
||||
{{#if isRemovable}}
|
||||
<a href="javascript:" data-action="removeLink" data-link="{{link}}">
|
||||
{{translate 'Remove'}}
|
||||
</a>
|
||||
|
||||
@@ -81,3 +81,27 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="cell form-group col-md-4"></div>
|
||||
<div class="cell form-group col-md-4" data-name="parentEntityTypeList">
|
||||
<label class="control-label" data-name="parentEntityTypeList">
|
||||
{{translate 'parentEntityTypeList' category='fields' scope='EntityManager'}}
|
||||
</label>
|
||||
<div class="field" data-name="parentEntityTypeList">
|
||||
{{{parentEntityTypeList}}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="cell form-group col-md-4"></div>
|
||||
<div class="cell form-group col-md-4" data-name="foreignLinkEntityTypeList">
|
||||
<label class="control-label" data-name="foreignLinkEntityTypeList">
|
||||
{{translate 'foreignLinkEntityTypeList' category='fields' scope='EntityManager'}}
|
||||
</label>
|
||||
<div class="field" data-name="foreignLinkEntityTypeList">
|
||||
{{{foreignLinkEntityTypeList}}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,3 +5,4 @@
|
||||
<label for="{{id}}" class="checklist-label">{{label}}</label>
|
||||
</div>
|
||||
{{/each}}
|
||||
{{#unless optionDataList.length}}{{translate 'None'}}{{/unless}}
|
||||
|
||||
@@ -5,3 +5,4 @@
|
||||
<label for="{{id}}" class="checklist-label">{{label}}</label>
|
||||
</div>
|
||||
{{/each}}
|
||||
{{#unless optionDataList.length}}{{translate 'None'}}{{/unless}}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2019 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://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 General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
define('views/admin/link-manager/fields/foreign-link-entity-type-list', 'views/fields/checklist', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
setup: function () {
|
||||
this.params.translation = 'Global.scopeNames';
|
||||
Dep.prototype.setup.call(this);
|
||||
},
|
||||
|
||||
afterRender: function () {
|
||||
Dep.prototype.afterRender.call(this);
|
||||
this.controlOptionsAviability();
|
||||
},
|
||||
|
||||
controlOptionsAviability: function () {
|
||||
this.params.options.forEach(function (item) {
|
||||
var link = this.model.get('link');
|
||||
var linkForeign = this.model.get('linkForeign');
|
||||
var entityType = this.model.get('entity');
|
||||
|
||||
var linkDefs = this.getMetadata().get(['entityDefs', item, 'links']) || {};
|
||||
|
||||
var isFound = false;
|
||||
for (var i in linkDefs) {
|
||||
if (linkDefs[i].foreign == link && !linkDefs[i].isCustom && linkDefs[i].entity == entityType) {
|
||||
isFound = true;
|
||||
} else if (i === linkForeign && linkDefs[i].type !== 'hasChildren') {
|
||||
isFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isFound) {
|
||||
this.$el.find('input[data-name="checklistItem-foreignLinkEntityTypeList-'+item+'"]').attr('disabled', 'disabled');
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
});
|
||||
});
|
||||
@@ -105,25 +105,30 @@ define('views/admin/link-manager/index', 'view', function (Dep) {
|
||||
linkList.forEach(function (link) {
|
||||
var d = links[link];
|
||||
|
||||
if (!d.foreign) return;
|
||||
if (!d.entity) return;
|
||||
var linkForeign = d.foreign;
|
||||
|
||||
var foreignType = this.getMetadata().get('entityDefs.' + d.entity + '.links.' + d.foreign + '.type');
|
||||
|
||||
var type = this.computeRelationshipType(d.type, foreignType);
|
||||
if (d.type === 'belongsToParent') {
|
||||
var type = 'childrenToParent';
|
||||
} else {
|
||||
if (!d.entity) return;
|
||||
if (!linkForeign) return;
|
||||
var foreignType = this.getMetadata().get('entityDefs.' + d.entity + '.links.' + d.foreign + '.type');
|
||||
var type = this.computeRelationshipType(d.type, foreignType);
|
||||
}
|
||||
|
||||
if (!type) return;
|
||||
|
||||
this.linkDataList.push({
|
||||
link: link,
|
||||
isCustom: d.isCustom,
|
||||
isRemovable: d.isCustom,
|
||||
customizable: d.customizable,
|
||||
type: type,
|
||||
entityForeign: d.entity,
|
||||
entity: this.scope,
|
||||
linkForeign: d.foreign,
|
||||
linkForeign: linkForeign,
|
||||
label: this.getLanguage().translate(link, 'links', this.scope),
|
||||
labelForeign: this.getLanguage().translate(d.foreign, 'links', d.entity)
|
||||
labelForeign: this.getLanguage().translate(d.foreign, 'links', d.entity),
|
||||
});
|
||||
|
||||
}, this);
|
||||
@@ -182,7 +187,7 @@ define('views/admin/link-manager/index', 'view', function (Dep) {
|
||||
type: 'POST',
|
||||
data: JSON.stringify({
|
||||
entity: this.scope,
|
||||
link: link
|
||||
link: link,
|
||||
})
|
||||
}).done(function () {
|
||||
this.$el.find('table tr[data-link="'+link+'"]').remove();
|
||||
|
||||
@@ -85,7 +85,18 @@ define('views/admin/link-manager/modals/edit',
|
||||
var type = this.getMetadata().get('entityDefs.' + entity + '.links.' + link + '.type');
|
||||
var foreignType = this.getMetadata().get('entityDefs.' + entityForeign + '.links.' + linkForeign + '.type');
|
||||
|
||||
var linkType = Index.prototype.computeRelationshipType.call(this, type, foreignType);
|
||||
if (type === 'belongsToParent') {
|
||||
var linkType = 'childrenToParent';
|
||||
labelForeign = null;
|
||||
|
||||
var entityTypeList = this.getMetadata().get(['entityDefs', entity, 'fields', link, 'entityList']) || [];
|
||||
this.model.set('parentEntityTypeList', entityTypeList);
|
||||
|
||||
var foreignLinkEntityTypeList = this.getForeignLinkEntityTypeList(entity, link, entityTypeList);
|
||||
this.model.set('foreignLinkEntityTypeList', foreignLinkEntityTypeList);
|
||||
} else {
|
||||
var linkType = Index.prototype.computeRelationshipType.call(this, type, foreignType);
|
||||
}
|
||||
|
||||
this.model.set('linkType', linkType);
|
||||
this.model.set('entityForeign', entityForeign);
|
||||
@@ -166,7 +177,7 @@ define('views/admin/link-manager/modals/edit',
|
||||
name: 'linkType',
|
||||
params: {
|
||||
required: true,
|
||||
options: ['', 'oneToMany', 'manyToOne', 'manyToMany', 'oneToOneRight', 'oneToOneLeft']
|
||||
options: ['', 'oneToMany', 'manyToOne', 'manyToMany', 'oneToOneRight', 'oneToOneLeft', 'childrenToParent']
|
||||
}
|
||||
},
|
||||
readOnly: !isNew
|
||||
@@ -285,8 +296,55 @@ define('views/admin/link-manager/modals/edit',
|
||||
tooltipText: this.translate('linkAudited', 'tooltips', 'EntityManager')
|
||||
});
|
||||
|
||||
this.createView('parentEntityTypeList', 'views/fields/entity-type-list', {
|
||||
model: model,
|
||||
mode: 'edit',
|
||||
el: this.options.el + ' .field[data-name="parentEntityTypeList"]',
|
||||
defs: {
|
||||
name: 'parentEntityTypeList',
|
||||
},
|
||||
});
|
||||
|
||||
this.createView('foreignLinkEntityTypeList', 'views/admin/link-manager/fields/foreign-link-entity-type-list', {
|
||||
model: model,
|
||||
mode: 'edit',
|
||||
el: this.options.el + ' .field[data-name="foreignLinkEntityTypeList"]',
|
||||
defs: {
|
||||
name: 'foreignLinkEntityTypeList',
|
||||
params: {
|
||||
options: this.model.get('parentEntityTypeList') || [],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
this.model.fetchedAttributes = this.model.getClonedAttributes();
|
||||
|
||||
this.listenTo(this.model, 'change', function () {
|
||||
if (
|
||||
!this.model.hasChanged('parentEntityTypeList')
|
||||
&&
|
||||
!this.model.hasChanged('linkForeign')
|
||||
&&
|
||||
!this.model.hasChanged('link')
|
||||
) return;
|
||||
|
||||
var view = this.getView('foreignLinkEntityTypeList');
|
||||
if (view) {
|
||||
view.setOptionList(this.model.get('parentEntityTypeList') || []);
|
||||
}
|
||||
var checkedList = Espo.Utils.clone(this.model.get('foreignLinkEntityTypeList') || []);
|
||||
|
||||
this.getForeignLinkEntityTypeList(
|
||||
this.model.get('entity'), this.model.get('link'), this.model.get('parentEntityTypeList') || [], true
|
||||
).forEach(function (item) {
|
||||
if (!~checkedList.indexOf(item)) {
|
||||
checkedList.push(item);
|
||||
}
|
||||
}, this);
|
||||
|
||||
this.model.set('foreignLinkEntityTypeList', checkedList)
|
||||
|
||||
}, this);
|
||||
},
|
||||
|
||||
toPlural: function (string) {
|
||||
@@ -301,13 +359,32 @@ define('views/admin/link-manager/modals/edit',
|
||||
var entityForeign = this.model.get('entityForeign');
|
||||
var linkType = this.model.get('linkType');
|
||||
|
||||
if (!entityForeign || !linkType) {
|
||||
this.model.set('link', '');
|
||||
this.model.set('linkForeign', '');
|
||||
if (linkType === 'childrenToParent') {
|
||||
this.model.set('link', 'parent');
|
||||
this.model.set('label', 'Parent');
|
||||
|
||||
this.model.set('label', '');
|
||||
this.model.set('labelForeign', '');
|
||||
return;
|
||||
var linkForeign = this.toPlural(Espo.Utils.lowerCaseFirst(this.scope));
|
||||
|
||||
if (this.getMetadata().get(['entityDefs', this.scope, 'links', 'parent'])) {
|
||||
this.model.set('link', 'parentAnother');
|
||||
this.model.set('label', 'Parent Another');
|
||||
linkForeign += 'Another';
|
||||
}
|
||||
|
||||
this.model.set('linkForeign', linkForeign);
|
||||
|
||||
this.model.set('labelForeign', '');
|
||||
this.model.set('entityForeign', null);
|
||||
return;
|
||||
} else {
|
||||
if (!entityForeign || !linkType) {
|
||||
this.model.set('link', '');
|
||||
this.model.set('linkForeign', '');
|
||||
|
||||
this.model.set('label', '');
|
||||
this.model.set('labelForeign', '');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var link;
|
||||
@@ -423,10 +500,16 @@ define('views/admin/link-manager/modals/edit',
|
||||
|
||||
handleLinkTypeChange: function () {
|
||||
var linkType = this.model.get('linkType');
|
||||
|
||||
this.showField('entityForeign');
|
||||
this.showField('labelForeign');
|
||||
|
||||
this.hideField('parentEntityTypeList');
|
||||
this.hideField('foreignLinkEntityTypeList');
|
||||
|
||||
if (linkType === 'manyToMany') {
|
||||
var relationNameView = this.getView('relationName');
|
||||
this.showField('relationName');
|
||||
this.showField('relationName');
|
||||
|
||||
this.showField('linkMultipleField');
|
||||
this.showField('linkMultipleFieldForeign');
|
||||
@@ -457,6 +540,11 @@ define('views/admin/link-manager/modals/edit',
|
||||
} else if (linkType == 'childrenToParent') {
|
||||
this.hideField('audited');
|
||||
this.showField('auditedForeign');
|
||||
this.hideField('entityForeign');
|
||||
this.hideField('labelForeign');
|
||||
|
||||
this.showField('parentEntityTypeList');
|
||||
this.showField('foreignLinkEntityTypeList');
|
||||
} else {
|
||||
this.hideField('audited');
|
||||
this.hideField('auditedForeign');
|
||||
@@ -504,6 +592,8 @@ define('views/admin/link-manager/modals/edit',
|
||||
'linkMultipleFieldForeign',
|
||||
'audited',
|
||||
'auditedForeign',
|
||||
'parentEntityTypeList',
|
||||
'foreignLinkEntityTypeList',
|
||||
];
|
||||
|
||||
var notValid = false;
|
||||
@@ -548,6 +638,8 @@ define('views/admin/link-manager/modals/edit',
|
||||
var audited = this.model.get('audited');
|
||||
var auditedForeign = this.model.get('auditedForeign');
|
||||
|
||||
var linkType = this.model.get('linkType');
|
||||
|
||||
var attributes = {
|
||||
entity: entity,
|
||||
entityForeign: entityForeign,
|
||||
@@ -555,14 +647,15 @@ define('views/admin/link-manager/modals/edit',
|
||||
linkForeign: linkForeign,
|
||||
label: label,
|
||||
labelForeign: labelForeign,
|
||||
linkType: this.model.get('linkType'),
|
||||
linkType: linkType,
|
||||
relationName: relationName,
|
||||
linkMultipleField: linkMultipleField,
|
||||
linkMultipleFieldForeign: linkMultipleFieldForeign,
|
||||
audited: audited,
|
||||
auditedForeign: auditedForeign
|
||||
auditedForeign: auditedForeign,
|
||||
};
|
||||
|
||||
|
||||
if (!this.isNew) {
|
||||
if (attributes.label === this.model.fetchedAttributes.label) {
|
||||
delete attributes.label;
|
||||
@@ -572,6 +665,13 @@ define('views/admin/link-manager/modals/edit',
|
||||
}
|
||||
}
|
||||
|
||||
if (linkType === 'childrenToParent') {
|
||||
delete attributes.entityForeign;
|
||||
delete attributes.labelForeign;
|
||||
attributes.parentEntityTypeList = this.model.get('parentEntityTypeList');
|
||||
attributes.foreignLinkEntityTypeList = this.model.get('foreignLinkEntityTypeList');
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'POST',
|
||||
@@ -603,9 +703,14 @@ define('views/admin/link-manager/modals/edit',
|
||||
(data.fields || {})[link] = label;
|
||||
(data.links || {})[link] = label;
|
||||
|
||||
data = ((this.getLanguage().data || {}) || {})[entityForeign];
|
||||
(data.fields || {})[linkForeign] = labelForeign;
|
||||
(data.links || {})[linkForeign] = labelForeign;
|
||||
if (entityForeign) {
|
||||
data = ((this.getLanguage().data || {}) || {})[entityForeign];
|
||||
|
||||
if (linkForeign) {
|
||||
(data.fields || {})[linkForeign] = labelForeign;
|
||||
(data.links || {})[linkForeign] = labelForeign;
|
||||
}
|
||||
}
|
||||
|
||||
this.getMetadata().load(function () {
|
||||
this.trigger('after:save');
|
||||
@@ -613,5 +718,32 @@ define('views/admin/link-manager/modals/edit',
|
||||
}.bind(this), true);
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
getForeignLinkEntityTypeList: function (entityType, link, entityTypeList, onlyNotCustom) {
|
||||
var list = [];
|
||||
|
||||
entityTypeList.forEach(function (item) {
|
||||
var linkDefs = this.getMetadata().get(['entityDefs', item, 'links']) || {};
|
||||
|
||||
var isFound = false;
|
||||
for (var i in linkDefs) {
|
||||
if (linkDefs[i].foreign == link && linkDefs[i].entity == entityType && linkDefs[i].type === 'hasChildren') {
|
||||
if (onlyNotCustom) {
|
||||
if (linkDefs[i].isCustom) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
isFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isFound) {
|
||||
list.push(item);
|
||||
}
|
||||
}, this);
|
||||
|
||||
return list;
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
Espo.define('views/fields/entity-type-list', 'views/fields/multi-enum', function (Dep) {
|
||||
define('views/fields/entity-type-list', 'views/fields/multi-enum', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
@@ -46,7 +46,6 @@ Espo.define('views/fields/entity-type-list', 'views/fields/multi-enum', function
|
||||
}.bind(this)).sort(function (v1, v2) {
|
||||
return this.translate(v1, 'scopeNames').localeCompare(this.translate(v2, 'scopeNames'));
|
||||
}.bind(this));
|
||||
this.params.options.unshift('');
|
||||
},
|
||||
|
||||
setup: function () {
|
||||
@@ -55,8 +54,7 @@ Espo.define('views/fields/entity-type-list', 'views/fields/multi-enum', function
|
||||
}
|
||||
this.setupOptions();
|
||||
Dep.prototype.setup.call(this);
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user