container and loaders refactoring

This commit is contained in:
Yuri Kuznetsov
2021-03-24 11:59:21 +02:00
parent f3818803fd
commit 4e2ff445e0
30 changed files with 221 additions and 55 deletions

View File

@@ -30,7 +30,7 @@
namespace Espo\Core;
use Espo\Core\{
ContainerBuilder,
Container\ContainerBuilder,
InjectableFactory,
Container,
ApplicationUser,

View File

@@ -43,6 +43,11 @@ class DefaultBinding
'container'
);
$binder->bindService(
'Espo\\Core\\Container\\Container',
'container'
);
$binder->bindService(
'Espo\\ORM\\EntityManager',
'entityManager'

View File

@@ -30,20 +30,21 @@
namespace Espo\Core;
use Espo\Core\{
Exceptions\Error,
InjectableFactory,
Loaders\Loader,
Container\Loader,
Container\Container as ContainerInterface,
Binding\BindingContainer,
};
use ReflectionClass;
use RuntimeException;
/**
* DI container for services. Lazy initialization is used. Services are instantiated only once.
*
* See https://docs.espocrm.com/development/di/.
*/
class Container
class Container implements ContainerInterface
{
private $data = [];
@@ -51,9 +52,9 @@ class Container
private $loaderClassNames;
protected $configuration = null;
private $configuration = null;
protected $injectableFactory;
private $injectableFactory;
public function __construct(
string $configurationClassName,
@@ -65,7 +66,7 @@ class Container
foreach ($services as $name => $service) {
if (!is_string($name) || !is_object($service)) {
throw new Error("Container: Bad service passed.");
throw new RuntimeException("Container: Bad service passed.");
}
$this->setForced($name, $service);
@@ -80,6 +81,8 @@ class Container
/**
* Obtain a service object.
*
* @throws RuntimeException If not gettable.
*/
public function get(string $name) : object
{
@@ -87,7 +90,7 @@ class Container
$this->load($name);
if (!$this->isSet($name)) {
throw new Error("Could not load '{$name}' service.");
throw new RuntimeException("Could not load '{$name}' service.");
}
}
@@ -133,7 +136,7 @@ class Container
return isset($this->data[$name]);
}
private function initClass(string $name)
private function initClass(string $name) : void
{
if ($this->isSet($name)) {
$object = $this->get($name);
@@ -165,7 +168,7 @@ class Container
$loadMethod = $loaderClass->getMethod('load');
if (!$loadMethod->hasReturnType()) {
throw new Error("Loader method for service '{$name}' does not have a return type.");
throw new RuntimeException("Loader method for service '{$name}' does not have a return type.");
}
$className = $loadMethod->getReturnType()->getName();
@@ -182,11 +185,13 @@ class Container
/**
* Get a class of a service.
*
* @throws RuntimeException If not gettable.
*/
public function getClass(string $name) : ReflectionClass
{
if (!$this->has($name)) {
throw new Error("Service '{$name}' does not exist.");
throw new RuntimeException("Service '{$name}' does not exist.");
}
if (!isset($this->classCache[$name])) {
@@ -198,21 +203,23 @@ class Container
/**
* Set a service object. Must be configured as settable.
*
* @throws RuntimeException Is not settable or already set.
*/
public function set(string $name, object $object) : void
{
if (!$this->configuration->isSettable($name)) {
throw new Error("Service '{$name}' is not settable.");
throw new RuntimeException("Service '{$name}' is not settable.");
}
if ($this->isSet($name)) {
throw new Error("Service '{$name}' is already set.");
throw new RuntimeException("Service '{$name}' is already set.");
}
$this->setForced($name, $object);
}
protected function setForced(string $name, object $object)
protected function setForced(string $name, object $object) : void
{
$this->data[$name] = $object;
}
@@ -254,7 +261,7 @@ class Container
$className = $this->configuration->getServiceClassName($name);
if (!$className || !class_exists($className)) {
throw new Error("Could not load '{$name}' service.");
throw new RuntimeException("Could not load '{$name}' service.");
}
$dependencyList = $this->configuration->getServiceDependencyList($name);

View File

@@ -0,0 +1,67 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2021 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\Container;
use ReflectionClass;
use RuntimeException;
/**
* DI container for services. Lazy initialization is used. Services are instantiated only once.
*
* See https://docs.espocrm.com/development/di/.
*/
interface Container
{
/**
* Obtain a service object.
*
* @throws RuntimeException If not gettable.
*/
public function get(string $name) : object;
/**
* Check whether a service can be obtained.
*/
public function has(string $name) : bool;
/**
* Set a service object. Must be configured as settable.
*
* @throws RuntimeException Is not settable or already set.
*/
public function set(string $name, object $object) : void;
/**
* Get a class of a service.
*
* @throws RuntimeException If not gettable.
*/
public function getClass(string $name) : ReflectionClass;
}

View File

@@ -27,11 +27,11 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core;
namespace Espo\Core\Container;
use Espo\Core\{
Container,
ContainerConfiguration,
Container\ContainerConfiguration,
Binding\BindingContainer,
Binding\BindingLoader,
Binding\EspoBindingLoader,

View File

@@ -27,7 +27,7 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core;
namespace Espo\Core\Container;
use Espo\Core\{
Utils\Log,
@@ -40,6 +40,7 @@ use Exception;
class ContainerConfiguration
{
protected $log;
protected $metadata;
public function __construct(Log $log, Metadata $metadata)

View File

@@ -0,0 +1,36 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2021 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\Container;
interface Loader
{
// @todo Uncomment when PHP 7.4 is a min supported version.
//public function load() : object;
}

View File

@@ -30,6 +30,7 @@
namespace Espo\Core\Loaders;
use Espo\Core\{
Container\Loader,
AclManager,
Acl as AclService,
};
@@ -38,8 +39,9 @@ use Espo\Entities\User;
class Acl implements Loader
{
protected $aclManager;
protected $user;
private $aclManager;
private $user;
public function __construct(AclManager $aclManager, User $user)
{

View File

@@ -30,13 +30,14 @@
namespace Espo\Core\Loaders;
use Espo\Core\{
Container\Loader,
InjectableFactory,
AclManager as AclManagerService,
};
class AclManager implements Loader
{
protected $injectableFactory;
private $injectableFactory;
public function __construct(InjectableFactory $injectableFactory)
{

View File

@@ -30,13 +30,14 @@
namespace Espo\Core\Loaders;
use Espo\Core\{
Container\Loader,
Container,
ApplicationState as ApplicationStateService,
};
class ApplicationState implements Loader
{
protected $container;
private $container;
public function __construct(Container $container)
{

View File

@@ -30,13 +30,14 @@
namespace Espo\Core\Loaders;
use Espo\Core\{
Container\Loader,
InjectableFactory,
ApplicationUser as Service,
};
class ApplicationUser implements Loader
{
protected $injectableFactory;
private $injectableFactory;
public function __construct(InjectableFactory $injectableFactory)
{

View File

@@ -30,6 +30,7 @@
namespace Espo\Core\Loaders;
use Espo\Core\{
Container\Loader,
Utils\Metadata,
Utils\Config,
Utils\File\Manager as FileManager,
@@ -40,8 +41,11 @@ use Espo\Core\{
class BaseLanguage implements Loader
{
protected $fileManager;
protected $config;
protected $metadata;
protected $dataCache;
public function __construct(FileManager $fileManager, Config $config, Metadata $metadata, DataCache $dataCache)

View File

@@ -30,6 +30,7 @@
namespace Espo\Core\Loaders;
use Espo\Core\{
Container\Loader,
InjectableFactory,
DataManager as DataManagerService,
};

View File

@@ -30,6 +30,7 @@
namespace Espo\Core\Loaders;
use Espo\Core\{
Container\Loader,
Utils\Config,
Utils\DateTime as DateTimeService,
};

View File

@@ -30,13 +30,14 @@
namespace Espo\Core\Loaders;
use Espo\Core\{
Container\Loader,
ORM\EntityManagerFactory,
ORM\EntityManager as EntityManagerService,
};
class EntityManager implements Loader
{
protected $entityManagerFactory;
private $entityManagerFactory;
public function __construct(EntityManagerFactory $entityManagerFactory)
{

View File

@@ -30,12 +30,15 @@
namespace Espo\Core\Loaders;
use Espo\Core\{
Container\Loader,
Container,
AclManager as AclManagerService,
};
class InternalAclManager implements Loader
{
private $container;
public function __construct(Container $container)
{
$this->container = $container;

View File

@@ -30,6 +30,7 @@
namespace Espo\Core\Loaders;
use Espo\Core\{
Container\Loader,
Utils\Metadata,
Utils\Config,
Utils\File\Manager as FileManager,
@@ -42,9 +43,13 @@ use Espo\Entities\Preferences;
class Language implements Loader
{
protected $fileManager;
protected $config;
protected $metadata;
protected $dataCache;
protected $preferences;
public function __construct(

View File

@@ -29,8 +29,11 @@
namespace Espo\Core\Loaders;
interface Loader
use Espo\Core\Container\Loader as BaseLoader;
/**
* @deprecated Since v6.2.0. Use `Espo\Core\Container\Loader`.
*/
interface Loader extends BaseLoader
{
// @todo Uncomment when PHP 7.4 is a min supported version.
//public function load() : object;
}

View File

@@ -30,13 +30,14 @@
namespace Espo\Core\Loaders;
use Espo\Core\{
Container\Loader,
Log\LogLoader,
Utils\Log as LogService,
};
class Log implements Loader
{
protected $logLoader;
private $logLoader;
public function __construct(LogLoader $logLoader)
{
@@ -47,6 +48,7 @@ class Log implements Loader
{
$log = $this->logLoader->load();
// @todo Remove in future.
$GLOBALS['log'] = $log;
return $log;

View File

@@ -30,8 +30,8 @@
namespace Espo\Core\Loaders;
use Espo\Core\{
Container\Loader,
Utils\Metadata as MetadataService,
InjectableFactory,
Utils\File\Manager as FileManager,
Utils\DataCache,
Utils\Config,
@@ -39,9 +39,11 @@ use Espo\Core\{
class Metadata implements Loader
{
protected $fileManager;
protected $dataCache;
protected $config;
private $fileManager;
private $dataCache;
private $config;
public function __construct(FileManager $fileManager, DataCache $dataCache, Config $config)
{

View File

@@ -30,13 +30,14 @@
namespace Espo\Core\Loaders;
use Espo\Core\{
Container\Loader,
Utils\Config,
Utils\NumberUtil as NumberUtilService,
};
class NumberUtil implements Loader
{
protected $config;
private $config;
public function __construct(Config $config)
{

View File

@@ -29,6 +29,10 @@
namespace Espo\Core\Loaders;
use Espo\{
Core\Container\Loader,
};
use Espo\{
ORM\Defs\Defs,
ORM\EntityManager,
@@ -36,7 +40,7 @@ use Espo\{
class OrmDefs implements Loader
{
protected $entityManager;
private $entityManager;
public function __construct(EntityManager $entityManager)
{

View File

@@ -30,13 +30,14 @@
namespace Espo\Core\Loaders;
use Espo\Core\{
Container\Loader,
InjectableFactory,
Portal\AclManagerContainer as PortalAclManagerContainerService
};
class PortalAclManagerContainer implements Loader
{
protected $injectableFactory;
private $injectableFactory;
public function __construct(InjectableFactory $injectableFactory) {
$this->injectableFactory = $injectableFactory;

View File

@@ -30,6 +30,7 @@
namespace Espo\Core\Loaders;
use Espo\Core\{
Container\Loader,
ORM\EntityManager,
ApplicationState,
};
@@ -40,8 +41,9 @@ use Espo\Entities\{
class Preferences implements Loader
{
protected $entityManager;
protected $applicationState;
private $entityManager;
private $applicationState;
public function __construct(EntityManager $entityManager, ApplicationState $applicationState)
{

View File

@@ -36,9 +36,9 @@ use Espo\Core\Exceptions\{
};
use Espo\Core\{
ContainerBuilder,
Container\ContainerBuilder,
Portal\Container as PortalContainer,
Portal\ContainerConfiguration as PortalContainerConfiguration,
Portal\Container\ContainerConfiguration as PortalContainerConfiguration,
Portal\Utils\Config,
Application as BaseApplication,
};

View File

@@ -27,10 +27,10 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\Portal;
namespace Espo\Core\Portal\Container;
use Espo\Core\{
ContainerConfiguration as BaseContainerConfiguration,
Container\ContainerConfiguration as BaseContainerConfiguration,
};
class ContainerConfiguration extends BaseContainerConfiguration

View File

@@ -30,8 +30,8 @@
namespace Espo\Core\Portal\Loaders;
use Espo\Core\{
Container\Loader,
AclManager,
Loaders\Loader,
Portal\Acl as AclService,
};
@@ -39,6 +39,10 @@ use Espo\Entities\User;
class Acl implements Loader
{
private $aclManager;
private $user;
public function __construct(AclManager $aclManager, User $user)
{
$this->aclManager = $aclManager;

View File

@@ -30,16 +30,17 @@
namespace Espo\Core\Portal\Loaders;
use Espo\Core\{
Container\Loader,
InjectableFactory,
AclManager as InternalAclManager,
Loaders\Loader,
Portal\AclManager as PortalAclManager,
};
class AclManager implements Loader
{
protected $injectableFactory;
protected $internalAclManager;
private $injectableFactory;
private $internalAclManager;
public function __construct(InjectableFactory $injectableFactory, InternalAclManager $internalAclManager)
{

View File

@@ -30,14 +30,14 @@
namespace Espo\Core\Portal\Loaders;
use Espo\Core\{
Loaders\Loader,
Container\Loader,
InjectableFactory,
AclManager as InternalAclManagerService,
};
class InternalAclManager implements Loader
{
protected $injectableFactory;
private $injectableFactory;
public function __construct(InjectableFactory $injectableFactory)
{

View File

@@ -30,11 +30,11 @@
namespace Espo\Core\Portal\Loaders;
use Espo\Core\{
Container\Loader,
Utils\Metadata,
Utils\Config,
Utils\File\Manager as FileManager,
Portal\Utils\Language as LanguageService,
Loaders\Loader as Loader,
Utils\DataCache,
};
@@ -45,15 +45,25 @@ use Espo\Entities\{
class Language implements Loader
{
protected $fileManager;
protected $config;
protected $metadata;
protected $dataCache;
protected $preferences;
protected $portal;
private $fileManager;
private $config;
private $metadata;
private $dataCache;
private $preferences;
private $portal;
public function __construct(
FileManager $fileManager, Config $config, Metadata $metadata, DataCache $dataCache, Preferences $preferences, Portal $portal
FileManager $fileManager,
Config $config,
Metadata $metadata,
DataCache $dataCache,
Preferences $preferences,
Portal $portal
) {
$this->fileManager = $fileManager;
$this->config = $config;