template entities repositories use existing classes
This commit is contained in:
Generated
+22
-3
@@ -22,15 +22,15 @@
|
||||
<option name="path" value="schema/metadata" />
|
||||
<option name="mappingKind" value="Directory" />
|
||||
</Item>
|
||||
<Item>
|
||||
<option name="path" value="schema/autoload.json" />
|
||||
</Item>
|
||||
<Item>
|
||||
<option name="path" value="schema/module.json" />
|
||||
</Item>
|
||||
<Item>
|
||||
<option name="path" value="schema/routes.json" />
|
||||
</Item>
|
||||
<Item>
|
||||
<option name="path" value="schema/autoload.json" />
|
||||
</Item>
|
||||
</list>
|
||||
</option>
|
||||
</SchemaInfo>
|
||||
@@ -588,6 +588,25 @@
|
||||
</SchemaInfo>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="metadata/app/entityTemplates">
|
||||
<value>
|
||||
<SchemaInfo>
|
||||
<option name="generatedName" value="New Schema" />
|
||||
<option name="name" value="metadata/app/entityTemplates" />
|
||||
<option name="relativePathToSchema" value="schema/metadata/app/entityTemplates.json" />
|
||||
<option name="schemaVersion" value="JSON Schema version 7" />
|
||||
<option name="patterns">
|
||||
<list>
|
||||
<Item>
|
||||
<option name="pattern" value="true" />
|
||||
<option name="path" value="*/Resources/metadata/app/entityTemplates.json" />
|
||||
<option name="mappingKind" value="Pattern" />
|
||||
</Item>
|
||||
</list>
|
||||
</option>
|
||||
</SchemaInfo>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="metadata/app/export">
|
||||
<value>
|
||||
<SchemaInfo>
|
||||
|
||||
Vendored
+6
@@ -268,6 +268,12 @@
|
||||
],
|
||||
"url": "./schema/metadata/app/entityTemplateList.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/entityTemplates.json"
|
||||
],
|
||||
"url": "./schema/metadata/app/entityTemplates.json"
|
||||
},
|
||||
{
|
||||
"fileMatch": [
|
||||
"*/Resources/metadata/app/export.json"
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
<?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\ORM;
|
||||
|
||||
use Espo\Core\ORM\Entity as BaseEntity;
|
||||
use Espo\Core\Repositories\Database as DatabaseRepository;
|
||||
use Espo\Core\Utils\ClassFinder;
|
||||
use Espo\Core\Utils\Metadata;
|
||||
use Espo\ORM\Entity as Entity;
|
||||
use Espo\ORM\Repository\Repository as Repository;
|
||||
|
||||
class ClassNameProvider
|
||||
{
|
||||
/** @var class-string<Entity> */
|
||||
private const DEFAULT_ENTITY_CLASS_NAME = BaseEntity::class;
|
||||
/** @var class-string<Repository<Entity>> */
|
||||
private const DEFAULT_REPOSITORY_CLASS_NAME = DatabaseRepository::class;
|
||||
|
||||
/** @var array<string, class-string<Entity>> */
|
||||
private array $entityCache = [];
|
||||
|
||||
/** @var array<string, class-string<Repository<Entity>>> */
|
||||
private array $repositoryCache = [];
|
||||
|
||||
public function __construct(
|
||||
private Metadata $metadata,
|
||||
private ClassFinder $classFinder
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @param string $entityType
|
||||
* @return class-string<Entity>
|
||||
*/
|
||||
public function getEntityClassName(string $entityType): string
|
||||
{
|
||||
if (!array_key_exists($entityType, $this->entityCache)) {
|
||||
$this->entityCache[$entityType] = $this->findEntityClassName($entityType);
|
||||
}
|
||||
|
||||
return $this->entityCache[$entityType];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $entityType
|
||||
* @return class-string<Repository<Entity>>
|
||||
*/
|
||||
public function getRepositoryClassName(string $entityType): string
|
||||
{
|
||||
if (!array_key_exists($entityType, $this->entityCache)) {
|
||||
$this->repositoryCache[$entityType] = $this->findRepositoryClassName($entityType);
|
||||
}
|
||||
|
||||
return $this->repositoryCache[$entityType];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $entityType
|
||||
* @return class-string<Entity>
|
||||
*/
|
||||
private function findEntityClassName(string $entityType): string
|
||||
{
|
||||
/** @var ?class-string<Entity> $className */
|
||||
$className = $this->classFinder->find('Entities', $entityType);
|
||||
|
||||
if ($className) {
|
||||
return $className;
|
||||
}
|
||||
|
||||
/** @var ?string $template */
|
||||
$template = $this->metadata->get(['scopes', $entityType, 'type']);
|
||||
|
||||
if ($template) {
|
||||
/** @var ?class-string<Entity> $className */
|
||||
$className = $this->metadata->get(['app', 'entityTemplates', $template, 'entityClassName']);
|
||||
}
|
||||
|
||||
if ($className) {
|
||||
return $className;
|
||||
}
|
||||
|
||||
return self::DEFAULT_ENTITY_CLASS_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $entityType
|
||||
* @return class-string<Repository<Entity>>
|
||||
*/
|
||||
private function findRepositoryClassName(string $entityType): string
|
||||
{
|
||||
/** @var ?class-string<Repository<Entity>> $className */
|
||||
$className = $this->classFinder->find('Repositories', $entityType);
|
||||
|
||||
if ($className) {
|
||||
return $className;
|
||||
}
|
||||
|
||||
/** @var ?string $template */
|
||||
$template = $this->metadata->get(['scopes', $entityType, 'type']);
|
||||
|
||||
if ($template) {
|
||||
/** @var ?class-string<Repository<Entity>> $className */
|
||||
$className = $this->metadata->get(['app', 'entityTemplates', $template, 'repositoryClassName']);
|
||||
}
|
||||
|
||||
if ($className) {
|
||||
return $className;
|
||||
}
|
||||
|
||||
return self::DEFAULT_REPOSITORY_CLASS_NAME;
|
||||
}
|
||||
}
|
||||
@@ -33,9 +33,6 @@ use Espo\Core\Binding\Binder;
|
||||
use Espo\Core\Binding\BindingContainer;
|
||||
use Espo\Core\Binding\BindingData;
|
||||
use Espo\Core\InjectableFactory;
|
||||
use Espo\Core\ORM\Entity as BaseEntity;
|
||||
use Espo\Core\Utils\ClassFinder;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\ORM\EntityFactory as EntityFactoryInterface;
|
||||
use Espo\ORM\EntityManager;
|
||||
@@ -49,20 +46,11 @@ class EntityFactory implements EntityFactoryInterface
|
||||
private ?ValueAccessorFactory $valueAccessorFactory = null;
|
||||
|
||||
public function __construct(
|
||||
private ClassFinder $classFinder,
|
||||
private ClassNameProvider $classNameProvider,
|
||||
private Helper $helper,
|
||||
private InjectableFactory $injectableFactory
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @return ?class-string<Entity>
|
||||
*/
|
||||
private function getClassName(string $entityType): ?string
|
||||
{
|
||||
/** @var ?class-string<Entity> */
|
||||
return $this->classFinder->find('Entities', $entityType);
|
||||
}
|
||||
|
||||
public function setEntityManager(EntityManager $entityManager): void
|
||||
{
|
||||
if ($this->entityManager) {
|
||||
@@ -85,10 +73,6 @@ class EntityFactory implements EntityFactoryInterface
|
||||
{
|
||||
$className = $this->getClassName($entityType);
|
||||
|
||||
if (!$className) {
|
||||
$className = BaseEntity::class;
|
||||
}
|
||||
|
||||
if (!$this->entityManager) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
@@ -96,7 +80,7 @@ class EntityFactory implements EntityFactoryInterface
|
||||
$defs = $this->entityManager->getMetadata()->get($entityType);
|
||||
|
||||
if (is_null($defs)) {
|
||||
throw new RuntimeException("Entity '{$entityType}' is not defined in metadata.");
|
||||
throw new RuntimeException("Entity '$entityType' is not defined in metadata.");
|
||||
}
|
||||
|
||||
$bindingContainer = $this->getBindingContainer($className, $entityType, $defs);
|
||||
@@ -104,6 +88,15 @@ class EntityFactory implements EntityFactoryInterface
|
||||
return $this->injectableFactory->createWithBinding($className, $bindingContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return class-string<Entity>
|
||||
*/
|
||||
private function getClassName(string $entityType): string
|
||||
{
|
||||
/** @var class-string<Entity> */
|
||||
return $this->classNameProvider->getEntityClassName($entityType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string<Entity> $className
|
||||
* @param array<string, mixed> $defs
|
||||
|
||||
@@ -32,41 +32,23 @@ namespace Espo\Core\ORM;
|
||||
use Espo\Core\Binding\BindingContainerBuilder;
|
||||
use Espo\Core\Binding\ContextualBinder;
|
||||
use Espo\Core\InjectableFactory;
|
||||
use Espo\Core\Repositories\Database as DatabaseRepository;
|
||||
use Espo\Core\Utils\ClassFinder;
|
||||
use Espo\ORM\Entity as OrmEntity;
|
||||
use Espo\ORM\Entity as Entity;
|
||||
use Espo\ORM\EntityFactory as EntityFactoryInterface;
|
||||
use Espo\ORM\Repository\Repository;
|
||||
use Espo\ORM\Repository\RepositoryFactory as RepositoryFactoryInterface;
|
||||
|
||||
class RepositoryFactory implements RepositoryFactoryInterface
|
||||
{
|
||||
/** @var class-string<Repository<OrmEntity>> */
|
||||
protected $defaultClassName = DatabaseRepository::class;
|
||||
|
||||
public function __construct(
|
||||
protected EntityFactoryInterface $entityFactory,
|
||||
protected InjectableFactory $injectableFactory,
|
||||
protected ClassFinder $classFinder
|
||||
private EntityFactoryInterface $entityFactory,
|
||||
private InjectableFactory $injectableFactory,
|
||||
private ClassNameProvider $classNameProvider
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @return ?class-string<Repository<OrmEntity>>
|
||||
*/
|
||||
protected function getClassName(string $entityType): ?string
|
||||
{
|
||||
/** @var ?class-string<Repository<OrmEntity>> */
|
||||
return $this->classFinder->find('Repositories', $entityType);
|
||||
}
|
||||
|
||||
public function create(string $entityType): Repository
|
||||
{
|
||||
$className = $this->getClassName($entityType);
|
||||
|
||||
if (!$className || !class_exists($className)) {
|
||||
$className = $this->defaultClassName;
|
||||
}
|
||||
|
||||
return $this->injectableFactory->createWithBinding(
|
||||
$className,
|
||||
BindingContainerBuilder::create()
|
||||
@@ -81,4 +63,13 @@ class RepositoryFactory implements RepositoryFactoryInterface
|
||||
->build()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return class-string<Repository<Entity>>
|
||||
*/
|
||||
private function getClassName(string $entityType): string
|
||||
{
|
||||
/** @var class-string<Repository<Entity>> */
|
||||
return $this->classNameProvider->getRepositoryClassName($entityType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"Base": {
|
||||
"entityClassName": "Espo\\Core\\Templates\\Entities\\Base",
|
||||
"repositoryClassName": "Espo\\Core\\Templates\\Repositories\\Base"
|
||||
},
|
||||
"BasePlus": {
|
||||
"entityClassName": "Espo\\Core\\Templates\\Entities\\BasePlus",
|
||||
"repositoryClassName": "Espo\\Core\\Templates\\Repositories\\BasePlus"
|
||||
},
|
||||
"Event": {
|
||||
"entityClassName": "Espo\\Core\\Templates\\Entities\\Event",
|
||||
"repositoryClassName": "Espo\\Core\\Templates\\Repositories\\Event"
|
||||
},
|
||||
"Company": {
|
||||
"entityClassName": "Espo\\Core\\Templates\\Entities\\Company",
|
||||
"repositoryClassName": "Espo\\Core\\Templates\\Repositories\\Company"
|
||||
},
|
||||
"Person": {
|
||||
"entityClassName": "Espo\\Core\\Templates\\Entities\\Person",
|
||||
"repositoryClassName": "Espo\\Core\\Templates\\Repositories\\Person"
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,3 @@
|
||||
{
|
||||
"readLoaderClassNameList": [
|
||||
"Espo\\Core\\FieldProcessing\\Link\\HasOneLoader",
|
||||
"Espo\\Core\\FieldProcessing\\Link\\NotJoinedLoader",
|
||||
"Espo\\Core\\FieldProcessing\\LinkMultiple\\Loader",
|
||||
"Espo\\Core\\FieldProcessing\\LinkParent\\Loader",
|
||||
"Espo\\Core\\FieldProcessing\\EmailAddress\\Loader",
|
||||
"Espo\\Core\\FieldProcessing\\PhoneNumber\\Loader",
|
||||
"Espo\\Core\\FieldProcessing\\Stream\\FollowersLoader"
|
||||
],
|
||||
"listLoaderClassNameList": [
|
||||
"Espo\\Core\\FieldProcessing\\LinkParent\\Loader",
|
||||
"Espo\\Core\\FieldProcessing\\LinkMultiple\\ListLoader"
|
||||
],
|
||||
"saverClassNameList": [
|
||||
"Espo\\Core\\FieldProcessing\\EmailAddress\\Saver",
|
||||
"Espo\\Core\\FieldProcessing\\PhoneNumber\\Saver",
|
||||
"Espo\\Core\\FieldProcessing\\Relation\\Saver",
|
||||
"Espo\\Core\\FieldProcessing\\MultiEnum\\Saver",
|
||||
"Espo\\Core\\FieldProcessing\\File\\Saver",
|
||||
"Espo\\Core\\FieldProcessing\\Wysiwyg\\Saver"
|
||||
]
|
||||
|
||||
}
|
||||
|
||||
@@ -133,18 +133,6 @@ class EntityManager
|
||||
$templatePath = "application/Espo/Modules/$normalizedTemplateModuleName/Core/Templates";
|
||||
}
|
||||
|
||||
$contents = "<" . "?" . "php\n\n".
|
||||
"namespace Espo\Custom\Entities;\n\n".
|
||||
"class $normalizedName extends $templateNamespace\Entities\\$type\n".
|
||||
"{\n".
|
||||
" public const ENTITY_TYPE = '$name';\n\n".
|
||||
" protected \$entityType = '$name';\n".
|
||||
"}\n";
|
||||
|
||||
$filePath = "custom/Espo/Custom/Entities/$normalizedName.php";
|
||||
|
||||
$this->fileManager->putContents($filePath, $contents);
|
||||
|
||||
$contents = "<" . "?" . "php\n\n".
|
||||
"namespace Espo\Custom\Controllers;\n\n".
|
||||
"class $normalizedName extends $templateNamespace\Controllers\\$type\n".
|
||||
@@ -165,16 +153,6 @@ class EntityManager
|
||||
|
||||
$this->fileManager->putContents($filePath, $contents);
|
||||
|
||||
$contents = "<" . "?" . "php\n\n".
|
||||
"namespace Espo\Custom\Repositories;\n\n".
|
||||
"class $normalizedName extends $templateNamespace\Repositories\\$type\n".
|
||||
"{\n".
|
||||
"}\n";
|
||||
|
||||
$filePath = "custom/Espo/Custom/Repositories/$normalizedName.php";
|
||||
|
||||
$this->fileManager->putContents($filePath, $contents);
|
||||
|
||||
$stream = false;
|
||||
|
||||
if (!empty($params['stream'])) {
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://www.espocrm.com/schema/metadata/app/entityTemplates.json",
|
||||
"title": "app/entityTemplates",
|
||||
"description": "Definitions for entity templates.",
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "object",
|
||||
"description": "A template name.",
|
||||
"properties": {
|
||||
"entityClassName": {
|
||||
"type": "string",
|
||||
"description": "An entity class name. Should implement Espo\\ORM\\Entity."
|
||||
},
|
||||
"repositoryClassName": {
|
||||
"type": "string",
|
||||
"description": "An repository class name. Should implement Espo\\ORM\\Repository\\Repository."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user