This commit is contained in:
Yuri Kuznetsov
2025-03-26 13:34:21 +02:00
parent e92b200eb3
commit 41b0dd4e78
39 changed files with 92 additions and 85 deletions

View File

@@ -31,6 +31,8 @@ namespace Espo\Core\EntryPoint\Traits;
/**
* @deprecated
* @todo Remove in v10.0.
* @phpstan-ignore-next-line
*/
trait NotStrictAuth
{

View File

@@ -31,6 +31,8 @@ namespace Espo\Core\EntryPoints;
/**
* @deprecated Use `Espo\Core\EntryPoint\Traits\NoAuth` instead.
* @todo Remove in v10.0.
* @phpstan-ignore-next-line
*/
trait NoAuth
{

View File

@@ -31,6 +31,8 @@ namespace Espo\Core\EntryPoints;
/**
* @deprecated
* @todo Remove in v10.0.
* @phpstan-ignore-next-line
*/
trait NotStrictAuth
{

View File

@@ -247,7 +247,7 @@ abstract class OAuth2Abstract implements IClient
$data['refreshToken'] = $result['refresh_token'] ?? null;
/**
* @var ?array{
* @var array{
* accessToken: ?string,
* tokenType: ?string,
* expiresAt: ?string,

View File

@@ -347,7 +347,7 @@ class Client
curl_setopt_array($ch, $curlOptions);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);

View File

@@ -49,8 +49,8 @@ class Manager
/**
* @var array<string, resource>
* @phpstan-ignore-next-line Used to prevent deleting from memory.
* @noinspection PhpPropertyOnlyWrittenInspection
* @phpstan-ignore-next-line Used to prevent deleting from memory.
*/
private $resourceMap = [];

View File

@@ -63,6 +63,7 @@ class AwsS3 implements Storage
throw new RuntimeException("AWS S3 bucket name is not specified in config.");
}
/** @var array<\AsyncAws\Core\Configuration::OPTION_*, string|null> $clientOptions */
$clientOptions = [
'region' => $region,
];

View File

@@ -80,7 +80,7 @@ class RetrieveType extends BaseFunction
return [];
}
/** @var string[] $pathArray */
/** @var list<string> $pathArray */
$pathArray = preg_split('/(?<!\\\)\./', $path);
foreach ($pathArray as $i => $item) {

View File

@@ -845,7 +845,7 @@ class Parser
return $this->split($expression, true);
}
if (count($statementList)) {
if ($statementList !== null && count($statementList)) {
return $this->processStatementList($expression, $statementList, $isRoot);
}

View File

@@ -409,7 +409,7 @@ class DefaultImporter implements Importer
$subject = $parser->getHeader($message, 'subject');
}
if (!empty($subject) && is_string($subject)) {
if (!empty($subject)) {
$subject = trim($subject);
}

View File

@@ -313,7 +313,6 @@ class MailMimeParser implements Parser
$content = '';
/** @var StreamInterface|null $binaryContentStream */
$binaryContentStream = $attachmentPart->getBinaryContentStream();
if ($binaryContentStream) {

View File

@@ -564,8 +564,7 @@ class Sender
$messageId = $email->getMessageId();
if (
empty($messageId) ||
!is_string($messageId) ||
!$messageId ||
strlen($messageId) < 4 ||
str_starts_with($messageId, 'dummy:')
) {

View File

@@ -450,7 +450,7 @@ class Entity extends BaseEntity
throw new LogicException("Non-object value in `$columnsAttribute`.");
}
return $object->$id?->$column ?? null;
return $object->$id->$column ?? null;
}
/**

View File

@@ -60,7 +60,7 @@ use stdClass;
*/
class LinkCheck
{
/** @var array<string, LinkChecker<Entity, Entity>>> */
/** @var array<string, LinkChecker<Entity, Entity>> */
private $linkCheckerCache = [];
/** @var string[] */

View File

@@ -144,7 +144,7 @@ class SearchParamsFetcher
$q = $request->getQueryParam('q');
if ($q && is_string($q)) {
if ($q) {
$params['q'] = trim($q);
}

View File

@@ -240,9 +240,6 @@ class Database extends RDBRepository
*/
protected function afterRelate(Entity $entity, $relationName, $foreign, $data = null, array $options = [])
{
/** @noinspection PhpDeprecationInspection */
parent::afterRelate($entity, $relationName, $foreign, $data, $options);
if ($this->hooksDisabled || !empty($options[SaveOption::SKIP_HOOKS])) {
return;
}
@@ -284,9 +281,6 @@ class Database extends RDBRepository
*/
protected function afterUnrelate(Entity $entity, $relationName, $foreign, array $options = [])
{
/** @noinspection PhpDeprecationInspection */
parent::afterUnrelate($entity, $relationName, $foreign, $options);
if ($this->hooksDisabled || !empty($options[SaveOption::SKIP_HOOKS])) {
return;
}

View File

@@ -111,7 +111,7 @@ class FilterFactory
$className1 = $this->metadata->get(['app', 'select', 'boolFilterClassNameMap', $name]);
if ($className1) {
/** @var ?class-string<Filter> */
/** @var class-string<Filter> */
return $className1;
}
@@ -121,7 +121,7 @@ class FilterFactory
return null;
}
/** @var ?class-string<Filter> */
/** @var class-string<Filter> */
return $className;
}
}

View File

@@ -68,7 +68,9 @@ class FieldHelper
private function getSeed(): Entity
{
return $this->seed ?? $this->entityManager->getNewEntity($this->entityType);
$this->seed ??= $this->entityManager->getNewEntity($this->entityType);
return $this->seed;
}
public function hasAssignedUsersField(): bool

View File

@@ -71,7 +71,6 @@ class Applier
if ($orderBy) {
if (
!is_string($orderBy) ||
str_contains($orderBy, '.') ||
str_contains($orderBy, ':')
) {

View File

@@ -169,8 +169,7 @@ class SelectBuilder
$this->applyAdditional();
/** @var QueryBuilder */
return $this->queryBuilder;
return $this->queryBuilder ?? throw new LogicException();
}
/**

View File

@@ -42,9 +42,9 @@ use Espo\Entities\User;
class Applier
{
/** @todo Move to metadata. */
private ?int $fullTextRelevanceThreshold = null;
private ?int $fullTextRelevanceThreshold = null; /** @phpstan-ignore-line */
/** @todo Move to metadata. */
private int $fullTextOrderRelevanceDivider = 5;
private int $fullTextOrderRelevanceDivider = 5; /** @phpstan-ignore-line */
private const DEFAULT_FT_ORDER = self::FT_ORDER_COMBINED;
private const DEFAULT_ATTRIBUTE_LIST = ['name'];

View File

@@ -227,7 +227,9 @@ class Checker
private function getSeed(): Entity
{
return $this->seed ?? $this->entityManager->getNewEntity($this->entityType);
$this->seed ??= $this->entityManager->getNewEntity($this->entityType);
return $this->seed;
}
private function getRelationParam(Entity $entity, string $relation, string $param): mixed

View File

@@ -29,7 +29,11 @@
namespace Espo\Core\Traits;
/** @deprecated */
/**
* @deprecated
* @todo Remove in v10.0.
* @phpstan-ignore-next-line
*/
trait Injectable
{
protected $injections = []; /** @phpstan-ignore-line */

View File

@@ -36,7 +36,7 @@ use RuntimeException;
class Helper
{
private ?Base $actionObject;
private ?Base $actionObject = null;
public function __construct(private EntityManager $entityManager)
{}

View File

@@ -36,9 +36,9 @@ use stdClass;
class DataUtil
{
/**
* @param array<string|int, mixed> $data
* @param array<string|int, mixed>|stdClass $data
* @param array<int, string|string[]>|string $unsetList
* @return array<string|int, mixed>
* @return array<string|int, mixed>|stdClass
*/
public static function unsetByKey(&$data, $unsetList, bool $removeEmptyItems = false)
{
@@ -168,7 +168,7 @@ class DataUtil
}
/** @var array<string|int, mixed>|stdClass */
return $overrideData;
return $overrideData; /** @phpstan-ignore-line */
}
if (is_object($overrideData)) {

View File

@@ -997,7 +997,6 @@ class Converter
}
}
/** @var array<string, mixed> */
return $indexList;
}

View File

@@ -98,7 +98,7 @@ class Utils
}
/** @var array<string, array<string, mixed>> */
return $indexList;
return $indexList; /** @phpstan-ignore-line */
}
private static function getIndexTypeByIndexDefs(IndexDefs $indexDefs): string

View File

@@ -926,7 +926,7 @@ class Manager
if (is_dir($path)) {
$fileList = $this->getFileList($path, true);
if (is_array($fileList) && empty($fileList)) {
if (empty($fileList)) {
return true;
}
}

View File

@@ -243,7 +243,10 @@ class Permission
$count++;
}
} else if (is_int((int) $octal)) { // Always true. @todo Fix.
} else if (
/** @phpstan-ignore-next-line */
is_int((int) $octal) // Always true. @todo Fix.
) {
$permission = [
'file' => $octal,
'dir' => $octal,

View File

@@ -47,7 +47,7 @@ class Log implements LoggerInterface
private Logger $logger;
/**
* @param HandlerInterface[] $handlers
* @param list<HandlerInterface> $handlers
* @param callable[] $processors
* @param ?DateTimeZone $timezone
*/

View File

@@ -45,7 +45,7 @@ class StreamUpdatedAtField implements AdditionalBuilder
$field = Field::STREAM_UPDATED_AT;
foreach (get_object_vars($data->entityDefs) as $entityType => $entityDefsItem) {
$hasStream = $data->scopes?->$entityType?->stream ?? false;
$hasStream = $data->scopes?->$entityType->stream ?? false;
if (!$hasStream) {
continue;

View File

@@ -164,9 +164,10 @@ class Util
/**
* Merge arrays recursively. $newArray overrides $currentArray.
*
* @param array<int|string, mixed> $currentArray A source array.
* @param array<int|string, mixed> $newArray A merge-array (priority is same as for array_merge()).
* @return array<int|string, mixed>
* @template T of array<int|string, mixed>
* @param T $currentArray A source array.
* @param T $newArray A merge-array (priority is same as for array_merge()).
* @return T
*/
public static function merge($currentArray, $newArray)
{
@@ -176,13 +177,16 @@ class Util
$mergeIdentifier = '__APPEND__';
if (is_array($currentArray) && !is_array($newArray)) {
/** @var T */
return $currentArray;
} else if (!is_array($currentArray) && is_array($newArray)) {
return $newArray;
/** @var T */
return $newArray; /** @phpstan-ignore-line */
} else if (
(!is_array($currentArray) || empty($currentArray)) &&
(!is_array($newArray) || empty($newArray))
) {
/** @var T */
return [];
}
@@ -482,26 +486,28 @@ class Util
$elementArr[] = &$elem;
for ($i = 0; $i <= $keyChainCount; $i++) {
if (is_array($elem) && array_key_exists($keyArr[$i], $elem)) {
if ($i == $keyChainCount) {
unset($elem[$keyArr[$i]]);
if (!array_key_exists($keyArr[$i], $elem)) {
continue;
}
if ($unsetParentEmptyArray) {
for ($j = count($elementArr); $j > 0; $j--) {
$pointer =& $elementArr[$j];
if ($i == $keyChainCount) {
unset($elem[$keyArr[$i]]);
if (is_array($pointer) && empty($pointer)) {
$previous =& $elementArr[$j - 1];
unset($previous[$keyArr[$j - 1]]);
}
if ($unsetParentEmptyArray) {
for ($j = count($elementArr); $j > 0; $j--) {
$pointer =& $elementArr[$j];
if (empty($pointer)) {
$previous =& $elementArr[$j - 1];
unset($previous[$keyArr[$j - 1]]);
}
}
} else if (is_array($elem[$keyArr[$i]])) {
$elem = &$elem[$keyArr[$i]];
$elementArr[] = &$elem;
}
} else if (is_array($elem[$keyArr[$i]])) {
$elem = &$elem[$keyArr[$i]];
$elementArr[] = &$elem;
}
}
}

View File

@@ -48,6 +48,7 @@ use Espo\Core\Utils\Metadata;
use Espo\Entities\Attachment;
use GdImage;
use RuntimeException;
use Throwable;
class Image implements EntryPoint
@@ -258,6 +259,10 @@ class Image implements EntryPoint
}
}
if ($targetWidth < 1 || $targetHeight < 1) {
throw new RuntimeException("No width or height.");
}
$targetImage = imagecreatetruecolor($targetWidth, $targetHeight);
if ($targetImage === false) {
@@ -378,7 +383,7 @@ class Image implements EntryPoint
$orientation = $this->getOrientation($filePath);
if ($orientation) {
$angle = array_values([0, 0, 0, 180, 0, 0, -90, 0, 90])[$orientation];
$angle = [0, 0, 0, 180, 0, 0, -90, 0, 90][$orientation];
$targetImage = imagerotate($targetImage, $angle, 0) ?: $targetImage;
}

View File

@@ -60,7 +60,7 @@ class CampaignTrackOpened implements EntryPoint
{
$id = $request->getQueryParam('id');
if (!$id || !is_string($id)) {
if (!$id) {
throw new BadRequest("No id.");
}

View File

@@ -72,7 +72,7 @@ class CampaignUrl implements EntryPoint
$hash = $request->getQueryParam('hash') ?? null;
$uid = $request->getQueryParam('uid') ?? null;
if (!$trackingUrlId || !is_string($trackingUrlId)) {
if (!$trackingUrlId) {
throw new BadRequest("No tracking URL ID.");
}
@@ -88,7 +88,7 @@ class CampaignUrl implements EntryPoint
} else if ($uid && $hash) {
$this->processWithUniqueId($trackingUrl, $uid, $hash);
} else {
if (!$queueItemId || !is_string($queueItemId)) {
if (!$queueItemId) {
throw new BadRequest("No item ID.");
}

View File

@@ -65,7 +65,7 @@ class SendEmailReminders implements JobDataLess
$maxPortionSize = $this->config->get('emailReminderPortionSize') ?? self::MAX_PORTION_SIZE;
$collection = $this->entityManager
->getRDBRepository(Reminder::ENTITY_TYPE)
->getRDBRepositoryByClass(Reminder::class)
->where([
'type' => Reminder::TYPE_EMAIL,
'remindAt<=' => $now,
@@ -74,7 +74,7 @@ class SendEmailReminders implements JobDataLess
->limit(0, $maxPortionSize)
->find();
if (is_countable($collection) && count($collection) === 0) {
if (count($collection) === 0) {
return;
}

View File

@@ -32,20 +32,15 @@ namespace Espo\Modules\Crm\Tools\Case\Distribution;
use Espo\Modules\Crm\Entities\CaseObj;
use Espo\ORM\EntityManager;
use Espo\Core\Utils\Metadata;
use Espo\Entities\User;
use Espo\Entities\Team;
class LeastBusy
{
private EntityManager $entityManager;
private Metadata $metadata;
public function __construct(EntityManager $entityManager, Metadata $metadata)
{
$this->entityManager = $entityManager;
$this->metadata = $metadata;
}
public function __construct(
private EntityManager $entityManager,
private Metadata $metadata
) {}
public function getUser(Team $team, ?string $targetUserPosition = null): ?User
{
@@ -64,7 +59,7 @@ class LeastBusy
->order('id')
->find();
if (is_countable($userList) && count($userList) == 0) {
if (count($userList) === 0) {
return null;
}

View File

@@ -31,18 +31,13 @@ namespace Espo\Modules\Crm\Tools\Case\Distribution;
use Espo\Entities\User;
use Espo\Entities\Team;
use Espo\Modules\Crm\Entities\CaseObj;
use Espo\ORM\EntityManager;
class RoundRobin
{
private EntityManager $entityManager;
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
public function __construct(private EntityManager $entityManager)
{}
public function getUser(Team $team, ?string $targetUserPosition = null): ?User
{
@@ -55,13 +50,13 @@ class RoundRobin
}
$userList = $this->entityManager
->getRDBRepository(Team::ENTITY_TYPE)
->getRDBRepositoryByClass(Team::class)
->getRelation($team, 'users')
->where($where)
->order('id')
->find();
if (is_countable($userList) && count($userList) == 0) {
if (count($userList) === 0) {
return null;
}

View File

@@ -55,7 +55,6 @@ use Espo\Modules\Crm\Entities\Opportunity;
use Espo\Modules\Crm\Tools\Lead\Convert\Params;
use Espo\Modules\Crm\Tools\Lead\Convert\Values;
use Espo\ORM\Collection;
use Espo\ORM\Entity;
use Espo\ORM\EntityManager;
use Espo\ORM\Name\Attribute;
use Espo\Repositories\Attachment as AttachmentRepository;
@@ -281,7 +280,7 @@ class ConvertService
}
/**
* @param Entity[] $duplicateList
* @param object[] $duplicateList
* @throws Forbidden
* @throws BadRequest
* @throws Conflict
@@ -334,7 +333,7 @@ class ConvertService
}
/**
* @param Entity[] $duplicateList
* @param object[] $duplicateList
* @throws Forbidden
* @throws BadRequest
* @throws Conflict
@@ -391,7 +390,7 @@ class ConvertService
}
/**
* @param Entity[] $duplicateList
* @param object[] $duplicateList
* @throws Forbidden
* @throws BadRequest
* @throws Conflict