orm converter refactoring

This commit is contained in:
Yuri Kuznetsov
2023-02-03 16:00:55 +02:00
parent d21857075e
commit 1762096532
31 changed files with 966 additions and 1599 deletions
@@ -31,6 +31,7 @@ namespace Espo\Core\ApplicationRunners;
use Espo\Core\Application\Runner;
use Espo\Core\DataManager;
use Espo\Core\Utils\Log;
use Exception;
/**
@@ -40,7 +41,7 @@ class Rebuild implements Runner
{
use Cli;
public function __construct(private DataManager $dataManager)
public function __construct(private DataManager $dataManager, private Log $log)
{}
public function run(): void
@@ -51,6 +52,11 @@ class Rebuild implements Runner
catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
$this->log->error('Rebuild: ' . $e->getMessage(), [
'file' => $e->getFile(),
'line' => $e->getLine(),
]);
exit(1);
}
}
@@ -1,291 +0,0 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii 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.
************************************************************************/
namespace Espo\Core\Utils\Database\Orm;
use Espo\Core\Utils\Config;
use Espo\Core\Utils\Metadata;
use RuntimeException;
class Base
{
/**
* @var ?string
*/
private $itemName = null;
/**
* @var ?string
*/
private $entityName = null;
private Metadata $metadata;
/**
* @var array<string,mixed>
*/
private $ormEntityDefs;
/**
* @var array<string,mixed>
*/
private $entityDefs;
protected Config $config;
/**
* @param array<string,mixed> $ormEntityDefs
* @param array<string,mixed> $entityDefs
*/
public function __construct(Metadata $metadata, array $ormEntityDefs, array $entityDefs, Config $config)
{
$this->metadata = $metadata;
$this->ormEntityDefs = $ormEntityDefs;
$this->entityDefs = $entityDefs;
$this->config = $config;
}
protected function getMetadata(): Metadata
{
return $this->metadata;
}
/**
* @return array<string,mixed>
*/
protected function getOrmEntityDefs()
{
return $this->ormEntityDefs;
}
/**
* @return array<string,mixed>
*/
protected function getEntityDefs()
{
return $this->entityDefs;
}
/**
* Set current Field name or Link name.
*
* @param string $itemName
* @return void
*/
protected function setItemName($itemName)
{
$this->itemName = $itemName;
}
/**
* Get current Field name.
*
* @return string
*/
protected function getFieldName()
{
if ($this->itemName === null) {
throw new RuntimeException("No item-name.");
}
return $this->itemName;
}
/**
* Get current Link name.
*
* @return string
*/
protected function getLinkName()
{
if ($this->itemName === null) {
throw new RuntimeException("No item-name.");
}
return $this->itemName;
}
/**
* Set current Entity Name.
*
* @param string $entityName
* @return void
*/
protected function setEntityName($entityName)
{
$this->entityName = $entityName;
}
/**
* Get current Entity Name.
*
* @return string
*/
protected function getEntityName()
{
if ($this->entityName === null) {
throw new RuntimeException("No entity-name.");
}
return $this->entityName;
}
/**
* @todo Call methods explicitly.
*
* @param array<string,mixed> $keyValueList
* @return void
*/
protected function setMethods(array $keyValueList)
{
foreach ($keyValueList as $key => $value) {
$methodName = 'set' . ucfirst($key);
if (method_exists($this, $methodName)) {
$this->$methodName($value);
}
}
}
/**
* Get Entity Defs by type (entity/orm).
*
* @param bool $isOrmEntityDefs
* @return array<string,mixed>
*/
protected function getDefs($isOrmEntityDefs = false)
{
$entityDefs = $isOrmEntityDefs ? $this->getOrmEntityDefs() : $this->getEntityDefs();
return $entityDefs;
}
/**
* Get entity params by name.
*
* @param string $entityName
* @param bool $isOrmEntityDefs
* @param mixed $returns
* @return mixed
*/
protected function getEntityParams($entityName = null, $isOrmEntityDefs = false, $returns = null)
{
if (!isset($entityName)) {
$entityName = $this->getEntityName();
}
$entityDefs = $this->getDefs($isOrmEntityDefs);
if (isset($entityDefs[$entityName])) {
return $entityDefs[$entityName];
}
return $returns;
}
/**
* Get field params by name for a specified entity.
*
* @param string $fieldName
* @param string $entityName
* @param bool $isOrmEntityDefs
* @param mixed $returns
* @return mixed
*/
protected function getFieldParams($fieldName = null, $entityName = null, $isOrmEntityDefs = false, $returns = null)
{
if (!isset($fieldName)) {
$fieldName = $this->getFieldName();
}
if (!isset($entityName)) {
$entityName = $this->getEntityName();
}
$entityDefs = $this->getDefs($isOrmEntityDefs);
if (isset($entityDefs[$entityName]) && isset($entityDefs[$entityName]['fields'][$fieldName])) {
return $entityDefs[$entityName]['fields'][$fieldName];
}
return $returns;
}
/**
* Get relation params by name for a specified entity.
*
* @param string $linkName
* @param string $entityName
* @param bool $isOrmEntityDefs
* @param mixed $returns
* @return mixed
*/
protected function getLinkParams($linkName = null, $entityName = null, $isOrmEntityDefs = false, $returns = null)
{
if (!isset($linkName)) {
$linkName = $this->getLinkName();
}
if (!isset($entityName)) {
$entityName = $this->getEntityName();
}
$entityDefs = $this->getDefs($isOrmEntityDefs);
$relationKeyName = $isOrmEntityDefs ? 'relations' : 'links';
if (isset($entityDefs[$entityName]) && isset($entityDefs[$entityName][$relationKeyName][$linkName])) {
return $entityDefs[$entityName][$relationKeyName][$linkName];
}
return $returns;
}
/**
* @return string
*/
protected function getForeignField(string $name, string $entityType)
{
return $name;
}
/**
* Set a value for all elements of array. So, in result all elements will have the same values.
*
* @param mixed $inputValue
* @param mixed[] $array
* @return mixed[]
*/
protected function setArrayValue($inputValue, array $array)
{
foreach ($array as &$value) {
$value = $inputValue;
}
return $array;
}
}
@@ -39,9 +39,7 @@ use Espo\ORM\Defs\IndexDefs;
use Espo\ORM\Defs\RelationDefs;
use Espo\ORM\Entity;
use Espo\Core\Utils\Metadata;
use Espo\Core\Utils\Config;
use Espo\Core\Utils\Metadata\Helper as MetadataHelper;
use ReflectionClass;
class Converter
{
@@ -109,7 +107,6 @@ class Converter
public function __construct(
private Metadata $metadata,
private Config $config,
private RelationConverter $relationConverter,
private MetadataHelper $metadataHelper,
private InjectableFactory $injectableFactory,
@@ -293,7 +290,7 @@ class Converter
default:
$constName = strtoupper(Util::toUnderScore($attributeType));
if (!defined('Espo\\ORM\\Entity::' . $constName)) {
if (!defined('Espo\\ORM\\Type\\AttributeType::' . $constName)) {
$attributeParams['type'] = $this->defaultAttributeType;
}
@@ -436,8 +433,6 @@ class Converter
*/
private function correctFields(string $entityType, array $ormMetadata): array
{
$entityDefs = $this->getEntityDefs();
$entityMetadata = $ormMetadata[$entityType];
foreach ($entityMetadata['fields'] as $field => $fieldParams) {
@@ -447,23 +442,10 @@ class Converter
continue;
}
/** @var ?class-string<FieldConverter> $className */
$className = $this->metadata->get(['fields', $fieldType, 'converterClassName']);
if (!$className) {
// Legacy.
$className = 'Espo\Custom\Core\Utils\Database\Orm\Fields\\' . ucfirst($fieldType);
if (!class_exists($className)) {
$className = 'Espo\Core\Utils\Database\Orm\Fields\\' . ucfirst($fieldType);
}
}
if (
class_exists($className) &&
(new ReflectionClass($className))->implementsInterface(FieldConverter::class)
) {
/** @var class-string<FieldConverter> $className */
if ($className) {
$toUnset =
!in_array('', $this->metadata->get(['fields', $fieldType, 'actualFields']) ?? []) &&
!in_array('', $this->metadata->get(['fields', $fieldType, 'notActualFields']) ?? []);
@@ -483,33 +465,6 @@ class Converter
/** @var array<string, mixed> $ormMetadata */
$ormMetadata = Util::merge($ormMetadata, [$entityType => $convertedEntityDefs->toAssoc()]);
// @todo Unset if needed.
$className = null;
}
if (
$className &&
class_exists($className) &&
method_exists($className, 'load') &&
method_exists($className, 'process')
) {
// Legacy.
$helperClass = new $className($this->metadata, $ormMetadata, $entityDefs, $this->config);
assert(method_exists($helperClass, 'process'));
$fieldResult = $helperClass->process($field, $entityType);
if (isset($fieldResult['unset'])) {
$ormMetadata = Util::unsetInArray($ormMetadata, $fieldResult['unset']);
unset($fieldResult['unset']);
}
/** @var array<string,mixed> $ormMetadata */
$ormMetadata = Util::merge($ormMetadata, $fieldResult);
}
$defaultAttributes = $this->metadata
@@ -520,7 +475,7 @@ class Converter
$entityType => [
'fields' => [
$field => [
'default' => $defaultAttributes[$field]
'default' => $defaultAttributes[$field],
]
]
]
@@ -92,7 +92,7 @@ class RelationDefs
/**
* Clone with a foreign relation name.
*/
public function withForeignRelationName(string $name): self
public function withForeignRelationName(?string $name): self
{
return $this->withParam('foreign', $name);
}
@@ -202,7 +202,7 @@ class RelationDefs
/**
* Clone with conditions. Conditions are used for relationships that share a same middle table.
*
* @param array<string, ?scalar> $conditions
* @param array<string, scalar|(array<int, mixed>)|null> $conditions
*/
public function withConditions(array $conditions): self
{
@@ -27,9 +27,15 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\Relations;
namespace Espo\Core\Utils\Database\Orm;
class HasManyHasMany extends ManyMany
use Espo\ORM\Defs\RelationDefs;
use Espo\Core\Utils\Database\Orm\Defs\EntityDefs;
/**
* Converts link definitions to ORM definitions.
*/
interface LinkConverter
{
public function convert(RelationDefs $linkDefs, string $entityType): EntityDefs;
}
@@ -27,41 +27,44 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\Relations;
namespace Espo\Core\Utils\Database\Orm\LinkConverters;
use RuntimeException;
use Espo\Core\Utils\Database\Orm\Defs\AttributeDefs;
use Espo\Core\Utils\Database\Orm\Defs\EntityDefs;
use Espo\Core\Utils\Database\Orm\LinkConverter;
use Espo\ORM\Defs\RelationDefs as LinkDefs;
use Espo\ORM\Type\AttributeType;
use LogicException;
class EmailEmailAddress extends HasMany
class Attachments implements LinkConverter
{
/**
* @param string $linkName
* @param string $entityName
* @return array<string,mixed>
*/
protected function load($linkName, $entityName)
public function __construct(private HasChildren $hasChildren) {}
public function convert(LinkDefs $linkDefs, string $entityType): EntityDefs
{
$parentRelation = parent::load($linkName, $entityName);
$name = $linkDefs->getName();
$foreignEntityName = $this->getForeignEntityName();
$entityDefs = $this->hasChildren->convert($linkDefs, $entityType);
if ($foreignEntityName === null) {
throw new RuntimeException("No foreign-entity-type.");
}
$relation = array(
$entityName => array(
'relations' => array(
$linkName => array(
'midKeys' => array(
lcfirst($entityName).'Id',
lcfirst($foreignEntityName).'Id',
),
),
),
),
$entityDefs = $entityDefs->withAttribute(
AttributeDefs::create($name . 'Types')
->withType(AttributeType::JSON_OBJECT)
->withNotStorable()
);
/** @var array<string,mixed> */
return \Espo\Core\Utils\Util::merge($parentRelation, $relation);
$relationDefs = $entityDefs->getRelation($name);
if (!$relationDefs) {
throw new LogicException();
}
$relationDefs = $relationDefs->withConditions([
'OR' => [
['field' => null],
['field' => $name],
]
]);
return $entityDefs->withRelation($relationDefs);
}
}
@@ -0,0 +1,91 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii 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.
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\LinkConverters;
use Espo\Core\Utils\Database\Orm\Defs\AttributeDefs;
use Espo\Core\Utils\Database\Orm\Defs\EntityDefs;
use Espo\Core\Utils\Database\Orm\Defs\RelationDefs;
use Espo\Core\Utils\Database\Orm\LinkConverter;
use Espo\ORM\Defs\RelationDefs as LinkDefs;
use Espo\ORM\Type\AttributeType;
use Espo\ORM\Type\RelationType;
class BelongsTo implements LinkConverter
{
public function convert(LinkDefs $linkDefs, string $entityType): EntityDefs
{
$name = $linkDefs->getName();
$foreignEntityType = $linkDefs->getForeignEntityType();
$foreignRelationName = $linkDefs->hasForeignRelationName() ? $linkDefs->getForeignRelationName() : null;
$noIndex = $linkDefs->getParam('noIndex');
$noForeignName = $linkDefs->getParam('noForeignName');
$foreignName = $linkDefs->getParam('foreignName') ?? 'name';
$noJoin = $linkDefs->getParam('noJoin');
$idName = $name . 'Id';
$nameName = $name . 'Name';
$idAttributeDefs = AttributeDefs::create($idName)
->withType(AttributeType::FOREIGN_ID)
->withParam('index', !$noIndex);
$relationDefs = RelationDefs::create($name)
->withType(RelationType::BELONGS_TO)
->withForeignEntityType($foreignEntityType)
->withKey($idName)
->withForeignKey('id')
->withForeignRelationName($foreignRelationName);
$nameAttributeDefs = !$noForeignName ?
(
$noJoin ?
AttributeDefs::create($nameName)
->withType(AttributeType::VARCHAR)
->withNotStorable()
->withParam('relation', $name)
->withParam('foreign', $foreignName) :
AttributeDefs::create($nameName)
->withType(AttributeType::FOREIGN)
->withNotStorable(true) // Used to be false before v7.4.
->withParam('relation', $name)
->withParam('foreign', $foreignName)
) : null;
$entityDefs = EntityDefs::create()
->withAttribute($idAttributeDefs)
->withRelation($relationDefs);
if ($nameAttributeDefs) {
$entityDefs = $entityDefs->withAttribute($nameAttributeDefs);
}
return $entityDefs;
}
}
@@ -0,0 +1,80 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii 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.
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\LinkConverters;
use Espo\Core\Utils\Database\Orm\Defs\AttributeDefs;
use Espo\Core\Utils\Database\Orm\Defs\EntityDefs;
use Espo\Core\Utils\Database\Orm\Defs\RelationDefs;
use Espo\Core\Utils\Database\Orm\LinkConverter;
use Espo\ORM\Defs\RelationDefs as LinkDefs;
use Espo\ORM\Type\AttributeType;
use Espo\ORM\Type\RelationType;
class BelongsToParent implements LinkConverter
{
private const TYPE_LENGTH = 100;
public function convert(LinkDefs $linkDefs, string $entityType): EntityDefs
{
$name = $linkDefs->getName();
$foreignRelationName = $linkDefs->hasForeignRelationName() ?
$linkDefs->getForeignRelationName() : null;
$idName = $name . 'Id';
$nameName = $name . 'Name';
$typeName = $name . 'Type';
$relationDefs = RelationDefs::create($name)
->withType(RelationType::BELONGS_TO_PARENT)
->withKey($idName)
->withForeignRelationName($foreignRelationName);
return EntityDefs::create()
->withAttribute(
AttributeDefs::create($idName)
->withType(AttributeType::FOREIGN_ID)
->withParam('index', $name)
)
->withAttribute(
AttributeDefs::create($typeName)
->withType(AttributeType::FOREIGN_TYPE)
->withParam('notNull', false) // Revise whether needed.
->withParam('index', $name)
->withLength(self::TYPE_LENGTH)
)
->withAttribute(
AttributeDefs::create($nameName)
->withType(AttributeType::VARCHAR)
->withNotStorable()
)
->withRelation($relationDefs);
}
}
@@ -0,0 +1,77 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii 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.
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\LinkConverters;
use Espo\Core\Utils\Database\Orm\Defs\AttributeDefs;
use Espo\Core\Utils\Database\Orm\Defs\EntityDefs;
use Espo\Core\Utils\Database\Orm\Defs\RelationDefs;
use Espo\Core\Utils\Database\Orm\LinkConverter;
use Espo\Entities\EmailAddress;
use Espo\ORM\Defs\RelationDefs as LinkDefs;
use Espo\ORM\Type\AttributeType;
use Espo\ORM\Type\RelationType;
class EmailEmailAddress implements LinkConverter
{
public function __construct() {}
public function convert(LinkDefs $linkDefs, string $entityType): EntityDefs
{
$name = $linkDefs->getName();
$hasField = $linkDefs->getParam('hasField');
$foreignEntityType = EmailAddress::ENTITY_TYPE;
$key1 = lcfirst($entityType) . 'Id';
$key2 = lcfirst($foreignEntityType) . 'Id';
$relationDefs = RelationDefs::create($name)
->withType(RelationType::MANY_MANY)
->withForeignEntityType($foreignEntityType)
->withKey('id')
->withForeignKey('id')
->withMidKeys($key1, $key2);
return EntityDefs::create()
->withAttribute(
AttributeDefs::create($name . 'Ids')
->withType(AttributeType::JSON_ARRAY)
->withNotStorable()
->withParam('isLinkStub', !$hasField)
)
->withAttribute(
AttributeDefs::create($name . 'Names')
->withType(AttributeType::JSON_OBJECT)
->withNotStorable()
->withParam('isLinkStub', !$hasField)
)
->withRelation($relationDefs);
}
}
@@ -27,44 +27,39 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\Fields;
namespace Espo\Core\Utils\Database\Orm\LinkConverters;
/**
* @deprecated As of v7.4. Use FieldConverter.
*/
class Base extends \Espo\Core\Utils\Database\Orm\Base
use Espo\Core\Utils\Database\Orm\Defs\AttributeDefs;
use Espo\Core\Utils\Database\Orm\Defs\EntityDefs;
use Espo\Core\Utils\Database\Orm\Defs\RelationDefs;
use Espo\Core\Utils\Database\Orm\LinkConverter;
use Espo\Entities\Team;
use Espo\ORM\Defs\RelationDefs as LinkDefs;
use Espo\ORM\Type\AttributeType;
use Espo\ORM\Type\RelationType;
class EntityTeam implements LinkConverter
{
/**
* ORM conversion for fields.
*
* @param string $itemName A field name.
* @param string $entityName
* @return array<string,mixed>
*/
public function process($itemName, $entityName)
private const ENTITY_TYPE_LENGTH = 100;
public function convert(LinkDefs $linkDefs, string $entityType): EntityDefs
{
$inputs = [
'itemName' => $itemName,
'entityName' => $entityName,
];
$name = $linkDefs->getName();
$relationshipName = $linkDefs->getRelationshipName();
$this->setMethods($inputs);
$convertedDefs = $this->load($itemName, $entityName);
$inputs = $this->setArrayValue(null, $inputs);
$this->setMethods($inputs);
return $convertedDefs;
}
/**
* @param string $fieldName
* @param string $entityType
* @return array<string,mixed>
*/
protected function load($fieldName, $entityType)
{
return [];
return EntityDefs::create()
->withRelation(
RelationDefs::create($name)
->withType(RelationType::MANY_MANY)
->withForeignEntityType(Team::ENTITY_TYPE)
->withRelationshipName($relationshipName)
->withMidKeys('entityId', 'teamId')
->withConditions(['entityType' => $entityType])
->withAdditionalColumn(
AttributeDefs::create('entityType')
->withType(AttributeType::VARCHAR)
->withLength(self::ENTITY_TYPE_LENGTH)
)
);
}
}
@@ -27,43 +27,39 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\Relations;
namespace Espo\Core\Utils\Database\Orm\LinkConverters;
use Espo\Core\Utils\Util;
use Espo\Core\Utils\Database\Orm\Defs\AttributeDefs;
use Espo\Core\Utils\Database\Orm\Defs\EntityDefs;
use Espo\Core\Utils\Database\Orm\Defs\RelationDefs;
use Espo\Core\Utils\Database\Orm\LinkConverter;
use Espo\Entities\User;
use Espo\ORM\Defs\RelationDefs as LinkDefs;
use Espo\ORM\Type\AttributeType;
use Espo\ORM\Type\RelationType;
class Attachments extends HasChildren
class EntityUser implements LinkConverter
{
/**
* @param string $linkName
* @param string $entityName
* @return array<string,mixed>
*/
protected function load($linkName, $entityName)
private const ENTITY_TYPE_LENGTH = 100;
public function convert(LinkDefs $linkDefs, string $entityType): EntityDefs
{
$parentRelation = parent::load($linkName, $entityName);
$name = $linkDefs->getName();
$relationshipName = $linkDefs->getRelationshipName();
$relation = [
$entityName => [
'fields' => [
$linkName.'Types' => [
'type' => 'jsonObject',
'notStorable' => true,
],
],
'relations' => [
$linkName => [
'conditions' => [
'OR' => [
['field' => null],
['field' => $linkName],
],
],
],
],
],
];
/** @var array<string,mixed> */
return Util::merge($parentRelation, $relation);
return EntityDefs::create()
->withRelation(
RelationDefs::create($name)
->withType(RelationType::MANY_MANY)
->withForeignEntityType(User::ENTITY_TYPE)
->withRelationshipName($relationshipName)
->withMidKeys('entityId', 'userId')
->withConditions(['entityType' => $entityType])
->withAdditionalColumn(
AttributeDefs::create('entityType')
->withType(AttributeType::VARCHAR)
->withLength(self::ENTITY_TYPE_LENGTH)
)
);
}
}
@@ -0,0 +1,71 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii 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.
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\LinkConverters;
use Espo\Core\Utils\Database\Orm\Defs\AttributeDefs;
use Espo\Core\Utils\Database\Orm\Defs\EntityDefs;
use Espo\Core\Utils\Database\Orm\Defs\RelationDefs;
use Espo\Core\Utils\Database\Orm\LinkConverter;
use Espo\ORM\Defs\RelationDefs as LinkDefs;
use Espo\ORM\Type\AttributeType;
use Espo\ORM\Type\RelationType;
class HasChildren implements LinkConverter
{
public function convert(LinkDefs $linkDefs, string $entityType): EntityDefs
{
$name = $linkDefs->getName();
$foreignEntityType = $linkDefs->getForeignEntityType();
$foreignRelationName = $linkDefs->hasForeignRelationName() ? $linkDefs->getForeignRelationName() : null;
$hasField = $linkDefs->getParam('hasField');
$relationDefs = RelationDefs::create($name)
->withType(RelationType::HAS_CHILDREN)
->withForeignEntityType($foreignEntityType)
->withForeignKey($foreignRelationName . 'Id')
->withParam('foreignType', $foreignRelationName . 'Type')
->withForeignRelationName($foreignRelationName);
return EntityDefs::create()
->withAttribute(
AttributeDefs::create($name . 'Ids')
->withType(AttributeType::JSON_ARRAY)
->withNotStorable()
->withParam('isLinkStub', !$hasField) // Revise. Change to notExportable?
)
->withAttribute(
AttributeDefs::create($name . 'Names')
->withType(AttributeType::JSON_OBJECT)
->withNotStorable()
->withParam('isLinkStub', !$hasField)
)
->withRelation($relationDefs);
}
}
@@ -0,0 +1,74 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii 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.
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\LinkConverters;
use Espo\Core\Utils\Database\Orm\Defs\AttributeDefs;
use Espo\Core\Utils\Database\Orm\Defs\EntityDefs;
use Espo\Core\Utils\Database\Orm\Defs\RelationDefs;
use Espo\Core\Utils\Database\Orm\LinkConverter;
use Espo\ORM\Defs\RelationDefs as LinkDefs;
use Espo\ORM\Type\AttributeType;
use Espo\ORM\Type\RelationType;
class HasMany implements LinkConverter
{
public function convert(LinkDefs $linkDefs, string $entityType): EntityDefs
{
$name = $linkDefs->getName();
$foreignEntityType = $linkDefs->getForeignEntityType();
$foreignRelationName = $linkDefs->getForeignRelationName();
$hasField = $linkDefs->getParam('hasField');
$type = $linkDefs->hasRelationshipName() ?
RelationType::MANY_MANY : // Revise.
RelationType::HAS_MANY;
return EntityDefs::create()
->withAttribute(
AttributeDefs::create($name . 'Ids')
->withType(AttributeType::JSON_ARRAY)
->withNotStorable()
->withParam('isLinkStub', !$hasField) // Revise. Change to notExportable?
)
->withAttribute(
AttributeDefs::create($name . 'Names')
->withType(AttributeType::JSON_OBJECT)
->withNotStorable()
->withParam('isLinkStub', !$hasField)
)
->withRelation(
RelationDefs::create($name)
->withType($type)
->withForeignEntityType($foreignEntityType)
->withForeignKey($foreignRelationName . 'Id')
->withForeignRelationName($foreignRelationName)
);
}
}
@@ -0,0 +1,89 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii 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.
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\LinkConverters;
use Espo\Core\Utils\Database\Orm\Defs\AttributeDefs;
use Espo\Core\Utils\Database\Orm\Defs\EntityDefs;
use Espo\Core\Utils\Database\Orm\Defs\RelationDefs;
use Espo\Core\Utils\Database\Orm\LinkConverter;
use Espo\ORM\Defs\RelationDefs as LinkDefs;
use Espo\ORM\Type\AttributeType;
use Espo\ORM\Type\RelationType;
class HasOne implements LinkConverter
{
public function convert(LinkDefs $linkDefs, string $entityType): EntityDefs
{
$name = $linkDefs->getName();
$foreignEntityType = $linkDefs->getForeignEntityType();
$foreignRelationName = $linkDefs->hasForeignRelationName() ? $linkDefs->getForeignRelationName() : null;
$noForeignName = $linkDefs->getParam('noForeignName');
$foreignName = $linkDefs->getParam('foreignName') ?? 'name';
$noJoin = $linkDefs->getParam('noJoin');
$idName = $name . 'Id';
$nameName = $name . 'Name';
$idAttributeDefs = AttributeDefs::create($idName)
->withType($noJoin ? AttributeType::VARCHAR : AttributeType::FOREIGN)
->withNotStorable()
->withParam('relation', $name)
->withParam('foreign', 'id');
$nameAttributeDefs = !$noForeignName ?
(
AttributeDefs::create($nameName)
->withType($noJoin ? AttributeType::VARCHAR : AttributeType::FOREIGN)
->withNotStorable()
->withParam('relation', $name)
->withParam('foreign', $foreignName)
) : null;
$relationDefs = RelationDefs::create($name)
->withType(RelationType::HAS_ONE)
->withForeignEntityType($foreignEntityType);
if ($foreignRelationName) {
$relationDefs = $relationDefs
->withForeignKey($foreignRelationName . 'Id')
->withForeignRelationName($foreignRelationName);
}
$entityDefs = EntityDefs::create()
->withAttribute($idAttributeDefs)
->withRelation($relationDefs);
if ($nameAttributeDefs) {
$entityDefs = $entityDefs->withAttribute($nameAttributeDefs);
}
return $entityDefs;
}
}
@@ -0,0 +1,104 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii 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.
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\LinkConverters;
use Espo\Core\Utils\Database\Orm\Defs\AttributeDefs;
use Espo\Core\Utils\Database\Orm\Defs\EntityDefs;
use Espo\Core\Utils\Database\Orm\Defs\RelationDefs;
use Espo\Core\Utils\Database\Orm\LinkConverter;
use Espo\Core\Utils\Util;
use Espo\ORM\Defs\RelationDefs as LinkDefs;
use Espo\ORM\Type\AttributeType;
use Espo\ORM\Type\RelationType;
class ManyMany implements LinkConverter
{
public function convert(LinkDefs $linkDefs, string $entityType): EntityDefs
{
$name = $linkDefs->getName();
$foreignEntityType = $linkDefs->getForeignEntityType();
$foreignRelationName = $linkDefs->getForeignRelationName();
$hasField = $linkDefs->getParam('hasField');
$columnAttributeMap = $linkDefs->getParam('columnAttributeMap');
$relationshipName = $linkDefs->hasRelationshipName() ?
$linkDefs->getRelationshipName() :
self::composeRelationshipName($entityType, $foreignEntityType);
$key1 = lcfirst($entityType) . 'Id';
$key2 = lcfirst($foreignEntityType) . 'Id';
if ($key1 === $key2) {
[$key1, $key2] = strcmp($name, $foreignRelationName) ?
['leftId', 'rightId'] :
['rightId', 'leftId'];
}
$relationDefs = RelationDefs::create($name)
->withType(RelationType::MANY_MANY)
->withForeignEntityType($foreignEntityType)
->withRelationshipName($relationshipName)
->withKey('id')
->withForeignKey('id')
->withMidKeys($key1, $key2)
->withForeignRelationName($foreignRelationName);
if ($columnAttributeMap) {
$relationDefs = $relationDefs->withParam('columnAttributeMap', $columnAttributeMap);
}
return EntityDefs::create()
->withAttribute(
AttributeDefs::create($name . 'Ids')
->withType(AttributeType::JSON_ARRAY)
->withNotStorable()
->withParam('isLinkStub', !$hasField) // Revise.
)
->withAttribute(
AttributeDefs::create($name . 'Names')
->withType(AttributeType::JSON_OBJECT)
->withNotStorable()
->withParam('isLinkStub', !$hasField) // Revise.
)
->withRelation($relationDefs);
}
private static function composeRelationshipName(string $left, string $right): string
{
$parts = [
Util::toCamelCase(lcfirst($left)),
Util::toCamelCase(lcfirst($right)),
];
sort($parts);
return Util::toCamelCase(implode('_', $parts));
}
}
@@ -0,0 +1,73 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii 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.
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\LinkConverters;
use Espo\Core\Utils\Database\Orm\Defs\AttributeDefs;
use Espo\Core\Utils\Database\Orm\Defs\EntityDefs;
use Espo\Core\Utils\Database\Orm\Defs\RelationDefs;
use Espo\Core\Utils\Database\Orm\LinkConverter;
use Espo\Entities\PhoneNumber;
use Espo\ORM\Defs\RelationDefs as LinkDefs;
use Espo\ORM\Type\AttributeType;
use Espo\ORM\Type\RelationType;
class SmsPhoneNumber implements LinkConverter
{
public function __construct() {}
public function convert(LinkDefs $linkDefs, string $entityType): EntityDefs
{
$name = $linkDefs->getName();
$foreignEntityType = PhoneNumber::ENTITY_TYPE;
$key1 = lcfirst($entityType) . 'Id';
$key2 = lcfirst($foreignEntityType) . 'Id';
$relationDefs = RelationDefs::create($name)
->withType(RelationType::MANY_MANY)
->withForeignEntityType($foreignEntityType)
->withKey('id')
->withForeignKey('id')
->withMidKeys($key1, $key2);
return EntityDefs::create()
->withAttribute(
AttributeDefs::create($name . 'Ids')
->withType(AttributeType::JSON_ARRAY)
->withNotStorable()
)
->withAttribute(
AttributeDefs::create($name . 'Names')
->withType(AttributeType::JSON_OBJECT)
->withNotStorable()
)
->withRelation($relationDefs);
}
}
@@ -29,118 +29,212 @@
namespace Espo\Core\Utils\Database\Orm;
use Espo\Core\InjectableFactory;
use Espo\Core\Utils\Database\Orm\LinkConverters\BelongsTo;
use Espo\Core\Utils\Database\Orm\LinkConverters\BelongsToParent;
use Espo\Core\Utils\Database\Orm\LinkConverters\HasChildren;
use Espo\Core\Utils\Database\Orm\LinkConverters\HasMany;
use Espo\Core\Utils\Database\Orm\LinkConverters\HasOne;
use Espo\Core\Utils\Database\Orm\LinkConverters\ManyMany;
use Espo\Core\Utils\Util;
use Espo\Core\Utils\Metadata;
use Espo\Core\Utils\Config;
use Espo\ORM\Defs\RelationDefs;
use Espo\ORM\Type\AttributeType;
use Espo\ORM\Type\RelationType;
use RuntimeException;
class RelationConverter
{
private const DEFAULT_VARCHAR_LENGTH = 255;
/** @var string[] */
private $allowedParams = [
'relationName',
'conditions',
'additionalColumns',
'midKeys',
'noJoin',
'indexes',
];
public function __construct(
private Metadata $metadata,
private Config $config
private InjectableFactory $injectableFactory
) {}
/**
* @param string $relationName
*/
private function relationExists($relationName): bool
{
if ($this->getRelationClass($relationName) !== false) {
return true;
}
return false;
}
/**
* @param string $relationName
* @return class-string<\Espo\Core\Utils\Database\Orm\Relations\Base>|false
*/
private function getRelationClass($relationName)
{
$relationName = ucfirst($relationName);
$className = 'Espo\Custom\Core\Utils\Database\Orm\Relations\\' . $relationName;
if (!class_exists($className)) {
$className = 'Espo\Core\Utils\Database\Orm\Relations\\' . $relationName;
}
if (class_exists($className)) {
/** @var class-string<\Espo\Core\Utils\Database\Orm\Relations\Base> */
return $className;
}
return false;
}
/**
* Get a foreign link.
*
* @param array<string, mixed> $parentLinkParams
* @param array<string, mixed> $currentEntityDefs
* @return array{name: string, params: array<string, mixed>}|false
*/
private function getForeignLink($parentLinkParams, $currentEntityDefs)
{
if (isset($parentLinkParams['foreign']) && isset($currentEntityDefs['links'][$parentLinkParams['foreign']])) {
return [
'name' => $parentLinkParams['foreign'],
'params' => $currentEntityDefs['links'][$parentLinkParams['foreign']],
];
}
return false;
}
/**
* @param string $linkName
* @param array<string, mixed> $linkParams
* @param string $name
* @param array<string, mixed> $params
* @param string $entityType
* @param array<string, mixed> $ormMetadata
* @return ?array<string, mixed>
*/
public function process(string $linkName, array $linkParams, string $entityType, array $ormMetadata): ?array
public function process(string $name, array $params, string $entityType, array $ormMetadata): ?array
{
$entityDefs = $this->metadata->get('entityDefs');
$foreignEntityType = $params['entity'] ?? null;
$foreignLinkName = $params['foreign'] ?? null;
$foreignEntityType = $linkParams['entity'] ?? $entityType;
$foreignLink = $this->getForeignLink($linkParams, $entityDefs[$foreignEntityType]);
/** @var ?array<string, mixed> $foreignParams */
$foreignParams = $foreignEntityType && $foreignLinkName ?
$this->metadata->get(['entityDefs', $foreignEntityType, 'links', $foreignLinkName]) :
null;
$currentType = $linkParams['type'];
/** @var ?string $relationshipName */
$relationshipName = $params['relationName'] ?? null;
$relType = $currentType;
if ($foreignLink !== false) {
$relType .= '_' . $foreignLink['params']['type'];
if ($relationshipName) {
$relationshipName = lcfirst($relationshipName);
$params['relationName'] = $relationshipName;
}
$relType = Util::toCamelCase($relType);
$linkType = $params['type'];
$foreignLinkType = $foreignParams ? $foreignParams['type'] : null;
$relationName = $this->relationExists($relType) ?
$relType /*hasManyHasMany*/ :
$currentType /*hasMany*/;
$params['hasField'] = (bool) $this->metadata
->get(['entityDefs', $entityType, 'fields', $name]);
if (isset($linkParams['relationName'])) {
$className = $this->getRelationClass($linkParams['relationName']);
$relationDefs = RelationDefs::fromRaw($params, $name);
if (!$className) {
$relationName = $this->relationExists($relType) ? $relType : $currentType;
$className = $this->getRelationClass($relationName);
$converter = $this->createLinkConverter($relationshipName, $linkType, $foreignLinkType);
$convertedEntityDefs = $converter->convert($relationDefs, $entityType);
$raw = $convertedEntityDefs->toAssoc();
if (isset($raw['relations'][$name])) {
$this->mergeAllowedParams($raw['relations'][$name], $params, $foreignParams ?? []);
$this->correct($raw['relations'][$name]);
}
return [$entityType => $raw];
}
private function createLinkConverter(?string $relationship, string $type, ?string $foreignType): LinkConverter
{
$className = $this->getLinkConverterClassName($relationship, $type, $foreignType);
return $this->injectableFactory->create($className);
}
/**
* @return class-string<LinkConverter>
*/
private function getLinkConverterClassName(?string $relationship, string $type, ?string $foreignType): string
{
if ($relationship) {
/** @var class-string<LinkConverter> $className */
$className = $this->metadata->get(['app', 'relationships', $relationship, 'converterClassName']);
if ($className) {
return $className;
}
} else {
$className = $this->getRelationClass($relationName);
}
if ($className) {
$foreignLinkName = (is_array($foreignLink) && array_key_exists('name', $foreignLink)) ?
$foreignLink['name'] : null;
if ($type === RelationType::HAS_MANY && $foreignType === RelationType::HAS_MANY) {
return ManyMany::class;
}
$helperClass = new $className($this->metadata, $ormMetadata, $entityDefs, $this->config);
if ($type === RelationType::HAS_MANY) {
return HasMany::class;
}
return $helperClass->process($linkName, $entityType, $foreignLinkName, $foreignEntityType);
if ($type === RelationType::HAS_CHILDREN) {
return HasChildren::class;
}
if ($type === RelationType::HAS_ONE) {
return HasOne::class;
}
if ($type === RelationType::BELONGS_TO) {
return BelongsTo::class;
}
if ($type === RelationType::BELONGS_TO_PARENT) {
return BelongsToParent::class;
}
throw new RuntimeException("Unsupported link type '{$type}'.");
}
/**
* @param array<string, mixed> $relationDefs
* @param array<string, mixed> $params
* @param array<string, mixed> $foreignParams
*/
private function mergeAllowedParams(array &$relationDefs, array $params, array $foreignParams): void
{
foreach ($this->allowedParams as $name) {
$additionalParam = $this->getAllowedParam($name, $params, $foreignParams);
if ($additionalParam === null) {
continue;
}
$relationDefs[$name] = $additionalParam;
}
}
/**
* @param array<string, mixed> $params
* @param array<string, mixed> $foreignParams
* @return array<string, mixed>|scalar|null
*/
private function getAllowedParam(string $name, array $params, array $foreignParams): mixed
{
$value = $params[$name] ?? null;
$foreignValue = $foreignParams[$name] ?? null;
if ($value !== null && $foreignValue !== null) {
if (!empty($value) && !is_array($value)) {
return $value;
}
if (!empty($foreignValue) && !is_array($foreignValue)) {
return $foreignValue;
}
/** @var array<int|string, mixed> $value */
/** @var array<int|string, mixed> $foreignValue */
/** @var array<string, mixed> */
return Util::merge($value, $foreignValue);
}
if (isset($value)) {
return $value;
}
if (isset($foreignValue)) {
return $foreignValue;
}
return null;
}
/**
* @param array<string, mixed> $relationDefs
*/
private function correct(array &$relationDefs): void
{
if (!isset($relationDefs['additionalColumns'])) {
return;
}
/** @var array<string, array<string, mixed>> $additionalColumns */
$additionalColumns = &$relationDefs['additionalColumns'];
foreach ($additionalColumns as &$columnDefs) {
$columnDefs['type'] ??= AttributeType::VARCHAR;
if (
$columnDefs['type'] === AttributeType::VARCHAR &&
!isset($columnDefs['len'])
) {
$columnDefs['len'] = self::DEFAULT_VARCHAR_LENGTH;
}
}
$relationDefs['additionalColumns'] = $additionalColumns;
}
}
@@ -1,285 +0,0 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii 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.
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\Relations;
use Espo\Core\Utils\Util;
use Espo\ORM\Entity;
class Base extends \Espo\Core\Utils\Database\Orm\Base
{
private const DEFAULT_VARCHAR_LENGTH = 255;
/**
* @var array<string, mixed>
*/
private $params;
/**
* @var array<string, mixed>
*/
private $foreignParams;
/**
* @var ?string
*/
protected $foreignLinkName = null;
/**
* @var ?string
*/
protected $foreignEntityName = null;
/**
* @var string[]
*/
protected $allowedParams = [
'relationName',
'conditions',
'additionalColumns',
'midKeys',
'noJoin',
'indexes',
];
/**
* @return array<string, mixed>
*/
protected function getParams()
{
return $this->params;
}
/**
* @return array<string, mixed>
*/
protected function getForeignParams()
{
return $this->foreignParams;
}
/**
* @param array<string, mixed> $params
* @return void
*/
protected function setParams(array $params)
{
$this->params = $params;
}
/**
* @param array<string, mixed> $foreignParams
* @return void
*/
protected function setForeignParams(array $foreignParams)
{
$this->foreignParams = $foreignParams;
}
/**
* @param string $foreignLinkName
* @return void
*/
protected function setForeignLinkName($foreignLinkName)
{
$this->foreignLinkName = $foreignLinkName;
}
/**
* @return ?string
*/
protected function getForeignLinkName()
{
return $this->foreignLinkName;
}
/**
* @param string $foreignEntityName
* @return void
*/
protected function setForeignEntityName($foreignEntityName)
{
$this->foreignEntityName = $foreignEntityName;
}
/**
* @return ?string
*/
protected function getForeignEntityName()
{
return $this->foreignEntityName;
}
/**
* @return array<string, mixed>
*/
protected function getForeignLinkParams()
{
$foreignLinkName = $this->getForeignLinkName();
$foreignEntityName = $this->getForeignEntityName();
$foreignLinkParams = $this->getLinkParams($foreignLinkName, $foreignEntityName);
return $foreignLinkParams;
}
/**
*
* @param string $linkName
* @param string $entityType
* @param ?string $foreignLinkName
* @param ?string $foreignEntityName
* @return array<string, mixed>
*/
public function process($linkName, $entityType, $foreignLinkName, $foreignEntityName)
{
$inputs = [
'itemName' => $linkName,
'entityName' => $entityType,
'foreignLinkName' => $foreignLinkName,
'foreignEntityName' => $foreignEntityName,
];
$this->setMethods($inputs);
$convertedDefs = $this->load($linkName, $entityType);
$convertedDefs = $this->mergeAllowedParams($convertedDefs);
if (isset($convertedDefs[$entityType]['relations'][$linkName])) {
$this->correct($convertedDefs[$entityType]['relations'][$linkName]);
}
$inputs = $this->setArrayValue(null, $inputs);
$this->setMethods($inputs);
return $convertedDefs;
}
/**
* @param array<string, mixed> $relationDefs
*/
private function correct(array &$relationDefs): void
{
if (!isset($relationDefs['additionalColumns'])) {
return;
}
/** @var array<string, array<string, mixed>> $additionalColumns */
$additionalColumns = &$relationDefs['additionalColumns'];
foreach ($additionalColumns as &$columnDefs) {
$columnDefs['type'] ??= Entity::VARCHAR;
if (
$columnDefs['type'] === Entity::VARCHAR &&
!isset($columnDefs['len'])
) {
$columnDefs['len'] = self::DEFAULT_VARCHAR_LENGTH;
}
}
$relationDefs['additionalColumns'] = $additionalColumns;
}
/**
* @param array<string, mixed> $loads
* @return array<string, mixed>
*/
private function mergeAllowedParams($loads)
{
$linkName = $this->getLinkName();
$entityName = $this->getEntityName();
if (!empty($this->allowedParams)) {
$linkParams = &$loads[$entityName]['relations'][$linkName];
foreach ($this->allowedParams as $name) {
$additionalParam = $this->getAllowedAdditionalParam($name);
if (isset($additionalParam)) {
$linkParams[$name] = $additionalParam;
if (is_array($linkParams[$name])) {
$linkParams[$name] = Util::merge($linkParams[$name], $additionalParam);
}
}
}
}
return $loads;
}
/**
* @param string $allowedItemName
* @return ?array<string, mixed>
*/
private function getAllowedAdditionalParam($allowedItemName)
{
$linkParams = $this->getLinkParams();
$foreignLinkParams = $this->getForeignLinkParams();
$itemLinkParams = $linkParams[$allowedItemName] ?? null;
$itemForeignLinkParams = $foreignLinkParams[$allowedItemName] ?? null;
$additionalParam = null;
if (isset($itemLinkParams) && isset($itemForeignLinkParams)) {
if (!empty($itemLinkParams) && !is_array($itemLinkParams)) {
$additionalParam = $itemLinkParams;
}
else if (!empty($itemForeignLinkParams) && !is_array($itemForeignLinkParams)) {
$additionalParam = $itemForeignLinkParams;
}
else {
/** @var array<int|string, mixed> $itemLinkParams */
/** @var array<int|string, mixed> $itemForeignLinkParams */
$additionalParam = Util::merge($itemLinkParams, $itemForeignLinkParams);
}
}
else if (isset($itemLinkParams)) {
$additionalParam = $itemLinkParams;
}
else if (isset($itemForeignLinkParams)) {
$additionalParam = $itemForeignLinkParams;
}
return $additionalParam;
}
/**
* @param string $linkName
* @param string $entityType
* @return array<string,mixed>
*/
protected function load($linkName, $entityType)
{
return [];
}
}
@@ -1,113 +0,0 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii 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.
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\Relations;
use RuntimeException;
class BelongsTo extends Base
{
/**
* @param string $linkName
* @param string $entityName
* @return array<string,mixed>
*/
protected function load($linkName, $entityName)
{
$linkParams = $this->getLinkParams();
$foreignEntityName = $this->getForeignEntityName();
$foreignLinkName = $this->getForeignLinkName();
if ($foreignEntityName === null) {
throw new RuntimeException("No foreign-entity-type.");
}
$index = true;
if (!empty($linkParams['noIndex'])) {
$index = false;
}
$noForeignName = false;
$foreign = null;
if (!empty($linkParams['noForeignName'])) {
$noForeignName = true;
} else {
if (!empty($linkParams['foreignName'])) {
$foreign = $linkParams['foreignName'];
} else {
$foreign = $this->getForeignField('name', $foreignEntityName);
}
}
if (!empty($linkParams['noJoin'])) {
$fieldNameDefs = [
'type' => 'varchar',
'notStorable' => true,
'relation' => $linkName,
'foreign' => $this->getForeignField('name', $foreignEntityName),
];
} else {
$fieldNameDefs = [
'type' => 'foreign',
'relation' => $linkName,
'foreign' => $foreign,
'notStorable' => false
];
}
$data = [
$entityName => [
'fields' => [
$linkName.'Id' => [
'type' => 'foreignId',
'index' => $index
]
],
'relations' => [
$linkName => [
'type' => 'belongsTo',
'entity' => $foreignEntityName,
'key' => $linkName.'Id',
'foreignKey' => 'id',
'foreign' => $foreignLinkName
]
]
]
];
if (!$noForeignName) {
$data[$entityName]['fields'][$linkName.'Name'] = $fieldNameDefs;
}
return $data;
}
}
@@ -1,71 +0,0 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii 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.
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\Relations;
class BelongsToParent extends Base
{
/**
* @param string $linkName
* @param string $entityName
* @return array<string,mixed>
*/
protected function load($linkName, $entityName)
{
$linkParams = $this->getLinkParams();
return [
$entityName => [
'fields' => [
$linkName.'Id' => [
'type' => 'foreignId',
'index' => $linkName,
],
$linkName.'Type' => [
'type' => 'foreignType',
'notNull' => false,
'index' => $linkName,
'len' => 100,
],
$linkName.'Name' => [
'type' => 'varchar',
'notStorable' => true,
],
],
'relations' => [
$linkName => [
'type' => 'belongsToParent',
'key' => $linkName .'Id',
'foreign' => $linkParams['foreign'] ?? null,
],
],
],
];
}
}
@@ -1,69 +0,0 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii 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.
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\Relations;
class EntityTeam extends Base
{
/**
* @param string $linkName
* @param string $entityType
* @return array<string,mixed>
*/
protected function load($linkName, $entityType)
{
$linkParams = $this->getLinkParams();
$foreignEntityName = $this->getForeignEntityName();
return [
$entityType => [
'relations' => [
$linkName => [
'type' => 'manyMany',
'entity' => $foreignEntityName,
'relationName' => lcfirst($linkParams['relationName']),
'midKeys' => [
'entityId',
'teamId',
],
'conditions' => [
'entityType' => $entityType,
],
'additionalColumns' => [
'entityType' => [
'type' => 'varchar',
'len' => 100,
],
],
],
],
]
];
}
}
@@ -1,69 +0,0 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii 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.
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\Relations;
class EntityUser extends Base
{
/**
* @param string $linkName
* @param string $entityType
* @return array<string,mixed>
*/
protected function load($linkName, $entityType)
{
$linkParams = $this->getLinkParams();
$foreignEntityName = $this->getForeignEntityName();
return [
$entityType => [
'relations' => [
$linkName => [
'type' => 'manyMany',
'entity' => $foreignEntityName,
'relationName' => lcfirst($linkParams['relationName']),
'midKeys' => [
'entityId',
'userId',
],
'conditions' => [
'entityType' => $entityType,
],
'additionalColumns' => [
'entityType' => [
'type' => 'varchar',
'len' => 100
],
],
]
]
]
];
}
}
@@ -1,72 +0,0 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii 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.
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\Relations;
class HasChildren extends Base
{
/**
* @param string $linkName
* @param string $entityName
* @return array<string,mixed>
*/
protected function load($linkName, $entityName)
{
$foreignLinkName = $this->getForeignLinkName();
$foreignEntityName = $this->getForeignEntityName();
$isStub = !$this->getMetadata()->get(['entityDefs', $entityName, 'fields', $linkName]);
return [
$entityName => [
'fields' => [
$linkName.'Ids' => [
'type' => 'jsonArray',
'notStorable' => true,
'isLinkStub' => $isStub,
],
$linkName.'Names' => [
'type' => 'jsonObject',
'notStorable' => true,
'isLinkStub' => $isStub,
],
],
'relations' => [
$linkName => [
'type' => 'hasChildren',
'entity' => $foreignEntityName,
'foreignKey' => $foreignLinkName.'Id',
'foreignType' => $foreignLinkName.'Type',
'foreign' => $foreignLinkName
],
],
],
];
}
}
@@ -1,76 +0,0 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii 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.
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\Relations;
class HasMany extends Base
{
/**
* @param string $linkName
* @param string $entityName
* @return array<string,mixed>
*/
protected function load($linkName, $entityName)
{
$linkParams = $this->getLinkParams();
$foreignLinkName = $this->getForeignLinkName();
$foreignEntityName = $this->getForeignEntityName();
$relationType = isset($linkParams['relationName']) ? 'manyMany' : 'hasMany';
$isStub = !$this->getMetadata()->get(['entityDefs', $entityName, 'fields', $linkName]);
$relation = [
$entityName => [
'fields' => [
$linkName.'Ids' => [
'type' => 'jsonArray',
'notStorable' => true,
'isLinkStub' => $isStub,
],
$linkName.'Names' => [
'type' => 'jsonObject',
'notStorable' => true,
'isLinkStub' => $isStub,
],
],
'relations' => [
$linkName => [
'type' => $relationType,
'entity' => $foreignEntityName,
'foreignKey' => lcfirst($foreignLinkName.'Id'),
'foreign' => $foreignLinkName
],
],
],
];
return $relation;
}
}
@@ -1,101 +0,0 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii 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.
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\Relations;
use RuntimeException;
class HasOne extends Base
{
/**
* @param string $linkName
* @param string $entityType
* @return array<string,mixed>
*/
protected function load($linkName, $entityType)
{
$linkParams = $this->getLinkParams();
$foreignLinkName = $this->getForeignLinkName();
$foreignEntityType = $this->getForeignEntityName();
if ($foreignEntityType === null) {
throw new RuntimeException();
}
$noForeignName = false;
$foreign = null;
if (!empty($linkParams['noForeignName'])) {
$noForeignName = true;
}
else {
if (!empty($linkParams['foreignName'])) {
$foreign = $linkParams['foreignName'];
}
else {
$foreign = $this->getForeignField('name', $foreignEntityType);
}
}
$relation = [
$entityType => [
'fields' => [
$linkName.'Id' => [
'type' => 'foreign',
'notStorable' => true,
'relation' => $linkName,
'foreign' => 'id',
],
$linkName.'Name' => [
'type' => 'foreign',
'notStorable' => true,
'relation' => $linkName,
'foreign' => $foreign,
],
],
'relations' => [
$linkName => [
'type' => 'hasOne',
'entity' => $foreignEntityType,
'foreignKey' => lcfirst($foreignLinkName.'Id'),
'foreign' => $foreignLinkName,
],
]
]
];
if (!empty($linkParams['noJoin'])) {
$relation[$entityType]['fields'][$linkName.'Name']['type'] = 'varchar';
$relation[$entityType]['fields'][$linkName.'Id']['type'] = 'varchar';
}
return $relation;
}
}
@@ -1,149 +0,0 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii 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.
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\Relations;
use Espo\Core\Utils\Util;
use RuntimeException;
class ManyMany extends Base
{
/**
* @param string $linkName
* @param string $entityType
* @return array<string, mixed>
*/
protected function load($linkName, $entityType)
{
$foreignEntityName = $this->getForeignEntityName();
$foreignLinkName = $this->getForeignLinkName();
if ($foreignEntityName === null) {
throw new RuntimeException("No foreign-entity-type.");
}
if ($foreignLinkName === null) {
throw new RuntimeException("No foreign-link-name.");
}
$linkParams = $this->getLinkParams();
if (!empty($linkParams['relationName'])) {
$relationName = $linkParams['relationName'];
} else {
$relationName = $this->getJoinTable($entityType, $foreignEntityName);
}
$isStub = !$this->getMetadata()->get(['entityDefs', $entityType, 'fields', $linkName]);
$key1 = lcfirst($entityType) . 'Id';
$key2 = lcfirst($foreignEntityName) . 'Id';
if ($key1 === $key2) {
if (strcmp($linkName, $foreignLinkName)) {
$key1 = 'leftId';
$key2 = 'rightId';
} else {
$key1 = 'rightId';
$key2 = 'leftId';
}
}
$relationDefs = [
'type' => 'manyMany',
'entity' => $foreignEntityName,
'relationName' => $relationName,
'key' => 'id',
'foreignKey' => 'id',
'midKeys' => [
$key1,
$key2,
],
'foreign' => $foreignLinkName,
];
$columnAttributeMap = $this->getMetadata()
->get(['entityDefs', $entityType, 'links', $linkName, 'columnAttributeMap']);
if ($columnAttributeMap) {
$relationDefs['columnAttributeMap'] = $columnAttributeMap;
}
return [
$entityType => [
'fields' => [
$linkName.'Ids' => [
'type' => 'jsonArray',
'notStorable' => true,
'isLinkStub' => $isStub,
],
$linkName.'Names' => [
'type' => 'jsonObject',
'notStorable' => true,
'isLinkStub' => $isStub,
],
],
'relations' => [
$linkName => $relationDefs,
],
],
];
}
/**
* @param string $tableName1
* @param string $tableName2
* @return string
*/
protected function getJoinTable($tableName1, $tableName2)
{
$tables = $this->getSortEntities($tableName1, $tableName2);
return Util::toCamelCase(implode('_', $tables));
}
/**
* @param string $entity1
* @param string $entity2
* @return array{string, string}
*/
protected function getSortEntities($entity1, $entity2)
{
$entities = [
Util::toCamelCase(lcfirst($entity1)),
Util::toCamelCase(lcfirst($entity2)),
];
sort($entities);
return $entities;
}
}
@@ -1,69 +0,0 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii 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.
************************************************************************/
namespace Espo\Core\Utils\Database\Orm\Relations;
use Espo\Core\Utils\Util;
use RuntimeException;
class SmsPhoneNumber extends HasMany
{
/**
* @param string $linkName
* @param string $entityName
* @return array<string,mixed>
*/
protected function load($linkName, $entityName)
{
$parentRelation = parent::load($linkName, $entityName);
$foreignEntityName = $this->getForeignEntityName();
if ($foreignEntityName === null) {
throw new RuntimeException();
}
$relation = [
$entityName => [
'relations' => [
$linkName => [
'midKeys' => [
lcfirst($entityName) . 'Id',
lcfirst($foreignEntityName) . 'Id',
],
],
],
],
];
/** @var array<string,mixed> */
return Util::merge($parentRelation, $relation);
}
}
@@ -27,6 +27,7 @@
["app", "rebuild"],
["app", "smsProviders", "__ANY__", "senderClassName"],
["app", "orm"],
["app", "relationships"],
["app", "linkManager"],
["app", "hook"],
["app", "api"],
@@ -0,0 +1,17 @@
{
"attachments": {
"converterClassName": "Espo\\Core\\Utils\\Database\\Orm\\LinkConverters\\Attachments"
},
"emailEmailAddress": {
"converterClassName": "Espo\\Core\\Utils\\Database\\Orm\\LinkConverters\\EmailEmailAddress"
},
"entityTeam": {
"converterClassName": "Espo\\Core\\Utils\\Database\\Orm\\LinkConverters\\EntityTeam"
},
"entityUser": {
"converterClassName": "Espo\\Core\\Utils\\Database\\Orm\\LinkConverters\\EntityUser"
},
"smsPhoneNumber": {
"converterClassName": "Espo\\Core\\Utils\\Database\\Orm\\LinkConverters\\SmsPhoneNumber"
}
}
@@ -82,7 +82,6 @@
"authToken": {
"type": "belongsTo",
"entity": "AuthToken",
"foreign": "authLog",
"foreignName": "id"
},
"actionHistoryRecords": {
+1
View File
@@ -266,6 +266,7 @@ class Export
return false;
}
// Revise.
if ($this->getAttributeParam($entity, $attribute, 'isLinkStub')) {
return false;
}