Initial commit
This commit is contained in:
185
application/Espo/Core/Binding/Binder.php
Normal file
185
application/Espo/Core/Binding/Binder.php
Normal file
@@ -0,0 +1,185 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Binding;
|
||||
|
||||
use Espo\Core\Binding\Key\NamedClassKey;
|
||||
use LogicException;
|
||||
use Closure;
|
||||
|
||||
class Binder
|
||||
{
|
||||
public function __construct(private BindingData $data)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Bind an interface to an implementation.
|
||||
*
|
||||
* @template T of object
|
||||
* @param class-string<T>|NamedClassKey<T> $key An interface or interface with a parameter name.
|
||||
* @param class-string<T> $implementationClassName An implementation class name.
|
||||
*/
|
||||
public function bindImplementation(string|NamedClassKey $key, string $implementationClassName): self
|
||||
{
|
||||
$key = self::keyToString($key);
|
||||
$this->validateBindingKey($key);
|
||||
|
||||
$this->data->addGlobal(
|
||||
$key,
|
||||
Binding::createFromImplementationClassName($implementationClassName)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind an interface to a specific service.
|
||||
*
|
||||
* @param class-string<object>|NamedClassKey<object> $key An interface or interface with a parameter name.
|
||||
* @param string $serviceName A service name.
|
||||
*/
|
||||
public function bindService(string|NamedClassKey $key, string $serviceName): self
|
||||
{
|
||||
$key = self::keyToString($key);
|
||||
$this->validateBindingKey($key);
|
||||
|
||||
$this->data->addGlobal(
|
||||
$key,
|
||||
Binding::createFromServiceName($serviceName)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind an interface to a callback.
|
||||
*
|
||||
* @template T of object
|
||||
* @param class-string<T>|NamedClassKey<T> $key An interface or interface with a parameter name.
|
||||
* @param Closure $callback A callback that will resolve a dependency.
|
||||
* @todo Change to Closure(...): T Once https://github.com/phpstan/phpstan/issues/8214 is implemented.
|
||||
*/
|
||||
public function bindCallback(string|NamedClassKey $key, Closure $callback): self
|
||||
{
|
||||
$key = self::keyToString($key);
|
||||
$this->validateBindingKey($key);
|
||||
|
||||
$this->data->addGlobal(
|
||||
$key,
|
||||
Binding::createFromCallback($callback)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind an interface to a specific instance.
|
||||
*
|
||||
* @template T of object
|
||||
* @param class-string<T>|NamedClassKey<T> $key An interface or interface with a parameter name.
|
||||
* @param T $instance An instance.
|
||||
* @noinspection PhpDocSignatureInspection
|
||||
*/
|
||||
public function bindInstance(string|NamedClassKey $key, object $instance): self
|
||||
{
|
||||
$key = self::keyToString($key);
|
||||
$this->validateBindingKey($key);
|
||||
|
||||
$this->data->addGlobal(
|
||||
$key,
|
||||
Binding::createFromValue($instance)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind an interface to a factory.
|
||||
*
|
||||
* @template T of object
|
||||
* @param class-string<T>|NamedClassKey<T> $key An interface or interface with a parameter name.
|
||||
* @param class-string<Factory<T>> $factoryClassName A factory class name.
|
||||
*/
|
||||
public function bindFactory(string|NamedClassKey $key, string $factoryClassName): self
|
||||
{
|
||||
$key = self::keyToString($key);
|
||||
$this->validateBindingKey($key);
|
||||
|
||||
$this->data->addGlobal(
|
||||
$key,
|
||||
Binding::createFromFactoryClassName($factoryClassName)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a contextual binder and pass it as an argument of a callback.
|
||||
*
|
||||
* @param class-string<object> $className A context.
|
||||
* @param Closure(ContextualBinder): void $callback A callback with a `ContextualBinder` argument.
|
||||
*/
|
||||
public function inContext(string $className, Closure $callback): self
|
||||
{
|
||||
$contextualBinder = new ContextualBinder($this->data, $className);
|
||||
|
||||
$callback($contextualBinder);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a contextual binder.
|
||||
*
|
||||
* @param class-string<object> $className A context.
|
||||
*/
|
||||
public function for(string $className): ContextualBinder
|
||||
{
|
||||
return new ContextualBinder($this->data, $className);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|NamedClassKey<object> $key
|
||||
*/
|
||||
private static function keyToString(string|NamedClassKey $key): string
|
||||
{
|
||||
return is_string($key) ? $key : $key->toString();
|
||||
}
|
||||
|
||||
private function validateBindingKey(string $key): void
|
||||
{
|
||||
if (!$key) {
|
||||
throw new LogicException("Bad binding.");
|
||||
}
|
||||
|
||||
if ($key[0] === '$') {
|
||||
throw new LogicException("Can't binding a parameter name w/o an interface globally.");
|
||||
}
|
||||
}
|
||||
}
|
||||
113
application/Espo/Core/Binding/Binding.php
Normal file
113
application/Espo/Core/Binding/Binding.php
Normal file
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Binding;
|
||||
|
||||
use LogicException;
|
||||
|
||||
class Binding
|
||||
{
|
||||
public const IMPLEMENTATION_CLASS_NAME = 1;
|
||||
public const CONTAINER_SERVICE = 2;
|
||||
public const VALUE = 3;
|
||||
public const CALLBACK = 4;
|
||||
public const FACTORY_CLASS_NAME = 5;
|
||||
|
||||
private int $type;
|
||||
/** @var mixed */
|
||||
private $value;
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
*/
|
||||
private function __construct(int $type, $value)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function getType(): int
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string<object> $implementationClassName
|
||||
*/
|
||||
public static function createFromImplementationClassName(string $implementationClassName): self
|
||||
{
|
||||
if (!$implementationClassName) {
|
||||
throw new LogicException("Bad binding.");
|
||||
}
|
||||
|
||||
return new self(self::IMPLEMENTATION_CLASS_NAME, $implementationClassName);
|
||||
}
|
||||
|
||||
public static function createFromServiceName(string $serviceName): self
|
||||
{
|
||||
if (!$serviceName) {
|
||||
throw new LogicException("Bad binding.");
|
||||
}
|
||||
|
||||
return new self(self::CONTAINER_SERVICE, $serviceName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
*/
|
||||
public static function createFromValue($value): self
|
||||
{
|
||||
return new self(self::VALUE, $value);
|
||||
}
|
||||
|
||||
public static function createFromCallback(callable $callback): self
|
||||
{
|
||||
return new self(self::CALLBACK, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string<Factory<object>> $factoryClassName
|
||||
*/
|
||||
public static function createFromFactoryClassName(string $factoryClassName): self
|
||||
{
|
||||
if (!$factoryClassName) {
|
||||
throw new LogicException("Bad binding.");
|
||||
}
|
||||
|
||||
return new self(self::FACTORY_CLASS_NAME, $factoryClassName);
|
||||
}
|
||||
}
|
||||
177
application/Espo/Core/Binding/BindingContainer.php
Normal file
177
application/Espo/Core/Binding/BindingContainer.php
Normal file
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Binding;
|
||||
|
||||
use ReflectionClass;
|
||||
use ReflectionParameter;
|
||||
use ReflectionNamedType;
|
||||
use LogicException;
|
||||
|
||||
/**
|
||||
* Access point for bindings.
|
||||
*/
|
||||
class BindingContainer
|
||||
{
|
||||
public function __construct(private BindingData $data)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Has binding by a reflection parameter.
|
||||
*
|
||||
* @param ?ReflectionClass<object> $class
|
||||
*/
|
||||
public function hasByParam(?ReflectionClass $class, ReflectionParameter $param): bool
|
||||
{
|
||||
if ($this->getInternal($class, $param) === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get binding by a reflection parameter.
|
||||
*
|
||||
* @param ?ReflectionClass<object> $class
|
||||
*/
|
||||
public function getByParam(?ReflectionClass $class, ReflectionParameter $param): Binding
|
||||
{
|
||||
if (!$this->hasByParam($class, $param)) {
|
||||
throw new LogicException("Cannot get not existing binding.");
|
||||
}
|
||||
|
||||
/** @var Binding */
|
||||
return $this->getInternal($class, $param);
|
||||
}
|
||||
|
||||
/**
|
||||
* Has global binding by an interface.
|
||||
*
|
||||
* @param class-string $interfaceName
|
||||
*/
|
||||
public function hasByInterface(string $interfaceName): bool
|
||||
{
|
||||
return $this->data->hasGlobal($interfaceName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get global binding by an interface.
|
||||
*
|
||||
* @param class-string $interfaceName
|
||||
*/
|
||||
public function getByInterface(string $interfaceName): Binding
|
||||
{
|
||||
if (!$this->hasByInterface($interfaceName)) {
|
||||
throw new LogicException("Binding for interface `$interfaceName` does not exist.");
|
||||
}
|
||||
|
||||
if (!interface_exists($interfaceName) && !class_exists($interfaceName)) {
|
||||
throw new LogicException("Interface `$interfaceName` does not exist.");
|
||||
}
|
||||
|
||||
return $this->data->getGlobal($interfaceName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ?ReflectionClass<object> $class
|
||||
*/
|
||||
private function getInternal(?ReflectionClass $class, ReflectionParameter $param): ?Binding
|
||||
{
|
||||
$className = null;
|
||||
|
||||
$key = null;
|
||||
|
||||
if ($class) {
|
||||
$className = $class->getName();
|
||||
|
||||
$key = '$' . $param->getName();
|
||||
}
|
||||
|
||||
$type = $param->getType();
|
||||
|
||||
if (
|
||||
$className &&
|
||||
$key &&
|
||||
$this->data->hasContext($className, $key)
|
||||
) {
|
||||
$binding = $this->data->getContext($className, $key);
|
||||
|
||||
$notMatching =
|
||||
$type instanceof ReflectionNamedType &&
|
||||
!$type->isBuiltin() &&
|
||||
$binding->getType() === Binding::VALUE &&
|
||||
is_scalar($binding->getValue());
|
||||
|
||||
if (!$notMatching) {
|
||||
return $binding;
|
||||
}
|
||||
}
|
||||
|
||||
$dependencyClassName = null;
|
||||
|
||||
if (
|
||||
$type instanceof ReflectionNamedType &&
|
||||
!$type->isBuiltin()
|
||||
) {
|
||||
$dependencyClassName = $type->getName();
|
||||
}
|
||||
|
||||
$key = null;
|
||||
$keyWithParamName = null;
|
||||
|
||||
if ($dependencyClassName) {
|
||||
$key = $dependencyClassName;
|
||||
|
||||
$keyWithParamName = $key . ' $' . $param->getName();
|
||||
}
|
||||
|
||||
if ($keyWithParamName) {
|
||||
if ($className && $this->data->hasContext($className, $keyWithParamName)) {
|
||||
return $this->data->getContext($className, $keyWithParamName);
|
||||
}
|
||||
|
||||
if ($this->data->hasGlobal($keyWithParamName)) {
|
||||
return $this->data->getGlobal($keyWithParamName);
|
||||
}
|
||||
}
|
||||
|
||||
if ($key) {
|
||||
if ($className && $this->data->hasContext($className, $key)) {
|
||||
return $this->data->getContext($className, $key);
|
||||
}
|
||||
|
||||
if ($this->data->hasGlobal($key)) {
|
||||
return $this->data->getGlobal($key);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
150
application/Espo/Core/Binding/BindingContainerBuilder.php
Normal file
150
application/Espo/Core/Binding/BindingContainerBuilder.php
Normal file
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Binding;
|
||||
|
||||
use Closure;
|
||||
use Espo\Core\Binding\Key\NamedClassKey;
|
||||
|
||||
class BindingContainerBuilder
|
||||
{
|
||||
private BindingData $data;
|
||||
private Binder $binder;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->data = new BindingData();
|
||||
$this->binder = new Binder($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind an interface to an implementation.
|
||||
*
|
||||
* @template T of object
|
||||
* @param class-string<T>|NamedClassKey<T> $key An interface or interface with a parameter name.
|
||||
* @param class-string<T> $implementationClassName An implementation class name.
|
||||
*/
|
||||
public function bindImplementation(string|NamedClassKey $key, string $implementationClassName): self
|
||||
{
|
||||
$this->binder->bindImplementation($key, $implementationClassName);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind an interface to a specific service.
|
||||
*
|
||||
* @param class-string<object>|NamedClassKey<object> $key An interface or interface with a parameter name.
|
||||
* @param string $serviceName A service name.
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function bindService(string|NamedClassKey $key, string $serviceName): self
|
||||
{
|
||||
$this->binder->bindService($key, $serviceName);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind an interface to a callback.
|
||||
*
|
||||
* @template T of object
|
||||
* @param class-string<T>|NamedClassKey<T> $key An interface or interface with a parameter name.
|
||||
* @param Closure $callback A callback that will resolve a dependency.
|
||||
* @todo Change to Closure(...): T Once https://github.com/phpstan/phpstan/issues/8214 is implemented.
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function bindCallback(string|NamedClassKey $key, Closure $callback): self
|
||||
{
|
||||
$this->binder->bindCallback($key, $callback);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind an interface to a specific instance.
|
||||
*
|
||||
* @template T of object
|
||||
* @param class-string<T>|NamedClassKey<T> $key An interface or interface with a parameter name.
|
||||
* @param T $instance An instance.
|
||||
* @noinspection PhpDocSignatureInspection
|
||||
*/
|
||||
public function bindInstance(string|NamedClassKey $key, object $instance): self
|
||||
{
|
||||
$this->binder->bindInstance($key, $instance);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind an interface to a factory.
|
||||
*
|
||||
* @template T of object
|
||||
* @param class-string<T>|NamedClassKey<T> $key An interface or interface with a parameter name.
|
||||
* @param class-string<Factory<T>> $factoryClassName A factory class name.
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function bindFactory(string|NamedClassKey $key, string $factoryClassName): self
|
||||
{
|
||||
$this->binder->bindFactory($key, $factoryClassName);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a contextual binder and pass it as an argument of a callback.
|
||||
*
|
||||
* @param class-string<object> $className A context.
|
||||
* @param Closure(ContextualBinder): void $callback A callback with a `ContextualBinder` argument.
|
||||
*/
|
||||
public function inContext(string $className, Closure $callback): self
|
||||
{
|
||||
$contextualBinder = new ContextualBinder($this->data, $className);
|
||||
|
||||
$callback($contextualBinder);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build.
|
||||
*/
|
||||
public function build(): BindingContainer
|
||||
{
|
||||
return new BindingContainer($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance.
|
||||
*/
|
||||
public static function create(): self
|
||||
{
|
||||
return new self();
|
||||
}
|
||||
}
|
||||
136
application/Espo/Core/Binding/BindingData.php
Normal file
136
application/Espo/Core/Binding/BindingData.php
Normal file
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Binding;
|
||||
|
||||
use LogicException;
|
||||
use stdClass;
|
||||
|
||||
class BindingData
|
||||
{
|
||||
private stdClass $global;
|
||||
private stdClass $context;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->global = (object) [];
|
||||
$this->context = (object) [];
|
||||
}
|
||||
|
||||
public function addContext(string $className, string $key, Binding $binding): void
|
||||
{
|
||||
if (!property_exists($this->context, $className)) {
|
||||
$this->context->$className = (object) [];
|
||||
}
|
||||
|
||||
$this->context->$className->$key = $binding;
|
||||
}
|
||||
|
||||
public function addGlobal(string $key, Binding $binding): void
|
||||
{
|
||||
$this->global->$key = $binding;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string<object> $className
|
||||
*/
|
||||
public function hasContext(string $className, string $key): bool
|
||||
{
|
||||
if (!property_exists($this->context, $className)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!property_exists($this->context->$className, $key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string<object> $className
|
||||
*/
|
||||
public function getContext(string $className, string $key): Binding
|
||||
{
|
||||
if (!$this->hasContext($className, $key)) {
|
||||
throw new LogicException("No data.");
|
||||
}
|
||||
|
||||
return $this->context->$className->$key;
|
||||
}
|
||||
|
||||
public function hasGlobal(string $key): bool
|
||||
{
|
||||
if (!property_exists($this->global, $key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getGlobal(string $key): Binding
|
||||
{
|
||||
if (!$this->hasGlobal($key)) {
|
||||
throw new LogicException("No data.");
|
||||
}
|
||||
|
||||
return $this->global->$key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getGlobalKeyList(): array
|
||||
{
|
||||
return array_keys(
|
||||
get_object_vars($this->global)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return class-string<object>[]
|
||||
*/
|
||||
public function getContextList(): array
|
||||
{
|
||||
/** @var class-string<object>[] */
|
||||
return array_keys(
|
||||
get_object_vars($this->context)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getContextKeyList(string $context): array
|
||||
{
|
||||
return array_keys(
|
||||
get_object_vars($this->context->$context ?? (object) [])
|
||||
);
|
||||
}
|
||||
}
|
||||
35
application/Espo/Core/Binding/BindingLoader.php
Normal file
35
application/Espo/Core/Binding/BindingLoader.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Binding;
|
||||
|
||||
interface BindingLoader
|
||||
{
|
||||
public function load(): BindingData;
|
||||
}
|
||||
35
application/Espo/Core/Binding/BindingProcessor.php
Normal file
35
application/Espo/Core/Binding/BindingProcessor.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Binding;
|
||||
|
||||
interface BindingProcessor
|
||||
{
|
||||
public function process(Binder $binder): void;
|
||||
}
|
||||
210
application/Espo/Core/Binding/ContextualBinder.php
Normal file
210
application/Espo/Core/Binding/ContextualBinder.php
Normal file
@@ -0,0 +1,210 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Binding;
|
||||
|
||||
use Closure;
|
||||
use Espo\Core\Binding\Key\NamedClassKey;
|
||||
use Espo\Core\Binding\Key\NamedKey;
|
||||
use LogicException;
|
||||
|
||||
class ContextualBinder
|
||||
{
|
||||
private BindingData $data;
|
||||
/** @var class-string<object> */
|
||||
private string $className;
|
||||
|
||||
/**
|
||||
* @param class-string<object> $className
|
||||
*/
|
||||
public function __construct(BindingData $data, string $className)
|
||||
{
|
||||
$this->data = $data;
|
||||
$this->className = $className;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind an interface to an implementation.
|
||||
*
|
||||
* @template T of object
|
||||
* @param class-string<T>|NamedClassKey<T> $key An interface or interface with a parameter name.
|
||||
* @param class-string<T> $implementationClassName An implementation class name.
|
||||
*/
|
||||
public function bindImplementation(string|NamedClassKey $key, string $implementationClassName): self
|
||||
{
|
||||
$key = self::keyToString($key);
|
||||
$this->validateBindingKeyNoParameterName($key);
|
||||
|
||||
$this->data->addContext(
|
||||
$this->className,
|
||||
$key,
|
||||
Binding::createFromImplementationClassName($implementationClassName)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind an interface to a specific service.
|
||||
*
|
||||
* @template T of object
|
||||
* @param class-string<T>|NamedClassKey<T> $key An interface or interface with a parameter name.
|
||||
* @param string $serviceName A service name.
|
||||
*/
|
||||
public function bindService(string|NamedClassKey $key, string $serviceName): self
|
||||
{
|
||||
$key = self::keyToString($key);
|
||||
$this->validateBindingKeyNoParameterName($key);
|
||||
|
||||
$this->data->addContext(
|
||||
$this->className,
|
||||
$key,
|
||||
Binding::createFromServiceName($serviceName)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind an interface or parameter name to a specific value.
|
||||
*
|
||||
* @param string|NamedKey|NamedClassKey<object> $key Parameter name (`$name`) or interface with a parameter name.
|
||||
* @param mixed $value A value of any type.
|
||||
*/
|
||||
public function bindValue(string|NamedKey|NamedClassKey $key, $value): self
|
||||
{
|
||||
$key = self::keyToString($key);
|
||||
$this->validateBindingKeyParameterName($key);
|
||||
|
||||
$this->data->addContext(
|
||||
$this->className,
|
||||
$key,
|
||||
Binding::createFromValue($value)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind an interface to a specific instance.
|
||||
*
|
||||
* @template T of object
|
||||
* @param class-string<T>|NamedClassKey<T> $key An interface or interface with a parameter name.
|
||||
* @param T $instance An instance.
|
||||
* @noinspection PhpDocSignatureInspection
|
||||
*/
|
||||
public function bindInstance(string|NamedClassKey $key, object $instance): self
|
||||
{
|
||||
$key = self::keyToString($key);
|
||||
$this->validateBindingKeyNoParameterName($key);
|
||||
|
||||
$this->data->addContext(
|
||||
$this->className,
|
||||
$key,
|
||||
Binding::createFromValue($instance)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind an interface or parameter name to a callback.
|
||||
*
|
||||
* @param class-string<object>|NamedClassKey<object>|NamedKey $key An interface, parameter name or both.
|
||||
* @param Closure $callback A callback that will resolve a dependency.
|
||||
* @todo Change to Closure(...): mixed Once https://github.com/phpstan/phpstan/issues/8214 is implemented.
|
||||
*/
|
||||
public function bindCallback(string|NamedClassKey|NamedKey $key, Closure $callback): self
|
||||
{
|
||||
$key = self::keyToString($key);
|
||||
$this->validateBinding($key);
|
||||
|
||||
$this->data->addContext(
|
||||
$this->className,
|
||||
$key,
|
||||
Binding::createFromCallback($callback)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind an interface to a factory.
|
||||
*
|
||||
* @template T of object
|
||||
* @param class-string<T>|NamedClassKey<T> $key An interface or interface with a parameter name.
|
||||
* @param class-string<Factory<T>> $factoryClassName A factory class name.
|
||||
*/
|
||||
public function bindFactory(string|NamedClassKey $key, string $factoryClassName): self
|
||||
{
|
||||
$key = self::keyToString($key);
|
||||
$this->validateBindingKeyNoParameterName($key);
|
||||
|
||||
$this->data->addContext(
|
||||
$this->className,
|
||||
$key,
|
||||
Binding::createFromFactoryClassName($factoryClassName)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function validateBinding(string $key): void
|
||||
{
|
||||
if (!$key) {
|
||||
throw new LogicException("Bad binding.");
|
||||
}
|
||||
}
|
||||
|
||||
private function validateBindingKeyNoParameterName(string $key): void
|
||||
{
|
||||
$this->validateBinding($key);
|
||||
|
||||
if ($key[0] === '$') {
|
||||
throw new LogicException("Can't bind a parameter name w/o an interface.");
|
||||
}
|
||||
}
|
||||
|
||||
private function validateBindingKeyParameterName(string $key): void
|
||||
{
|
||||
$this->validateBinding($key);
|
||||
|
||||
if (!str_contains($key, '$')) {
|
||||
throw new LogicException("Can't bind w/o a parameter name.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|NamedKey|NamedClassKey<object> $key
|
||||
*/
|
||||
private static function keyToString(string|NamedKey|NamedClassKey $key): string
|
||||
{
|
||||
return is_string($key) ? $key : $key->toString();
|
||||
}
|
||||
}
|
||||
87
application/Espo/Core/Binding/EspoBindingLoader.php
Normal file
87
application/Espo/Core/Binding/EspoBindingLoader.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Binding;
|
||||
|
||||
use Espo\Core\Utils\Module;
|
||||
use Espo\Binding;
|
||||
|
||||
class EspoBindingLoader implements BindingLoader
|
||||
{
|
||||
/** @var string[] */
|
||||
private array $moduleNameList;
|
||||
|
||||
public function __construct(Module $module)
|
||||
{
|
||||
$this->moduleNameList = $module->getOrderedList();
|
||||
}
|
||||
|
||||
public function load(): BindingData
|
||||
{
|
||||
$data = new BindingData();
|
||||
$binder = new Binder($data);
|
||||
|
||||
(new Binding())->process($binder);
|
||||
|
||||
foreach ($this->moduleNameList as $moduleName) {
|
||||
$this->loadModule($binder, $moduleName);
|
||||
}
|
||||
|
||||
$this->loadCustom($binder);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function loadModule(Binder $binder, string $moduleName): void
|
||||
{
|
||||
$className = 'Espo\\Modules\\' . $moduleName . '\\Binding';
|
||||
|
||||
if (!class_exists($className)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var class-string<BindingProcessor> $className */
|
||||
|
||||
(new $className())->process($binder);
|
||||
}
|
||||
|
||||
private function loadCustom(Binder $binder): void
|
||||
{
|
||||
/** @var class-string<BindingProcessor>|string $className */
|
||||
$className = 'Espo\\Custom\\Binding';
|
||||
|
||||
if (!class_exists($className)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var class-string<BindingProcessor> $className */
|
||||
|
||||
(new $className())->process($binder);
|
||||
}
|
||||
}
|
||||
42
application/Espo/Core/Binding/Factory.php
Normal file
42
application/Espo/Core/Binding/Factory.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Binding;
|
||||
|
||||
/**
|
||||
* @template T of object
|
||||
*/
|
||||
interface Factory
|
||||
{
|
||||
/**
|
||||
* @return T
|
||||
* @noinspection PhpDocSignatureInspection
|
||||
*/
|
||||
public function create(): object;
|
||||
}
|
||||
62
application/Espo/Core/Binding/Key/NamedClassKey.php
Normal file
62
application/Espo/Core/Binding/Key/NamedClassKey.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Binding\Key;
|
||||
|
||||
/**
|
||||
* A key for a class-type-hinted constructor parameter with a parameter name.
|
||||
*
|
||||
* @template-covariant T of object
|
||||
*/
|
||||
class NamedClassKey
|
||||
{
|
||||
/**
|
||||
* @param class-string<T> $className
|
||||
*/
|
||||
private function __construct(private string $className, private string $parameterName)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Create.
|
||||
*
|
||||
* @template TC of object
|
||||
* @param class-string<TC> $className An interface.
|
||||
* @param string $parameterName A constructor parameter name (w/o '$').
|
||||
* @return self<TC>
|
||||
*/
|
||||
public static function create(string $className, string $parameterName): self
|
||||
{
|
||||
return new self($className, $parameterName);
|
||||
}
|
||||
|
||||
public function toString(): string
|
||||
{
|
||||
return $this->className . ' $' . $this->parameterName;
|
||||
}
|
||||
}
|
||||
54
application/Espo/Core/Binding/Key/NamedKey.php
Normal file
54
application/Espo/Core/Binding/Key/NamedKey.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Binding\Key;
|
||||
|
||||
/**
|
||||
* A parameter-name-only key.
|
||||
*/
|
||||
class NamedKey
|
||||
{
|
||||
private function __construct(private string $parameterName)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Create.
|
||||
*
|
||||
* @param string $parameterName A constructor parameter name (w/o '$').
|
||||
*/
|
||||
public static function create(string $parameterName): self
|
||||
{
|
||||
return new self($parameterName);
|
||||
}
|
||||
|
||||
public function toString(): string
|
||||
{
|
||||
return '$' . $this->parameterName;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user