ref cs
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
namespace Espo\Core\Api;
|
||||
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Conflict;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\NotFound;
|
||||
@@ -59,6 +60,7 @@ class ActionHandler implements RequestHandlerInterface
|
||||
* @throws Forbidden
|
||||
* @throws Error
|
||||
* @throws NotFound
|
||||
* @throws Conflict
|
||||
*/
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
@@ -93,6 +95,7 @@ class ActionHandler implements RequestHandlerInterface
|
||||
|
||||
$response->setHeader('X-App-Timestamp', (string) ($this->config->get('appTimestamp') ?? '0'));
|
||||
|
||||
/** @noinspection PhpConditionAlreadyCheckedInspection */
|
||||
return $response instanceof ResponseWrapper ?
|
||||
$response->toPsr7() :
|
||||
self::responseToPsr7($response);
|
||||
|
||||
@@ -33,7 +33,6 @@ use Espo\Core\InjectableFactory;
|
||||
|
||||
class AuthBuilderFactory
|
||||
{
|
||||
|
||||
public function __construct(private InjectableFactory $injectableFactory)
|
||||
{}
|
||||
|
||||
|
||||
@@ -156,7 +156,6 @@ class ControllerActionProcessor
|
||||
$type = $params[0]->getType();
|
||||
|
||||
if (
|
||||
!$type ||
|
||||
!$type instanceof ReflectionNamedType ||
|
||||
$type->isBuiltin()
|
||||
) {
|
||||
|
||||
@@ -90,7 +90,7 @@ class ErrorOutput
|
||||
?string $route = null
|
||||
): void {
|
||||
|
||||
$this->processInternal($request, $response, $exception, $route, false);
|
||||
$this->processInternal($request, $response, $exception, $route);
|
||||
}
|
||||
|
||||
public function processWithBodyPrinting(
|
||||
@@ -133,7 +133,7 @@ class ErrorOutput
|
||||
$logMessageItemList = [];
|
||||
|
||||
if ($message) {
|
||||
$logMessageItemList[] = "{$message}";
|
||||
$logMessageItemList[] = "$message";
|
||||
}
|
||||
|
||||
$logMessageItemList[] = $request->getMethod() . ' ' . $request->getResourcePath();
|
||||
|
||||
@@ -32,7 +32,6 @@ namespace Espo\Core\Api;
|
||||
use Espo\Core\Api\Request as ApiRequest;
|
||||
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
use Slim\Psr7\Factory\UriFactory;
|
||||
|
||||
use stdClass;
|
||||
@@ -49,6 +48,7 @@ class RequestNull implements ApiRequest
|
||||
|
||||
/**
|
||||
* @return null
|
||||
* @noinspection PhpDocSignatureInspection
|
||||
*/
|
||||
public function getQueryParam(string $name): ?string
|
||||
{
|
||||
|
||||
@@ -275,6 +275,7 @@ class RequestWrapper implements ApiRequest
|
||||
return $this->getMethod() === 'PUT';
|
||||
}
|
||||
|
||||
/** @noinspection PhpUnused */
|
||||
public function isUpdate(): bool
|
||||
{
|
||||
return $this->getMethod() === 'UPDATE';
|
||||
|
||||
@@ -202,7 +202,7 @@ class RouteProcessor
|
||||
$action = $crudMethodActionMap[strtolower($method)] ?? null;
|
||||
|
||||
if (!$action) {
|
||||
throw new BadRequest("No action for method `{$method}`.");
|
||||
throw new BadRequest("No action for method `$method`.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ class RunnerRunner
|
||||
public function run(string $className, ?Params $params = null): void
|
||||
{
|
||||
if (!class_exists($className)) {
|
||||
$this->log->error("Application runner '{$className}' does not exist.");
|
||||
$this->log->error("Application runner '$className' does not exist.");
|
||||
|
||||
throw new RunnerException();
|
||||
}
|
||||
|
||||
@@ -38,14 +38,8 @@ use Espo\Core\Utils\Config;
|
||||
*/
|
||||
class Client implements Runner
|
||||
{
|
||||
private ClientManager $clientManager;
|
||||
private Config $config;
|
||||
|
||||
public function __construct(ClientManager $clientManager, Config $config)
|
||||
{
|
||||
$this->clientManager = $clientManager;
|
||||
$this->config = $config;
|
||||
}
|
||||
public function __construct(private ClientManager $clientManager, private Config $config)
|
||||
{}
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
|
||||
@@ -60,6 +60,9 @@ class PortalClient implements RunnerParameterized
|
||||
private ErrorOutput $errorOutput
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
*/
|
||||
public function run(Params $params): void
|
||||
{
|
||||
$id = $params->get('id') ??
|
||||
|
||||
@@ -43,6 +43,9 @@ class Preload implements Runner
|
||||
{
|
||||
use Cli;
|
||||
|
||||
/**
|
||||
* @throws Throwable
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$preload = new PreloadUtil();
|
||||
@@ -59,7 +62,7 @@ class Preload implements Runner
|
||||
$count = $preload->getCount();
|
||||
|
||||
echo "Success." . PHP_EOL;
|
||||
echo "Files loaded: " . (string) $count . "." . PHP_EOL;
|
||||
echo "Files loaded: " . $count . "." . PHP_EOL;
|
||||
}
|
||||
|
||||
protected function processException(Throwable $e): void
|
||||
@@ -69,13 +72,13 @@ class Preload implements Runner
|
||||
$msg = $e->getMessage();
|
||||
|
||||
if ($msg) {
|
||||
echo "Message: {$msg}" . PHP_EOL;
|
||||
echo "Message: $msg" . PHP_EOL;
|
||||
}
|
||||
|
||||
$file = $e->getFile();
|
||||
|
||||
if ($file) {
|
||||
echo "File: {$file}" . PHP_EOL;
|
||||
echo "File: $file" . PHP_EOL;
|
||||
}
|
||||
|
||||
echo "Line: " . $e->getLine() . PHP_EOL;
|
||||
|
||||
@@ -41,6 +41,8 @@ use RuntimeException;
|
||||
* in another storage. E.g. a single Redis data store can be utilized with
|
||||
* multiple Espo replicas (for scalability purposes).
|
||||
* Defined at metadata > app > containerServices > authTokenManager.
|
||||
*
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
class EspoManager implements Manager
|
||||
{
|
||||
@@ -56,8 +58,7 @@ class EspoManager implements Manager
|
||||
|
||||
public function get(string $token): ?AuthToken
|
||||
{
|
||||
/** @var ?AuthTokenEntity $authToken */
|
||||
$authToken = $this->repository
|
||||
return $this->repository
|
||||
->select([
|
||||
'id',
|
||||
'isActive',
|
||||
@@ -72,13 +73,10 @@ class EspoManager implements Manager
|
||||
])
|
||||
->where(['token' => $token])
|
||||
->findOne();
|
||||
|
||||
return $authToken;
|
||||
}
|
||||
|
||||
public function create(Data $data): AuthToken
|
||||
{
|
||||
/** @var AuthTokenEntity $authToken */
|
||||
$authToken = $this->repository->getNew();
|
||||
|
||||
$authToken
|
||||
@@ -102,6 +100,7 @@ class EspoManager implements Manager
|
||||
|
||||
public function inactivate(AuthToken $authToken): void
|
||||
{
|
||||
/** @noinspection PhpConditionAlreadyCheckedInspection */
|
||||
if (!$authToken instanceof AuthTokenEntity) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
@@ -115,6 +114,7 @@ class EspoManager implements Manager
|
||||
|
||||
public function renew(AuthToken $authToken): void
|
||||
{
|
||||
/** @noinspection PhpConditionAlreadyCheckedInspection */
|
||||
if (!$authToken instanceof AuthTokenEntity) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
@@ -159,11 +159,11 @@ class EspoManager implements Manager
|
||||
$length = self::TOKEN_RANDOM_LENGTH;
|
||||
|
||||
if (function_exists('random_bytes')) {
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
return bin2hex(random_bytes($length));
|
||||
}
|
||||
|
||||
if (function_exists('openssl_random_pseudo_bytes')) {
|
||||
/** @var string $randomValue */
|
||||
$randomValue = openssl_random_pseudo_bytes($length);
|
||||
|
||||
return bin2hex($randomValue);
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Espo\Core\Authentication\AuthToken;
|
||||
interface Manager
|
||||
{
|
||||
/**
|
||||
* Get an auth token. If does not exist then returns NULL.
|
||||
* Get an auth token. If it does not exist, then returns NULL.
|
||||
*/
|
||||
public function get(string $token): ?AuthToken;
|
||||
|
||||
|
||||
@@ -34,20 +34,13 @@ namespace Espo\Core\Authentication;
|
||||
*/
|
||||
class AuthenticationData
|
||||
{
|
||||
private ?string $username;
|
||||
private ?string $password;
|
||||
private ?string $method;
|
||||
private bool $byTokenOnly = false;
|
||||
|
||||
public function __construct(
|
||||
?string $username = null,
|
||||
?string $password = null,
|
||||
?string $method = null
|
||||
) {
|
||||
$this->username = $username;
|
||||
$this->password = $password;
|
||||
$this->method = $method;
|
||||
}
|
||||
private ?string $username = null,
|
||||
private ?string $password = null,
|
||||
private ?string $method = null
|
||||
) {}
|
||||
|
||||
public static function create(): self
|
||||
{
|
||||
|
||||
@@ -34,21 +34,13 @@ use Espo\Core\Authentication\Logins\Espo;
|
||||
use Espo\Core\Utils\Config;
|
||||
use Espo\Core\Utils\Metadata;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class ConfigDataProvider
|
||||
{
|
||||
private const FAILED_ATTEMPTS_PERIOD = '60 seconds';
|
||||
private const MAX_FAILED_ATTEMPT_NUMBER = 10;
|
||||
|
||||
private Config $config;
|
||||
private Metadata $metadata;
|
||||
|
||||
public function __construct(Config $config, Metadata $metadata)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->metadata = $metadata;
|
||||
}
|
||||
public function __construct(private Config $config, private Metadata $metadata)
|
||||
{}
|
||||
|
||||
/**
|
||||
* A period for max failed attempts checking.
|
||||
@@ -155,16 +147,4 @@ class ConfigDataProvider
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
public function getMethodLoginMetadataParams(string $method): MetadataParams
|
||||
{
|
||||
/** @var ?array<string, mixed> $data */
|
||||
$data = $this->metadata->get(['authenticationMethods', $method]);
|
||||
|
||||
if ($data === null) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
return MetadataParams::fromRaw($method, $data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,60 +32,46 @@ namespace Espo\Core\Authentication\Helper;
|
||||
use Espo\Core\Authentication\Logins\ApiKey;
|
||||
use Espo\Core\Authentication\Logins\Hmac;
|
||||
use Espo\ORM\EntityManager;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
class UserFinder
|
||||
{
|
||||
private EntityManager $entityManager;
|
||||
|
||||
public function __construct(EntityManager $entityManager)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
public function __construct(private EntityManager $entityManager)
|
||||
{}
|
||||
|
||||
public function find(string $username, string $hash): ?User
|
||||
{
|
||||
/** @var ?User $user */
|
||||
$user = $this->entityManager
|
||||
->getRDBRepository(User::ENTITY_TYPE)
|
||||
return $this->entityManager
|
||||
->getRDBRepositoryByClass(User::class)
|
||||
->where([
|
||||
'userName' => $username,
|
||||
'password' => $hash,
|
||||
'type!=' => [User::TYPE_API, User::TYPE_SYSTEM],
|
||||
])
|
||||
->findOne();
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function findApiHmac(string $apiKey): ?User
|
||||
{
|
||||
/** @var ?User $user */
|
||||
$user = $this->entityManager
|
||||
->getRDBRepository(User::ENTITY_TYPE)
|
||||
return $this->entityManager
|
||||
->getRDBRepositoryByClass(User::class)
|
||||
->where([
|
||||
'type' => User::TYPE_API,
|
||||
'apiKey' => $apiKey,
|
||||
'authMethod' => Hmac::NAME,
|
||||
])
|
||||
->findOne();
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function findApiApiKey(string $apiKey): ?User
|
||||
{
|
||||
/** @var ?User $user */
|
||||
$user = $this->entityManager
|
||||
->getRDBRepository(User::ENTITY_TYPE)
|
||||
return $this->entityManager
|
||||
->getRDBRepositoryByClass(User::class)
|
||||
->where([
|
||||
'type' => User::TYPE_API,
|
||||
'apiKey' => $apiKey,
|
||||
'authMethod' => ApiKey::NAME,
|
||||
])
|
||||
->findOne();
|
||||
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,12 @@ use Espo\ORM\EntityManager;
|
||||
use Espo\Entities\AuthLogRecord;
|
||||
|
||||
use DateTime;
|
||||
use Exception;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
class FailedAttemptsLimit implements BeforeLogin
|
||||
{
|
||||
public function __construct(
|
||||
@@ -70,7 +75,12 @@ class FailedAttemptsLimit implements BeforeLogin
|
||||
|
||||
$requestTime = intval($request->getServerParam('REQUEST_TIME_FLOAT'));
|
||||
|
||||
$requestTimeFrom = (new DateTime('@' . $requestTime))->modify('-' . $failedAttemptsPeriod);
|
||||
try {
|
||||
$requestTimeFrom = (new DateTime('@' . $requestTime))->modify('-' . $failedAttemptsPeriod);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
throw new RuntimeException($e->getMessage());
|
||||
}
|
||||
|
||||
$ip = $this->util->obtainIpFromRequest($request);
|
||||
|
||||
@@ -99,7 +109,7 @@ class FailedAttemptsLimit implements BeforeLogin
|
||||
return;
|
||||
}
|
||||
|
||||
$this->log->warning("AUTH: Max failed login attempts exceeded for IP '{$ip}'.");
|
||||
$this->log->warning("AUTH: Max failed login attempts exceeded for IP '$ip'.");
|
||||
|
||||
throw new Forbidden("Max failed login attempts exceeded.");
|
||||
}
|
||||
|
||||
@@ -31,21 +31,15 @@ namespace Espo\Core\Authentication\Hook;
|
||||
|
||||
use Espo\Core\Utils\Metadata;
|
||||
use Espo\Core\InjectableFactory;
|
||||
|
||||
use Espo\Core\Authentication\AuthenticationData;
|
||||
use Espo\Core\Api\Request;
|
||||
use Espo\Core\Authentication\Result;
|
||||
|
||||
class Manager
|
||||
{
|
||||
private Metadata $metadata;
|
||||
private InjectableFactory $injectableFactory;
|
||||
|
||||
public function __construct(Metadata $metadata, InjectableFactory $injectableFactory)
|
||||
{
|
||||
$this->metadata = $metadata;
|
||||
$this->injectableFactory = $injectableFactory;
|
||||
}
|
||||
public function __construct(private Metadata $metadata, private InjectableFactory $injectableFactory)
|
||||
{}
|
||||
|
||||
public function processBeforeLogin(AuthenticationData $data, Request $request): void
|
||||
{
|
||||
|
||||
@@ -63,7 +63,7 @@ class Hmac implements SignatureVerifier
|
||||
$this->key = $key;
|
||||
|
||||
if (!in_array($algorithm, self::SUPPORTED_ALGORITHM_LIST)) {
|
||||
throw new RuntimeException("Unsupported algorithm {$algorithm}.");
|
||||
throw new RuntimeException("Unsupported algorithm $algorithm.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ class Rsa implements SignatureVerifier
|
||||
$this->keys = $keys;
|
||||
|
||||
if (!in_array($algorithm, self::SUPPORTED_ALGORITHM_LIST)) {
|
||||
throw new RuntimeException("Unsupported algorithm {$algorithm}.");
|
||||
throw new RuntimeException("Unsupported algorithm $algorithm.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ class Header
|
||||
try {
|
||||
$parsed = Json::decode($raw);
|
||||
}
|
||||
catch (JsonException $e) {}
|
||||
catch (JsonException) {}
|
||||
|
||||
if (!$parsed instanceof stdClass) {
|
||||
throw new RuntimeException();
|
||||
@@ -88,23 +88,25 @@ class Header
|
||||
);
|
||||
}
|
||||
|
||||
/** @noinspection PhpSameParameterValueInspection */
|
||||
private static function obtainFromParsedString(stdClass $parsed, string $name): string
|
||||
{
|
||||
$value = $parsed->$name ?? null;
|
||||
|
||||
if (!is_string($value)) {
|
||||
throw new RuntimeException("No or bad `{$name}` in JWT header.");
|
||||
throw new RuntimeException("No or bad `$name` in JWT header.");
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/** @noinspection PhpSameParameterValueInspection */
|
||||
private static function obtainFromParsedStringNull(stdClass $parsed, string $name): ?string
|
||||
{
|
||||
$value = $parsed->$name ?? null;
|
||||
|
||||
if ($value !== null && !is_string($value)) {
|
||||
throw new RuntimeException("Bad `{$name}` in JWT header.");
|
||||
throw new RuntimeException("Bad `$name` in JWT header.");
|
||||
}
|
||||
|
||||
return $value;
|
||||
|
||||
@@ -123,6 +123,7 @@ class Payload
|
||||
return $this->authTime;
|
||||
}
|
||||
|
||||
/** @noinspection PhpUnused */
|
||||
public function getSid(): ?string
|
||||
{
|
||||
return $this->sid;
|
||||
@@ -143,7 +144,7 @@ class Payload
|
||||
try {
|
||||
$parsed = Json::decode($raw);
|
||||
}
|
||||
catch (JsonException $e) {}
|
||||
catch (JsonException) {}
|
||||
|
||||
if (!$parsed instanceof stdClass) {
|
||||
throw new RuntimeException();
|
||||
|
||||
@@ -29,4 +29,6 @@
|
||||
|
||||
namespace Espo\Core\Authentication\Ldap;
|
||||
|
||||
class Client extends \Laminas\Ldap\Ldap {}
|
||||
use Laminas\Ldap\Ldap;
|
||||
|
||||
class Client extends Ldap {}
|
||||
|
||||
@@ -29,11 +29,13 @@
|
||||
|
||||
namespace Espo\Core\Authentication\Ldap;
|
||||
|
||||
use Laminas\Ldap\Exception\LdapException;
|
||||
|
||||
class ClientFactory
|
||||
{
|
||||
/**
|
||||
* @param array<string, mixed> $options
|
||||
* @throws \Laminas\Ldap\Exception\LdapException
|
||||
* @throws LdapException
|
||||
*/
|
||||
public function create(array $options): Client
|
||||
{
|
||||
|
||||
@@ -52,7 +52,12 @@ use Espo\Core\Utils\Log;
|
||||
use Espo\Core\Utils\PasswordHash;
|
||||
use Espo\Entities\User;
|
||||
use Exception;
|
||||
use Laminas\Ldap\Exception\LdapException;
|
||||
use Laminas\Ldap\Ldap;
|
||||
|
||||
/**
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
class LdapLogin implements Login
|
||||
{
|
||||
private LDAPUtils $utils;
|
||||
@@ -81,6 +86,7 @@ class LdapLogin implements Login
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
* @noinspection PhpUnusedPrivateFieldInspection
|
||||
*/
|
||||
private $ldapFieldMap = [
|
||||
'userName' => 'userNameAttribute',
|
||||
@@ -93,6 +99,7 @@ class LdapLogin implements Login
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
* @noinspection PhpUnusedPrivateFieldInspection
|
||||
*/
|
||||
private $userFieldMap = [
|
||||
'teamsIds' => 'userTeamsIds',
|
||||
@@ -101,12 +108,16 @@ class LdapLogin implements Login
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
* @noinspection PhpUnusedPrivateFieldInspection
|
||||
*/
|
||||
private $portalUserFieldMap = [
|
||||
'portalsIds' => 'portalUserPortalsIds',
|
||||
'portalRolesIds' => 'portalUserRolesIds',
|
||||
];
|
||||
|
||||
/**
|
||||
* @throws LdapException
|
||||
*/
|
||||
public function login(Data $data, Request $request): Result
|
||||
{
|
||||
$username = $data->getUsername();
|
||||
@@ -219,7 +230,7 @@ class LdapLogin implements Login
|
||||
if (!isset($user)) {
|
||||
if (!$this->utils->getOption('createEspoUser')) {
|
||||
$this->log->warning(
|
||||
"LDAP: Authentication success for user {$username}, but user is not created in EspoCRM."
|
||||
"LDAP: Authentication success for user $username, but user is not created in EspoCRM."
|
||||
);
|
||||
|
||||
return Result::fail(FailReason::USER_NOT_FOUND);
|
||||
@@ -369,13 +380,14 @@ class LdapLogin implements Login
|
||||
$user->setAsNotNew();
|
||||
$user->updateFetchedValues();
|
||||
|
||||
/** @var ?User */
|
||||
return $this->entityManager->getEntityById(User::ENTITY_TYPE, $user->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Find LDAP user DN by his username.
|
||||
*
|
||||
* @throws \Laminas\Ldap\Exception\LdapException
|
||||
* @throws LdapException
|
||||
*/
|
||||
private function findLdapUserDnByUsername(string $username): ?string
|
||||
{
|
||||
@@ -395,7 +407,8 @@ class LdapLogin implements Login
|
||||
$loginFilterString . ')';
|
||||
|
||||
/** @var array<int, array{dn: string}> $result */
|
||||
$result = $ldapClient->search($searchString, null, Client::SEARCH_SCOPE_SUB);
|
||||
/** @noinspection PhpRedundantOptionalArgumentInspection */
|
||||
$result = $ldapClient->search($searchString, null, Ldap::SEARCH_SCOPE_SUB);
|
||||
|
||||
$this->log->debug('LDAP: user search string: "' . $searchString . '"');
|
||||
|
||||
@@ -413,11 +426,11 @@ class LdapLogin implements Login
|
||||
{
|
||||
$filter = trim($filter);
|
||||
|
||||
if (substr($filter, 0, 1) != '(') {
|
||||
if (!str_starts_with($filter, '(')) {
|
||||
$filter = '(' . $filter;
|
||||
}
|
||||
|
||||
if (substr($filter, -1) != ')') {
|
||||
if (!str_ends_with($filter, ')')) {
|
||||
$filter = $filter . ')';
|
||||
}
|
||||
|
||||
|
||||
@@ -188,8 +188,6 @@ class Utils
|
||||
{
|
||||
$options = $this->getOptions();
|
||||
|
||||
$zendOptions = array_diff_key($options, array_flip($this->permittedEspoOptions));
|
||||
|
||||
return $zendOptions;
|
||||
return array_diff_key($options, array_flip($this->permittedEspoOptions));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
namespace Espo\Core\Authentication;
|
||||
|
||||
use Espo\Core\Api\Request;
|
||||
use Espo\Core\Authentication\Result;
|
||||
use Espo\Core\Authentication\Login\Data;
|
||||
|
||||
/**
|
||||
|
||||
@@ -43,14 +43,8 @@ class Hmac implements Login
|
||||
{
|
||||
public const NAME = 'Hmac';
|
||||
|
||||
private UserFinder $userFinder;
|
||||
private ApiKey $apiKeyUtil;
|
||||
|
||||
public function __construct(UserFinder $userFinder, ApiKey $apiKeyUtil)
|
||||
{
|
||||
$this->userFinder = $userFinder;
|
||||
$this->apiKeyUtil = $apiKeyUtil;
|
||||
}
|
||||
public function __construct(private UserFinder $userFinder, private ApiKey $apiKeyUtil)
|
||||
{}
|
||||
|
||||
public function login(Data $data, Request $request): Result
|
||||
{
|
||||
|
||||
@@ -36,14 +36,8 @@ use RuntimeException;
|
||||
|
||||
class LogoutFactory
|
||||
{
|
||||
private InjectableFactory $injectableFactory;
|
||||
private Metadata $metadata;
|
||||
|
||||
public function __construct(InjectableFactory $injectableFactory, Metadata $metadata)
|
||||
{
|
||||
$this->injectableFactory = $injectableFactory;
|
||||
$this->metadata = $metadata;
|
||||
}
|
||||
public function __construct(private InjectableFactory $injectableFactory, private Metadata $metadata)
|
||||
{}
|
||||
|
||||
public function create(string $method): Logout
|
||||
{
|
||||
|
||||
@@ -81,7 +81,7 @@ class BackchannelLogout
|
||||
$username = $token->getPayload()->get($usernameClaim);
|
||||
|
||||
if (!$username) {
|
||||
throw new Invalid("No username claim `{$usernameClaim}` in token.");
|
||||
throw new Invalid("No username claim `$usernameClaim` in token.");
|
||||
}
|
||||
|
||||
$user = $this->userRepository->findByUsername($username);
|
||||
|
||||
@@ -64,7 +64,7 @@ class DefaultSignatureVerifierFactory implements SignatureVerifierFactory
|
||||
$className = self::ALGORITHM_VERIFIER_CLASS_NAME_MAP[$algorithm] ?? null;
|
||||
|
||||
if (!$className) {
|
||||
throw new RuntimeException("Not supported algorithm {$algorithm}.");
|
||||
throw new RuntimeException("Not supported algorithm $algorithm.");
|
||||
}
|
||||
|
||||
if ($className === Rsa::class) {
|
||||
|
||||
@@ -67,7 +67,7 @@ class KeysProvider
|
||||
try {
|
||||
$list[] = $this->factory->create($raw);
|
||||
}
|
||||
catch (UnsupportedKey $e) {
|
||||
catch (UnsupportedKey) {
|
||||
$this->log->debug("OIDC: Unsupported key " . print_r($raw, true));
|
||||
}
|
||||
}
|
||||
@@ -127,7 +127,7 @@ class KeysProvider
|
||||
}
|
||||
|
||||
if ($error) {
|
||||
throw new RuntimeException("OIDC: JWKS request error. Status: {$status}.");
|
||||
throw new RuntimeException("OIDC: JWKS request error. Status: $status.");
|
||||
}
|
||||
|
||||
$parsedResponse = null;
|
||||
|
||||
@@ -282,10 +282,10 @@ class Login implements LoginInterface
|
||||
private static function composeLogMessage(string $text, ?int $status = null, ?string $response = null): string
|
||||
{
|
||||
if ($status === null) {
|
||||
return "OIDC: {$text}";
|
||||
return "OIDC: $text";
|
||||
}
|
||||
|
||||
return "OIDC: {$text}; Status: {$status}; Response: {$response}";
|
||||
return "OIDC: $text; Status: $status; Response: $response";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,6 +34,9 @@ use Espo\Core\Authentication\Logout as LogoutInterface;
|
||||
use Espo\Core\Authentication\Logout\Params;
|
||||
use Espo\Core\Authentication\Logout\Result;
|
||||
|
||||
/**
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
class Logout implements LogoutInterface
|
||||
{
|
||||
public function __construct(
|
||||
|
||||
@@ -53,7 +53,7 @@ class TokenValidator
|
||||
$allowedAlgorithmList = $this->configDataProvider->getJwtSignatureAlgorithmList();
|
||||
|
||||
if (!in_array($algorithm, $allowedAlgorithmList)) {
|
||||
throw new Invalid("JWT signing algorithm `{$algorithm}` not allowed.");
|
||||
throw new Invalid("JWT signing algorithm `$algorithm` not allowed.");
|
||||
}
|
||||
|
||||
$verifier = $this->signatureVerifierFactory->create($algorithm);
|
||||
|
||||
@@ -71,7 +71,7 @@ class DefaultUserProvider implements UserProvider
|
||||
$username = $payload->get($usernameClaim);
|
||||
|
||||
if (!$username) {
|
||||
throw new RuntimeException("No username claim `{$usernameClaim}` in token.");
|
||||
throw new RuntimeException("No username claim `$usernameClaim` in token.");
|
||||
}
|
||||
|
||||
$username = $this->sync->normalizeUsername($username);
|
||||
@@ -91,13 +91,13 @@ class DefaultUserProvider implements UserProvider
|
||||
$isPortal = $this->applicationState->isPortal();
|
||||
|
||||
if (!$isPortal && !$user->isRegular() && !$user->isAdmin()) {
|
||||
$this->log->info("Oidc: User {$userId} found but it's neither regular user not admin.");
|
||||
$this->log->info("Oidc: User $userId found but it's neither regular user not admin.");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($isPortal && !$user->isPortal()) {
|
||||
$this->log->info("Oidc: User {$userId} found but it's not portal user.");
|
||||
$this->log->info("Oidc: User $userId found but it's not portal user.");
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -106,20 +106,20 @@ class DefaultUserProvider implements UserProvider
|
||||
$portalId = $this->applicationState->getPortalId();
|
||||
|
||||
if (!$user->getPortals()->hasId($portalId)) {
|
||||
$this->log->info("Oidc: User {$userId} found but it's not related to current portal.");
|
||||
$this->log->info("Oidc: User $userId found but it's not related to current portal.");
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if ($user->isSuperAdmin()) {
|
||||
$this->log->info("Oidc: User {$userId} found but it's super-admin, not allowed.");
|
||||
$this->log->info("Oidc: User $userId found but it's super-admin, not allowed.");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($user->isAdmin() && !$this->configDataProvider->allowAdminUser()) {
|
||||
$this->log->info("Oidc: User {$userId} found but it's admin, not allowed.");
|
||||
$this->log->info("Oidc: User $userId found but it's admin, not allowed.");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -238,7 +238,7 @@ class Sync
|
||||
$username = strtolower($username);
|
||||
|
||||
/** @var string $result */
|
||||
$result = preg_replace("/{$regExp}/", '_', $username);
|
||||
$result = preg_replace("/$regExp/", '_', $username);
|
||||
|
||||
/** @var string */
|
||||
return str_replace(' ', '_', $result);
|
||||
|
||||
@@ -46,7 +46,7 @@ class UsernameValidator
|
||||
->getLength();
|
||||
|
||||
if ($maxLength && $maxLength < strlen($username)) {
|
||||
throw new RuntimeException("Value in username claim exceeds max length of `{$maxLength}`. " .
|
||||
throw new RuntimeException("Value in username claim exceeds max length of `$maxLength`. " .
|
||||
"Increase maxLength parameter for User.userName field (up to 255).");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,13 +45,13 @@ class Result
|
||||
public const STATUS_SECOND_STEP_REQUIRED = 'secondStepRequired';
|
||||
public const STATUS_FAIL = 'fail';
|
||||
|
||||
private ?User $user = null;
|
||||
private ?User $user;
|
||||
private string $status;
|
||||
private ?string $message = null;
|
||||
private ?string $token = null;
|
||||
private ?string $view = null;
|
||||
private ?string $failReason = null;
|
||||
private ?Data $data = null;
|
||||
private ?Data $data;
|
||||
|
||||
private function __construct(string $status, ?User $user = null, ?Data $data = null)
|
||||
{
|
||||
@@ -173,7 +173,7 @@ class Result
|
||||
*/
|
||||
public function getData(): ?stdClass
|
||||
{
|
||||
return $this->data ? $this->data->getData() : null;
|
||||
return $this->data?->getData();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,24 +36,16 @@ use stdClass;
|
||||
*/
|
||||
class Data
|
||||
{
|
||||
private ?string $message = null;
|
||||
private ?string $token = null;
|
||||
private ?string $view = null;
|
||||
private ?string $failReason = null;
|
||||
/** @var array<string, mixed> */
|
||||
private array $data = [];
|
||||
|
||||
/** @noinspection PhpSameParameterValueInspection */
|
||||
private function __construct(
|
||||
?string $message = null,
|
||||
?string $failReason = null,
|
||||
?string $token = null,
|
||||
?string $view = null
|
||||
) {
|
||||
$this->message = $message;
|
||||
$this->failReason = $failReason;
|
||||
$this->token = $token;
|
||||
$this->view = $view;
|
||||
}
|
||||
private ?string $message = null,
|
||||
private ?string $failReason = null,
|
||||
private ?string $token = null,
|
||||
private ?string $view = null
|
||||
) {}
|
||||
|
||||
public static function create(): self
|
||||
{
|
||||
@@ -103,6 +95,7 @@ class Data
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/** @noinspection PhpUnused */
|
||||
public function withFailReason(?string $failReason): self
|
||||
{
|
||||
$obj = clone $this;
|
||||
@@ -111,6 +104,7 @@ class Data
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/** @noinspection PhpUnused */
|
||||
public function withToken(?string $token): self
|
||||
{
|
||||
$obj = clone $this;
|
||||
@@ -119,6 +113,7 @@ class Data
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/** @noinspection PhpUnused */
|
||||
public function withView(?string $view): self
|
||||
{
|
||||
$obj = clone $this;
|
||||
|
||||
@@ -40,7 +40,6 @@ use stdClass;
|
||||
*/
|
||||
class EmailUserSetup implements UserSetup
|
||||
{
|
||||
|
||||
public function __construct(private Util $util)
|
||||
{}
|
||||
|
||||
|
||||
@@ -36,14 +36,8 @@ use LogicException;
|
||||
|
||||
class LoginFactory
|
||||
{
|
||||
private InjectableFactory $injectableFactory;
|
||||
private Metadata $metadata;
|
||||
|
||||
public function __construct(InjectableFactory $injectableFactory, Metadata $metadata)
|
||||
{
|
||||
$this->injectableFactory = $injectableFactory;
|
||||
$this->metadata = $metadata;
|
||||
}
|
||||
public function __construct(private InjectableFactory $injectableFactory, private Metadata $metadata)
|
||||
{}
|
||||
|
||||
public function create(string $method): Login
|
||||
{
|
||||
@@ -51,7 +45,7 @@ class LoginFactory
|
||||
$className = $this->metadata->get(['app', 'authentication2FAMethods', $method, 'loginClassName']);
|
||||
|
||||
if (!$className) {
|
||||
throw new LogicException("No login-class class for '{$method}'.");
|
||||
throw new LogicException("No login-class class for '$method'.");
|
||||
}
|
||||
|
||||
return $this->injectableFactory->create($className);
|
||||
|
||||
@@ -36,7 +36,6 @@ use RuntimeException;
|
||||
|
||||
class UserSetupFactory
|
||||
{
|
||||
|
||||
public function __construct(
|
||||
private InjectableFactory $injectableFactory,
|
||||
private Metadata $metadata
|
||||
|
||||
@@ -104,6 +104,7 @@ class Binder
|
||||
* @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
|
||||
{
|
||||
|
||||
@@ -89,11 +89,11 @@ class BindingContainer
|
||||
public function getByInterface(string $interfaceName): Binding
|
||||
{
|
||||
if (!$this->hasByInterface($interfaceName)) {
|
||||
throw new LogicException("Binding for interface `{$interfaceName}` does not exist.");
|
||||
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.");
|
||||
throw new LogicException("Interface `$interfaceName` does not exist.");
|
||||
}
|
||||
|
||||
return $this->data->getGlobal($interfaceName);
|
||||
|
||||
@@ -62,6 +62,7 @@ class BindingContainerBuilder
|
||||
*
|
||||
* @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
|
||||
{
|
||||
@@ -77,6 +78,7 @@ class BindingContainerBuilder
|
||||
* @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
|
||||
{
|
||||
@@ -91,6 +93,7 @@ class BindingContainerBuilder
|
||||
* @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
|
||||
{
|
||||
@@ -105,6 +108,7 @@ class BindingContainerBuilder
|
||||
* @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
|
||||
{
|
||||
|
||||
@@ -117,6 +117,7 @@ class ContextualBinder
|
||||
* @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
|
||||
{
|
||||
|
||||
@@ -36,6 +36,7 @@ interface Factory
|
||||
{
|
||||
/**
|
||||
* @return T
|
||||
* @noinspection PhpDocSignatureInspection
|
||||
*/
|
||||
public function create(): object;
|
||||
}
|
||||
|
||||
@@ -41,17 +41,11 @@ use Espo\Core\Console\Command\Params;
|
||||
*/
|
||||
class CommandManager
|
||||
{
|
||||
private InjectableFactory $injectableFactory;
|
||||
private Metadata $metadata;
|
||||
|
||||
private const DEFAULT_COMMAND = 'Help';
|
||||
private const DEFAULT_COMMAND_FLAG = 'help';
|
||||
|
||||
public function __construct(InjectableFactory $injectableFactory, Metadata $metadata)
|
||||
{
|
||||
$this->injectableFactory = $injectableFactory;
|
||||
$this->metadata = $metadata;
|
||||
}
|
||||
public function __construct(private InjectableFactory $injectableFactory, private Metadata $metadata)
|
||||
{}
|
||||
|
||||
/**
|
||||
* @param array<int, string> $argv
|
||||
|
||||
@@ -40,6 +40,8 @@ use Espo\Core\Portal\Application as PortalApplication;
|
||||
|
||||
/**
|
||||
* Checks access for websocket topic subscription. Prints `true` if access allowed.
|
||||
*
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
class AclCheck implements Command
|
||||
{
|
||||
@@ -62,6 +64,7 @@ class AclCheck implements Command
|
||||
$container = $this->container;
|
||||
$entityManager = $this->container->getByClass(EntityManager::class);
|
||||
|
||||
/** @var ?User $user */
|
||||
$user = $entityManager->getEntityById(User::ENTITY_TYPE, $userId);
|
||||
|
||||
if (!$user) {
|
||||
@@ -69,7 +72,6 @@ class AclCheck implements Command
|
||||
}
|
||||
|
||||
if ($user->isPortal()) {
|
||||
/** @var string[] $portalIdList */
|
||||
$portalIdList = $user->getLinkMultipleIdList('portals');
|
||||
|
||||
foreach ($portalIdList as $portalId) {
|
||||
@@ -86,7 +88,7 @@ class AclCheck implements Command
|
||||
$result = $this->check($user, $scope, $id, $action, $containerPortal);
|
||||
|
||||
if ($result) {
|
||||
$io->write('true');;
|
||||
$io->write('true');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,9 @@ use Espo\Core\InjectableFactory;
|
||||
use Espo\Core\Utils\File\Manager as FileManager;
|
||||
use Espo\Core\Utils\Util;
|
||||
|
||||
/**
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
class AppInfo implements Command
|
||||
{
|
||||
public function __construct(private InjectableFactory $injectableFactory, private FileManager $fileManager)
|
||||
|
||||
@@ -36,16 +36,13 @@ use Espo\Core\Console\Command\Params;
|
||||
use Espo\Core\Console\IO;
|
||||
use Espo\Core\ORM\EntityManager;
|
||||
|
||||
/**
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
class AuthTokenCheck implements Command
|
||||
{
|
||||
private EntityManager $entityManager;
|
||||
private AuthTokenManager $authTokenManager;
|
||||
|
||||
public function __construct(EntityManager $entityManager, AuthTokenManager $authTokenManager)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
$this->authTokenManager = $authTokenManager;
|
||||
}
|
||||
public function __construct(private EntityManager $entityManager, private AuthTokenManager $authTokenManager)
|
||||
{}
|
||||
|
||||
public function run(Params $params, IO $io): void
|
||||
{
|
||||
|
||||
@@ -35,6 +35,9 @@ use Espo\Core\Console\IO;
|
||||
use Espo\Core\DataManager;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
|
||||
/**
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
class ClearCache implements Command
|
||||
{
|
||||
public function __construct(private DataManager $dataManager)
|
||||
|
||||
@@ -33,6 +33,4 @@ namespace Espo\Core\Console\Commands;
|
||||
* @deprecated
|
||||
*/
|
||||
interface Command
|
||||
{
|
||||
|
||||
}
|
||||
{}
|
||||
|
||||
@@ -36,14 +36,13 @@ use Espo\Core\Console\IO;
|
||||
use Espo\Tools\EntityManager\Rename\Renamer;
|
||||
use Espo\Tools\EntityManager\Rename\FailReason as RenameFailReason;
|
||||
|
||||
/**
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
class EntityUtil implements Command
|
||||
{
|
||||
private Renamer $renamer;
|
||||
|
||||
public function __construct(Renamer $renamer)
|
||||
{
|
||||
$this->renamer = $renamer;
|
||||
}
|
||||
public function __construct(private Renamer $renamer)
|
||||
{}
|
||||
|
||||
public function run(Params $params, IO $io): void
|
||||
{
|
||||
@@ -57,8 +56,6 @@ class EntityUtil implements Command
|
||||
|
||||
if ($subCommand === 'rename') {
|
||||
$this->runRename($params, $io);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,13 +122,13 @@ class EntityUtil implements Command
|
||||
}
|
||||
|
||||
if ($failReason === RenameFailReason::DOES_NOT_EXIST) {
|
||||
$io->writeLine("Entity type `{$entityType}` does not exist.");
|
||||
$io->writeLine("Entity type `$entityType` does not exist.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($failReason === RenameFailReason::NOT_CUSTOM) {
|
||||
$io->writeLine("Entity type `{$entityType}` is not custom, hence can't be renamed.");
|
||||
$io->writeLine("Entity type `$entityType` is not custom, hence can't be renamed.");
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -150,8 +147,6 @@ class EntityUtil implements Command
|
||||
|
||||
if ($failReason === RenameFailReason::ERROR) {
|
||||
$io->writeLine("Error occurred.");
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,29 +32,29 @@ namespace Espo\Core\Console\Commands;
|
||||
use Espo\Core\Console\Command;
|
||||
use Espo\Core\Console\Command\Params;
|
||||
use Espo\Core\Console\IO;
|
||||
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Entities\Extension as ExtensionEntity;
|
||||
use Espo\ORM\EntityManager;
|
||||
|
||||
use Espo\Core\Upgrades\ExtensionManager;
|
||||
use Espo\Core\Container;
|
||||
use Espo\Core\Utils\File\Manager as FileManager;
|
||||
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
class Extension implements Command
|
||||
{
|
||||
private Container $container;
|
||||
private EntityManager $entityManager;
|
||||
private FileManager $fileManager;
|
||||
|
||||
public function __construct(Container $container, EntityManager $entityManager, FileManager $fileManager)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->entityManager = $entityManager;
|
||||
$this->fileManager = $fileManager;
|
||||
}
|
||||
public function __construct(
|
||||
private Container $container,
|
||||
private EntityManager $entityManager,
|
||||
private FileManager $fileManager
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @throws Error
|
||||
*/
|
||||
public function run(Params $params, IO $io): void
|
||||
{
|
||||
if ($params->hasFlag('l') || $params->hasFlag('list')) {
|
||||
@@ -104,6 +104,9 @@ class Extension implements Command
|
||||
$this->runInstall($file, $io);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Error
|
||||
*/
|
||||
private function runInstall(string $file, IO $io): void
|
||||
{
|
||||
$manager = $this->createExtensionManager();
|
||||
@@ -155,7 +158,7 @@ class Extension implements Command
|
||||
}
|
||||
|
||||
$io->writeLine("");
|
||||
$io->writeLine("Extension '{$name}' v{$version} is installed.\nExtension ID: '{$id}'.");
|
||||
$io->writeLine("Extension '$name' v$version is installed.\nExtension ID: '$id'.");
|
||||
}
|
||||
|
||||
protected function runUninstall(Params $params, IO $io): void
|
||||
@@ -174,7 +177,7 @@ class Extension implements Command
|
||||
->findOne();
|
||||
|
||||
if (!$record) {
|
||||
$io->writeLine("Extension with ID '{$id}' is not installed.");
|
||||
$io->writeLine("Extension with ID '$id' is not installed.");
|
||||
$io->setExitStatus(1);
|
||||
|
||||
return;
|
||||
@@ -199,7 +202,7 @@ class Extension implements Command
|
||||
->findOne();
|
||||
|
||||
if (!$record) {
|
||||
$io->writeLine("Extension '{$name}' is not installed.");
|
||||
$io->writeLine("Extension '$name' is not installed.");
|
||||
$io->setExitStatus(1);
|
||||
|
||||
return;
|
||||
@@ -226,7 +229,7 @@ class Extension implements Command
|
||||
$io->writeLine("");
|
||||
|
||||
if ($toKeep) {
|
||||
$io->writeLine("Extension '{$name}' is uninstalled.");
|
||||
$io->writeLine("Extension '$name' is uninstalled.");
|
||||
$io->setExitStatus(1);
|
||||
|
||||
return;
|
||||
@@ -237,14 +240,12 @@ class Extension implements Command
|
||||
}
|
||||
catch (Throwable $e) {
|
||||
$io->writeLine($e->getMessage());
|
||||
$io->writeLine("Extension '{$name}' is uninstalled but could not be deleted.");
|
||||
$io->writeLine("Extension '$name' is uninstalled but could not be deleted.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$io->writeLine("Extension '{$name}' is uninstalled and deleted.");
|
||||
|
||||
return;
|
||||
$io->writeLine("Extension '$name' is uninstalled and deleted.");
|
||||
}
|
||||
|
||||
private function printList(IO $io): void
|
||||
@@ -253,8 +254,10 @@ class Extension implements Command
|
||||
->getRDBRepository(ExtensionEntity::ENTITY_TYPE)
|
||||
->find();
|
||||
|
||||
/** @noinspection PhpParamsInspection */
|
||||
$count = is_countable($collection) ? count($collection) : iterator_count($collection);
|
||||
|
||||
/** @noinspection PhpIfWithCommonPartsInspection */
|
||||
if ($count === 0) {
|
||||
$io->writeLine("");
|
||||
$io->writeLine("No extensions.");
|
||||
|
||||
@@ -36,14 +36,13 @@ use Espo\Core\Console\IO;
|
||||
use Espo\Core\Utils\Metadata;
|
||||
use Espo\Core\Utils\Util;
|
||||
|
||||
/**
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
class Help implements Command
|
||||
{
|
||||
private $metadata;
|
||||
|
||||
public function __construct(Metadata $metadata)
|
||||
{
|
||||
$this->metadata = $metadata;
|
||||
}
|
||||
public function __construct(private Metadata $metadata)
|
||||
{}
|
||||
|
||||
public function run(Params $params, IO $io): void
|
||||
{
|
||||
|
||||
@@ -36,6 +36,9 @@ use Espo\Core\DataManager;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Utils\Database\Schema\RebuildMode;
|
||||
|
||||
/**
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
class Rebuild implements Command
|
||||
{
|
||||
public function __construct(private DataManager $dataManager)
|
||||
|
||||
@@ -40,9 +40,11 @@ use Espo\Entities\Job;
|
||||
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
class RunJob implements Command
|
||||
{
|
||||
|
||||
public function __construct(private JobManager $jobManager, private EntityManager $entityManager)
|
||||
{}
|
||||
|
||||
@@ -79,6 +81,7 @@ class RunJob implements Command
|
||||
|
||||
$entityManager = $this->entityManager;
|
||||
|
||||
/** @var Job $job */
|
||||
$job = $entityManager->createEntity(Job::ENTITY_TYPE, [
|
||||
'name' => $jobName,
|
||||
'job' => $jobName,
|
||||
@@ -92,7 +95,7 @@ class RunJob implements Command
|
||||
$this->jobManager->runJob($job);
|
||||
}
|
||||
catch (Throwable $e) {
|
||||
$message = "Error: Job '{$jobName}' failed to execute.";
|
||||
$message = "Error: Job '$jobName' failed to execute.";
|
||||
|
||||
if ($e->getMessage()) {
|
||||
$message .= ' ' . $e->getMessage();
|
||||
@@ -104,6 +107,6 @@ class RunJob implements Command
|
||||
return;
|
||||
}
|
||||
|
||||
$io->writeLine("Job '{$jobName}' has been executed.");
|
||||
$io->writeLine("Job '$jobName' has been executed.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,9 @@ use Espo\Core\Console\IO;
|
||||
use Espo\Core\ORM\EntityManager;
|
||||
use Espo\Core\Utils\PasswordHash;
|
||||
|
||||
/**
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
class SetPassword implements Command
|
||||
{
|
||||
public function __construct(private EntityManager $entityManager, private PasswordHash $passwordHash)
|
||||
@@ -59,7 +62,7 @@ class SetPassword implements Command
|
||||
->findOne();
|
||||
|
||||
if (!$user) {
|
||||
$io->writeLine("User '{$userName}' not found.");
|
||||
$io->writeLine("User '$userName' not found.");
|
||||
$io->setExitStatus(1);
|
||||
|
||||
return;
|
||||
@@ -75,7 +78,7 @@ class SetPassword implements Command
|
||||
];
|
||||
|
||||
if (!in_array($userType, $allowedTypes)) {
|
||||
$io->writeLine("Can't set password for a user of the type '{$userType}'.");
|
||||
$io->writeLine("Can't set password for a user of the type '$userType'.");
|
||||
$io->setExitStatus(1);
|
||||
|
||||
return;
|
||||
@@ -96,6 +99,6 @@ class SetPassword implements Command
|
||||
|
||||
$em->saveEntity($user);
|
||||
|
||||
$io->writeLine("Password for user '{$userName}' has been changed.");
|
||||
$io->writeLine("Password for user '$userName' has been changed.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,13 +46,22 @@ use Exception;
|
||||
use Throwable;
|
||||
use stdClass;
|
||||
|
||||
use const CURLOPT_FILE;
|
||||
use const CURLOPT_RETURNTRANSFER;
|
||||
use const CURLOPT_SSL_VERIFYPEER;
|
||||
use const CURLOPT_TIMEOUT;
|
||||
use const CURLOPT_URL;
|
||||
use const FILTER_VALIDATE_URL;
|
||||
use const STDOUT;
|
||||
|
||||
/**
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
class Upgrade implements Command
|
||||
{
|
||||
private ?UpgradeManager $upgradeManager = null;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
/** @var string[] */
|
||||
private $upgradeStepList = [
|
||||
'copyBefore',
|
||||
'rebuild',
|
||||
@@ -66,9 +75,7 @@ class Upgrade implements Command
|
||||
'rebuild',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
/** @var array<string, string> */
|
||||
private $upgradeStepLabels = [
|
||||
'init' => 'Initialization',
|
||||
'copyBefore' => 'Copying before upgrade files',
|
||||
@@ -81,17 +88,15 @@ class Upgrade implements Command
|
||||
'revert' => 'Reverting',
|
||||
];
|
||||
|
||||
private FileManager $fileManager;
|
||||
private Config $config;
|
||||
private Log $log;
|
||||
|
||||
public function __construct(FileManager $fileManager, Config $config, Log $log)
|
||||
{
|
||||
$this->fileManager = $fileManager;
|
||||
$this->config = $config;
|
||||
$this->log = $log;
|
||||
}
|
||||
public function __construct(
|
||||
private FileManager $fileManager,
|
||||
private Config $config,
|
||||
private Log $log
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @throws Error
|
||||
*/
|
||||
public function run(Params $params, IO $io): void
|
||||
{
|
||||
$options = $params->getOptions();
|
||||
@@ -122,10 +127,10 @@ class Upgrade implements Command
|
||||
$nextVersion = $manifest['version'];
|
||||
}
|
||||
|
||||
fwrite(\STDOUT, "Current version is {$fromVersion}.\n");
|
||||
fwrite(STDOUT, "Current version is $fromVersion.\n");
|
||||
|
||||
if (!$upgradeParams->skipConfirmation) {
|
||||
fwrite(\STDOUT, "EspoCRM will be upgraded to version {$nextVersion} now. Enter [Y] to continue.\n");
|
||||
fwrite(STDOUT, "EspoCRM will be upgraded to version $nextVersion now. Enter [Y] to continue.\n");
|
||||
|
||||
if (!$this->confirm()) {
|
||||
echo "Upgrade canceled.\n";
|
||||
@@ -134,17 +139,17 @@ class Upgrade implements Command
|
||||
}
|
||||
}
|
||||
|
||||
fwrite(\STDOUT, "This may take a while. Do not close the terminal.\n");
|
||||
fwrite(STDOUT, "This may take a while. Do not close the terminal.\n");
|
||||
|
||||
if (filter_var($packageFile, \FILTER_VALIDATE_URL)) {
|
||||
fwrite(\STDOUT, "Downloading...");
|
||||
if (filter_var($packageFile, FILTER_VALIDATE_URL)) {
|
||||
fwrite(STDOUT, "Downloading...");
|
||||
|
||||
$packageFile = $this->downloadFile($packageFile);
|
||||
|
||||
fwrite(\STDOUT, "\n");
|
||||
fwrite(STDOUT, "\n");
|
||||
|
||||
if (!$packageFile) {
|
||||
fwrite(\STDOUT, "Error: Unable to download upgrade package.\n");
|
||||
fwrite(STDOUT, "Error: Unable to download upgrade package.\n");
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -152,7 +157,7 @@ class Upgrade implements Command
|
||||
|
||||
$upgradeId = $upgradeId ?? $this->upload($packageFile);
|
||||
|
||||
fwrite(\STDOUT, "Upgrading...");
|
||||
fwrite(STDOUT, "Upgrading...");
|
||||
|
||||
try {
|
||||
$this->runUpgradeProcess($upgradeId, $upgradeParams);
|
||||
@@ -162,7 +167,7 @@ class Upgrade implements Command
|
||||
$errorMessage = $e->getMessage();
|
||||
}
|
||||
|
||||
fwrite(\STDOUT, "\n");
|
||||
fwrite(STDOUT, "\n");
|
||||
|
||||
if (!$upgradeParams->keepPackageFile) {
|
||||
$this->fileManager->unlink($packageFile);
|
||||
@@ -171,25 +176,23 @@ class Upgrade implements Command
|
||||
if (isset($errorMessage)) {
|
||||
$errorMessage = !empty($errorMessage) ? $errorMessage : "Error: An unexpected error occurred.";
|
||||
|
||||
fwrite(\STDOUT, $errorMessage . "\n");
|
||||
fwrite(STDOUT, $errorMessage . "\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$currentVersion = $this->getCurrentVersion();
|
||||
|
||||
fwrite(\STDOUT, "Upgrade is complete. Current version is {$currentVersion}.\n");
|
||||
fwrite(STDOUT, "Upgrade is complete. Current version is $currentVersion.\n");
|
||||
|
||||
if ($lastVersion && $lastVersion !== $currentVersion && $fromVersion !== $currentVersion) {
|
||||
fwrite(\STDOUT, "Newer version is available. Run command again to upgrade.\n");
|
||||
fwrite(STDOUT, "Newer version is available. Run command again to upgrade.\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($lastVersion && $lastVersion === $currentVersion) {
|
||||
fwrite(\STDOUT, "You have the latest version.\n");
|
||||
|
||||
return;
|
||||
fwrite(STDOUT, "You have the latest version.\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +206,8 @@ class Upgrade implements Command
|
||||
* @param array<string, string> $options
|
||||
* @param string[] $flagList
|
||||
* @param string[] $argumentList
|
||||
* @return \stdClass
|
||||
* @return stdClass
|
||||
* @noinspection PhpUnusedParameterInspection
|
||||
*/
|
||||
private function normalizeParams(array $options, array $flagList, array $argumentList): object
|
||||
{
|
||||
@@ -253,19 +257,19 @@ class Upgrade implements Command
|
||||
|
||||
if (!$params->localMode) {
|
||||
if (empty($versionInfo)) {
|
||||
fwrite(\STDOUT, "Error: Upgrade server is currently unavailable. Please try again later.\n");
|
||||
fwrite(STDOUT, "Error: Upgrade server is currently unavailable. Please try again later.\n");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!isset($versionInfo->nextVersion)) {
|
||||
fwrite(\STDOUT, "There are no available upgrades.\n");
|
||||
fwrite(STDOUT, "There are no available upgrades.\n");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!isset($versionInfo->nextPackage)) {
|
||||
fwrite(\STDOUT, "Error: Upgrade package is not found.\n");
|
||||
fwrite(STDOUT, "Error: Upgrade package is not found.\n");
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -274,7 +278,7 @@ class Upgrade implements Command
|
||||
}
|
||||
|
||||
if (!$packageFile || !file_exists($packageFile)) {
|
||||
fwrite(\STDOUT, "Error: Upgrade package is not found.\n");
|
||||
fwrite(STDOUT, "Error: Upgrade package is not found.\n");
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -310,7 +314,7 @@ class Upgrade implements Command
|
||||
$stepList = !empty($params->step) ? [$params->step] : $this->upgradeStepList;
|
||||
|
||||
array_unshift($stepList, 'init');
|
||||
array_push($stepList, 'finalize');
|
||||
$stepList[] = 'finalize';
|
||||
|
||||
if (!$useSingleProcess && $this->isShellEnabled()) {
|
||||
$this->runSteps($upgradeId, $stepList);
|
||||
@@ -342,7 +346,7 @@ class Upgrade implements Command
|
||||
try {
|
||||
$this->log->error('Upgrade Error: ' . $e->getMessage());
|
||||
}
|
||||
catch (Throwable $t) {}
|
||||
catch (Throwable) {}
|
||||
|
||||
throw new Error($e->getMessage());
|
||||
}
|
||||
@@ -380,7 +384,7 @@ class Upgrade implements Command
|
||||
{
|
||||
$stepLabel = $this->upgradeStepLabels[$stepName] ?? "";
|
||||
|
||||
fwrite(\STDOUT, "\n {$stepLabel}...");
|
||||
fwrite(STDOUT, "\n $stepLabel...");
|
||||
}
|
||||
|
||||
private function confirm(): bool
|
||||
@@ -435,9 +439,9 @@ class Upgrade implements Command
|
||||
|
||||
$ch = curl_init();
|
||||
|
||||
curl_setopt($ch, \CURLOPT_SSL_VERIFYPEER, true);
|
||||
curl_setopt($ch, \CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, \CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
|
||||
$result = curl_exec($ch);
|
||||
|
||||
@@ -446,7 +450,7 @@ class Upgrade implements Command
|
||||
try {
|
||||
$data = json_decode($result); /** @phpstan-ignore-line */
|
||||
}
|
||||
catch (Exception $e) { /** @phpstan-ignore-line */
|
||||
catch (Exception) { /** @phpstan-ignore-line */
|
||||
echo "Could not parse info about next version.\n";
|
||||
|
||||
return null;
|
||||
@@ -472,9 +476,9 @@ class Upgrade implements Command
|
||||
}
|
||||
else {
|
||||
$options = [
|
||||
\CURLOPT_FILE => fopen($localFilePath, 'w'),
|
||||
\CURLOPT_TIMEOUT => 3600,
|
||||
\CURLOPT_URL => $url,
|
||||
CURLOPT_FILE => fopen($localFilePath, 'w'),
|
||||
CURLOPT_TIMEOUT => 3600,
|
||||
CURLOPT_URL => $url,
|
||||
];
|
||||
|
||||
$ch = curl_init();
|
||||
|
||||
@@ -37,6 +37,9 @@ use Espo\Core\Upgrades\UpgradeManager;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
class UpgradeStep implements Command
|
||||
{
|
||||
public function __construct() {}
|
||||
|
||||
@@ -33,5 +33,4 @@ use RuntimeException;
|
||||
|
||||
class CommandNotSpecified extends RuntimeException
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -94,6 +94,7 @@ class ContainerBuilder
|
||||
|
||||
/**
|
||||
* @param array<string, class-string<Loader>> $classNames
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function withLoaderClassNames(array $classNames): self
|
||||
{
|
||||
@@ -136,6 +137,7 @@ class ContainerBuilder
|
||||
|
||||
/**
|
||||
* @param class-string $fileManagerClassName
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function withFileManagerClassName(string $fileManagerClassName): self
|
||||
{
|
||||
@@ -146,6 +148,7 @@ class ContainerBuilder
|
||||
|
||||
/**
|
||||
* @param class-string $dataCacheClassName
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function withDataCacheClassName(string $dataCacheClassName): self
|
||||
{
|
||||
|
||||
@@ -40,6 +40,7 @@ class ContainerConfiguration implements Configuration
|
||||
/**
|
||||
* Log must be loaded before anything.
|
||||
* @phpstan-ignore-next-line
|
||||
* @noinspection PhpPropertyOnlyWrittenInspection
|
||||
*/
|
||||
private Log $log;
|
||||
|
||||
|
||||
@@ -141,6 +141,8 @@ class RecordBase extends Base implements
|
||||
* @throws NotFoundSilent
|
||||
* @throws ForbiddenSilent
|
||||
* @throws BadRequest
|
||||
* @throws Forbidden
|
||||
* @noinspection PhpUnusedParameterInspection
|
||||
*/
|
||||
public function getActionRead(Request $request, Response $response): stdClass
|
||||
{
|
||||
@@ -188,6 +190,7 @@ class RecordBase extends Base implements
|
||||
* @throws NotFound
|
||||
* @throws Forbidden
|
||||
* @throws Conflict
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function patchActionUpdate(Request $request, Response $response): stdClass
|
||||
{
|
||||
@@ -201,6 +204,7 @@ class RecordBase extends Base implements
|
||||
* @throws NotFound
|
||||
* @throws Forbidden
|
||||
* @throws Conflict
|
||||
* @noinspection PhpUnusedParameterInspection
|
||||
*/
|
||||
public function putActionUpdate(Request $request, Response $response): stdClass
|
||||
{
|
||||
@@ -254,6 +258,7 @@ class RecordBase extends Base implements
|
||||
* @throws Forbidden
|
||||
* @throws BadRequest
|
||||
* @throws NotFound
|
||||
* @noinspection PhpUnusedParameterInspection
|
||||
*/
|
||||
public function deleteActionDelete(Request $request, Response $response): bool
|
||||
{
|
||||
@@ -288,6 +293,7 @@ class RecordBase extends Base implements
|
||||
* @throws Forbidden
|
||||
* @throws NotFound
|
||||
* @throws ForbiddenSilent
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function postActionGetDuplicateAttributes(Request $request): stdClass
|
||||
{
|
||||
@@ -304,6 +310,7 @@ class RecordBase extends Base implements
|
||||
* @throws BadRequest
|
||||
* @throws Forbidden
|
||||
* @throws NotFound
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function postActionRestoreDeleted(Request $request): bool
|
||||
{
|
||||
|
||||
@@ -33,6 +33,8 @@ use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
|
||||
use Espo\Core\Exceptions\NotFound;
|
||||
use Espo\Core\ORM\Entity;
|
||||
use Espo\Services\RecordTree as Service;
|
||||
use Espo\Core\Api\Request;
|
||||
|
||||
@@ -51,7 +53,8 @@ class RecordTree extends Record
|
||||
* @throws BadRequest
|
||||
* @throws Error
|
||||
* @throws Forbidden
|
||||
* @throws \Espo\Core\Exceptions\NotFound
|
||||
* @throws NotFound
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function getActionListTree(Request $request): stdClass
|
||||
{
|
||||
@@ -96,6 +99,8 @@ class RecordTree extends Record
|
||||
/**
|
||||
* @return string[]
|
||||
* @throws Forbidden
|
||||
* @throws BadRequest
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function getActionLastChildrenIdList(Request $request): array
|
||||
{
|
||||
@@ -109,7 +114,7 @@ class RecordTree extends Record
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Service<\Espo\Core\ORM\Entity>
|
||||
* @return Service<Entity>
|
||||
*/
|
||||
protected function getRecordTreeService(): Service
|
||||
{
|
||||
|
||||
@@ -47,7 +47,7 @@ class Factory
|
||||
$className = $this->metadata->get(['app', 'fileStorage', 'implementationClassNameMap', $name]);
|
||||
|
||||
if (!$className) {
|
||||
throw new RuntimeException("Unknown file storage '{$name}'.");
|
||||
throw new RuntimeException("Unknown file storage '$name'.");
|
||||
}
|
||||
|
||||
return $this->injectableFactory->create($className);
|
||||
|
||||
@@ -42,23 +42,20 @@ use RuntimeException;
|
||||
*/
|
||||
class Manager
|
||||
{
|
||||
/** @var array<string, Storage> */
|
||||
private array $implHash = [];
|
||||
|
||||
private const DEFAULT_STORAGE = 'EspoUploadDir';
|
||||
|
||||
private Factory $factory;
|
||||
/** @var array<string, Storage> */
|
||||
private array $implHash = [];
|
||||
|
||||
/**
|
||||
* @var array<string, resource>
|
||||
* @phpstan-ignore-next-line Used to prevent deleting from memory.
|
||||
* @noinspection PhpPropertyOnlyWrittenInspection
|
||||
*/
|
||||
private $resourceMap = [];
|
||||
|
||||
public function __construct(Factory $factory)
|
||||
{
|
||||
$this->factory = $factory;
|
||||
}
|
||||
public function __construct(private Factory $factory)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Whether a file exists in a storage.
|
||||
|
||||
@@ -36,19 +36,15 @@ use Espo\Core\Utils\File\Manager as FileManager;
|
||||
use Espo\Core\Utils\File\Exceptions\FileError;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
use GuzzleHttp\Psr7\Stream;
|
||||
|
||||
class EspoUploadDir implements Storage, Local
|
||||
{
|
||||
protected FileManager $fileManager;
|
||||
|
||||
public const NAME = 'EspoUploadDir';
|
||||
|
||||
public function __construct(FileManager $fileManager)
|
||||
{
|
||||
$this->fileManager = $fileManager;
|
||||
}
|
||||
public function __construct(protected FileManager $fileManager)
|
||||
{}
|
||||
|
||||
public function unlink(Attachment $attachment): void
|
||||
{
|
||||
@@ -69,7 +65,7 @@ class EspoUploadDir implements Storage, Local
|
||||
$filePath = $this->getFilePath($attachment);
|
||||
|
||||
if (!$this->exists($attachment)) {
|
||||
throw new FileError("Could not get size for non-existing file '{$filePath}'.");
|
||||
throw new FileError("Could not get size for non-existing file '$filePath'.");
|
||||
}
|
||||
|
||||
return $this->fileManager->getSize($filePath);
|
||||
@@ -80,13 +76,13 @@ class EspoUploadDir implements Storage, Local
|
||||
$filePath = $this->getFilePath($attachment);
|
||||
|
||||
if (!$this->exists($attachment)) {
|
||||
throw new FileError("Could not get stream for non-existing '{$filePath}'.");
|
||||
throw new FileError("Could not get stream for non-existing '$filePath'.");
|
||||
}
|
||||
|
||||
$resource = fopen($filePath, 'r');
|
||||
|
||||
if ($resource === false) {
|
||||
throw new FileError("Could not open '{$filePath}'.");
|
||||
throw new FileError("Could not open '$filePath'.");
|
||||
}
|
||||
|
||||
return new Stream($resource);
|
||||
@@ -104,7 +100,7 @@ class EspoUploadDir implements Storage, Local
|
||||
$result = $this->fileManager->putContents($filePath, $contents);
|
||||
|
||||
if (!$result) {
|
||||
throw new FileError("Could not store a file '{$filePath}'.");
|
||||
throw new FileError("Could not store a file '$filePath'.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user